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 | |
34 | inline uint qHash(const QPoint& point) |
35 | { |
36 | return (static_cast<uint>(point.x()) << 16) + static_cast<uint>(point.y()); |
37 | } |
38 | |
39 | namespace Calligra |
40 | { |
41 | namespace Sheets |
42 | { |
43 | class Cell; |
44 | class Map; |
45 | class 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 | */ |
53 | class CALLIGRA_SHEETS_ODF_EXPORT Region |
54 | { |
55 | public: |
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 | |
347 | protected: |
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 | |
410 | private: |
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 | */ |
428 | class CALLIGRA_SHEETS_ODF_EXPORT Region::Element |
429 | { |
430 | public: |
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 | |
492 | protected: |
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 | */ |
515 | class CALLIGRA_SHEETS_ODF_EXPORT Region::Point : public Region::Element |
516 | { |
517 | public: |
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 | |
577 | private: |
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 | */ |
598 | class CALLIGRA_SHEETS_ODF_EXPORT Region::Range : public Region::Element |
599 | { |
600 | public: |
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 | |
647 | private: |
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 | |
658 | Q_DECLARE_TYPEINFO(Calligra::Sheets::Region, Q_MOVABLE_TYPE); |
659 | |
660 | |
661 | /*************************************************************************** |
662 | kDebug support |
663 | ****************************************************************************/ |
664 | |
665 | inline QDebug operator<<(QDebug str, const Calligra::Sheets::Region& r) |
666 | { |
667 | return str << qPrintable(r.name()); |
668 | } |
669 | |
670 | #endif // CALLIGRA_SHEETS_REGION |
671 | |