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 
calculateHorizontalPageParameters(int _column)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         debugSheets << "startCol:" << startCol << "col:" << col << "x:" << x
90                  << "offset:" << offset << repeatedColumns;
91 
92         while ((col <= _column) && (col < printRange.right())) {
93             debugSheets << "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                     debugSheets << "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             debugSheets << "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     debugSheets << "m_maxCheckedNewPageX:" << m_maxCheckedNewPageX;
137     if (_column > m_maxCheckedNewPageX) {
138         m_maxCheckedNewPageX = _column;
139         m_lnewPageListX.last().setEndItem(_column);
140     }
141 }
142 
calculateVerticalPageParameters(int _row)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 
calculateZoomForPageLimitX()245 void SheetPrint::Private::calculateZoomForPageLimitX()
246 {
247     debugSheets << "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     debugSheets << "Calculated factor for scaling m_settings->zoom():" << factor;
270     m_settings->setZoom(m_settings->zoom()*factor);
271 
272     debugSheets << "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     debugSheets << "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     debugSheets << "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         debugSheets << "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 
calculateZoomForPageLimitY()305 void SheetPrint::Private::calculateZoomForPageLimitY()
306 {
307     debugSheets << "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     debugSheets << "Calculated factor for scaling m_settings->zoom():" << factor;
329     m_settings->setZoom(m_settings->zoom()*factor);
330 
331     debugSheets << "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     debugSheets << "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     debugSheets << "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         debugSheets << "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 
updateRepeatedColumnsWidth()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 
updateRepeatedRowsHeight()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 
operator ==(PrintNewPageEntry const & entry) const384 bool PrintNewPageEntry::operator==(PrintNewPageEntry const & entry) const
385 {
386     return m_iStartItem == entry.m_iStartItem;
387 }
388