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 }