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#include "SheetPrint_p.h"
24
25#include "PrintSettings.h"
26#include "Region.h"
27#include "RowColumnFormat.h"
28#include "RowFormatStorage.h"
29#include "Sheet.h"
30
31using namespace Calligra::Sheets;
32
33void SheetPrint::Private::calculateHorizontalPageParameters(int _column)
34{
35 // Zoom the print width ONCE here, instead for each column width.
36 const double printWidth = m_settings->printWidth() / m_settings->zoom();
37
38 float offset = 0.0;
39
40 //Are these the edges of the print range?
41 const QRect printRange = m_settings->printRegion().lastRange();
42#if 0
43 if (_column == printRange.left() || _column == printRange.right()) {
44 if (_column > m_maxCheckedNewPageX)
45 m_maxCheckedNewPageX = _column;
46 return;
47 }
48
49 //We don't check beyond the print range
50 if (_column < printRange.left() || _column > printRange.right()) {
51 if (_column > m_maxCheckedNewPageX)
52 m_maxCheckedNewPageX = _column;
53 if (_column > printRange.right()) {
54 if (m_lnewPageListX.last().endItem() == 0)
55 m_lnewPageListX.last().setEndItem(printRange.right());
56 }
57 return;
58 }
59#endif
60
61 // Check if the pre-calculated width matches the repeated columns setting.
62 const bool repetitions = m_settings->repeatedColumns().first != 0;
63 if (repetitions != (m_dPrintRepeatColumnsWidth == 0.0)) {
64 // Existing column repetitions, but their pre-calculated width is zero?
65 // Must be the first run. Or the other way around? Seem to be orphaned.
66 // Either way, seems they do not match. Calculate them!
67 updateRepeatedColumnsWidth();
68 }
69
70 // The end of the last item (zero, if list is empty).
71 const int end = m_lnewPageListX.empty() ? 0 : m_lnewPageListX.last().endItem();
72
73 //If _column is greater than the last entry, we need to calculate the result
74 if (_column > end &&
75 _column > m_maxCheckedNewPageX) { //this columns hasn't been calculated before
76 int startCol = end + 1;
77 int col = startCol;
78 double x = m_pSheet->columnFormat(col)->width();
79
80 // Add a new page.
81 m_lnewPageListX.append(PrintNewPageEntry(startCol));
82
83 //Add repeated column width, when necessary
84 const QPair<int, int> repeatedColumns = m_settings->repeatedColumns();
85 if (col > repeatedColumns.first) {
86 x += m_dPrintRepeatColumnsWidth;
87 offset = m_dPrintRepeatColumnsWidth;
88 }
89 kDebug() << "startCol:" << startCol << "col:" << col << "x:" << x
90 << "offset:" << offset << repeatedColumns;
91
92 while ((col <= _column) && (col < printRange.right())) {
93 kDebug() << "loop:" << "startCol:" << startCol << "col:" << col
94 << "x:" << x << "offset:" << offset;
95 // end of page?
96 if (x > printWidth || m_pSheet->columnFormat(col)->hasPageBreak()) {
97 //Now store into the previous entry the enditem and the width
98 m_lnewPageListX.last().setEndItem(col - 1);
99 m_lnewPageListX.last().setSize(x - m_pSheet->columnFormat(col)->width());
100 m_lnewPageListX.last().setOffset(offset);
101
102 //start a new page
103 m_lnewPageListX.append(PrintNewPageEntry(col));
104 startCol = col;
105 x = m_pSheet->columnFormat(col)->width();
106 if (col >= repeatedColumns.first) {
107 kDebug() << "col >= repeatedColumns.first:" << col << repeatedColumns.first;
108 x += m_dPrintRepeatColumnsWidth;
109 offset = m_dPrintRepeatColumnsWidth;
110 }
111 }
112 col++;
113 x += m_pSheet->columnFormat(col)->width();
114 }
115
116 // Iterate to the end of the page.
117 while (m_lnewPageListX.last().endItem() == 0) {
118 kDebug() << "loop to end" << "col:" << col << "x:" << x << "offset:" << offset
119 << "m_maxCheckedNewPageX:" << m_maxCheckedNewPageX;
120 if (x > printWidth || m_pSheet->columnFormat(col)->hasPageBreak()) {
121 // Now store into the previous entry the enditem and the width
122 m_lnewPageListX.last().setEndItem(col - 1);
123 m_lnewPageListX.last().setSize(x - m_pSheet->columnFormat(col)->width());
124 m_lnewPageListX.last().setOffset(offset);
125
126 if (col - 1 > m_maxCheckedNewPageX) {
127 m_maxCheckedNewPageX = col - 1;
128 }
129 return;
130 }
131 ++col;
132 x += m_pSheet->columnFormat(col)->width();
133 }
134 }
135
136 kDebug() << "m_maxCheckedNewPageX:" << m_maxCheckedNewPageX;
137 if (_column > m_maxCheckedNewPageX) {
138 m_maxCheckedNewPageX = _column;
139 m_lnewPageListX.last().setEndItem(_column);
140 }
141}
142
143void SheetPrint::Private::calculateVerticalPageParameters(int _row)
144{
145 // Zoom the print height ONCE here, instead for each row height.
146 const double printHeight = m_settings->printHeight() / m_settings->zoom();
147
148 float offset = 0.0;
149
150 //Are these the edges of the print range?
151 const QRect printRange = m_settings->printRegion().lastRange();
152#if 0
153 if (_row == printRange.top() || _row == printRange.bottom()) {
154 if (_row > m_maxCheckedNewPageY)
155 m_maxCheckedNewPageY = _row;
156 return;
157 }
158
159 //beyond the print range it's always false
160 if (_row < printRange.top() || _row > printRange.bottom()) {
161 if (_row > m_maxCheckedNewPageY)
162 m_maxCheckedNewPageY = _row;
163 if (_row > printRange.bottom()) {
164 if (m_lnewPageListY.last().endItem() == 0)
165 m_lnewPageListY.last().setEndItem(printRange.bottom());
166 }
167 return;
168 }
169#endif
170
171 // Check if the pre-calculated height matches the repeated rows setting.
172 const bool repetitions = m_settings->repeatedRows().first != 0;
173 if (repetitions != (m_dPrintRepeatRowsHeight == 0.0)) {
174 // Existing row repetitions, but their pre-calculated height is zero?
175 // Must be the first run. Or the other way around? Seem to be orphaned.
176 // Either way, seems they do not match. Calculate them!
177 updateRepeatedRowsHeight();
178 }
179
180 // The end of the last item (zero, if list is empty).
181 const int end = m_lnewPageListY.empty() ? 0 : m_lnewPageListY.last().endItem();
182
183 //If _column is greater than the last entry, we need to calculate the result
184 if (_row > end &&
185 _row > m_maxCheckedNewPageY) { //this columns hasn't been calculated before
186 int startRow = end + 1;
187 int row = startRow;
188 double y = m_pSheet->rowFormats()->rowHeight(row);
189
190 // Add a new page.
191 m_lnewPageListY.append(PrintNewPageEntry(startRow));
192
193 //Add repeated row height, when necessary
194 const QPair<int, int> repeatedRows = m_settings->repeatedRows();
195 if (row > repeatedRows.first) {
196 y += m_dPrintRepeatRowsHeight;
197 offset = m_dPrintRepeatRowsHeight;
198 }
199
200 while ((row <= _row) && (row < printRange.bottom())) {
201 // end of page?
202 if (y > printHeight || m_pSheet->rowFormats()->hasPageBreak(row)) {
203 //Now store into the previous entry the enditem and the width
204 m_lnewPageListY.last().setEndItem(row - 1);
205 m_lnewPageListY.last().setSize(y - m_pSheet->rowFormats()->rowHeight(row));
206 m_lnewPageListY.last().setOffset(offset);
207
208 //start a new page
209 m_lnewPageListY.append(PrintNewPageEntry(row));
210 startRow = row;
211 y = m_pSheet->rowFormats()->rowHeight(row);
212 if (row >= repeatedRows.first) {
213 y += m_dPrintRepeatRowsHeight;
214 offset = m_dPrintRepeatRowsHeight;
215 }
216 }
217 row++;
218 y += m_pSheet->rowFormats()->rowHeight(row);
219 }
220
221 // Iterate to the end of the page.
222 while (m_lnewPageListY.last().endItem() == 0) {
223 if (y > printHeight || m_pSheet->rowFormats()->hasPageBreak(row)) {
224 // Now store into the previous entry the enditem and the width
225 m_lnewPageListY.last().setEndItem(row - 1);
226 m_lnewPageListY.last().setSize(y - m_pSheet->rowFormats()->rowHeight(row));
227 m_lnewPageListY.last().setOffset(offset);
228
229 if (row - 1 > m_maxCheckedNewPageY) {
230 m_maxCheckedNewPageY = row - 1;
231 }
232 return;
233 }
234 ++row;
235 y += m_pSheet->rowFormats()->rowHeight(row);
236 }
237 }
238
239 if (_row > m_maxCheckedNewPageY) {
240 m_maxCheckedNewPageY = _row;
241 m_lnewPageListY.last().setEndItem(_row);
242 }
243}
244
245void SheetPrint::Private::calculateZoomForPageLimitX()
246{
247 kDebug() << "Calculating zoom for X limit";
248 const int horizontalPageLimit = m_settings->pageLimits().width();
249 if (horizontalPageLimit == 0)
250 return;
251
252 const double origZoom = m_settings->zoom();
253
254 if (m_settings->zoom() < 1.0) {
255 q->updateHorizontalPageParameters(0); // clear all parameters
256 m_settings->setZoom(1.0);
257 }
258
259 QRect printRange = m_pSheet->usedArea(true);
260 calculateHorizontalPageParameters(printRange.right());
261 int currentPages = m_lnewPageListX.count();
262
263 if (currentPages <= horizontalPageLimit)
264 return;
265
266 //calculating a factor for scaling the zoom down makes it lots faster
267 double factor = (double)horizontalPageLimit / (double)currentPages +
268 1 - (double)currentPages / ((double)currentPages + 1); //add possible error;
269 kDebug() << "Calculated factor for scaling m_settings->zoom():" << factor;
270 m_settings->setZoom(m_settings->zoom()*factor);
271
272 kDebug() << "New exact zoom:" << m_settings->zoom();
273
274 if (m_settings->zoom() < 0.01)
275 m_settings->setZoom(0.01);
276 if (m_settings->zoom() > 1.0)
277 m_settings->setZoom(1.0);
278
279 m_settings->setZoom((((int)(m_settings->zoom()*100 + 0.5)) / 100.0));
280
281 kDebug() << "New rounded zoom:" << m_settings->zoom();
282
283 q->updateHorizontalPageParameters(0); // clear all parameters
284 calculateHorizontalPageParameters(printRange.right());
285 currentPages = m_lnewPageListX.count();
286
287 kDebug() << "Number of pages with this zoom:" << currentPages;
288
289 while ((currentPages > horizontalPageLimit) && (m_settings->zoom() > 0.01)) {
290 m_settings->setZoom(m_settings->zoom() - 0.01);
291 q->updateHorizontalPageParameters(0); // clear all parameters
292 calculateHorizontalPageParameters(printRange.right());
293 currentPages = m_lnewPageListX.count();
294 kDebug() << "Looping -0.01; current zoom:" << m_settings->zoom();
295 }
296
297 if (m_settings->zoom() < origZoom) {
298 // Trigger an update of the vertical page parameters.
299 q->updateVerticalPageParameters(0); // clear all parameters
300 calculateVerticalPageParameters(printRange.bottom());
301 } else
302 m_settings->setZoom(origZoom);
303}
304
305void SheetPrint::Private::calculateZoomForPageLimitY()
306{
307 kDebug() << "Calculating zoom for Y limit";
308 const int verticalPageLimit = m_settings->pageLimits().height();
309 if (verticalPageLimit == 0)
310 return;
311
312 const double origZoom = m_settings->zoom();
313
314 if (m_settings->zoom() < 1.0) {
315 q->updateVerticalPageParameters(0); // clear all parameters
316 m_settings->setZoom(1.0);
317 }
318
319 QRect printRange = m_pSheet->usedArea(true);
320 calculateVerticalPageParameters(printRange.bottom());
321 int currentPages = m_lnewPageListY.count();
322
323 if (currentPages <= verticalPageLimit)
324 return;
325
326 double factor = (double)verticalPageLimit / (double)currentPages +
327 1 - (double)currentPages / ((double)currentPages + 1); //add possible error
328 kDebug() << "Calculated factor for scaling m_settings->zoom():" << factor;
329 m_settings->setZoom(m_settings->zoom()*factor);
330
331 kDebug() << "New exact zoom:" << m_settings->zoom();
332
333 if (m_settings->zoom() < 0.01)
334 m_settings->setZoom(0.01);
335 if (m_settings->zoom() > 1.0)
336 m_settings->setZoom(1.0);
337
338 m_settings->setZoom((((int)(m_settings->zoom()*100 + 0.5)) / 100.0));
339
340 kDebug() << "New rounded zoom:" << m_settings->zoom();
341
342 q->updateVerticalPageParameters(0); // clear all parameters
343 calculateVerticalPageParameters(printRange.bottom());
344 currentPages = m_lnewPageListY.count();
345
346 kDebug() << "Number of pages with this zoom:" << currentPages;
347
348 while ((currentPages > verticalPageLimit) && (m_settings->zoom() > 0.01)) {
349 m_settings->setZoom(m_settings->zoom() - 0.01);
350 q->updateVerticalPageParameters(0); // clear all parameters
351 calculateVerticalPageParameters(printRange.bottom());
352 currentPages = m_lnewPageListY.count();
353 kDebug() << "Looping -0.01; current zoom:" << m_settings->zoom();
354 }
355
356 if (m_settings->zoom() < origZoom) {
357 // Trigger an update of the horizontal page parameters.
358 q->updateHorizontalPageParameters(0); // clear all parameters
359 calculateHorizontalPageParameters(printRange.right());
360 } else
361 m_settings->setZoom(origZoom);
362}
363
364void SheetPrint::Private::updateRepeatedColumnsWidth()
365{
366 m_dPrintRepeatColumnsWidth = 0.0;
367 const QPair<int, int> repeatedColumns = m_settings->repeatedColumns();
368 if (repeatedColumns.first != 0) {
369 for (int i = repeatedColumns.first; i <= repeatedColumns.second; i++) {
370 m_dPrintRepeatColumnsWidth += m_pSheet->columnFormat(i)->width();
371 }
372 }
373}
374
375void SheetPrint::Private::updateRepeatedRowsHeight()
376{
377 m_dPrintRepeatRowsHeight = 0.0;
378 const QPair<int, int> repeatedRows = m_settings->repeatedRows();
379 if (repeatedRows.first != 0) {
380 m_dPrintRepeatRowsHeight += m_pSheet->rowFormats()->totalRowHeight(repeatedRows.first, repeatedRows.second);
381 }
382}
383
384bool PrintNewPageEntry::operator==(PrintNewPageEntry const & entry) const
385{
386 return m_iStartItem == entry.m_iStartItem;
387}
388