1/* This file is part of the KDE project
2 Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3 Copyright (C) 2000 - 2005 The KSpread Team <calligra-devel@kde.org>
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// Local
22#include "RowColumnFormat.h"
23
24#include <float.h>
25#include <iostream>
26#include <stdlib.h>
27#include <stdio.h>
28
29#include <kdebug.h>
30#include <klocale.h>
31
32#include <KoXmlNS.h>
33#include <KoGenStyles.h>
34#include <KoGlobal.h>
35#include <KoStyleStack.h>
36#include <KoOdfLoadingContext.h>
37#include <KoOdfStylesReader.h>
38
39#include "CellStorage.h"
40#include "Global.h"
41#include "Map.h"
42#include "Region.h"
43#include "RowFormatStorage.h"
44#include "Sheet.h"
45#include "SheetPrint.h"
46#include "Style.h"
47#include "StyleManager.h"
48
49using namespace std;
50using namespace Calligra::Sheets;
51
52/*****************************************************************************
53 *
54 * RowFormat
55 *
56 *****************************************************************************/
57
58class RowFormat::Private
59{
60public:
61 Sheet* sheet;
62 RowFormat* next;
63 RowFormat* prev;
64 double height;
65 int row;
66 bool hide : 1;
67 bool filtered : 1;
68 bool pageBreak : 1; // before row
69};
70
71RowFormat::RowFormat()
72 : d(new Private)
73{
74 d->sheet = 0;
75 d->row = 0;
76 d->height = 0.0;
77 d->hide = false;
78 d->filtered = false;
79 d->pageBreak = false;
80 d->next = 0;
81 d->prev = 0;
82}
83
84RowFormat::RowFormat(const RowFormat& other)
85 : d(new Private(*other.d))
86{
87}
88
89RowFormat::RowFormat(const RowFormatStorage *rows, int row)
90 : d(new Private)
91{
92 d->sheet = rows->sheet();
93 d->row = row;
94 d->height = rows->rowHeight(row);
95 d->hide = rows->isHidden(row);
96 d->filtered = rows->isFiltered(row);
97 d->pageBreak = rows->hasPageBreak(row);
98 d->next = d->prev = 0;
99}
100
101RowFormat::~RowFormat()
102{
103 if (d->next)
104 d->next->setPrevious(d->prev);
105 if (d->prev)
106 d->prev->setNext(d->next);
107 delete d;
108}
109
110void RowFormat::setSheet(Sheet* sheet)
111{
112 d->sheet = sheet;
113}
114
115void RowFormat::setHeight(double height)
116{
117 // avoid unnecessary updates
118 if (qAbs(height - this->height()) < DBL_EPSILON)
119 return;
120
121 // default RowFormat?
122 if (!d->sheet) {
123 d->height = height;
124 return;
125 }
126
127 // Raise document height by new height and lower it by old height.
128 if (!isHidden() && !isFiltered())
129 d->sheet->adjustDocumentHeight(height - d->height);
130
131 d->height = height;
132
133 d->sheet->print()->updateVerticalPageParameters(row());
134}
135
136double RowFormat::height() const
137{
138 return d->height;
139}
140
141double RowFormat::visibleHeight() const
142{
143 if (d->hide || d->filtered)
144 return 0.0;
145 return d->height;
146}
147
148QDomElement RowFormat::save(QDomDocument& doc, int yshift) const
149{
150 Q_ASSERT(d->sheet);
151 QDomElement row = doc.createElement("row");
152 row.setAttribute("height", d->height);
153 row.setAttribute("row", d->row - yshift);
154 if (d->hide)
155 row.setAttribute("hide", (int) d->hide);
156
157 const Style style = d->sheet->cellStorage()->style(QRect(1, d->row, KS_colMax, 1));
158 if (!style.isEmpty()) {
159 kDebug(36003) << "saving cell style of row" << d->row;
160 QDomElement format;
161 style.saveXML(doc, format, d->sheet->map()->styleManager());
162 row.appendChild(format);
163 }
164
165 return row;
166}
167
168bool RowFormat::load(const KoXmlElement & row, int yshift, Paste::Mode mode)
169{
170 Q_ASSERT(d->sheet);
171 bool ok;
172
173 d->row = row.attribute("row").toInt(&ok) + yshift;
174 if (!ok)
175 return false;
176
177 if (row.hasAttribute("height")) {
178 if (d->sheet->map()->syntaxVersion() < 1) //compatibility with old format - was in millimeter
179 d->height = qRound(MM_TO_POINT(row.attribute("height").toDouble(&ok)));
180 else
181 d->height = row.attribute("height").toDouble(&ok);
182
183 if (!ok) return false;
184 }
185
186 // Validation
187 if (d->height < 0) {
188 kDebug(36001) << "Value height=" << d->height << " out of range";
189 return false;
190 }
191 if (d->row < 1 || d->row > KS_rowMax) {
192 kDebug(36001) << "Value row=" << d->row << " out of range";
193 return false;
194 }
195
196 if (row.hasAttribute("hide")) {
197 setHidden((int) row.attribute("hide").toInt(&ok));
198 if (!ok)
199 return false;
200 }
201
202 KoXmlElement f(row.namedItem("format").toElement());
203
204 if (!f.isNull() && (mode == Paste::Normal || mode == Paste::Format || mode == Paste::NoBorder)) {
205 Style style;
206 if (!style.loadXML(f, mode))
207 return false;
208 d->sheet->cellStorage()->setStyle(Region(QRect(1, d->row, KS_colMax, 1)), style);
209 return true;
210 }
211
212 return true;
213}
214
215int RowFormat::row() const
216{
217 return d->row;
218}
219
220void RowFormat::setRow(int row)
221{
222 d->row = row;
223}
224
225RowFormat* RowFormat::next() const
226{
227 return d->next;
228}
229
230RowFormat* RowFormat::previous() const
231{
232 return d->prev;
233}
234
235void RowFormat::setNext(RowFormat* next)
236{
237 d->next = next;
238}
239
240void RowFormat::setPrevious(RowFormat* prev)
241{
242 d->prev = prev;
243}
244
245void RowFormat::setHidden(bool _hide, bool repaint)
246{
247 Q_UNUSED(repaint);
248 Q_ASSERT(d->sheet);
249 if (_hide != d->hide) { // only if we change the status
250 if (_hide) {
251 // Lower maximum size by height of row
252 d->sheet->adjustDocumentHeight(- height());
253 d->hide = _hide; //hide must be set after we requested the height
254 } else {
255 // Rise maximum size by height of row
256 d->hide = _hide; //unhide must be set before we request the height
257 d->sheet->adjustDocumentHeight(height());
258 }
259 }
260}
261
262bool RowFormat::isHidden() const
263{
264 return d->hide;
265}
266
267void RowFormat::setFiltered(bool filtered)
268{
269 d->filtered = filtered;
270}
271
272bool RowFormat::isFiltered() const
273{
274 return d->filtered;
275}
276
277bool RowFormat::isHiddenOrFiltered() const
278{
279 return d->hide || d->filtered;
280}
281
282bool RowFormat::isDefault() const
283{
284 return !d->sheet;
285}
286
287void RowFormat::setPageBreak(bool enable)
288{
289 d->pageBreak = enable;
290}
291
292bool RowFormat::hasPageBreak() const
293{
294 return d->pageBreak;
295}
296
297bool RowFormat::operator==(const RowFormat& other) const
298{
299 // NOTE Stefan: Don't compare sheet and cell.
300 if (d->height != other.d->height)
301 return false;
302 if (d->hide != other.d->hide)
303 return false;
304 if (d->filtered != other.d->filtered)
305 return false;
306 if (d->pageBreak != other.d->pageBreak) {
307 return false;
308 }
309 return true;
310}
311
312
313/*****************************************************************************
314 *
315 * ColumnFormat
316 *
317 *****************************************************************************/
318
319class ColumnFormat::Private
320{
321public:
322 Sheet* sheet;
323 ColumnFormat* next;
324 ColumnFormat* prev;
325 double width;
326 int column;
327 bool hide : 1;
328 bool filtered : 1;
329 bool pageBreak : 1; // before column
330};
331
332ColumnFormat::ColumnFormat()
333 : d(new Private)
334{
335 d->sheet = 0;
336 d->column = 0;
337 d->width = 0.0;
338 d->hide = false;
339 d->filtered = false;
340 d->pageBreak = false;
341 d->next = 0;
342 d->prev = 0;
343}
344
345ColumnFormat::ColumnFormat(const ColumnFormat& other)
346 : d(new Private(*other.d))
347{
348}
349
350ColumnFormat::~ColumnFormat()
351{
352 if (d->next)
353 d->next->setPrevious(d->prev);
354 if (d->prev)
355 d->prev->setNext(d->next);
356 delete d;
357}
358
359void ColumnFormat::setSheet(Sheet* sheet)
360{
361 d->sheet = sheet;
362}
363
364void ColumnFormat::setWidth(double width)
365{
366 // avoid unnecessary updates
367 if (qAbs(width - this->width()) < DBL_EPSILON)
368 return;
369
370 // default ColumnFormat?
371 if (!d->sheet) {
372 d->width = width;
373 return;
374 }
375
376 // Raise document width by new width and lower it by old width.
377 if (!isHidden() && !isFiltered())
378 d->sheet->adjustDocumentWidth(width - d->width);
379
380 d->width = width;
381
382 d->sheet->print()->updateHorizontalPageParameters(column());
383}
384
385double ColumnFormat::width() const
386{
387 return d->width;
388}
389
390double ColumnFormat::visibleWidth() const
391{
392 if (d->hide || d->filtered)
393 return 0.0;
394 return d->width;
395}
396
397QDomElement ColumnFormat::save(QDomDocument& doc, int xshift) const
398{
399 Q_ASSERT(d->sheet);
400 QDomElement col(doc.createElement("column"));
401 col.setAttribute("width", d->width);
402 col.setAttribute("column", d->column - xshift);
403
404 if (d->hide)
405 col.setAttribute("hide", (int) d->hide);
406
407 const Style style = d->sheet->cellStorage()->style(QRect(d->column, 1, 1, KS_rowMax));
408 if (!style.isEmpty()) {
409 kDebug(36003) << "saving cell style of column" << d->column;
410 QDomElement format(doc.createElement("format"));
411 style.saveXML(doc, format, d->sheet->map()->styleManager());
412 col.appendChild(format);
413 }
414
415 return col;
416}
417
418bool ColumnFormat::load(const KoXmlElement & col, int xshift, Paste::Mode mode)
419{
420 Q_ASSERT(d->sheet);
421 bool ok;
422 if (col.hasAttribute("width")) {
423 if (d->sheet->map()->syntaxVersion() < 1) //combatibility to old format - was in millimeter
424 d->width = qRound(MM_TO_POINT(col.attribute("width").toDouble(&ok)));
425 else
426 d->width = col.attribute("width").toDouble(&ok);
427
428 if (!ok)
429 return false;
430 }
431
432 d->column = col.attribute("column").toInt(&ok) + xshift;
433
434 if (!ok)
435 return false;
436
437 // Validation
438 if (d->width < 0) {
439 kDebug(36001) << "Value width=" << d->width << " out of range";
440 return false;
441 }
442 if (d->column < 1 || d->column > KS_colMax) {
443 kDebug(36001) << "Value col=" << d->column << " out of range";
444 return false;
445 }
446 if (col.hasAttribute("hide")) {
447 setHidden((int) col.attribute("hide").toInt(&ok));
448 if (!ok)
449 return false;
450 }
451
452 KoXmlElement f(col.namedItem("format").toElement());
453
454 if (!f.isNull() && (mode == Paste::Normal || mode == Paste::Format || mode == Paste::NoBorder)) {
455 Style style;
456 if (!style.loadXML(f, mode))
457 return false;
458 d->sheet->cellStorage()->setStyle(Region(QRect(d->column, 1, 1, KS_rowMax)), style);
459 return true;
460 }
461
462 return true;
463}
464
465int ColumnFormat::column() const
466{
467 return d->column;
468}
469
470void ColumnFormat::setColumn(int column)
471{
472 d->column = column;
473}
474
475ColumnFormat* ColumnFormat::next() const
476{
477 return d->next;
478}
479
480ColumnFormat* ColumnFormat::previous() const
481{
482 return d->prev;
483}
484
485void ColumnFormat::setNext(ColumnFormat* next)
486{
487 d->next = next;
488}
489
490void ColumnFormat::setPrevious(ColumnFormat* prev)
491{
492 d->prev = prev;
493}
494
495void ColumnFormat::setHidden(bool _hide)
496{
497 Q_ASSERT(d->sheet);
498 if (_hide != d->hide) { // only if we change the status
499 if (_hide) {
500 // Lower maximum size by width of column
501 d->sheet->adjustDocumentWidth(- width());
502 d->hide = _hide; //hide must be set after we requested the width
503 } else {
504 // Rise maximum size by width of column
505 d->hide = _hide; //unhide must be set before we request the width
506 d->sheet->adjustDocumentWidth(width());
507 }
508 }
509}
510
511bool ColumnFormat::isHidden() const
512{
513 return d->hide;
514}
515
516void ColumnFormat::setFiltered(bool filtered)
517{
518 d->filtered = filtered;
519}
520
521bool ColumnFormat::isFiltered() const
522{
523 return d->filtered;
524}
525
526bool ColumnFormat::isHiddenOrFiltered() const
527{
528 return d->hide || d->filtered;
529}
530
531bool ColumnFormat::isDefault() const
532{
533 return !d->sheet;
534}
535
536void ColumnFormat::setPageBreak(bool enable)
537{
538 d->pageBreak = enable;
539}
540
541bool ColumnFormat::hasPageBreak() const
542{
543 return d->pageBreak;
544}
545
546bool ColumnFormat::operator==(const ColumnFormat& other) const
547{
548 // NOTE Stefan: Don't compare sheet and cell.
549 if (d->width != other.d->width)
550 return false;
551 if (d->hide != other.d->hide)
552 return false;
553 if (d->filtered != other.d->filtered)
554 return false;
555 if (d->pageBreak != other.d->pageBreak) {
556 return false;
557 }
558 return true;
559}
560