1/* This file is part of the KDE project
2 Copyright 2007, 2009 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
3 Copyright 2005 Raphael Langerhorst <raphael.langerhorst@kdemail.net>
4 Copyright 2003 Philipp Müller <philipp.mueller@gmx.de>
5 Copyright 1998, 1999 Torben Weis <weis@kde.org>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21*/
22
23// Local
24#include "SheetPrint.h"
25#include "SheetPrint_p.h"
26
27#include "HeaderFooter.h"
28#include "PrintSettings.h"
29#include "calligra_sheets_limits.h"
30#include "Region.h"
31#include "Sheet.h"
32
33#include <kdebug.h>
34#include <kmessagebox.h>
35
36using namespace Calligra::Sheets;
37
38SheetPrint::SheetPrint(Sheet *sheet)
39 : d(new Private(this))
40{
41 d->m_pSheet = sheet;
42
43 d->m_settings = new PrintSettings();
44 d->m_headerFooter = new HeaderFooter(sheet);
45
46 d->m_maxCheckedNewPageX = 0;
47 d->m_maxCheckedNewPageY = 0;
48 d->m_dPrintRepeatColumnsWidth = 0.0;
49 d->m_dPrintRepeatRowsHeight = 0.0;
50}
51
52SheetPrint::SheetPrint(const SheetPrint &other)
53 : d(new Private(this))
54{
55 d->m_pSheet = other.d->m_pSheet;
56
57 d->m_settings = new PrintSettings(*other.d->m_settings);
58 d->m_headerFooter = new HeaderFooter(*other.d->m_headerFooter);
59
60 d->m_maxCheckedNewPageX = other.d->m_maxCheckedNewPageX;
61 d->m_maxCheckedNewPageY = other.d->m_maxCheckedNewPageY;
62 d->m_dPrintRepeatColumnsWidth = other.d->m_dPrintRepeatColumnsWidth;
63 d->m_dPrintRepeatRowsHeight = other.d->m_dPrintRepeatRowsHeight;
64 d->m_lnewPageListX = other.d->m_lnewPageListX;
65 d->m_lnewPageListY = other.d->m_lnewPageListY;
66}
67
68SheetPrint::~SheetPrint()
69{
70 delete d->m_headerFooter;
71 delete d->m_settings;
72 delete d;
73}
74
75PrintSettings *SheetPrint::settings() const
76{
77 return d->m_settings;
78}
79
80void SheetPrint::setSettings(const PrintSettings &settings, bool force)
81{
82 // Relayout forced?
83 if (force) {
84 *d->m_settings = settings;
85 d->updateRepeatedColumnsWidth();
86 d->updateRepeatedRowsHeight();
87 const QSize pageLimits = settings.pageLimits();
88 const QSize usedArea = d->m_pSheet->usedArea(true).size();
89 if (pageLimits.width() > 0) {
90 d->calculateZoomForPageLimitX();
91 } else {
92 updateHorizontalPageParameters(0);
93 d->calculateHorizontalPageParameters(usedArea.width());
94 }
95 if (pageLimits.height() > 0) {
96 d->calculateZoomForPageLimitY();
97 } else {
98 updateVerticalPageParameters(0);
99 d->calculateVerticalPageParameters(usedArea.height());
100 }
101 return;
102 }
103
104 const KoPageLayout oldPageLayout = d->m_settings->pageLayout();
105 const KoPageLayout pageLayout = settings.pageLayout();
106 const QRect oldPrintRange = d->m_settings->printRegion().lastRange();
107 const QRect printRange = settings.printRegion().lastRange();
108 const QSize oldPageLimits = d->m_settings->pageLimits();
109 const QSize pageLimits = settings.pageLimits();
110 const QPair<int, int> oldRepeatedColumns = d->m_settings->repeatedColumns();
111 const QPair<int, int> repeatedColumns = settings.repeatedColumns();
112 const QPair<int, int> oldRepeatedRows = d->m_settings->repeatedRows();
113 const QPair<int, int> repeatedRows = settings.repeatedRows();
114
115 const bool pageWidthChanged = oldPageLayout.width != pageLayout.width;
116 const bool pageHeightChanged = oldPageLayout.height != pageLayout.height;
117 const bool horizontalLimitChanged = oldPageLimits.width() != pageLimits.width();
118 const bool verticalLimitChanged = oldPageLimits.height() != pageLimits.height();
119 const bool repeatedColumnsChanged = oldRepeatedColumns != repeatedColumns;
120 const bool repeatedRowsChanged = oldRepeatedRows != repeatedRows;
121 const bool zoomChanged = d->m_settings->zoom() != settings.zoom();
122
123 *d->m_settings = settings;
124
125 // The starting column/row for the page parameter updates.
126 int column = KS_colMax + 1;
127 int row = KS_rowMax + 1;
128
129 // The print range.
130 if (oldPrintRange.left() != printRange.left()) {
131 column = qMin(oldPrintRange.left(), printRange.left());
132 }
133 if (oldPrintRange.top() != printRange.top()) {
134 row = qMin(oldPrintRange.top(), printRange.top());
135 }
136
137 // The zoom.
138 if (zoomChanged) {
139 column = 0;
140 row = 0;
141 }
142
143 // The page limits.
144 if (horizontalLimitChanged && pageLimits.width() <= 0) {
145 column = 0;
146 }
147 if (verticalLimitChanged && pageLimits.height() <= 0) {
148 row = 0;
149 }
150
151 // The page dimensions.
152 if (pageWidthChanged) {
153 column = 0;
154 }
155 if (pageHeightChanged) {
156 row = 0;
157 }
158
159 // The column/row repetitions.
160 if (repeatedColumnsChanged) {
161 d->updateRepeatedColumnsWidth();
162 column = qMin(column, oldRepeatedColumns.first);
163 column = qMin(column, repeatedColumns.first);
164 }
165 if (repeatedRowsChanged) {
166 d->updateRepeatedRowsHeight();
167 row = qMin(row, oldRepeatedRows.first);
168 row = qMin(row, repeatedRows.first);
169 }
170
171 // Update the page parameters.
172 // If page limits are set to non-zero, call the special methods.
173 if (horizontalLimitChanged && pageLimits.width() > 0) {
174 d->calculateZoomForPageLimitX();
175 } else if (column <= KS_colMax) {
176 updateHorizontalPageParameters(column);
177 }
178 if (verticalLimitChanged && pageLimits.height() > 0) {
179 d->calculateZoomForPageLimitY();
180 } else if (row <= KS_rowMax) {
181 updateVerticalPageParameters(row);
182 }
183}
184
185HeaderFooter *SheetPrint::headerFooter() const
186{
187 return d->m_headerFooter;
188}
189
190bool SheetPrint::isColumnOnNewPage(int _column)
191{
192 if (_column > d->m_maxCheckedNewPageX)
193 d->calculateHorizontalPageParameters(_column);
194
195 //Are these the edges of the print range?
196 const QRect printRange = d->m_settings->printRegion().lastRange();
197 if (_column == printRange.left() || _column == printRange.right()) {
198 return true;
199 }
200
201 //beyond the print range it's always false
202 if (_column < printRange.left() || _column > printRange.right()) {
203 return false;
204 }
205
206 //Now check if we find the column already in the list
207 if (d->m_lnewPageListX.indexOf(PrintNewPageEntry(_column)) != -1) {
208 if (_column > d->m_maxCheckedNewPageX)
209 d->m_maxCheckedNewPageX = _column;
210 return true;
211 }
212 return false;
213}
214
215
216
217bool SheetPrint::isRowOnNewPage(int _row)
218{
219 if (_row > d->m_maxCheckedNewPageY)
220 d->calculateVerticalPageParameters(_row);
221
222 //Are these the edges of the print range?
223 const QRect printRange = d->m_settings->printRegion().lastRange();
224 if (_row == printRange.top() || _row == printRange.bottom()) {
225 return true;
226 }
227
228 //beyond the print range it's always false
229 if (_row < printRange.top() || _row > printRange.bottom()) {
230 return false;
231 }
232
233 //Now check if we find the row already in the list
234 if (d->m_lnewPageListY.indexOf(PrintNewPageEntry(_row)) != -1) {
235 if (_row > d->m_maxCheckedNewPageY)
236 d->m_maxCheckedNewPageY = _row;
237 return true;
238 }
239
240 return false;
241}
242
243void SheetPrint::updateHorizontalPageParameters(int _col)
244{
245 //If the new range is after the first entry, we need to delete the whole list
246 const QRect printRange = d->m_settings->printRegion().lastRange();
247 if (d->m_lnewPageListX.isEmpty() || d->m_lnewPageListX.first().startItem() != printRange.left() || _col == 0) {
248 d->m_lnewPageListX.clear();
249 d->m_maxCheckedNewPageX = 0;
250 d->updateRepeatedColumnsWidth();
251 return;
252 }
253
254 if (_col <= d->m_lnewPageListX.last().endItem()) {
255 // Find the page entry for this column
256 int index = d->m_lnewPageListX.count() - 1;
257 while (_col < d->m_lnewPageListX[index].startItem()) {
258 --index;
259 }
260
261 //Remove later pages
262 while (index != d->m_lnewPageListX.count())
263 d->m_lnewPageListX.removeAt(index);
264
265 d->m_maxCheckedNewPageX = d->m_lnewPageListX.isEmpty() ? 0 : d->m_lnewPageListX.last().endItem();
266 }
267
268 // The column is not beyond the repeated columns?
269 if (_col <= d->m_settings->repeatedColumns().second) {
270 d->updateRepeatedColumnsWidth();
271 }
272}
273
274void SheetPrint::updateVerticalPageParameters(int _row)
275{
276 //If the new range is after the first entry, we need to delete the whole list
277 const QRect printRange = d->m_settings->printRegion().lastRange();
278 if (d->m_lnewPageListY.isEmpty() || d->m_lnewPageListY.first().startItem() != printRange.top() || _row == 0) {
279 d->m_lnewPageListY.clear();
280 d->m_maxCheckedNewPageY = 0;
281 d->updateRepeatedRowsHeight();
282 return;
283 }
284
285 if (_row <= d->m_lnewPageListY.last().endItem()) {
286 // Find the page entry for this row
287 int index = d->m_lnewPageListY.count() - 1;
288 while (_row < d->m_lnewPageListY[index].startItem()) {
289 --index;
290 }
291
292 //Remove later pages
293 while (index != d->m_lnewPageListY.count())
294 d->m_lnewPageListY.removeAt(index);
295
296 d->m_maxCheckedNewPageY = d->m_lnewPageListY.isEmpty() ? 0 : d->m_lnewPageListY.last().endItem();
297 }
298
299 // The row is not beyond the repeated rows?
300 if (_row <= d->m_settings->repeatedRows().second) {
301 d->updateRepeatedRowsHeight();
302 }
303}
304
305void SheetPrint::insertColumn(int col, int nbCol)
306{
307 //update print range, when it has been defined
308 const QRect printRange = d->m_settings->printRegion().lastRange();
309 if (printRange != QRect(QPoint(1, 1), QPoint(KS_colMax, KS_rowMax))) {
310 int left = printRange.left();
311 int right = printRange.right();
312
313 for (int i = 0; i < nbCol; i++) {
314 if (left >= col) left++;
315 if (right >= col) right++;
316 }
317 //Validity checks
318 if (left > KS_colMax) left = KS_colMax;
319 if (right > KS_colMax) right = KS_colMax;
320 const Region region(QRect(QPoint(left, printRange.top()),
321 QPoint(right, printRange.bottom())), d->m_pSheet);
322 // Trigger an update by setting it indirectly.
323 PrintSettings settings = *d->m_settings;
324 settings.setPrintRegion(region);
325 setSettings(settings);
326 }
327}
328
329void SheetPrint::insertRow(int row, int nbRow)
330{
331 //update print range, when it has been defined
332 const QRect printRange = d->m_settings->printRegion().lastRange();
333 if (printRange != QRect(QPoint(1, 1), QPoint(KS_colMax, KS_rowMax))) {
334 int top = printRange.top();
335 int bottom = printRange.bottom();
336
337 for (int i = 0; i < nbRow; i++) {
338 if (top >= row) top++;
339 if (bottom >= row) bottom++;
340 }
341 //Validity checks
342 if (top > KS_rowMax) top = KS_rowMax;
343 if (bottom > KS_rowMax) bottom = KS_rowMax;
344 const Region region(QRect(QPoint(printRange.left(), top),
345 QPoint(printRange.right(), bottom)), d->m_pSheet);
346 // Trigger an update by setting it indirectly.
347 PrintSettings settings = *d->m_settings;
348 settings.setPrintRegion(region);
349 setSettings(settings);
350 }
351}
352
353void SheetPrint::removeColumn(int col, int nbCol)
354{
355 PrintSettings settings = *d->m_settings;
356 //update print range, when it has been defined
357 const QRect printRange = d->m_settings->printRegion().lastRange();
358 if (printRange != QRect(QPoint(1, 1), QPoint(KS_colMax, KS_rowMax))) {
359 int left = printRange.left();
360 int right = printRange.right();
361
362 for (int i = 0; i < nbCol; i++) {
363 if (left > col) left--;
364 if (right >= col) right--;
365 }
366 //Validity checks
367 if (left < 1) left = 1;
368 if (right < 1) right = 1;
369 const Region region(QRect(QPoint(left, printRange.top()),
370 QPoint(right, printRange.bottom())), d->m_pSheet);
371 settings.setPrintRegion(region);
372 }
373
374 //update repeat columns, when it has been defined
375 const QPair<int, int> repeatedColumns = d->m_settings->repeatedColumns();
376 if (repeatedColumns.first != 0) {
377 int left = repeatedColumns.first;
378 int right = repeatedColumns.second;
379
380 for (int i = 0; i < nbCol; i++) {
381 if (left > col) left--;
382 if (right >= col) right--;
383 }
384 //Validity checks
385 if (left < 1) left = 1;
386 if (right < 1) right = 1;
387 settings.setRepeatedColumns(qMakePair(left, right));
388 }
389 // Trigger an update by setting them indirectly.
390 setSettings(settings);
391}
392
393void SheetPrint::removeRow(int row, int nbRow)
394{
395 PrintSettings settings = *d->m_settings;
396 //update print range, when it has been defined
397 const QRect printRange = d->m_settings->printRegion().lastRange();
398 if (printRange != QRect(QPoint(1, 1), QPoint(KS_colMax, KS_rowMax))) {
399 int top = printRange.top();
400 int bottom = printRange.bottom();
401
402 for (int i = 0; i < nbRow; i++) {
403 if (top > row) top--;
404 if (bottom >= row) bottom--;
405 }
406 //Validity checks
407 if (top < 1) top = 1;
408 if (bottom < 1) bottom = 1;
409 const Region region(QRect(QPoint(printRange.left(), top),
410 QPoint(printRange.right(), bottom)), d->m_pSheet);
411 settings.setPrintRegion(region);
412 }
413
414 //update repeat rows, when it has been defined
415 const QPair<int, int> repeatedRows = d->m_settings->repeatedRows();
416 if (repeatedRows.first != 0) {
417 int top = repeatedRows.first;
418 int bottom = repeatedRows.second;
419
420 for (int i = 0; i < nbRow; i++) {
421 if (top > row) top--;
422 if (bottom >= row) bottom--;
423 }
424 //Validity checks
425 if (top < 1) top = 1;
426 if (bottom < 1) bottom = 1;
427 settings.setRepeatedRows(qMakePair(top, bottom));
428 }
429 // Trigger an update by setting them indirectly.
430 setSettings(settings);
431}
432
433int SheetPrint::pageCount() const
434{
435 return d->m_lnewPageListX.count() * d->m_lnewPageListY.count();
436}
437
438QRect SheetPrint::cellRange(int page) const
439{
440 if (d->m_lnewPageListX.isEmpty() || d->m_lnewPageListY.isEmpty()) {
441 return QRect();
442 }
443 if (page - 1 > pageCount()) {
444 return QRect();
445 }
446 kDebug() << "page:" << page << "of" << pageCount();
447
448 int horizontalIndex = 0;
449 int verticalIndex = 0;
450 if (d->m_settings->pageOrder() == PrintSettings::LeftToRight) {
451 horizontalIndex = (page - 1) % d->m_lnewPageListX.count();
452 verticalIndex = (page - 1) / d->m_lnewPageListX.count();
453 } else {
454 horizontalIndex = (page - 1) / d->m_lnewPageListY.count();
455 verticalIndex = (page - 1) % d->m_lnewPageListY.count();
456 }
457 kDebug() << "horizontal:" << horizontalIndex + 1 << "of" << d->m_lnewPageListX.count();
458 kDebug() << "vertical:" << verticalIndex + 1 << "of" << d->m_lnewPageListY.count();
459
460 const PrintNewPageEntry horizontalParameters = d->m_lnewPageListX[horizontalIndex];
461 const PrintNewPageEntry verticalParameters = d->m_lnewPageListY[verticalIndex];
462
463 QRect cellRange;
464 cellRange.setLeft(horizontalParameters.startItem());
465 cellRange.setRight(horizontalParameters.endItem());
466 cellRange.setTop(verticalParameters.startItem());
467 cellRange.setBottom(verticalParameters.endItem());
468 return cellRange;
469}
470
471QRectF SheetPrint::documentArea(int page) const
472{
473 if (d->m_lnewPageListX.isEmpty() || d->m_lnewPageListY.isEmpty()) {
474 return QRectF();
475 }
476 if (page - 1 > pageCount()) {
477 return QRectF();
478 }
479
480 int horizontalIndex = 0;
481 int verticalIndex = 0;
482 if (d->m_settings->pageOrder() == PrintSettings::LeftToRight) {
483 horizontalIndex = (page - 1) % d->m_lnewPageListX.count();
484 verticalIndex = (page - 1) / d->m_lnewPageListX.count();
485 } else {
486 horizontalIndex = (page - 1) / d->m_lnewPageListY.count();
487 verticalIndex = (page - 1) % d->m_lnewPageListY.count();
488 }
489
490 const PrintNewPageEntry horizontalParameters = d->m_lnewPageListX[horizontalIndex];
491 const PrintNewPageEntry verticalParameters = d->m_lnewPageListY[verticalIndex];
492
493 QRectF documentArea;
494 documentArea.setLeft(horizontalParameters.offset());
495 documentArea.setWidth(horizontalParameters.size());
496 documentArea.setTop(verticalParameters.offset());
497 documentArea.setHeight(verticalParameters.size());
498 return documentArea;
499}
500
501void SheetPrint::operator=(const SheetPrint & other)
502{
503 d->m_pSheet = other.d->m_pSheet;
504
505 *d->m_settings = *other.d->m_settings;
506 *d->m_headerFooter = *other.d->m_headerFooter;
507
508 d->m_maxCheckedNewPageX = other.d->m_maxCheckedNewPageX;
509 d->m_maxCheckedNewPageY = other.d->m_maxCheckedNewPageY;
510 d->m_dPrintRepeatColumnsWidth = other.d->m_dPrintRepeatColumnsWidth;
511 d->m_dPrintRepeatRowsHeight = other.d->m_dPrintRepeatRowsHeight;
512 d->m_lnewPageListX = other.d->m_lnewPageListX;
513 d->m_lnewPageListY = other.d->m_lnewPageListY;
514}
515