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 // Local
0024 #include "SheetPrint.h"
0025 #include "SheetPrint_p.h"
0026 
0027 #include "HeaderFooter.h"
0028 #include "PrintSettings.h"
0029 #include "calligra_sheets_limits.h"
0030 #include "Region.h"
0031 #include "Sheet.h"
0032 #include "SheetsDebug.h"
0033 
0034 using namespace Calligra::Sheets;
0035 
0036 SheetPrint::SheetPrint(Sheet *sheet)
0037         : d(new Private(this))
0038 {
0039     d->m_pSheet = sheet;
0040 
0041     d->m_settings = new PrintSettings();
0042     d->m_headerFooter = new HeaderFooter(sheet);
0043 
0044     d->m_maxCheckedNewPageX = 0;
0045     d->m_maxCheckedNewPageY = 0;
0046     d->m_dPrintRepeatColumnsWidth = 0.0;
0047     d->m_dPrintRepeatRowsHeight = 0.0;
0048 }
0049 
0050 SheetPrint::SheetPrint(const SheetPrint &other)
0051         : d(new Private(this))
0052 {
0053     d->m_pSheet = other.d->m_pSheet;
0054 
0055     d->m_settings = new PrintSettings(*other.d->m_settings);
0056     d->m_headerFooter = new HeaderFooter(*other.d->m_headerFooter);
0057 
0058     d->m_maxCheckedNewPageX = other.d->m_maxCheckedNewPageX;
0059     d->m_maxCheckedNewPageY = other.d->m_maxCheckedNewPageY;
0060     d->m_dPrintRepeatColumnsWidth = other.d->m_dPrintRepeatColumnsWidth;
0061     d->m_dPrintRepeatRowsHeight = other.d->m_dPrintRepeatRowsHeight;
0062     d->m_lnewPageListX = other.d->m_lnewPageListX;
0063     d->m_lnewPageListY = other.d->m_lnewPageListY;
0064 }
0065 
0066 SheetPrint::~SheetPrint()
0067 {
0068     delete d->m_headerFooter;
0069     delete d->m_settings;
0070     delete d;
0071 }
0072 
0073 PrintSettings *SheetPrint::settings() const
0074 {
0075     return d->m_settings;
0076 }
0077 
0078 void SheetPrint::setSettings(const PrintSettings &settings, bool force)
0079 {
0080     // Relayout forced?
0081     if (force) {
0082         *d->m_settings = settings;
0083         d->updateRepeatedColumnsWidth();
0084         d->updateRepeatedRowsHeight();
0085         const QSize pageLimits = settings.pageLimits();
0086         const QSize usedArea = d->m_pSheet->usedArea(true).size();
0087         if (pageLimits.width() > 0) {
0088             d->calculateZoomForPageLimitX();
0089         } else {
0090             updateHorizontalPageParameters(0);
0091             d->calculateHorizontalPageParameters(usedArea.width());
0092         }
0093         if (pageLimits.height() > 0) {
0094             d->calculateZoomForPageLimitY();
0095         } else {
0096             updateVerticalPageParameters(0);
0097             d->calculateVerticalPageParameters(usedArea.height());
0098         }
0099         return;
0100     }
0101 
0102     const KoPageLayout oldPageLayout = d->m_settings->pageLayout();
0103     const KoPageLayout pageLayout = settings.pageLayout();
0104     const QRect oldPrintRange = d->m_settings->printRegion().lastRange();
0105     const QRect printRange = settings.printRegion().lastRange();
0106     const QSize oldPageLimits = d->m_settings->pageLimits();
0107     const QSize pageLimits = settings.pageLimits();
0108     const QPair<int, int> oldRepeatedColumns = d->m_settings->repeatedColumns();
0109     const QPair<int, int> repeatedColumns = settings.repeatedColumns();
0110     const QPair<int, int> oldRepeatedRows = d->m_settings->repeatedRows();
0111     const QPair<int, int> repeatedRows = settings.repeatedRows();
0112 
0113     const bool pageWidthChanged = oldPageLayout.width != pageLayout.width;
0114     const bool pageHeightChanged = oldPageLayout.height != pageLayout.height;
0115     const bool horizontalLimitChanged = oldPageLimits.width() != pageLimits.width();
0116     const bool verticalLimitChanged = oldPageLimits.height() != pageLimits.height();
0117     const bool repeatedColumnsChanged = oldRepeatedColumns != repeatedColumns;
0118     const bool repeatedRowsChanged = oldRepeatedRows != repeatedRows;
0119     const bool zoomChanged = d->m_settings->zoom() != settings.zoom();
0120 
0121     *d->m_settings = settings;
0122 
0123     // The starting column/row for the page parameter updates.
0124     int column = KS_colMax + 1;
0125     int row = KS_rowMax + 1;
0126 
0127     // The print range.
0128     if (oldPrintRange.left() != printRange.left()) {
0129         column = qMin(oldPrintRange.left(), printRange.left());
0130     }
0131     if (oldPrintRange.top() != printRange.top()) {
0132         row = qMin(oldPrintRange.top(), printRange.top());
0133     }
0134 
0135     // The zoom.
0136     if (zoomChanged) {
0137         column = 0;
0138         row = 0;
0139     }
0140 
0141     // The page limits.
0142     if (horizontalLimitChanged && pageLimits.width() <= 0) {
0143         column = 0;
0144     }
0145     if (verticalLimitChanged && pageLimits.height() <= 0) {
0146         row = 0;
0147     }
0148 
0149     // The page dimensions.
0150     if (pageWidthChanged) {
0151         column = 0;
0152     }
0153     if (pageHeightChanged) {
0154         row = 0;
0155     }
0156 
0157     // The column/row repetitions.
0158     if (repeatedColumnsChanged) {
0159         d->updateRepeatedColumnsWidth();
0160         column = qMin(column, oldRepeatedColumns.first);
0161         column = qMin(column, repeatedColumns.first);
0162     }
0163     if (repeatedRowsChanged) {
0164         d->updateRepeatedRowsHeight();
0165         row = qMin(row, oldRepeatedRows.first);
0166         row = qMin(row, repeatedRows.first);
0167     }
0168 
0169     // Update the page parameters.
0170     // If page limits are set to non-zero, call the special methods.
0171     if (horizontalLimitChanged && pageLimits.width() > 0) {
0172         d->calculateZoomForPageLimitX();
0173     } else if (column <= KS_colMax) {
0174         updateHorizontalPageParameters(column);
0175     }
0176     if (verticalLimitChanged && pageLimits.height() > 0) {
0177         d->calculateZoomForPageLimitY();
0178     } else if (row <= KS_rowMax) {
0179         updateVerticalPageParameters(row);
0180     }
0181 }
0182 
0183 HeaderFooter *SheetPrint::headerFooter() const
0184 {
0185     return d->m_headerFooter;
0186 }
0187 
0188 bool SheetPrint::isColumnOnNewPage(int _column)
0189 {
0190     if (_column > d->m_maxCheckedNewPageX)
0191         d->calculateHorizontalPageParameters(_column);
0192 
0193     //Are these the edges of the print range?
0194     const QRect printRange = d->m_settings->printRegion().lastRange();
0195     if (_column == printRange.left() || _column == printRange.right()) {
0196         return true;
0197     }
0198 
0199     //beyond the print range it's always false
0200     if (_column < printRange.left() || _column > printRange.right()) {
0201         return false;
0202     }
0203 
0204     //Now check if we find the column already in the list
0205     if (d->m_lnewPageListX.indexOf(PrintNewPageEntry(_column)) != -1) {
0206         if (_column > d->m_maxCheckedNewPageX)
0207             d->m_maxCheckedNewPageX = _column;
0208         return true;
0209     }
0210     return false;
0211 }
0212 
0213 
0214 
0215 bool SheetPrint::isRowOnNewPage(int _row)
0216 {
0217     if (_row > d->m_maxCheckedNewPageY)
0218         d->calculateVerticalPageParameters(_row);
0219 
0220     //Are these the edges of the print range?
0221     const QRect printRange = d->m_settings->printRegion().lastRange();
0222     if (_row == printRange.top() || _row == printRange.bottom()) {
0223         return true;
0224     }
0225 
0226     //beyond the print range it's always false
0227     if (_row < printRange.top() || _row > printRange.bottom()) {
0228         return false;
0229     }
0230 
0231     //Now check if we find the row already in the list
0232     if (d->m_lnewPageListY.indexOf(PrintNewPageEntry(_row)) != -1) {
0233         if (_row > d->m_maxCheckedNewPageY)
0234             d->m_maxCheckedNewPageY = _row;
0235         return true;
0236     }
0237 
0238     return false;
0239 }
0240 
0241 void SheetPrint::updateHorizontalPageParameters(int _col)
0242 {
0243     //If the new range is after the first entry, we need to delete the whole list
0244     const QRect printRange = d->m_settings->printRegion().lastRange();
0245     if (d->m_lnewPageListX.isEmpty() || d->m_lnewPageListX.first().startItem() != printRange.left() || _col == 0) {
0246         d->m_lnewPageListX.clear();
0247         d->m_maxCheckedNewPageX = 0;
0248         d->updateRepeatedColumnsWidth();
0249         return;
0250     }
0251 
0252     if (_col <= d->m_lnewPageListX.last().endItem()) {
0253         // Find the page entry for this column
0254         int index = d->m_lnewPageListX.count() - 1;
0255         while (_col < d->m_lnewPageListX[index].startItem()) {
0256             --index;
0257         }
0258 
0259         //Remove later pages
0260         while (index != d->m_lnewPageListX.count())
0261             d->m_lnewPageListX.removeAt(index);
0262 
0263         d->m_maxCheckedNewPageX = d->m_lnewPageListX.isEmpty() ? 0 : d->m_lnewPageListX.last().endItem();
0264     }
0265 
0266     // The column is not beyond the repeated columns?
0267     if (_col <= d->m_settings->repeatedColumns().second) {
0268         d->updateRepeatedColumnsWidth();
0269     }
0270 }
0271 
0272 void SheetPrint::updateVerticalPageParameters(int _row)
0273 {
0274     //If the new range is after the first entry, we need to delete the whole list
0275     const QRect printRange = d->m_settings->printRegion().lastRange();
0276     if (d->m_lnewPageListY.isEmpty() || d->m_lnewPageListY.first().startItem() != printRange.top() || _row == 0) {
0277         d->m_lnewPageListY.clear();
0278         d->m_maxCheckedNewPageY = 0;
0279         d->updateRepeatedRowsHeight();
0280         return;
0281     }
0282 
0283     if (_row <= d->m_lnewPageListY.last().endItem()) {
0284         // Find the page entry for this row
0285         int index = d->m_lnewPageListY.count() - 1;
0286         while (_row < d->m_lnewPageListY[index].startItem()) {
0287             --index;
0288         }
0289 
0290         //Remove later pages
0291         while (index != d->m_lnewPageListY.count())
0292             d->m_lnewPageListY.removeAt(index);
0293 
0294         d->m_maxCheckedNewPageY = d->m_lnewPageListY.isEmpty() ? 0 : d->m_lnewPageListY.last().endItem();
0295     }
0296 
0297     // The row is not beyond the repeated rows?
0298     if (_row <= d->m_settings->repeatedRows().second) {
0299         d->updateRepeatedRowsHeight();
0300     }
0301 }
0302 
0303 void SheetPrint::insertColumn(int col, int nbCol)
0304 {
0305     //update print range, when it has been defined
0306     const QRect printRange = d->m_settings->printRegion().lastRange();
0307     if (printRange != QRect(QPoint(1, 1), QPoint(KS_colMax, KS_rowMax))) {
0308         int left = printRange.left();
0309         int right = printRange.right();
0310 
0311         for (int i = 0; i < nbCol; i++) {
0312             if (left >= col) left++;
0313             if (right >= col) right++;
0314         }
0315         //Validity checks
0316         if (left > KS_colMax) left = KS_colMax;
0317         if (right > KS_colMax) right = KS_colMax;
0318         const Region region(QRect(QPoint(left, printRange.top()),
0319                                   QPoint(right, printRange.bottom())), d->m_pSheet);
0320         // Trigger an update by setting it indirectly.
0321         PrintSettings settings = *d->m_settings;
0322         settings.setPrintRegion(region);
0323         setSettings(settings);
0324     }
0325 }
0326 
0327 void SheetPrint::insertRow(int row, int nbRow)
0328 {
0329     //update print range, when it has been defined
0330     const QRect printRange = d->m_settings->printRegion().lastRange();
0331     if (printRange != QRect(QPoint(1, 1), QPoint(KS_colMax, KS_rowMax))) {
0332         int top = printRange.top();
0333         int bottom = printRange.bottom();
0334 
0335         for (int i = 0; i < nbRow; i++) {
0336             if (top >= row) top++;
0337             if (bottom >= row) bottom++;
0338         }
0339         //Validity checks
0340         if (top > KS_rowMax) top = KS_rowMax;
0341         if (bottom > KS_rowMax) bottom = KS_rowMax;
0342         const Region region(QRect(QPoint(printRange.left(), top),
0343                                   QPoint(printRange.right(), bottom)), d->m_pSheet);
0344         // Trigger an update by setting it indirectly.
0345         PrintSettings settings = *d->m_settings;
0346         settings.setPrintRegion(region);
0347         setSettings(settings);
0348     }
0349 }
0350 
0351 void SheetPrint::removeColumn(int col, int nbCol)
0352 {
0353     PrintSettings settings = *d->m_settings;
0354     //update print range, when it has been defined
0355     const QRect printRange = d->m_settings->printRegion().lastRange();
0356     if (printRange != QRect(QPoint(1, 1), QPoint(KS_colMax, KS_rowMax))) {
0357         int left = printRange.left();
0358         int right = printRange.right();
0359 
0360         for (int i = 0; i < nbCol; i++) {
0361             if (left > col) left--;
0362             if (right >= col) right--;
0363         }
0364         //Validity checks
0365         if (left < 1) left = 1;
0366         if (right < 1) right = 1;
0367         const Region region(QRect(QPoint(left, printRange.top()),
0368                                   QPoint(right, printRange.bottom())), d->m_pSheet);
0369         settings.setPrintRegion(region);
0370     }
0371 
0372     //update repeat columns, when it has been defined
0373     const QPair<int, int> repeatedColumns = d->m_settings->repeatedColumns();
0374     if (repeatedColumns.first != 0) {
0375         int left = repeatedColumns.first;
0376         int right = repeatedColumns.second;
0377 
0378         for (int i = 0; i < nbCol; i++) {
0379             if (left > col) left--;
0380             if (right >= col) right--;
0381         }
0382         //Validity checks
0383         if (left < 1) left = 1;
0384         if (right < 1) right = 1;
0385         settings.setRepeatedColumns(qMakePair(left, right));
0386     }
0387     // Trigger an update by setting them indirectly.
0388     setSettings(settings);
0389 }
0390 
0391 void SheetPrint::removeRow(int row, int nbRow)
0392 {
0393     PrintSettings settings = *d->m_settings;
0394     //update print range, when it has been defined
0395     const QRect printRange = d->m_settings->printRegion().lastRange();
0396     if (printRange != QRect(QPoint(1, 1), QPoint(KS_colMax, KS_rowMax))) {
0397         int top = printRange.top();
0398         int bottom = printRange.bottom();
0399 
0400         for (int i = 0; i < nbRow; i++) {
0401             if (top > row) top--;
0402             if (bottom >= row) bottom--;
0403         }
0404         //Validity checks
0405         if (top < 1) top = 1;
0406         if (bottom < 1) bottom = 1;
0407         const Region region(QRect(QPoint(printRange.left(), top),
0408                                   QPoint(printRange.right(), bottom)), d->m_pSheet);
0409         settings.setPrintRegion(region);
0410     }
0411 
0412     //update repeat rows, when it has been defined
0413     const QPair<int, int> repeatedRows = d->m_settings->repeatedRows();
0414     if (repeatedRows.first != 0) {
0415         int top = repeatedRows.first;
0416         int bottom = repeatedRows.second;
0417 
0418         for (int i = 0; i < nbRow; i++) {
0419             if (top > row) top--;
0420             if (bottom >= row) bottom--;
0421         }
0422         //Validity checks
0423         if (top < 1) top = 1;
0424         if (bottom < 1) bottom = 1;
0425         settings.setRepeatedRows(qMakePair(top, bottom));
0426     }
0427     // Trigger an update by setting them indirectly.
0428     setSettings(settings);
0429 }
0430 
0431 int SheetPrint::pageCount() const
0432 {
0433     return d->m_lnewPageListX.count() * d->m_lnewPageListY.count();
0434 }
0435 
0436 QRect SheetPrint::cellRange(int page) const
0437 {
0438     if (d->m_lnewPageListX.isEmpty() || d->m_lnewPageListY.isEmpty()) {
0439         return QRect();
0440     }
0441     if (page - 1 > pageCount()) {
0442         return QRect();
0443     }
0444     debugSheets << "page:" << page << "of" << pageCount();
0445 
0446     int horizontalIndex = 0;
0447     int verticalIndex = 0;
0448     if (d->m_settings->pageOrder() == PrintSettings::LeftToRight) {
0449         horizontalIndex = (page - 1) % d->m_lnewPageListX.count();
0450         verticalIndex = (page - 1) / d->m_lnewPageListX.count();
0451     } else {
0452         horizontalIndex = (page - 1) / d->m_lnewPageListY.count();
0453         verticalIndex = (page - 1) % d->m_lnewPageListY.count();
0454     }
0455     debugSheets << "horizontal:" << horizontalIndex + 1 << "of" << d->m_lnewPageListX.count();
0456     debugSheets << "vertical:" << verticalIndex + 1 << "of" << d->m_lnewPageListY.count();
0457 
0458     const PrintNewPageEntry horizontalParameters = d->m_lnewPageListX[horizontalIndex];
0459     const PrintNewPageEntry verticalParameters = d->m_lnewPageListY[verticalIndex];
0460 
0461     QRect cellRange;
0462     cellRange.setLeft(horizontalParameters.startItem());
0463     cellRange.setRight(horizontalParameters.endItem());
0464     cellRange.setTop(verticalParameters.startItem());
0465     cellRange.setBottom(verticalParameters.endItem());
0466     return cellRange;
0467 }
0468 
0469 QRectF SheetPrint::documentArea(int page) const
0470 {
0471     if (d->m_lnewPageListX.isEmpty() || d->m_lnewPageListY.isEmpty()) {
0472         return QRectF();
0473     }
0474     if (page - 1 > pageCount()) {
0475         return QRectF();
0476     }
0477 
0478     int horizontalIndex = 0;
0479     int verticalIndex = 0;
0480     if (d->m_settings->pageOrder() == PrintSettings::LeftToRight) {
0481         horizontalIndex = (page - 1) % d->m_lnewPageListX.count();
0482         verticalIndex = (page - 1) / d->m_lnewPageListX.count();
0483     } else {
0484         horizontalIndex = (page - 1) / d->m_lnewPageListY.count();
0485         verticalIndex = (page - 1) % d->m_lnewPageListY.count();
0486     }
0487 
0488     const PrintNewPageEntry horizontalParameters = d->m_lnewPageListX[horizontalIndex];
0489     const PrintNewPageEntry verticalParameters = d->m_lnewPageListY[verticalIndex];
0490 
0491     QRectF documentArea;
0492     documentArea.setLeft(horizontalParameters.offset());
0493     documentArea.setWidth(horizontalParameters.size());
0494     documentArea.setTop(verticalParameters.offset());
0495     documentArea.setHeight(verticalParameters.size());
0496     return documentArea;
0497 }
0498 
0499 void SheetPrint::operator=(const SheetPrint & other)
0500 {
0501     d->m_pSheet = other.d->m_pSheet;
0502 
0503     *d->m_settings = *other.d->m_settings;
0504     *d->m_headerFooter = *other.d->m_headerFooter;
0505 
0506     d->m_maxCheckedNewPageX = other.d->m_maxCheckedNewPageX;
0507     d->m_maxCheckedNewPageY = other.d->m_maxCheckedNewPageY;
0508     d->m_dPrintRepeatColumnsWidth = other.d->m_dPrintRepeatColumnsWidth;
0509     d->m_dPrintRepeatRowsHeight = other.d->m_dPrintRepeatRowsHeight;
0510     d->m_lnewPageListX = other.d->m_lnewPageListX;
0511     d->m_lnewPageListY = other.d->m_lnewPageListY;
0512 }