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 | |
36 | using namespace Calligra::Sheets; |
37 | |
38 | SheetPrint::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 | |
52 | SheetPrint::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 | |
68 | SheetPrint::~SheetPrint() |
69 | { |
70 | delete d->m_headerFooter; |
71 | delete d->m_settings; |
72 | delete d; |
73 | } |
74 | |
75 | PrintSettings *SheetPrint::settings() const |
76 | { |
77 | return d->m_settings; |
78 | } |
79 | |
80 | void 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 | |
185 | HeaderFooter *SheetPrint::() const |
186 | { |
187 | return d->m_headerFooter; |
188 | } |
189 | |
190 | bool 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 | |
217 | bool 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 | |
243 | void 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 | |
274 | void 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 | |
305 | void 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 | |
329 | void 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 | |
353 | void 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 | |
393 | void 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 | |
433 | int SheetPrint::pageCount() const |
434 | { |
435 | return d->m_lnewPageListX.count() * d->m_lnewPageListY.count(); |
436 | } |
437 | |
438 | QRect 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 | |
471 | QRectF 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 | |
501 | void 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 | |