1 /* This file is part of the KDE project
2 Copyright 2010 Marijn Kruisselbrink <mkruisselbrink@kde.org>
3 Copyright 2005-2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Library General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program 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
13 GNU 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 program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20
21 #ifndef CALLIGRA_SHEETS_REGION
22 #define CALLIGRA_SHEETS_REGION
23
24 #include <QList>
25 #include <QRect>
26 #include <QSet>
27 #include <QSharedDataPointer>
28 #include <QString>
29
30 #include "SheetsDebug.h"
31 #include "sheets_odf_export.h"
32
qHash(const QPoint & point)33 inline uint qHash(const QPoint& point)
34 {
35 return (static_cast<uint>(point.x()) << 16) + static_cast<uint>(point.y());
36 }
37
38 namespace Calligra
39 {
40 namespace Sheets
41 {
42 class Cell;
43 class Map;
44 class Sheet;
45
46 /**
47 * \class Region
48 * \brief The one for all class for points and ranges.
49 * \author Stefan Nikolaus <stefan.nikolaus@kdemail.net>
50 * \since 1.5
51 */
52 class CALLIGRA_SHEETS_ODF_EXPORT Region
53 {
54 public:
55 class Element;
56 class Point;
57 class Range;
58
59 /**
60 * Constructor.
61 * Creates an empty region.
62 */
63 Region();
64
65 /**
66 * Constructor.
67 * Creates a region consisting of a point.
68 * @param point the point's location
69 * @param sheet the sheet the point belongs to
70 */
71 explicit Region(const QPoint& point, Sheet* sheet = 0);
72
73 /**
74 * Constructor.
75 * Creates a region consisting of a range.
76 * @param range the range's location
77 * @param sheet the sheet the range belongs to
78 */
79 explicit Region(const QRect& range, Sheet* sheet = 0);
80
81 /**
82 * Constructor.
83 * Creates a region consisting of the region defined in @p expression .
84 * @param expression a string representing the region (e.g. "A1:B3")
85 * @param map used to determine the sheet, if it's named in the string
86 * @param sheet the fallback sheet, if \p expression does not contain one
87 */
88 explicit Region(const QString& expression, const Map* map = 0, Sheet* sheet = 0);
89
90 /**
91 * Copy Constructor.
92 * Creates a copy of the region.
93 * @param region the region to copy
94 */
95 Region(const Region& region);
96
97 /**
98 * Constructor.
99 * Creates a region consisting of a point.
100 * @param col the column of the point
101 * @param row the row of the point
102 * @param sheet the sheet the point belongs to
103 */
104 Region(int col, int row, Sheet* sheet = 0);
105
106 /**
107 * Constructor.
108 * Creates a region consisting of a range at the location
109 * @param col the column of the range' starting point
110 * @param row the row of the range' starting point
111 * @param width the width of the range
112 * @param height the height of the range
113 * @param sheet the sheet the range belongs to
114 */
115 Region(int col, int row, int width, int height, Sheet* sheet = 0);
116
117 /**
118 * Destructor.
119 */
120 virtual ~Region();
121
122
123 /**
124 * @return a QRegion that unifies all contained ranges
125 */
126 QVector<QRect> rects() const;
127
128 /**
129 * @param originSheet The name is created relative to this sheet.
130 * @return the name of the region (e.g. "A1:A2")
131 */
132 QString name(Sheet* originSheet = 0) const;
133
134 /**
135 * @param sRegion will be modified, if a valid sheet was found. The sheetname
136 * will be removed
137 * @return sheet named in the @p sRegion or null
138 */
139 Sheet* filterSheetName(QString& sRegion);
140
141
142
143 /**
144 * @return @c true, if this region contains no elements
145 */
146 bool isEmpty() const;
147
148 /**
149 * @return @c true, if this region contains only a single point
150 */
151 bool isSingular() const;
152
153 /**
154 * @return @c true, if this region is contiguous
155 */
156 bool isContiguous() const;
157
158 /**
159 * @return @c true, if this region contains at least one valid point or one valid range
160 */
161 bool isValid() const;
162
163 /**
164 * @param col The column to check
165 *
166 * @return @c True, if the column @p col is selected. If column @p col
167 * is not given, it returns true, if at least one column is selected
168 *
169 * \note If you want to check more than one column for selection, use
170 * columnsSelected(). It returns a set of all selected columns at once.
171 */
172 bool isColumnSelected(uint col = 0) const;
173
174 /**
175 * @param row the row to check
176 *
177 * @return @c true , if the row @p row is selected. If row @p row
178 * is not given, it returns true, if at least one row is selected
179 *
180 * \note If you want to check more than one row for selection, use
181 * rowsSelected(). It returns a set of all selected rows at once.
182 */
183 bool isRowSelected(uint row = 0) const;
184
185 /**
186 * @return @c true , if at least one column or one row is selected
187 */
188 bool isColumnOrRowSelected() const;
189
190 /**
191 * @return @c true , if all cells in the sheet are selected
192 */
193 bool isAllSelected() const;
194
195 /**
196 * @return a set of column numbers, for those columns, that are selected
197 */
198 QSet<int> columnsSelected() const;
199
200 /**
201 * @return a set of row numbers, for those rows, that are selected
202 */
203 QSet<int> rowsSelected() const;
204
205 /**
206 * @return a set of column numbers, for those columns, that have at least
207 * one cell selected
208 */
209 QSet<int> columnsAffected() const;
210
211 /**
212 * @return a set of row numbers, for those rows, that have at least
213 * one cell selected
214 */
215 QSet<int> rowsAffected() const;
216
217 /**
218 * @param point the point's location
219 * @param sheet the sheet the point belongs to
220 * @return @c true, if the region contains the point @p point
221 */
222 bool contains(const QPoint& point, Sheet* sheet = 0) const;
223
224
225
226 /* TODO Stefan #2: Optimize! Adjacent Points/Ranges */
227 /**
228 * Adds the point @p point to this region.
229 * @param point the point's location
230 * @param sheet the sheet the point belongs to
231 */
232 Element* add(const QPoint& point, Sheet* sheet = 0);
233
234 /**
235 * Adds the range @p range to this region.
236 * @param range the range's location
237 * @param sheet the sheet the range belongs to
238 */
239 Element* add(const QRect& range, Sheet* sheet = 0);
240
241 /**
242 * Adds the region @p region to this region.
243 * @param region the region to be added
244 * @param sheet the fallback sheet used, if an element has no sheet set
245 */
246 Element* add(const Region& region, Sheet* sheet = 0);
247
248 /* TODO Stefan #3: Improve! */
249 /**
250 * Subtracts the point @p point from this region.
251 * @param point the point's location
252 * @param sheet the sheet the point belongs to
253 */
254 void sub(const QPoint& point, Sheet* sheet);
255
256 /**
257 * Subtracts the range @p range from this region.
258 * @param range the range's location
259 * @param sheet the sheet the range belongs to
260 */
261 void sub(const QRect& range, Sheet* sheet);
262
263 /**
264 * Subtracts the region @p region from this region.
265 * @param region the region to subtract
266 */
267 void sub(const Region& region);
268
269 /**
270 * Intersects the region @p region and this region and
271 * returns the result of the intersection as a new Region.
272 */
273 Region intersected(const Region& region) const;
274
275 /**
276 * Intersects this region with the row @p row and returns
277 * the result of the intersection as a new Region.
278 */
279 Region intersectedWithRow(int row) const;
280
281 /**
282 * @param point the point's location
283 * @param sheet the sheet the point belongs to
284 */
285 virtual Element* eor(const QPoint& point, Sheet* sheet = 0);
286
287 /**
288 * Deletes all elements of the region. The result is an empty region.
289 */
290 virtual void clear();
291
292
293 QRect firstRange() const;
294 QRect lastRange() const;
295 Sheet* firstSheet() const;
296 Sheet* lastSheet() const;
297
298 QRect boundingRect() const;
299
300
301 static QRect normalized(const QRect& rect);
302
303
304 /**
305 * @param region the region to compare
306 * @return @c true, if this region equals region @p region
307 */
308 bool operator==(const Region& region) const;
309 inline bool operator!=(const Region& region) const {
310 return !operator==(region);
311 }
312
313 /**
314 * @param region the region to copy
315 */
316 void operator=(const Region& region);
317
318
319
320 /**
321 * @return the map to which this region belongs.
322 */
323 const Map* map() const;
324
325 /**
326 * Sets the map to which this region belongs.
327 */
328 void setMap(const Map*);
329
330
331 typedef QList<Element*>::Iterator Iterator;
332 typedef QList<Element*>::ConstIterator ConstIterator;
333
334 ConstIterator constBegin() const;
335 ConstIterator constEnd() const;
336
337 static bool isValid(const QPoint& point);
338 static bool isValid(const QRect& rect);
339
340 protected:
341 /**
342 * @return the list of elements
343 */
344 QList<Element*>& cells() const;
345
346 /**
347 * @param index the index of the element in whose front the new point
348 * is inserted
349 * @param point the location of the point to be inserted
350 * @param sheet the sheet the point belongs to
351 * @param multi @c true to allow multiple occurrences of a point
352 * @return the added point, a null pointer, if @p point is not
353 * valid or the element containing @p point
354 */
355 Element* insert(int index, const QPoint& point, Sheet* sheet, bool multi = true);
356
357 /**
358 * @param index the index of the element in whose front the new range
359 * is inserted
360 * @param range the location of the range to be inserted
361 * @param sheet the sheet the range belongs to
362 * @param multi @c true to allow multiple occurrences of a range
363 * @return the added range, a null pointer, if @p range is not
364 * valid or the element containing @p range
365 */
366 Element* insert(int index, const QRect& range, Sheet* sheet, bool multi = true);
367
368 /**
369 * @internal used to create derived Points
370 */
371 virtual Point* createPoint(const QPoint&) const;
372
373 /**
374 * @internal used to create derived Points
375 */
376 virtual Point* createPoint(const QString&) const;
377
378 /**
379 * @internal used to create derived Points
380 */
381 virtual Point* createPoint(const Point&) const;
382
383 /**
384 * @internal used to create derived Ranges
385 */
386 virtual Range* createRange(const QRect&) const;
387
388 /**
389 * @internal used to create derived Ranges
390 */
391 virtual Range* createRange(const Point&, const Point&) const;
392
393 /**
394 * @internal used to create derived Ranges
395 */
396 virtual Range* createRange(const QString&) const;
397
398 /**
399 * @internal used to create derived Ranges
400 */
401 virtual Range* createRange(const Range&) const;
402
403 private:
404 class Private;
405 QSharedDataPointer<Private> d;
406 };
407
408
409 /***************************************************************************
410 class Region::Element
411 ****************************************************************************/
412 /**
413 * Base class for region elements, which can be points or ranges.
414 * This class is used by Calligra::Sheets::Region and could not be used outside of it.
415 *
416 * Size:
417 * m_sheet: 4 bytes
418 * vtable: 4 bytes
419 * sum: 8 bytes
420 */
421 class CALLIGRA_SHEETS_ODF_EXPORT Region::Element
422 {
423 public:
424 enum Type { Undefined, Point, Range };
425
426 Element();
427 virtual ~Element();
428
type()429 virtual Type type() const {
430 return Undefined;
431 }
isValid()432 virtual bool isValid() const {
433 return false;
434 }
isColumn()435 virtual bool isColumn() const {
436 return false;
437 }
isRow()438 virtual bool isRow() const {
439 return false;
440 }
isAll()441 virtual bool isAll() const {
442 return false;
443 }
444
contains(const QPoint &)445 virtual bool contains(const QPoint&) const {
446 return false;
447 }
contains(const QRect &)448 virtual bool contains(const QRect&) const {
449 return false;
450 }
451
452 virtual QString name(Sheet* = 0) const {
453 return QString("");
454 }
rect()455 virtual QRect rect() const {
456 return QRect();
457 }
458
isColumnFixed()459 virtual bool isColumnFixed() const {
460 return false;
461 }
isRowFixed()462 virtual bool isRowFixed() const {
463 return false;
464 }
isTopFixed()465 virtual bool isTopFixed() const {
466 return false;
467 }
isLeftFixed()468 virtual bool isLeftFixed() const {
469 return false;
470 }
isBottomFixed()471 virtual bool isBottomFixed() const {
472 return false;
473 }
isRightFixed()474 virtual bool isRightFixed() const {
475 return false;
476 }
477
sheet()478 Sheet* sheet() const {
479 return m_sheet;
480 }
setSheet(Sheet * sheet)481 void setSheet(Sheet* sheet) {
482 m_sheet = sheet;
483 }
484
485 protected:
486 /* TODO Stefan #6:
487 Elaborate, if this pointer could be avoided by QDict or whatever in
488 Region.
489 */
490 Sheet* m_sheet;
491 };
492
493
494 /***************************************************************************
495 class Region::Point
496 ****************************************************************************/
497
498 /**
499 * A point in a region.
500 * This class is used by Calligra::Sheets::Region and could not be used outside of it.
501 *
502 * Size:
503 * m_sheet: 4 bytes
504 * vtable: 4 bytes
505 * m_point: 8 bytes
506 * sum: 16 bytes
507 */
508 class CALLIGRA_SHEETS_ODF_EXPORT Region::Point : public Region::Element
509 {
510 public:
Point()511 Point() : Element(), m_point() {}
Point(int col,int row)512 Point(int col, int row) : Element(), m_point(col, row) {}
513 Point(const QPoint&);
514 Point(const QString&);
515 ~Point() override;
516
type()517 Type type() const override {
518 return Element::Point;
519 }
isValid()520 bool isValid() const override {
521 return (!m_point.isNull() && Region::isValid(m_point));
522 }
isColumn()523 bool isColumn() const override {
524 return false;
525 }
isRow()526 bool isRow() const override {
527 return false;
528 }
isAll()529 bool isAll() const override {
530 return false;
531 }
532
533 bool contains(const QPoint&) const override;
534 bool contains(const QRect&) const override;
535
536 QString name(Sheet* originSheet = 0) const override;
537
rect()538 QRect rect() const override {
539 return QRect(m_point, m_point);
540 }
541
isColumnFixed()542 bool isColumnFixed() const override {
543 return m_fixedColumn;
544 }
isRowFixed()545 bool isRowFixed() const override {
546 return m_fixedRow;
547 }
isTopFixed()548 bool isTopFixed() const override {
549 return m_fixedRow;
550 }
isLeftFixed()551 bool isLeftFixed() const override {
552 return m_fixedColumn;
553 }
isBottomFixed()554 bool isBottomFixed() const override {
555 return m_fixedRow;
556 }
isRightFixed()557 bool isRightFixed() const override {
558 return m_fixedColumn;
559 }
560
pos()561 QPoint pos() const {
562 return m_point;
563 }
564 Cell cell() const;
565
566 bool operator==(const Point& other) const {
567 return ((m_point == other.m_point) && (m_sheet == other.m_sheet));
568 }
569
570 private:
571 QPoint m_point;
572 bool m_fixedColumn;
573 bool m_fixedRow;
574 };
575
576
577 /***************************************************************************
578 class Region:.Range
579 ****************************************************************************/
580
581 /**
582 * A range in a region.
583 * This class is used by Calligra::Sheets::Region and could not be used outside of it.
584 *
585 * Size:
586 * m_sheet: 4 bytes
587 * vtable: 4 bytes
588 * m_range: 16 bytes
589 * sum: 24 bytes
590 */
591 class CALLIGRA_SHEETS_ODF_EXPORT Region::Range : public Region::Element
592 {
593 public:
594 Range(const QRect&);
595 Range(const Region::Point&, const Region::Point&);
596 Range(const QString&);
597 ~Range() override;
598
type()599 Type type() const override {
600 return Element::Range;
601 }
isValid()602 bool isValid() const override {
603 return !m_range.isNull() && Region::isValid(m_range);
604 }
605 bool isColumn() const override;
606 bool isRow() const override;
607 bool isAll() const override;
608
609 bool contains(const QPoint&) const override;
610 bool contains(const QRect&) const override;
611
612 QString name(Sheet* originSheet = 0) const override;
613
rect()614 QRect rect() const override {
615 return m_range;
616 }
617
isColumnFixed()618 bool isColumnFixed() const override {
619 return m_fixedLeft && m_fixedRight;
620 }
isRowFixed()621 bool isRowFixed() const override {
622 return m_fixedTop && m_fixedBottom;
623 }
isTopFixed()624 bool isTopFixed() const override {
625 return m_fixedTop;
626 }
isLeftFixed()627 bool isLeftFixed() const override {
628 return m_fixedLeft;
629 }
isBottomFixed()630 bool isBottomFixed() const override {
631 return m_fixedBottom;
632 }
isRightFixed()633 bool isRightFixed() const override {
634 return m_fixedRight;
635 }
636
637 int width() const;
638 int height() const;
639
640 private:
641 QRect m_range;
642 bool m_fixedTop;
643 bool m_fixedLeft;
644 bool m_fixedBottom;
645 bool m_fixedRight;
646 };
647
648 } // namespace Sheets
649 } // namespace Calligra
650
651 Q_DECLARE_TYPEINFO(Calligra::Sheets::Region, Q_MOVABLE_TYPE);
652
653
654 /***************************************************************************
655 QDebug support
656 ****************************************************************************/
657
658 inline QDebug operator<<(QDebug str, const Calligra::Sheets::Region& r)
659 {
660 return str << qPrintable(r.name());
661 }
662
663 #endif // CALLIGRA_SHEETS_REGION
664