File indexing completed on 2024-04-28 16:21:31

0001 /* This file is part of the KDE project
0002    Copyright 2007, 2009 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
0003    Copyright 2005 Raphael Langerhorst <raphael.langerhorst@kdemail.net>
0004    Copyright 2003 Philipp Müller <philipp.mueller@gmx.de>
0005    Copyright 1998, 1999 Torben Weis <weis@kde.org>
0006 
0007    This library is free software; you can redistribute it and/or
0008    modify it under the terms of the GNU Library General Public
0009    License as published by the Free Software Foundation; either
0010    version 2 of the License, or (at your option) any later version.
0011 
0012    This library is distributed in the hope that it will be useful,
0013    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015    Library General Public License for more details.
0016 
0017    You should have received a copy of the GNU Library General Public License
0018    along with this library; see the file COPYING.LIB.  If not, write to
0019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020    Boston, MA 02110-1301, USA.
0021 */
0022 
0023 #include "SheetPrint_p.h"
0024 
0025 #include "PrintSettings.h"
0026 #include "Region.h"
0027 #include "RowColumnFormat.h"
0028 #include "RowFormatStorage.h"
0029 #include "Sheet.h"
0030 
0031 using namespace Calligra::Sheets;
0032 
0033 void SheetPrint::Private::calculateHorizontalPageParameters(int _column)
0034 {
0035     // Zoom the print width ONCE here, instead for each column width.
0036     const double printWidth = m_settings->printWidth() / m_settings->zoom();
0037 
0038     float offset = 0.0;
0039 
0040     //Are these the edges of the print range?
0041     const QRect printRange = m_settings->printRegion().lastRange();
0042 #if 0
0043     if (_column == printRange.left() || _column == printRange.right()) {
0044         if (_column > m_maxCheckedNewPageX)
0045             m_maxCheckedNewPageX = _column;
0046         return;
0047     }
0048 
0049     //We don't check beyond the print range
0050     if (_column < printRange.left() || _column > printRange.right()) {
0051         if (_column > m_maxCheckedNewPageX)
0052             m_maxCheckedNewPageX = _column;
0053         if (_column > printRange.right()) {
0054             if (m_lnewPageListX.last().endItem() == 0)
0055                 m_lnewPageListX.last().setEndItem(printRange.right());
0056         }
0057         return;
0058     }
0059 #endif
0060 
0061     // Check if the pre-calculated width matches the repeated columns setting.
0062     const bool repetitions = m_settings->repeatedColumns().first != 0;
0063     if (repetitions != (m_dPrintRepeatColumnsWidth == 0.0)) {
0064         // Existing column repetitions, but their pre-calculated width is zero?
0065         // Must be the first run. Or the other way around? Seem to be orphaned.
0066         // Either way, seems they do not match. Calculate them!
0067         updateRepeatedColumnsWidth();
0068     }
0069 
0070     // The end of the last item (zero, if list is empty).
0071     const int end = m_lnewPageListX.empty() ? 0 : m_lnewPageListX.last().endItem();
0072 
0073     //If _column is greater than the last entry, we need to calculate the result
0074     if (_column > end &&
0075             _column > m_maxCheckedNewPageX) { //this columns hasn't been calculated before
0076         int startCol = end + 1;
0077         int col = startCol;
0078         double x = m_pSheet->columnFormat(col)->width();
0079 
0080         // Add a new page.
0081         m_lnewPageListX.append(PrintNewPageEntry(startCol));
0082 
0083         //Add repeated column width, when necessary
0084         const QPair<int, int> repeatedColumns = m_settings->repeatedColumns();
0085         if (col > repeatedColumns.first) {
0086             x += m_dPrintRepeatColumnsWidth;
0087             offset = m_dPrintRepeatColumnsWidth;
0088         }
0089         debugSheets << "startCol:" << startCol << "col:" << col << "x:" << x
0090                  << "offset:" << offset << repeatedColumns;
0091 
0092         while ((col <= _column) && (col < printRange.right())) {
0093             debugSheets << "loop:" << "startCol:" << startCol << "col:" << col
0094                      << "x:" << x << "offset:" << offset;
0095             // end of page?
0096             if (x > printWidth || m_pSheet->columnFormat(col)->hasPageBreak()) {
0097                 //Now store into the previous entry the enditem and the width
0098                 m_lnewPageListX.last().setEndItem(col - 1);
0099                 m_lnewPageListX.last().setSize(x - m_pSheet->columnFormat(col)->width());
0100                 m_lnewPageListX.last().setOffset(offset);
0101 
0102                 //start a new page
0103                 m_lnewPageListX.append(PrintNewPageEntry(col));
0104                 startCol = col;
0105                 x = m_pSheet->columnFormat(col)->width();
0106                 if (col >= repeatedColumns.first) {
0107                     debugSheets << "col >= repeatedColumns.first:" << col << repeatedColumns.first;
0108                     x += m_dPrintRepeatColumnsWidth;
0109                     offset = m_dPrintRepeatColumnsWidth;
0110                 }
0111             }
0112             col++;
0113             x += m_pSheet->columnFormat(col)->width();
0114         }
0115 
0116         // Iterate to the end of the page.
0117         while (m_lnewPageListX.last().endItem() == 0) {
0118             debugSheets << "loop to end" << "col:" << col << "x:" << x << "offset:" << offset
0119                         << "m_maxCheckedNewPageX:" << m_maxCheckedNewPageX;
0120             if (x > printWidth || m_pSheet->columnFormat(col)->hasPageBreak()) {
0121                 // Now store into the previous entry the enditem and the width
0122                 m_lnewPageListX.last().setEndItem(col - 1);
0123                 m_lnewPageListX.last().setSize(x - m_pSheet->columnFormat(col)->width());
0124                 m_lnewPageListX.last().setOffset(offset);
0125 
0126                 if (col - 1 > m_maxCheckedNewPageX) {
0127                     m_maxCheckedNewPageX = col - 1;
0128                 }
0129                 return;
0130             }
0131             ++col;
0132             x += m_pSheet->columnFormat(col)->width();
0133         }
0134     }
0135 
0136     debugSheets << "m_maxCheckedNewPageX:" << m_maxCheckedNewPageX;
0137     if (_column > m_maxCheckedNewPageX) {
0138         m_maxCheckedNewPageX = _column;
0139         m_lnewPageListX.last().setEndItem(_column);
0140     }
0141 }
0142 
0143 void SheetPrint::Private::calculateVerticalPageParameters(int _row)
0144 {
0145     // Zoom the print height ONCE here, instead for each row height.
0146     const double printHeight = m_settings->printHeight() / m_settings->zoom();
0147 
0148     float offset = 0.0;
0149 
0150     //Are these the edges of the print range?
0151     const QRect printRange = m_settings->printRegion().lastRange();
0152 #if 0
0153     if (_row == printRange.top() || _row == printRange.bottom()) {
0154         if (_row > m_maxCheckedNewPageY)
0155             m_maxCheckedNewPageY = _row;
0156         return;
0157     }
0158 
0159     //beyond the print range it's always false
0160     if (_row < printRange.top() || _row > printRange.bottom()) {
0161         if (_row > m_maxCheckedNewPageY)
0162             m_maxCheckedNewPageY = _row;
0163         if (_row > printRange.bottom()) {
0164             if (m_lnewPageListY.last().endItem() == 0)
0165                 m_lnewPageListY.last().setEndItem(printRange.bottom());
0166         }
0167         return;
0168     }
0169 #endif
0170 
0171     // Check if the pre-calculated height matches the repeated rows setting.
0172     const bool repetitions = m_settings->repeatedRows().first != 0;
0173     if (repetitions != (m_dPrintRepeatRowsHeight == 0.0)) {
0174         // Existing row repetitions, but their pre-calculated height is zero?
0175         // Must be the first run. Or the other way around? Seem to be orphaned.
0176         // Either way, seems they do not match. Calculate them!
0177         updateRepeatedRowsHeight();
0178     }
0179 
0180     // The end of the last item (zero, if list is empty).
0181     const int end = m_lnewPageListY.empty() ? 0 : m_lnewPageListY.last().endItem();
0182 
0183     //If _column is greater than the last entry, we need to calculate the result
0184     if (_row > end &&
0185             _row > m_maxCheckedNewPageY) { //this columns hasn't been calculated before
0186         int startRow = end + 1;
0187         int row = startRow;
0188         double y = m_pSheet->rowFormats()->rowHeight(row);
0189 
0190         // Add a new page.
0191         m_lnewPageListY.append(PrintNewPageEntry(startRow));
0192 
0193         //Add repeated row height, when necessary
0194         const QPair<int, int> repeatedRows = m_settings->repeatedRows();
0195         if (row > repeatedRows.first) {
0196             y += m_dPrintRepeatRowsHeight;
0197             offset = m_dPrintRepeatRowsHeight;
0198         }
0199 
0200         while ((row <= _row) && (row < printRange.bottom())) {
0201             // end of page?
0202             if (y > printHeight || m_pSheet->rowFormats()->hasPageBreak(row)) {
0203                 //Now store into the previous entry the enditem and the width
0204                 m_lnewPageListY.last().setEndItem(row - 1);
0205                 m_lnewPageListY.last().setSize(y - m_pSheet->rowFormats()->rowHeight(row));
0206                 m_lnewPageListY.last().setOffset(offset);
0207 
0208                 //start a new page
0209                 m_lnewPageListY.append(PrintNewPageEntry(row));
0210                 startRow = row;
0211                 y = m_pSheet->rowFormats()->rowHeight(row);
0212                 if (row >= repeatedRows.first) {
0213                     y += m_dPrintRepeatRowsHeight;
0214                     offset = m_dPrintRepeatRowsHeight;
0215                 }
0216             }
0217             row++;
0218             y += m_pSheet->rowFormats()->rowHeight(row);
0219         }
0220 
0221         // Iterate to the end of the page.
0222         while (m_lnewPageListY.last().endItem() == 0) {
0223             if (y > printHeight || m_pSheet->rowFormats()->hasPageBreak(row)) {
0224                 // Now store into the previous entry the enditem and the width
0225                 m_lnewPageListY.last().setEndItem(row - 1);
0226                 m_lnewPageListY.last().setSize(y - m_pSheet->rowFormats()->rowHeight(row));
0227                 m_lnewPageListY.last().setOffset(offset);
0228 
0229                 if (row - 1 > m_maxCheckedNewPageY) {
0230                     m_maxCheckedNewPageY = row - 1;
0231                 }
0232                 return;
0233             }
0234             ++row;
0235             y += m_pSheet->rowFormats()->rowHeight(row);
0236         }
0237     }
0238 
0239     if (_row > m_maxCheckedNewPageY) {
0240         m_maxCheckedNewPageY = _row;
0241         m_lnewPageListY.last().setEndItem(_row);
0242     }
0243 }
0244 
0245 void SheetPrint::Private::calculateZoomForPageLimitX()
0246 {
0247     debugSheets << "Calculating zoom for X limit";
0248     const int horizontalPageLimit = m_settings->pageLimits().width();
0249     if (horizontalPageLimit == 0)
0250         return;
0251 
0252     const double origZoom = m_settings->zoom();
0253 
0254     if (m_settings->zoom() < 1.0) {
0255         q->updateHorizontalPageParameters(0);   // clear all parameters
0256         m_settings->setZoom(1.0);
0257     }
0258 
0259     QRect printRange = m_pSheet->usedArea(true);
0260     calculateHorizontalPageParameters(printRange.right());
0261     int currentPages = m_lnewPageListX.count();
0262 
0263     if (currentPages <= horizontalPageLimit)
0264         return;
0265 
0266     //calculating a factor for scaling the zoom down makes it lots faster
0267     double factor = (double)horizontalPageLimit / (double)currentPages +
0268                     1 - (double)currentPages / ((double)currentPages + 1); //add possible error;
0269     debugSheets << "Calculated factor for scaling m_settings->zoom():" << factor;
0270     m_settings->setZoom(m_settings->zoom()*factor);
0271 
0272     debugSheets << "New exact zoom:" << m_settings->zoom();
0273 
0274     if (m_settings->zoom() < 0.01)
0275         m_settings->setZoom(0.01);
0276     if (m_settings->zoom() > 1.0)
0277         m_settings->setZoom(1.0);
0278 
0279     m_settings->setZoom((((int)(m_settings->zoom()*100 + 0.5)) / 100.0));
0280 
0281     debugSheets << "New rounded zoom:" << m_settings->zoom();
0282 
0283     q->updateHorizontalPageParameters(0);   // clear all parameters
0284     calculateHorizontalPageParameters(printRange.right());
0285     currentPages = m_lnewPageListX.count();
0286 
0287     debugSheets << "Number of pages with this zoom:" << currentPages;
0288 
0289     while ((currentPages > horizontalPageLimit) && (m_settings->zoom() > 0.01)) {
0290         m_settings->setZoom(m_settings->zoom() - 0.01);
0291         q->updateHorizontalPageParameters(0);   // clear all parameters
0292         calculateHorizontalPageParameters(printRange.right());
0293         currentPages = m_lnewPageListX.count();
0294         debugSheets << "Looping -0.01; current zoom:" << m_settings->zoom();
0295     }
0296 
0297     if (m_settings->zoom() < origZoom) {
0298         // Trigger an update of the vertical page parameters.
0299         q->updateVerticalPageParameters(0); // clear all parameters
0300         calculateVerticalPageParameters(printRange.bottom());
0301     } else
0302         m_settings->setZoom(origZoom);
0303 }
0304 
0305 void SheetPrint::Private::calculateZoomForPageLimitY()
0306 {
0307     debugSheets << "Calculating zoom for Y limit";
0308     const int verticalPageLimit = m_settings->pageLimits().height();
0309     if (verticalPageLimit == 0)
0310         return;
0311 
0312     const double origZoom = m_settings->zoom();
0313 
0314     if (m_settings->zoom() < 1.0) {
0315         q->updateVerticalPageParameters(0);   // clear all parameters
0316         m_settings->setZoom(1.0);
0317     }
0318 
0319     QRect printRange = m_pSheet->usedArea(true);
0320     calculateVerticalPageParameters(printRange.bottom());
0321     int currentPages = m_lnewPageListY.count();
0322 
0323     if (currentPages <= verticalPageLimit)
0324         return;
0325 
0326     double factor = (double)verticalPageLimit / (double)currentPages +
0327                     1 - (double)currentPages / ((double)currentPages + 1); //add possible error
0328     debugSheets << "Calculated factor for scaling m_settings->zoom():" << factor;
0329     m_settings->setZoom(m_settings->zoom()*factor);
0330 
0331     debugSheets << "New exact zoom:" << m_settings->zoom();
0332 
0333     if (m_settings->zoom() < 0.01)
0334         m_settings->setZoom(0.01);
0335     if (m_settings->zoom() > 1.0)
0336         m_settings->setZoom(1.0);
0337 
0338     m_settings->setZoom((((int)(m_settings->zoom()*100 + 0.5)) / 100.0));
0339 
0340     debugSheets << "New rounded zoom:" << m_settings->zoom();
0341 
0342     q->updateVerticalPageParameters(0);   // clear all parameters
0343     calculateVerticalPageParameters(printRange.bottom());
0344     currentPages = m_lnewPageListY.count();
0345 
0346     debugSheets << "Number of pages with this zoom:" << currentPages;
0347 
0348     while ((currentPages > verticalPageLimit) && (m_settings->zoom() > 0.01)) {
0349         m_settings->setZoom(m_settings->zoom() - 0.01);
0350         q->updateVerticalPageParameters(0);   // clear all parameters
0351         calculateVerticalPageParameters(printRange.bottom());
0352         currentPages = m_lnewPageListY.count();
0353         debugSheets << "Looping -0.01; current zoom:" << m_settings->zoom();
0354     }
0355 
0356     if (m_settings->zoom() < origZoom) {
0357         // Trigger an update of the horizontal page parameters.
0358         q->updateHorizontalPageParameters(0); // clear all parameters
0359         calculateHorizontalPageParameters(printRange.right());
0360     } else
0361         m_settings->setZoom(origZoom);
0362 }
0363 
0364 void SheetPrint::Private::updateRepeatedColumnsWidth()
0365 {
0366     m_dPrintRepeatColumnsWidth = 0.0;
0367     const QPair<int, int> repeatedColumns = m_settings->repeatedColumns();
0368     if (repeatedColumns.first != 0) {
0369         for (int i = repeatedColumns.first; i <= repeatedColumns.second; i++) {
0370             m_dPrintRepeatColumnsWidth += m_pSheet->columnFormat(i)->width();
0371         }
0372     }
0373 }
0374 
0375 void SheetPrint::Private::updateRepeatedRowsHeight()
0376 {
0377     m_dPrintRepeatRowsHeight = 0.0;
0378     const QPair<int, int> repeatedRows = m_settings->repeatedRows();
0379     if (repeatedRows.first != 0) {
0380         m_dPrintRepeatRowsHeight += m_pSheet->rowFormats()->totalRowHeight(repeatedRows.first, repeatedRows.second);
0381     }
0382 }
0383 
0384 bool PrintNewPageEntry::operator==(PrintNewPageEntry const & entry) const
0385 {
0386     return m_iStartItem == entry.m_iStartItem;
0387 }