kspread

selection.cpp
1/* This file is part of the KDE project
2 Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3 Copyright (C) 2005-2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include <tqregexp.h>
22
23#include <kdebug.h>
24
25#include "kspread_canvas.h"
26#include "kspread_cell.h"
27#include "kspread_doc.h"
28#include "kspread_editors.h"
29#include "kspread_sheet.h"
30#include "kspread_view.h"
31#include "kspread_util.h"
32
33#include "selection.h"
34
35// TODO Stefan: Substract points in selections
36// TODO Stefan: KPart signal (kspread_events.h)
37
38using namespace KSpread;
39
40/***************************************************************************
41 class Selection::Private
42****************************************************************************/
43
44class Selection::Private
45{
46public:
47 Private(View *v)
48 {
49 view = v;
50 sheet = 0;
51 anchor = TQPoint(1,1);
52 cursor = TQPoint(1,1);
53 marker = TQPoint(1,1);
54
55 colors.push_back(TQt::red);
56 colors.push_back(TQt::blue);
57 colors.push_back(TQt::magenta);
58 colors.push_back(TQt::darkRed);
59 colors.push_back(TQt::darkGreen);
60 colors.push_back(TQt::darkMagenta);
61 colors.push_back(TQt::darkCyan);
62 colors.push_back(TQt::darkYellow);
63
64 multipleSelection = false;
65
66 activeElement = Iterator();
67 activeSubRegionStart = 0;
68 activeSubRegionLength = 0;
69 }
70
71 View* view;
72 Sheet* sheet;
73 TQPoint anchor;
74 TQPoint cursor;
75 TQPoint marker;
76 TQValueList<TQColor> colors;
77
78 bool multipleSelection : 1;
79
80 Selection::Iterator activeElement;
81 uint activeSubRegionStart;
82 uint activeSubRegionLength;
83};
84
85/***************************************************************************
86 class Selection
87****************************************************************************/
88namespace KSpread {
89
90Selection::Selection(View *view)
91 : TQObject(view), Region(1,1)
92{
93 d = new Private(view);
94 d->activeSubRegionStart = 0;
95 d->activeSubRegionLength = 1;
96}
97
98Selection::Selection(const Selection& selection)
99 : TQObject(selection.d->view), Region()
100{
101/* kdDebug() << k_funcinfo << endl;*/
102 d = new Private(selection.d->view);
103 d->sheet = selection.d->sheet;
104 d->activeSubRegionStart = 0;
105 d->activeSubRegionLength = cells().count();
106}
107
108Selection::~Selection()
109{
110 delete d;
111}
112
113void Selection::initialize(const TQPoint& point, Sheet* sheet)
114{
115 if (!util_isPointValid(point))
116 return;
117
118 if (!d->view->activeSheet())
119 return;
120
121 if (!sheet)
122 {
123 if (d->sheet)
124 {
125 sheet = d->sheet;
126 }
127 else
128 {
129 sheet = d->view->activeSheet();
130 }
131 }
132
133 Region changedRegion(*this);
134 changedRegion.add(extendToMergedAreas(TQRect(d->anchor,d->marker)));
135
136 TQPoint topLeft(point);
137 Cell* cell = d->view->activeSheet()->cellAt(point);
138 if (cell->isObscured() && cell->isPartOfMerged())
139 {
140 cell = cell->obscuringCells().first();
141 topLeft = TQPoint(cell->column(), cell->row());
142 }
143
144 d->anchor = topLeft;
145 d->cursor = point;
146 d->marker = topLeft;
147
148 fixSubRegionDimension(); // TODO remove this sanity check
149 Iterator it = cells().begin() += d->activeSubRegionStart + d->activeSubRegionLength;
150 if (it != insert(it, topLeft, sheet/*, true*/))
151 {
152 // if the point was inserted
153 clearSubRegion();
154 }
155 Element* element = *(cells().begin() += d->activeSubRegionStart);
156 // we end up with one element in the subregion
157 d->activeSubRegionLength = 1;
158 if (element && element->type() == Element::Point)
159 {
160 Point* point = static_cast<Point*>(element);
161 point->setColor(d->colors[cells().size() % d->colors.size()]);
162 }
163 else if (element && element->type() == Element::Range)
164 {
165 Range* range = static_cast<Range*>(element);
166 range->setColor(d->colors[cells().size() % d->colors.size()]);
167 }
168
169 d->activeElement = cells().begin();
170
171 if (changedRegion == *this)
172 {
173 emit changed(Region(topLeft, sheet));
174 return;
175 }
176 changedRegion.add(topLeft, sheet);
177
178 emit changed(changedRegion);
179}
180
181void Selection::initialize(const TQRect& range, Sheet* sheet)
182{
183 if (!util_isRectValid(range) || ( range == TQRect(0,0,1,1) ))
184 return;
185
186 if (!sheet)
187 {
188 if (d->sheet)
189 {
190 sheet = d->sheet;
191 }
192 else
193 {
194 sheet = d->view->activeSheet();
195 }
196 }
197
198 Region changedRegion(*this);
199 changedRegion.add(extendToMergedAreas(TQRect(d->anchor,d->marker)));
200
201 TQPoint topLeft(range.topLeft());
202 Cell* cell = d->view->activeSheet()->cellAt(topLeft);
203 if (cell->isObscured() && cell->isPartOfMerged())
204 {
205 cell = cell->obscuringCells().first();
206 topLeft = TQPoint(cell->column(), cell->row());
207 }
208
209 TQPoint bottomRight(range.bottomRight());
210 cell = d->view->activeSheet()->cellAt(bottomRight);
211 if (cell->isObscured() && cell->isPartOfMerged())
212 {
213 cell = cell->obscuringCells().first();
214 bottomRight = TQPoint(cell->column(), cell->row());
215 }
216
217 d->anchor = topLeft;
218 d->cursor = bottomRight;
219 d->marker = bottomRight;
220
221 fixSubRegionDimension(); // TODO remove this sanity check
222 Iterator it = cells().begin() += d->activeSubRegionStart + d->activeSubRegionLength;
223 if (it != insert(it, TQRect(topLeft, bottomRight), sheet/*, true*/))
224 {
225 // if the range was inserted
226 clearSubRegion();
227 }
228
229 Element* element = *(cells().begin() += d->activeSubRegionStart);
230 // we end up with one element in the subregion
231 d->activeSubRegionLength = 1;
232 if (element && element->type() == Element::Point)
233 {
234 Point* point = static_cast<Point*>(element);
235 point->setColor(d->colors[cells().size() % d->colors.size()]);
236 }
237 else if (element && element->type() == Element::Range)
238 {
239 Range* range = static_cast<Range*>(element);
240 range->setColor(d->colors[cells().size() % d->colors.size()]);
241 }
242
243 d->activeElement = cells().begin();
244
245 if (changedRegion == *this)
246 {
247 return;
248 }
249 changedRegion.add(TQRect(topLeft, bottomRight), sheet);
250
251 emit changed(changedRegion);
252}
253
254void Selection::initialize(const Region& region, Sheet* sheet)
255{
256 if (!region.isValid())
257 return;
258
259 if (!sheet)
260 {
261 if (d->sheet)
262 {
263 sheet = d->sheet;
264 }
265 else
266 {
267 sheet = d->view->activeSheet();
268 }
269 }
270
271 Region changedRegion(*this);
272 changedRegion.add(extendToMergedAreas(TQRect(d->anchor,d->marker)));
273
274 // TODO Stefan: handle subregion insertion
275 // TODO Stefan: handle obscured cells correctly
276 clear();
277 Element* element = add(region);
278 if (element && element->type() == Element::Point)
279 {
280 Point* point = static_cast<Point*>(element);
281 point->setColor(d->colors[cells().size() % d->colors.size()]);
282 }
283 else if (element && element->type() == Element::Range)
284 {
285 Range* range = static_cast<Range*>(element);
286 range->setColor(d->colors[cells().size() % d->colors.size()]);
287 }
288
289 TQPoint topLeft(cells().last()->rect().normalize().topLeft());
290 Cell* cell = d->view->activeSheet()->cellAt(topLeft);
291 if (cell->isObscured() && cell->isPartOfMerged())
292 {
293 cell = cell->obscuringCells().first();
294 topLeft = TQPoint(cell->column(), cell->row());
295 }
296
297 TQPoint bottomRight(cells().last()->rect().normalize().bottomRight());
298 cell = d->view->activeSheet()->cellAt(bottomRight);
299 if (cell->isObscured() && cell->isPartOfMerged())
300 {
301 cell = cell->obscuringCells().first();
302 bottomRight = TQPoint(cell->column(), cell->row());
303 }
304
305 d->anchor = topLeft;
306 d->cursor = topLeft;
307 d->marker = bottomRight;
308
309 d->activeElement = --cells().end();
310 d->activeSubRegionStart = 0;
311 d->activeSubRegionLength = cells().count();
312
313 if (changedRegion == *this)
314 {
315 return;
316 }
317 changedRegion.add( region );
318
319 emit changed(changedRegion);
320}
321
322void Selection::update()
323{
324 emit changed(*this);
325}
326
327void Selection::update(const TQPoint& point)
328{
329 uint count = cells().count();
330
331 if (cells().isEmpty())
332 {
333 add(point);
334 d->activeSubRegionLength += cells().count() - count;
335 return;
336 }
337 if (d->activeElement == cells().end())
338 {
339 // we're not empty, so this will not become again end()
340 d->activeElement--;
341 }
342
343 Sheet* sheet = (*d->activeElement)->sheet();
344 if (sheet != d->view->activeSheet())
345 {
346 extend(point);
347 d->activeSubRegionLength += cells().count() - count;
348 return;
349 }
350
351 TQPoint topLeft(point);
352 Cell* cell = d->view->activeSheet()->cellAt(point);
353 if (cell->isObscured() && cell->isPartOfMerged())
354 {
355 cell = cell->obscuringCells().first();
356 topLeft = TQPoint(cell->column(), cell->row());
357 }
358
359 if (topLeft == d->marker)
360 {
361 return;
362 }
363
364 TQRect area1 = (*d->activeElement)->rect().normalize();
365 TQRect newRange = extendToMergedAreas(TQRect(d->anchor, topLeft));
366
367 Element* oldElement = *d->activeElement;
368 // returns iterator to the next element or end
369 Iterator it = cells().remove(d->activeElement);
370 delete oldElement;
371 // returns iterator to the new element (before 'it') or 'it'
372 d->activeElement = insert(it, newRange, sheet, d->multipleSelection);
373 d->activeSubRegionLength += cells().count() - count;
374
375 // The call to insert() above can just return the iterator which has been
376 // passed in. This may be cells.end(), if the old active element was the
377 // iterator to the list's end (!= last element). So attempts to dereference
378 // it will fail.
379 if (d->activeElement == cells().end())
380 {
381 d->activeElement--;
382 }
383
384 TQRect area2 = (*d->activeElement)->rect().normalize();
385 Region changedRegion;
386
387 bool newLeft = area1.left() != area2.left();
388 bool newTop = area1.top() != area2.top();
389 bool newRight = area1.right() != area2.right();
390 bool newBottom = area1.bottom() != area2.bottom();
391
392 /* first, calculate some numbers that we'll use a few times */
393 int farLeft = TQMIN(area1.left(), area2.left());
394 int innerLeft = TQMAX(area1.left(), area2.left());
395
396 int farTop = TQMIN(area1.top(), area2.top());
397 int innerTop = TQMAX(area1.top(), area2.top());
398
399 int farRight = TQMAX(area1.right(), area2.right());
400 int innerRight = TQMIN(area1.right(), area2.right());
401
402 int farBottom = TQMAX(area1.bottom(), area2.bottom());
403 int innerBottom = TQMIN(area1.bottom(), area2.bottom());
404
405 if (newLeft)
406 {
407 changedRegion.add(TQRect(TQPoint(farLeft, innerTop),
408 TQPoint(innerLeft-1, innerBottom)));
409 if (newTop)
410 {
411 changedRegion.add(TQRect(TQPoint(farLeft, farTop),
412 TQPoint(innerLeft-1, innerTop-1)));
413 }
414 if (newBottom)
415 {
416 changedRegion.add(TQRect(TQPoint(farLeft, innerBottom+1),
417 TQPoint(innerLeft-1, farBottom)));
418 }
419 }
420
421 if (newTop)
422 {
423 changedRegion.add(TQRect(TQPoint(innerLeft, farTop),
424 TQPoint(innerRight, innerTop-1)));
425 }
426
427 if (newRight)
428 {
429 changedRegion.add(TQRect(TQPoint(innerRight+1, innerTop),
430 TQPoint(farRight, innerBottom)));
431 if (newTop)
432 {
433 changedRegion.add(TQRect(TQPoint(innerRight+1, farTop),
434 TQPoint(farRight, innerTop-1)));
435 }
436 if (newBottom)
437 {
438 changedRegion.add(TQRect(TQPoint(innerRight+1, innerBottom+1),
439 TQPoint(farRight, farBottom)));
440 }
441 }
442
443 if (newBottom)
444 {
445 changedRegion.add(TQRect(TQPoint(innerLeft, innerBottom+1),
446 TQPoint(innerRight, farBottom)));
447 }
448
449 d->marker = topLeft;
450 d->cursor = point;
451
452 emit changed(changedRegion);
453}
454
455void Selection::extend(const TQPoint& point, Sheet* sheet)
456{
457 if (!util_isPointValid(point))
458 return;
459
460 if (isEmpty())
461 {
462 initialize(point, sheet);
463 return;
464 }
465 if (d->activeElement == cells().end())
466 {
467 // we're not empty, so this will not become again end()
468 d->activeElement--;
469 }
470
471 if (!sheet)
472 {
473 if (d->sheet)
474 {
475 sheet = d->sheet;
476 }
477 else
478 {
479 sheet = d->view->activeSheet();
480 }
481 }
482
483 Region changedRegion = Region(extendToMergedAreas(TQRect(d->marker,d->marker)));
484
485 TQPoint topLeft(point);
486 Cell* cell = d->view->activeSheet()->cellAt(point);
487 if (cell->isObscured() && cell->isPartOfMerged())
488 {
489 cell = cell->obscuringCells().first();
490 topLeft = TQPoint(cell->column(), cell->row());
491 }
492
493 uint count = cells().count();
494 if (d->multipleSelection)
495 {
496 d->activeElement = insert(++d->activeElement, point, sheet, false);
497 }
498 else
499 {
500 eor(topLeft, sheet);
501 d->activeElement = --cells().end();
502 }
503 d->anchor = (*d->activeElement)->rect().topLeft();
504 d->cursor = (*d->activeElement)->rect().bottomRight();
505 d->marker = d->cursor;
506
507 d->activeSubRegionLength += cells().count() - count;
508
509 changedRegion.add(topLeft, sheet);
510 changedRegion.add(*this);
511
512 emit changed(changedRegion);
513}
514
515void Selection::extend(const TQRect& range, Sheet* sheet)
516{
517 //See comment in Selection::initialize(const TQRect& range, Sheet* sheet)
518 if (!util_isRectValid(range) || (range == TQRect(0,0,1,1)))
519 return;
520
521 if (isEmpty())
522 {
523 initialize(range, sheet);
524 return;
525 }
526 if (d->activeElement == cells().end())
527 {
528 // we're not empty, so this will not become again end()
529 d->activeElement--;
530 }
531
532 if (!sheet)
533 {
534 if (d->sheet)
535 {
536 sheet = d->sheet;
537 }
538 else
539 {
540 sheet = d->view->activeSheet();
541 }
542 }
543
544 TQPoint topLeft(range.topLeft());
545 Cell* cell = d->view->activeSheet()->cellAt(topLeft);
546 if (cell->isObscured() && cell->isPartOfMerged())
547 {
548 cell = cell->obscuringCells().first();
549 topLeft = TQPoint(cell->column(), cell->row());
550 }
551
552 TQPoint bottomRight(range.bottomRight());
553 cell = d->view->activeSheet()->cellAt(bottomRight);
554 if (cell->isObscured() && cell->isPartOfMerged())
555 {
556 cell = cell->obscuringCells().first();
557 bottomRight = TQPoint(cell->column(), cell->row());
558 }
559
560 d->anchor = topLeft;
561 d->cursor = topLeft;
562 d->marker = bottomRight;
563
564 uint count = cells().count();
565 Element* element;
566 if (d->multipleSelection)
567 {
568 d->activeElement = insert(++d->activeElement, extendToMergedAreas(TQRect(topLeft, bottomRight)).normalize(), sheet, false);
569 element = (d->activeElement == cells().end()) ? 0 : *d->activeElement;
570 }
571 else
572 {
573 element = add(extendToMergedAreas(TQRect(topLeft, bottomRight)).normalize(), sheet);
574 d->activeElement = --cells().end();
575 }
576 if (element && element->type() == Element::Point)
577 {
578 Point* point = static_cast<Point*>(element);
579 point->setColor(d->colors[cells().size() % d->colors.size()]);
580 }
581 else if (element && element->type() == Element::Range)
582 {
583 Range* range = static_cast<Range*>(element);
584 range->setColor(d->colors[cells().size() % d->colors.size()]);
585 }
586
587 d->activeSubRegionLength += cells().count() - count;
588
589 emit changed(*this);
590}
591
592void Selection::extend(const Region& region)
593{
594 if (!region.isValid())
595 return;
596
597 uint count = cells().count();
598 ConstIterator end(region.constEnd());
599 for (ConstIterator it = region.constBegin(); it != end; ++it)
600 {
601 Element *element = *it;
602 if (!element) continue;
603 if (element->type() == Element::Point)
604 {
605 Point* point = static_cast<Point*>(element);
606 extend(point->pos(), element->sheet());
607 }
608 else
609 {
610 extend(element->rect(), element->sheet());
611 }
612 }
613
614 d->activeSubRegionLength += cells().count() - count;
615
616 emit changed(*this);
617}
618
619Selection::Element* Selection::eor(const TQPoint& point, Sheet* sheet)
620{
621 if (isSingular())
622 {
623 return Region::add(point, sheet);
624 }
625 return Region::eor(point, sheet);
626}
627
628const TQPoint& Selection::anchor() const
629{
630 return d->anchor;
631}
632
633const TQPoint& Selection::cursor() const
634{
635 return d->cursor;
636}
637
638const TQPoint& Selection::marker() const
639{
640 return d->marker;
641}
642
643bool Selection::isSingular() const
644{
645 return Region::isSingular();
646}
647
648TQRect Selection::selectionHandleArea() const
649{
650 int column, row;
651
652 // complete rows/columns are selected, use the marker.
653 if (isColumnOrRowSelected())
654 {
655 column = d->marker.x();
656 row = d->marker.y();
657 }
658 else
659 {
660 column = lastRange().right();
661 row = lastRange().bottom();
662 }
663 const Cell* cell = d->view->activeSheet()->cellAt(column, row);
664
665 double xpos = d->view->activeSheet()->dblColumnPos( column );
666 double ypos = d->view->activeSheet()->dblRowPos( row );
667 double width = cell->dblWidth( column );
668 double height = cell->dblHeight( row );
669
670 TQPoint rightBottom( d->view->doc()->zoomItX( xpos + width ),
671 d->view->doc()->zoomItY( ypos + height ) );
672
673 TQRect handle( ( rightBottom.x() - 2 ),
674 ( rightBottom.y() - 2 ),
675 ( 5 ),
676 ( 5 ) );
677 return handle;
678}
679
680TQString Selection::name(Sheet* sheet) const
681{
682 return Region::name(sheet ? sheet : d->sheet);
683}
684
685void Selection::setSheet(Sheet* sheet)
686{
687 d->sheet = sheet;
688}
689
690Sheet* Selection::sheet() const
691{
692 return d->sheet;
693}
694
695void Selection::setActiveElement(const TQPoint& point)
696{
697 uint counter = 0;
698 Iterator end = cells().end();
699 for (Iterator it = cells().begin(); it != end; ++it)
700 {
701 TQRect range = (*it)->rect();
702 if (range.topLeft() == point || range.bottomRight() == point)
703 {
704 d->anchor = range.topLeft();
705 d->cursor = range.bottomRight();
706 d->marker = range.bottomRight();
707 d->activeElement = it;
708 d->activeSubRegionStart = counter;
709 d->activeSubRegionLength = 1;
710 if (d->view->canvasWidget()->editor())
711 {
712 d->view->canvasWidget()->editor()->setCursorToRange(counter);
713 }
714 }
715 counter++;
716 }
717}
718
719void Selection::setActiveElement(uint pos)
720{
721 if (pos >= cells().count())
722 {
723 kdDebug() << "Selection::setActiveElement: position exceeds list" << endl;
724 d->activeElement = cells().begin();
725 return;
726 }
727
728 Iterator it = cells().begin() += pos;
729 TQRect range = (*it)->rect();
730 d->anchor = range.topLeft();
731 d->cursor = range.bottomRight();
732 d->marker = range.bottomRight();
733 d->activeElement = it;
734}
735
736Region::Element* Selection::activeElement() const
737{
738 return (d->activeElement == cells().end()) ? 0 : *d->activeElement;
739}
740
741void Selection::clear()
742{
743 d->activeSubRegionStart = 0;
744 d->activeSubRegionLength = 0;
746 d->activeElement = cells().begin();
747}
748
749void Selection::clearSubRegion()
750{
751 if (isEmpty())
752 {
753 return;
754 }
755// kdDebug() << *this << endl;
756// kdDebug() << d->activeSubRegionStart << endl;
757// kdDebug() << d->activeSubRegionLength << endl;
758
759 Iterator it = cells().begin();
760 Iterator end = it += d->activeSubRegionStart;
761 end += d->activeSubRegionLength;
762 while (it != end)
763 {
764/* kdDebug() << (*it)->name() << endl;*/
765 delete *it;
766 it = cells().remove(it);
767 }
768 d->activeSubRegionLength = 0;
769 d->activeElement = it;
770/* kdDebug() << "ENDE" << endl;*/
771}
772
773void Selection::fixSubRegionDimension()
774{
775 if (d->activeSubRegionStart > cells().count())
776 {
777 kdDebug() << "Selection::fixSubRegionDimension: start position exceeds list" << endl;
778 d->activeSubRegionStart = 0;
779 d->activeSubRegionLength = cells().count();
780 return;
781 }
782 if (d->activeSubRegionStart + d->activeSubRegionLength > cells().count())
783 {
784 kdDebug() << "Selection::fixSubRegionDimension: length exceeds list" << endl;
785 d->activeSubRegionLength = cells().count() - d->activeSubRegionStart;
786 return;
787 }
788}
789
790void Selection::setActiveSubRegion(uint start, uint length)
791{
792// kdDebug() << k_funcinfo << endl;
793 d->activeSubRegionStart = start;
794 d->activeSubRegionLength = length;
795 fixSubRegionDimension();
796 d->activeElement = cells().begin() += d->activeSubRegionStart;
797}
798
799TQString Selection::activeSubRegionName() const
800{
801// kdDebug() << k_funcinfo << endl;
802// kdDebug() << *this << endl;
803// kdDebug() << "start = " << d->activeSubRegionStart << ", len = " << d->activeSubRegionLength << endl;
804
805 TQStringList names;
806 Iterator it = cells().begin();
807 it += d->activeSubRegionStart;
808 Iterator end = it;
809 end += d->activeSubRegionLength;
810 while (it != end)
811 {
812 names += (*it++)->name(d->sheet);
813 }
814/* kdDebug() << "ENDE" << endl;*/
815 return names.isEmpty() ? "" : names.join(";");
816}
817
818void Selection::setMultipleSelection(bool state)
819{
820 d->multipleSelection = state;
821}
822
823const TQValueList<TQColor>& Selection::colors() const
824{
825 return d->colors;
826}
827
828TQRect Selection::lastRange(bool extend) const
829{
830 TQRect selection = TQRect(d->anchor, d->marker).normalize();
831 return extend ? extendToMergedAreas(selection) : selection;
832}
833
834TQRect Selection::selection(bool extend) const
835{
836 TQRect selection = TQRect(d->anchor, d->marker).normalize();
837 return extend ? extendToMergedAreas(selection) : selection;
838}
839
840TQRect Selection::extendToMergedAreas(TQRect area) const
841{
842 if (!d->view->activeSheet())
843 return area;
844
845 area = area.normalize(); // TODO Stefan: avoid this
846 const Cell *cell = d->view->activeSheet()->cellAt(area.left(), area.top());
847
848 if( Region::Range(area).isColumn() || Region::Range(area).isRow() )
849 {
850 return area;
851 }
852 else if ( !(cell->isObscured() && cell->isPartOfMerged()) &&
853 (cell->mergedXCells() + 1) >= area.width() &&
854 (cell->mergedYCells() + 1) >= area.height())
855 {
856 /* if just a single cell is selected, we need to merge even when
857 the obscuring isn't forced. But only if this is the cell that
858 is doing the obscuring -- we still want to be able to click on a cell
859 that is being obscured.
860 */
861 area.setWidth(cell->mergedXCells() + 1);
862 area.setHeight(cell->mergedYCells() + 1);
863 }
864 else
865 {
866 int top=area.top();
867 int left=area.left();
868 int bottom=area.bottom();
869 int right=area.right();
870 for ( int x = area.left(); x <= area.right(); x++ )
871 for ( int y = area.top(); y <= area.bottom(); y++ )
872 {
873 cell = d->view->activeSheet()->cellAt( x, y );
874 if( cell->doesMergeCells())
875 {
876 right=TQMAX(right,cell->mergedXCells()+x);
877 bottom=TQMAX(bottom,cell->mergedYCells()+y);
878 }
879 else if ( cell->isObscured() && cell->isPartOfMerged() )
880 {
881 cell = cell->obscuringCells().first();
882 left=TQMIN(left,cell->column());
883 top=TQMIN(top,cell->row());
884 bottom=TQMAX(bottom,cell->row() + cell->mergedYCells());
885 right=TQMAX(right,cell->column() + cell->mergedXCells());
886 }
887 }
888
889 area.setCoords(left,top,right,bottom);
890 }
891 return area;
892}
893
894Selection::Region::Point* Selection::createPoint(const TQPoint& point) const
895{
896 return new Point(point);
897}
898
899Selection::Region::Point* Selection::createPoint(const TQString& string) const
900{
901 return new Point(string);
902}
903
904Selection::Region::Point* Selection::createPoint(const Point& point) const
905{
906 return new Point(point);
907}
908
909Selection::Region::Range* Selection::createRange(const TQRect& rect) const
910{
911 return new Range(rect);
912}
913
914Selection::Region::Range* Selection::createRange(const TQString& string) const
915{
916 return new Range(string);
917}
918
919Selection::Region::Range* Selection::createRange(const Range& range) const
920{
921 return new Range(range);
922}
923
924/***************************************************************************
925 class Point
926****************************************************************************/
927
928Selection::Point::Point(const TQPoint& point)
929 : Region::Point(point),
930 m_color(TQt::black),
931 m_columnFixed(false),
932 m_rowFixed(false)
933{
934}
935
936Selection::Point::Point(const TQString& string)
937 : Region::Point(string),
938 m_color(TQt::black),
939 m_columnFixed(false),
940 m_rowFixed(false)
941{
942 if (!isValid())
943 {
944 return;
945 }
946
947 uint p = 0;
948 // Fixed?
949 if (string[p++] == '$')
950 {
951 m_columnFixed = true;
952 }
953
954 //search for the first character != text
955 int result = string.find( TQRegExp("[^A-Za-z]+"), p );
956 if (string[result] == '$')
957 {
958 m_rowFixed = true;
959 }
960}
961
962/***************************************************************************
963 class Range
964****************************************************************************/
965
966Selection::Range::Range(const TQRect& range)
967 : Region::Range(range),
968 m_color(TQt::black),
969 m_leftFixed(false),
970 m_rightFixed(false),
971 m_topFixed(false),
972 m_bottomFixed(false)
973{
974}
975
976Selection::Range::Range(const TQString& string)
977 : Region::Range(string),
978 m_color(TQt::black),
979 m_leftFixed(false),
980 m_rightFixed(false),
981 m_topFixed(false),
982 m_bottomFixed(false)
983{
984 if (!isValid())
985 {
986 return;
987 }
988
989 int delimiterPos = string.find(':');
990 if (delimiterPos == -1)
991 {
992 return;
993 }
994
995 Selection::Point ul(string.left(delimiterPos));
996 Selection::Point lr(string.mid(delimiterPos + 1));
997
998 if (!ul.isValid() || !lr.isValid())
999 {
1000 return;
1001 }
1002 m_leftFixed = ul.columnFixed();
1003 m_rightFixed = lr.columnFixed();
1004 m_topFixed = ul.rowFixed();
1005 m_bottomFixed = lr.rowFixed();
1006}
1007
1008} // namespace KSpread
1009#include "selection.moc"
For every cell in the spread sheet there is a Cell object.
double dblHeight(int _row=-1, const Canvas *_canvas=0L) const
int row() const
Returns the cell's row.
TQValueList< Cell * > obscuringCells() const
bool isObscured() const
bool doesMergeCells() const
int column() const
Returns the cell's column.
int mergedXCells() const
double dblWidth(int _col=-1, const Canvas *_canvas=0L) const
bool isPartOfMerged() const
If this cell is part of a merged cell, then the marker may never reside on this cell.
int mergedYCells() const
Represents the position of a single cell in a workbook.
Represents a region within a workbook.
Base class for region elements, which can be points or ranges.
Definition region.h:325
A range in a region.
Definition region.h:411
The one for all class for points and ranges.
Definition region.h:44
Element * add(const TQPoint &point, Sheet *sheet=0)
Adds the point point to this region.
Definition region.cpp:245
virtual void clear()
Deletes all elements of the region.
Definition region.cpp:600
bool isSingular() const
Definition region.cpp:215
bool isValid() const
Definition region.cpp:202
TQString name(Sheet *originSheet=0) const
Definition region.cpp:233
virtual Element * eor(const TQPoint &point, Sheet *sheet=0)
Definition region.cpp:330
The View class displays a KSpread document.
The KSpread namespace.
Definition commands.h:39