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