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