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 | |
31 | using namespace Calligra::Sheets; |
32 | |
33 | void 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 | |
143 | void 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 | |
245 | void 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 | |
305 | void 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 | |
364 | void 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 | |
375 | void 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 | |
384 | bool PrintNewPageEntry::operator==(PrintNewPageEntry const & entry) const |
385 | { |
386 | return m_iStartItem == entry.m_iStartItem; |
387 | } |
388 | |