File indexing completed on 2024-05-12 16:35:53

0001 /* This file is part of the KDE project
0002    Copyright 2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 */
0019 
0020 // Local
0021 #include "TableShape.h"
0022 
0023 #include "TablePageManager.h"
0024 
0025 #include <QPainter>
0026 
0027 #include <KoShapeContainer.h>
0028 #include <KoXmlNS.h>
0029 
0030 #include <SheetsDebug.h>
0031 #include <CellView.h>
0032 #include <Damages.h>
0033 #include <Condition.h>
0034 #include <Map.h>
0035 #include <PrintSettings.h>
0036 #include <Region.h>
0037 #include <RowColumnFormat.h>
0038 #include <RowFormatStorage.h>
0039 #include <Sheet.h>
0040 #include <SheetView.h>
0041 #include <Value.h>
0042 #include <odf/SheetsOdf.h>
0043 
0044 using namespace Calligra::Sheets;
0045 
0046 class TableShape::Private
0047 {
0048 public:
0049     int         columns;
0050     int         rows;
0051     SheetView*  sheetView;
0052     bool        isMaster;
0053     TablePageManager* pageManager;
0054 
0055 public:
0056     void adjustColumnDimensions(Sheet* sheet, double factor);
0057     void adjustRowDimensions(Sheet* sheet, double factor);
0058 };
0059 
0060 void TableShape::Private::adjustColumnDimensions(Sheet* sheet, double factor)
0061 {
0062     for (int col = 1; col <= columns; ++col) {
0063         ColumnFormat* const columnFormat = sheet->nonDefaultColumnFormat(col);
0064         columnFormat->setWidth(columnFormat->width() * factor);
0065     }
0066 }
0067 
0068 void TableShape::Private::adjustRowDimensions(Sheet* sheet, double factor)
0069 {
0070     for (int row = 1; row <= rows; ++row) {
0071         sheet->rowFormats()->setRowHeight(row, row, sheet->rowFormats()->rowHeight(row) * factor);
0072     }
0073 }
0074 
0075 
0076 
0077 TableShape::TableShape(int columns, int rows)
0078         : d(new Private)
0079 {
0080     setObjectName(QLatin1String("TableShape"));
0081     d->columns = columns;
0082     d->rows = rows;
0083     d->sheetView = 0;
0084     d->isMaster = false;
0085     d->pageManager = 0;
0086 }
0087 
0088 TableShape::~TableShape()
0089 {
0090     delete d->pageManager;
0091     delete d->sheetView;
0092     if (KoShape::userData()) {
0093         map()->removeSheet(qobject_cast<Sheet*>(KoShape::userData())); // declare the sheet as deleted
0094     }
0095     delete d;
0096 }
0097 
0098 int TableShape::columns() const
0099 {
0100     return d->columns;
0101 }
0102 
0103 int TableShape::rows() const
0104 {
0105     return d->rows;
0106 }
0107 
0108 void TableShape::setColumns(int columns)
0109 {
0110     Q_ASSERT(columns > 0);
0111     if(!sheet())
0112         return;
0113     const double factor = (double) d->columns / columns;
0114     d->columns = columns;
0115     d->adjustColumnDimensions(qobject_cast<Sheet*>(KoShape::userData()), factor);
0116     setVisibleCellRange(QRect(1, 1, d->columns, d->rows));
0117     d->sheetView->invalidate();
0118     if (!d->pageManager) {
0119         return;
0120     }
0121     PrintSettings settings = *sheet()->printSettings();
0122     settings.setPrintRegion(Region(1, 1, d->columns, d->rows, sheet()));
0123     d->pageManager->setPrintSettings(settings);
0124 }
0125 
0126 void TableShape::setRows(int rows)
0127 {
0128     Q_ASSERT(rows > 0);
0129     if(!sheet())
0130         return;
0131     const double factor = (double) d->rows / rows;
0132     d->rows = rows;
0133     d->adjustRowDimensions(qobject_cast<Sheet*>(KoShape::userData()), factor);
0134     setVisibleCellRange(QRect(1, 1, d->columns, d->rows));
0135     d->sheetView->invalidate();
0136     if (!d->pageManager) {
0137         return;
0138     }
0139     PrintSettings settings = *sheet()->printSettings();
0140     settings.setPrintRegion(Region(1, 1, d->columns, d->rows, sheet()));
0141     d->pageManager->setPrintSettings(settings);
0142 }
0143 
0144 void TableShape::paint(QPainter& painter, const KoViewConverter& converter, KoShapePaintingContext &)
0145 {
0146 #ifndef NDEBUG
0147     if (KoShape::parent()) {
0148         debugSheets << KoShape::parent()->name() <<  KoShape::parent()->shapeId() << KoShape::parent()->boundingRect();
0149     }
0150 #endif
0151     const QRectF paintRect = QRectF(QPointF(0.0, 0.0), size());
0152 
0153     applyConversion(painter, converter);
0154     painter.setClipRect(paintRect, Qt::IntersectClip);
0155 
0156     // painting cell contents
0157     d->sheetView->setViewConverter(&converter);
0158     d->sheetView->paintCells(painter, paintRect, QPointF(0.0, 0.0));
0159 }
0160 
0161 bool TableShape::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
0162 {
0163     //debugSheets << "LOADING TABLE SHAPE";
0164     if (sheet() && element.namespaceURI() == KoXmlNS::table && element.localName() == "table") {
0165         if (!Odf::loadTableShape(sheet(), element, context)) return false;
0166 
0167         const QRect usedArea = sheet()->usedArea();
0168         d->columns = usedArea.width();
0169         d->rows = usedArea.height();
0170 
0171         QSizeF size(0.0, 0.0);
0172         for (int col = 1; col <= d->columns; ++col) {
0173             size.rwidth() += sheet()->columnFormat(col)->visibleWidth();
0174         }
0175         size.rheight() = sheet()->rowFormats()->totalVisibleRowHeight(1, d->rows);
0176         KoShape::setSize(size);
0177         return true;
0178     }
0179     return false;
0180 }
0181 
0182 void TableShape::saveOdf(KoShapeSavingContext & context) const
0183 {
0184     if (!sheet())
0185         return;
0186     Odf::saveTableShape(sheet(), context);
0187 }
0188 
0189 void TableShape::setMap(Map *map)
0190 {
0191     if (map == 0)
0192         return;
0193     Sheet* const sheet = map->addNewSheet();
0194     d->sheetView = new SheetView(sheet);
0195     KoShape::setUserData(sheet);
0196     d->isMaster = true;
0197     setVisibleCellRange(QRect(1, 1, d->columns, d->rows));
0198 
0199     connect(map, SIGNAL(damagesFlushed(QList<Damage*>)),
0200             this, SLOT(handleDamages(QList<Damage*>)));
0201 
0202     // Initialize the size using the default column/row dimensions.
0203     QSize size;
0204     for (int col = 1; col <= d->columns; ++col) {
0205         size.rwidth() += sheet->columnFormat(col)->visibleWidth();
0206     }
0207     size.rheight() = sheet->rowFormats()->totalVisibleRowHeight(1, d->rows);
0208     KoShape::setSize(size);
0209 }
0210 
0211 void TableShape::setSize(const QSizeF& newSize)
0212 {
0213     const QSizeF oldSize = size();
0214     if (oldSize == newSize)
0215         return;
0216 
0217     QSizeF size2 = oldSize;
0218     const qreal cellWidth = map()->defaultColumnFormat()->width();
0219     const qreal cellHeight = map()->defaultRowFormat()->height();
0220 
0221     // Note that the following four variables can also be negative
0222     const qreal dx = newSize.width() - oldSize.width();
0223     const qreal dy = newSize.height() - oldSize.height();
0224     int numAddedCols = 0;
0225     int numAddedRows = 0;
0226 
0227     if (qAbs(dx) >= cellWidth) {
0228         numAddedCols = int(dx / cellWidth);
0229         size2.rwidth() += cellWidth * numAddedCols;
0230     }
0231     if (qAbs(dy) >= cellHeight) {
0232         numAddedRows = int(dy / cellHeight);
0233         size2.rheight() += cellHeight * numAddedRows;
0234     }
0235     if (qAbs(dx) >= cellWidth || qAbs(dy) >= cellHeight) {
0236         d->columns += numAddedCols;
0237         d->rows += numAddedRows;
0238         setVisibleCellRange(QRect(1, 1, d->columns, d->rows));
0239         d->sheetView->invalidate();
0240         KoShape::setSize(size2);
0241     }
0242 }
0243 
0244 Map* TableShape::map() const
0245 {
0246     return qobject_cast<Sheet*>(KoShape::userData())->map();
0247 }
0248 
0249 Sheet* TableShape::sheet() const
0250 {
0251     return qobject_cast<Sheet*>(KoShape::userData());
0252 }
0253 
0254 SheetView* TableShape::sheetView() const
0255 {
0256     return d->sheetView;
0257 }
0258 
0259 void TableShape::setSheet(const QString& sheetName)
0260 {
0261     Sheet* const sheet = map()->findSheet(sheetName);
0262     if (! sheet)
0263         return;
0264     delete d->sheetView;
0265     d->sheetView = new SheetView(sheet);
0266     KoShape::setUserData(sheet);
0267     setColumns(d->columns);
0268     setRows(d->rows);
0269     setVisibleCellRange(QRect(1, 1, d->columns, d->rows));
0270     update();
0271 }
0272 
0273 void TableShape::setVisibleCellRange(const QRect& cellRange)
0274 {
0275     Q_ASSERT(KoShape::userData());
0276     if (!d->sheetView) {
0277         d->sheetView = new SheetView(sheet());
0278     }
0279     d->sheetView->setPaintCellRange(cellRange & QRect(1, 1, d->columns, d->rows));
0280 }
0281 
0282 void TableShape::shapeChanged(ChangeType type, KoShape *shape)
0283 {
0284     Q_UNUSED(shape);
0285     // If this is a master table shape, the parent changed and we have no parent yet...
0286     if (d->isMaster && type == ParentChanged && !d->pageManager) {
0287         d->pageManager = new TablePageManager(this);
0288         return;
0289     }
0290     // Not the master table shape? Not embedded into a container?
0291     if (!d->isMaster || !KoShape::parent()) {
0292         return;
0293     }
0294     // Not the changes, we want to react on?
0295     if (type != SizeChanged) {
0296         return;
0297     }
0298     d->pageManager->layoutPages();
0299 }
0300 
0301 void TableShape::handleDamages(const QList<Damage*>& damages)
0302 {
0303     QList<Damage*>::ConstIterator end(damages.end());
0304     for (QList<Damage*>::ConstIterator it = damages.begin(); it != end; ++it) {
0305         Damage* damage = *it;
0306         if (!damage) continue;
0307 
0308         if (damage->type() == Damage::Cell) {
0309             CellDamage* cellDamage = static_cast<CellDamage*>(damage);
0310             const Region region = cellDamage->region();
0311 
0312             if (cellDamage->changes() & CellDamage::Appearance)
0313                 d->sheetView->invalidateRegion(region);
0314             continue;
0315         }
0316 
0317         if (damage->type() == Damage::Sheet) {
0318             SheetDamage* sheetDamage = static_cast<SheetDamage*>(damage);
0319 
0320             if (sheetDamage->changes() & SheetDamage::PropertiesChanged)
0321                 d->sheetView->invalidate();
0322             continue;
0323         }
0324     }
0325 
0326     update();
0327 }