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

0001 /* This file is part of the KDE project
0002    Copyright (C) 1998, 1999  Torben Weis <weis@kde.org>
0003    Copyright (C) 2000 - 2005 The KSpread Team <calligra-devel@kde.org>
0004    
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018    Boston, MA 02110-1301, USA.
0019 */
0020 
0021 // Local
0022 #include "RowColumnFormat.h"
0023 
0024 #include <float.h>
0025 #include <iostream>
0026 #include <stdlib.h>
0027 #include <stdio.h>
0028 
0029 #include <KoXmlNS.h>
0030 #include <KoUnit.h>
0031 
0032 #include "SheetsDebug.h"
0033 #include "CellStorage.h"
0034 #include "Global.h"
0035 #include "Map.h"
0036 #include "Region.h"
0037 #include "RowFormatStorage.h"
0038 #include "Sheet.h"
0039 #include "SheetPrint.h"
0040 #include "Style.h"
0041 #include "StyleManager.h"
0042 
0043 using namespace std;
0044 using namespace Calligra::Sheets;
0045 
0046 /*****************************************************************************
0047  *
0048  * RowFormat
0049  *
0050  *****************************************************************************/
0051 
0052 class Q_DECL_HIDDEN RowFormat::Private
0053 {
0054 public:
0055     Sheet*      sheet;
0056     RowFormat*  next;
0057     RowFormat*  prev;
0058     double      height;
0059     int         row;
0060     bool        hide : 1;
0061     bool        filtered : 1;
0062     bool        pageBreak : 1; // before row
0063 };
0064 
0065 RowFormat::RowFormat()
0066         : d(new Private)
0067 {
0068     d->sheet    = 0;
0069     d->row      = 0;
0070     d->height   = 0.0;
0071     d->hide     = false;
0072     d->filtered = false;
0073     d->pageBreak = false;
0074     d->next     = 0;
0075     d->prev     = 0;
0076 }
0077 
0078 RowFormat::RowFormat(const RowFormat& other)
0079         : d(new Private(*other.d))
0080 {
0081 }
0082 
0083 RowFormat::RowFormat(const RowFormatStorage *rows, int row)
0084         : d(new Private)
0085 {
0086     d->sheet = rows->sheet();
0087     d->row = row;
0088     d->height = rows->rowHeight(row);
0089     d->hide = rows->isHidden(row);
0090     d->filtered = rows->isFiltered(row);
0091     d->pageBreak = rows->hasPageBreak(row);
0092     d->next = d->prev = 0;
0093 }
0094 
0095 RowFormat::~RowFormat()
0096 {
0097     if (d->next)
0098         d->next->setPrevious(d->prev);
0099     if (d->prev)
0100         d->prev->setNext(d->next);
0101     delete d;
0102 }
0103 
0104 void RowFormat::setSheet(Sheet* sheet)
0105 {
0106     d->sheet = sheet;
0107 }
0108 
0109 void RowFormat::setHeight(double height)
0110 {
0111     // avoid unnecessary updates
0112     if (qAbs(height - this->height()) < DBL_EPSILON)
0113         return;
0114 
0115     // default RowFormat?
0116     if (!d->sheet) {
0117         d->height = height;
0118         return;
0119     }
0120 
0121     // Raise document height by new height and lower it by old height.
0122     if (!isHidden() && !isFiltered())
0123         d->sheet->adjustDocumentHeight(height - d->height);
0124 
0125     d->height = height;
0126 
0127     d->sheet->print()->updateVerticalPageParameters(row());
0128 }
0129 
0130 double RowFormat::height() const
0131 {
0132     return d->height;
0133 }
0134 
0135 double RowFormat::visibleHeight() const
0136 {
0137     if (d->hide || d->filtered)
0138         return 0.0;
0139     return d->height;
0140 }
0141 
0142 QDomElement RowFormat::save(QDomDocument& doc, int yshift) const
0143 {
0144     Q_ASSERT(d->sheet);
0145     QDomElement row = doc.createElement("row");
0146     row.setAttribute("height", QString::number(d->height));
0147     row.setAttribute("row", QString::number(d->row - yshift));
0148     if (d->hide)
0149         row.setAttribute("hide", QString::number((int) d->hide));
0150 
0151     const Style style = d->sheet->cellStorage()->style(QRect(1, d->row, KS_colMax, 1));
0152     if (!style.isEmpty()) {
0153         debugSheetsODF << "saving cell style of row" << d->row;
0154         QDomElement format;
0155         style.saveXML(doc, format, d->sheet->map()->styleManager());
0156         row.appendChild(format);
0157     }
0158 
0159     return row;
0160 }
0161 
0162 bool RowFormat::load(const KoXmlElement & row, int yshift, Paste::Mode mode)
0163 {
0164     Q_ASSERT(d->sheet);
0165     bool ok;
0166 
0167     d->row = row.attribute("row").toInt(&ok) + yshift;
0168     if (!ok)
0169         return false;
0170 
0171     if (row.hasAttribute("height")) {
0172         if (d->sheet->map()->syntaxVersion() < 1) //compatibility with old format - was in millimeter
0173             d->height = qRound(MM_TO_POINT(row.attribute("height").toDouble(&ok)));
0174         else
0175             d->height = row.attribute("height").toDouble(&ok);
0176 
0177         if (!ok) return false;
0178     }
0179 
0180     // Validation
0181     if (d->height < 0) {
0182         debugSheets << "Value height=" << d->height << " out of range";
0183         return false;
0184     }
0185     if (d->row < 1 || d->row > KS_rowMax) {
0186         debugSheets << "Value row=" << d->row << " out of range";
0187         return false;
0188     }
0189 
0190     if (row.hasAttribute("hide")) {
0191         setHidden((int) row.attribute("hide").toInt(&ok));
0192         if (!ok)
0193             return false;
0194     }
0195 
0196     KoXmlElement f(row.namedItem("format").toElement());
0197 
0198     if (!f.isNull() && (mode == Paste::Normal || mode == Paste::Format || mode == Paste::NoBorder)) {
0199         Style style;
0200         if (!style.loadXML(f, mode))
0201             return false;
0202         d->sheet->cellStorage()->setStyle(Region(QRect(1, d->row, KS_colMax, 1)), style);
0203         return true;
0204     }
0205 
0206     return true;
0207 }
0208 
0209 int RowFormat::row() const
0210 {
0211     return d->row;
0212 }
0213 
0214 void RowFormat::setRow(int row)
0215 {
0216     d->row = row;
0217 }
0218 
0219 RowFormat* RowFormat::next() const
0220 {
0221     return d->next;
0222 }
0223 
0224 RowFormat* RowFormat::previous() const
0225 {
0226     return d->prev;
0227 }
0228 
0229 void RowFormat::setNext(RowFormat* next)
0230 {
0231     d->next = next;
0232 }
0233 
0234 void RowFormat::setPrevious(RowFormat* prev)
0235 {
0236     d->prev = prev;
0237 }
0238 
0239 void RowFormat::setHidden(bool _hide, bool repaint)
0240 {
0241     Q_UNUSED(repaint);
0242     Q_ASSERT(d->sheet);
0243     if (_hide != d->hide) { // only if we change the status
0244         if (_hide) {
0245             // Lower maximum size by height of row
0246             d->sheet->adjustDocumentHeight(- height());
0247             d->hide = _hide; //hide must be set after we requested the height
0248         } else {
0249             // Rise maximum size by height of row
0250             d->hide = _hide; //unhide must be set before we request the height
0251             d->sheet->adjustDocumentHeight(height());
0252         }
0253     }
0254 }
0255 
0256 bool RowFormat::isHidden() const
0257 {
0258     return d->hide;
0259 }
0260 
0261 void RowFormat::setFiltered(bool filtered)
0262 {
0263     d->filtered = filtered;
0264 }
0265 
0266 bool RowFormat::isFiltered() const
0267 {
0268     return d->filtered;
0269 }
0270 
0271 bool RowFormat::isHiddenOrFiltered() const
0272 {
0273     return d->hide || d->filtered;
0274 }
0275 
0276 bool RowFormat::isDefault() const
0277 {
0278     return !d->sheet;
0279 }
0280 
0281 void RowFormat::setPageBreak(bool enable)
0282 {
0283     d->pageBreak = enable;
0284 }
0285 
0286 bool RowFormat::hasPageBreak() const
0287 {
0288     return d->pageBreak;
0289 }
0290 
0291 bool RowFormat::operator==(const RowFormat& other) const
0292 {
0293     // NOTE Stefan: Don't compare sheet and cell.
0294     if (d->height != other.d->height)
0295         return false;
0296     if (d->hide != other.d->hide)
0297         return false;
0298     if (d->filtered != other.d->filtered)
0299         return false;
0300     if (d->pageBreak != other.d->pageBreak) {
0301         return false;
0302     }
0303     return true;
0304 }
0305 
0306 
0307 /*****************************************************************************
0308  *
0309  * ColumnFormat
0310  *
0311  *****************************************************************************/
0312 
0313 class Q_DECL_HIDDEN ColumnFormat::Private
0314 {
0315 public:
0316     Sheet*          sheet;
0317     ColumnFormat*   next;
0318     ColumnFormat*   prev;
0319     double          width;
0320     int             column;
0321     bool            hide : 1;
0322     bool            filtered : 1;
0323     bool            pageBreak : 1; // before column
0324 };
0325 
0326 ColumnFormat::ColumnFormat()
0327         : d(new Private)
0328 {
0329     d->sheet    = 0;
0330     d->column   = 0;
0331     d->width    = 0.0;
0332     d->hide     = false;
0333     d->filtered = false;
0334     d->pageBreak = false;
0335     d->next     = 0;
0336     d->prev     = 0;
0337 }
0338 
0339 ColumnFormat::ColumnFormat(const ColumnFormat& other)
0340         : d(new Private(*other.d))
0341 {
0342 }
0343 
0344 ColumnFormat::~ColumnFormat()
0345 {
0346     if (d->next)
0347         d->next->setPrevious(d->prev);
0348     if (d->prev)
0349         d->prev->setNext(d->next);
0350     delete d;
0351 }
0352 
0353 void ColumnFormat::setSheet(Sheet* sheet)
0354 {
0355     d->sheet = sheet;
0356 }
0357 
0358 void ColumnFormat::setWidth(double width)
0359 {
0360     // avoid unnecessary updates
0361     if (qAbs(width - this->width()) < DBL_EPSILON)
0362         return;
0363 
0364     // default ColumnFormat?
0365     if (!d->sheet) {
0366         d->width = width;
0367         return;
0368     }
0369 
0370     // Raise document width by new width and lower it by old width.
0371     if (!isHidden() && !isFiltered())
0372         d->sheet->adjustDocumentWidth(width - d->width);
0373 
0374     d->width = width;
0375 
0376     d->sheet->print()->updateHorizontalPageParameters(column());
0377 }
0378 
0379 double ColumnFormat::width() const
0380 {
0381     return d->width;
0382 }
0383 
0384 double ColumnFormat::visibleWidth() const
0385 {
0386     if (d->hide || d->filtered)
0387         return 0.0;
0388     return d->width;
0389 }
0390 
0391 QDomElement ColumnFormat::save(QDomDocument& doc, int xshift) const
0392 {
0393     Q_ASSERT(d->sheet);
0394     QDomElement col(doc.createElement("column"));
0395     col.setAttribute("width", QString::number(d->width));
0396     col.setAttribute("column", QString::number(d->column - xshift));
0397 
0398     if (d->hide)
0399         col.setAttribute("hide", QString::number((int) d->hide));
0400 
0401     const Style style = d->sheet->cellStorage()->style(QRect(d->column, 1, 1, KS_rowMax));
0402     if (!style.isEmpty()) {
0403         debugSheetsODF << "saving cell style of column" << d->column;
0404         QDomElement format(doc.createElement("format"));
0405         style.saveXML(doc, format, d->sheet->map()->styleManager());
0406         col.appendChild(format);
0407     }
0408 
0409     return col;
0410 }
0411 
0412 bool ColumnFormat::load(const KoXmlElement & col, int xshift, Paste::Mode mode)
0413 {
0414     Q_ASSERT(d->sheet);
0415     bool ok;
0416     if (col.hasAttribute("width")) {
0417         if (d->sheet->map()->syntaxVersion() < 1) //combatibility to old format - was in millimeter
0418             d->width = qRound(MM_TO_POINT(col.attribute("width").toDouble(&ok)));
0419         else
0420             d->width = col.attribute("width").toDouble(&ok);
0421 
0422         if (!ok)
0423             return false;
0424     }
0425 
0426     d->column = col.attribute("column").toInt(&ok) + xshift;
0427 
0428     if (!ok)
0429         return false;
0430 
0431     // Validation
0432     if (d->width < 0) {
0433         debugSheets << "Value width=" << d->width << " out of range";
0434         return false;
0435     }
0436     if (d->column < 1 || d->column > KS_colMax) {
0437         debugSheets << "Value col=" << d->column << " out of range";
0438         return false;
0439     }
0440     if (col.hasAttribute("hide")) {
0441         setHidden((int) col.attribute("hide").toInt(&ok));
0442         if (!ok)
0443             return false;
0444     }
0445 
0446     KoXmlElement f(col.namedItem("format").toElement());
0447 
0448     if (!f.isNull() && (mode == Paste::Normal || mode == Paste::Format || mode == Paste::NoBorder)) {
0449         Style style;
0450         if (!style.loadXML(f, mode))
0451             return false;
0452         d->sheet->cellStorage()->setStyle(Region(QRect(d->column, 1, 1, KS_rowMax)), style);
0453         return true;
0454     }
0455 
0456     return true;
0457 }
0458 
0459 int ColumnFormat::column() const
0460 {
0461     return d->column;
0462 }
0463 
0464 void ColumnFormat::setColumn(int column)
0465 {
0466     d->column = column;
0467 }
0468 
0469 ColumnFormat* ColumnFormat::next() const
0470 {
0471     return d->next;
0472 }
0473 
0474 ColumnFormat* ColumnFormat::previous() const
0475 {
0476     return d->prev;
0477 }
0478 
0479 void ColumnFormat::setNext(ColumnFormat* next)
0480 {
0481     d->next = next;
0482 }
0483 
0484 void ColumnFormat::setPrevious(ColumnFormat* prev)
0485 {
0486     d->prev = prev;
0487 }
0488 
0489 void ColumnFormat::setHidden(bool _hide)
0490 {
0491     Q_ASSERT(d->sheet);
0492     if (_hide != d->hide) { // only if we change the status
0493         if (_hide) {
0494             // Lower maximum size by width of column
0495             d->sheet->adjustDocumentWidth(- width());
0496             d->hide = _hide; //hide must be set after we requested the width
0497         } else {
0498             // Rise maximum size by width of column
0499             d->hide = _hide; //unhide must be set before we request the width
0500             d->sheet->adjustDocumentWidth(width());
0501         }
0502     }
0503 }
0504 
0505 bool ColumnFormat::isHidden() const
0506 {
0507     return d->hide;
0508 }
0509 
0510 void ColumnFormat::setFiltered(bool filtered)
0511 {
0512     d->filtered = filtered;
0513 }
0514 
0515 bool ColumnFormat::isFiltered() const
0516 {
0517     return d->filtered;
0518 }
0519 
0520 bool ColumnFormat::isHiddenOrFiltered() const
0521 {
0522     return d->hide || d->filtered;
0523 }
0524 
0525 bool ColumnFormat::isDefault() const
0526 {
0527     return !d->sheet;
0528 }
0529 
0530 void ColumnFormat::setPageBreak(bool enable)
0531 {
0532     d->pageBreak = enable;
0533 }
0534 
0535 bool ColumnFormat::hasPageBreak() const
0536 {
0537     return d->pageBreak;
0538 }
0539 
0540 bool ColumnFormat::operator==(const ColumnFormat& other) const
0541 {
0542     // NOTE Stefan: Don't compare sheet and cell.
0543     if (d->width != other.d->width)
0544         return false;
0545     if (d->hide != other.d->hide)
0546         return false;
0547     if (d->filtered != other.d->filtered)
0548         return false;
0549     if (d->pageBreak != other.d->pageBreak) {
0550         return false;
0551     }
0552     return true;
0553 }