1 /* This file is part of the KDE project
2 Copyright 2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18 */
19
20 // Local
21 #include "TableShape.h"
22
23 #include "TablePageManager.h"
24
25 #include <QPainter>
26
27 #include <KoShapeContainer.h>
28 #include <KoXmlNS.h>
29
30 #include <SheetsDebug.h>
31 #include <CellView.h>
32 #include <Damages.h>
33 #include <Condition.h>
34 #include <Map.h>
35 #include <PrintSettings.h>
36 #include <Region.h>
37 #include <RowColumnFormat.h>
38 #include <RowFormatStorage.h>
39 #include <Sheet.h>
40 #include <SheetView.h>
41 #include <Value.h>
42 #include <odf/SheetsOdf.h>
43
44 using namespace Calligra::Sheets;
45
46 class TableShape::Private
47 {
48 public:
49 int columns;
50 int rows;
51 SheetView* sheetView;
52 bool isMaster;
53 TablePageManager* pageManager;
54
55 public:
56 void adjustColumnDimensions(Sheet* sheet, double factor);
57 void adjustRowDimensions(Sheet* sheet, double factor);
58 };
59
adjustColumnDimensions(Sheet * sheet,double factor)60 void TableShape::Private::adjustColumnDimensions(Sheet* sheet, double factor)
61 {
62 for (int col = 1; col <= columns; ++col) {
63 ColumnFormat* const columnFormat = sheet->nonDefaultColumnFormat(col);
64 columnFormat->setWidth(columnFormat->width() * factor);
65 }
66 }
67
adjustRowDimensions(Sheet * sheet,double factor)68 void TableShape::Private::adjustRowDimensions(Sheet* sheet, double factor)
69 {
70 for (int row = 1; row <= rows; ++row) {
71 sheet->rowFormats()->setRowHeight(row, row, sheet->rowFormats()->rowHeight(row) * factor);
72 }
73 }
74
75
76
TableShape(int columns,int rows)77 TableShape::TableShape(int columns, int rows)
78 : d(new Private)
79 {
80 setObjectName(QLatin1String("TableShape"));
81 d->columns = columns;
82 d->rows = rows;
83 d->sheetView = 0;
84 d->isMaster = false;
85 d->pageManager = 0;
86 }
87
~TableShape()88 TableShape::~TableShape()
89 {
90 delete d->pageManager;
91 delete d->sheetView;
92 if (KoShape::userData()) {
93 map()->removeSheet(qobject_cast<Sheet*>(KoShape::userData())); // declare the sheet as deleted
94 }
95 delete d;
96 }
97
columns() const98 int TableShape::columns() const
99 {
100 return d->columns;
101 }
102
rows() const103 int TableShape::rows() const
104 {
105 return d->rows;
106 }
107
setColumns(int columns)108 void TableShape::setColumns(int columns)
109 {
110 Q_ASSERT(columns > 0);
111 if(!sheet())
112 return;
113 const double factor = (double) d->columns / columns;
114 d->columns = columns;
115 d->adjustColumnDimensions(qobject_cast<Sheet*>(KoShape::userData()), factor);
116 setVisibleCellRange(QRect(1, 1, d->columns, d->rows));
117 d->sheetView->invalidate();
118 if (!d->pageManager) {
119 return;
120 }
121 PrintSettings settings = *sheet()->printSettings();
122 settings.setPrintRegion(Region(1, 1, d->columns, d->rows, sheet()));
123 d->pageManager->setPrintSettings(settings);
124 }
125
setRows(int rows)126 void TableShape::setRows(int rows)
127 {
128 Q_ASSERT(rows > 0);
129 if(!sheet())
130 return;
131 const double factor = (double) d->rows / rows;
132 d->rows = rows;
133 d->adjustRowDimensions(qobject_cast<Sheet*>(KoShape::userData()), factor);
134 setVisibleCellRange(QRect(1, 1, d->columns, d->rows));
135 d->sheetView->invalidate();
136 if (!d->pageManager) {
137 return;
138 }
139 PrintSettings settings = *sheet()->printSettings();
140 settings.setPrintRegion(Region(1, 1, d->columns, d->rows, sheet()));
141 d->pageManager->setPrintSettings(settings);
142 }
143
paint(QPainter & painter,const KoViewConverter & converter,KoShapePaintingContext &)144 void TableShape::paint(QPainter& painter, const KoViewConverter& converter, KoShapePaintingContext &)
145 {
146 #ifndef NDEBUG
147 if (KoShape::parent()) {
148 debugSheets << KoShape::parent()->name() << KoShape::parent()->shapeId() << KoShape::parent()->boundingRect();
149 }
150 #endif
151 const QRectF paintRect = QRectF(QPointF(0.0, 0.0), size());
152
153 applyConversion(painter, converter);
154 painter.setClipRect(paintRect, Qt::IntersectClip);
155
156 // painting cell contents
157 d->sheetView->setViewConverter(&converter);
158 d->sheetView->paintCells(painter, paintRect, QPointF(0.0, 0.0));
159 }
160
loadOdf(const KoXmlElement & element,KoShapeLoadingContext & context)161 bool TableShape::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
162 {
163 //debugSheets << "LOADING TABLE SHAPE";
164 if (sheet() && element.namespaceURI() == KoXmlNS::table && element.localName() == "table") {
165 if (!Odf::loadTableShape(sheet(), element, context)) return false;
166
167 const QRect usedArea = sheet()->usedArea();
168 d->columns = usedArea.width();
169 d->rows = usedArea.height();
170
171 QSizeF size(0.0, 0.0);
172 for (int col = 1; col <= d->columns; ++col) {
173 size.rwidth() += sheet()->columnFormat(col)->visibleWidth();
174 }
175 size.rheight() = sheet()->rowFormats()->totalVisibleRowHeight(1, d->rows);
176 KoShape::setSize(size);
177 return true;
178 }
179 return false;
180 }
181
saveOdf(KoShapeSavingContext & context) const182 void TableShape::saveOdf(KoShapeSavingContext & context) const
183 {
184 if (!sheet())
185 return;
186 Odf::saveTableShape(sheet(), context);
187 }
188
setMap(Map * map)189 void TableShape::setMap(Map *map)
190 {
191 if (map == 0)
192 return;
193 Sheet* const sheet = map->addNewSheet();
194 d->sheetView = new SheetView(sheet);
195 KoShape::setUserData(sheet);
196 d->isMaster = true;
197 setVisibleCellRange(QRect(1, 1, d->columns, d->rows));
198
199 connect(map, SIGNAL(damagesFlushed(QList<Damage*>)),
200 this, SLOT(handleDamages(QList<Damage*>)));
201
202 // Initialize the size using the default column/row dimensions.
203 QSize size;
204 for (int col = 1; col <= d->columns; ++col) {
205 size.rwidth() += sheet->columnFormat(col)->visibleWidth();
206 }
207 size.rheight() = sheet->rowFormats()->totalVisibleRowHeight(1, d->rows);
208 KoShape::setSize(size);
209 }
210
setSize(const QSizeF & newSize)211 void TableShape::setSize(const QSizeF& newSize)
212 {
213 const QSizeF oldSize = size();
214 if (oldSize == newSize)
215 return;
216
217 QSizeF size2 = oldSize;
218 const qreal cellWidth = map()->defaultColumnFormat()->width();
219 const qreal cellHeight = map()->defaultRowFormat()->height();
220
221 // Note that the following four variables can also be negative
222 const qreal dx = newSize.width() - oldSize.width();
223 const qreal dy = newSize.height() - oldSize.height();
224 int numAddedCols = 0;
225 int numAddedRows = 0;
226
227 if (qAbs(dx) >= cellWidth) {
228 numAddedCols = int(dx / cellWidth);
229 size2.rwidth() += cellWidth * numAddedCols;
230 }
231 if (qAbs(dy) >= cellHeight) {
232 numAddedRows = int(dy / cellHeight);
233 size2.rheight() += cellHeight * numAddedRows;
234 }
235 if (qAbs(dx) >= cellWidth || qAbs(dy) >= cellHeight) {
236 d->columns += numAddedCols;
237 d->rows += numAddedRows;
238 setVisibleCellRange(QRect(1, 1, d->columns, d->rows));
239 d->sheetView->invalidate();
240 KoShape::setSize(size2);
241 }
242 }
243
map() const244 Map* TableShape::map() const
245 {
246 return qobject_cast<Sheet*>(KoShape::userData())->map();
247 }
248
sheet() const249 Sheet* TableShape::sheet() const
250 {
251 return qobject_cast<Sheet*>(KoShape::userData());
252 }
253
sheetView() const254 SheetView* TableShape::sheetView() const
255 {
256 return d->sheetView;
257 }
258
setSheet(const QString & sheetName)259 void TableShape::setSheet(const QString& sheetName)
260 {
261 Sheet* const sheet = map()->findSheet(sheetName);
262 if (! sheet)
263 return;
264 delete d->sheetView;
265 d->sheetView = new SheetView(sheet);
266 KoShape::setUserData(sheet);
267 setColumns(d->columns);
268 setRows(d->rows);
269 setVisibleCellRange(QRect(1, 1, d->columns, d->rows));
270 update();
271 }
272
setVisibleCellRange(const QRect & cellRange)273 void TableShape::setVisibleCellRange(const QRect& cellRange)
274 {
275 Q_ASSERT(KoShape::userData());
276 if (!d->sheetView) {
277 d->sheetView = new SheetView(sheet());
278 }
279 d->sheetView->setPaintCellRange(cellRange & QRect(1, 1, d->columns, d->rows));
280 }
281
shapeChanged(ChangeType type,KoShape * shape)282 void TableShape::shapeChanged(ChangeType type, KoShape *shape)
283 {
284 Q_UNUSED(shape);
285 // If this is a master table shape, the parent changed and we have no parent yet...
286 if (d->isMaster && type == ParentChanged && !d->pageManager) {
287 d->pageManager = new TablePageManager(this);
288 return;
289 }
290 // Not the master table shape? Not embedded into a container?
291 if (!d->isMaster || !KoShape::parent()) {
292 return;
293 }
294 // Not the changes, we want to react on?
295 if (type != SizeChanged) {
296 return;
297 }
298 d->pageManager->layoutPages();
299 }
300
handleDamages(const QList<Damage * > & damages)301 void TableShape::handleDamages(const QList<Damage*>& damages)
302 {
303 QList<Damage*>::ConstIterator end(damages.end());
304 for (QList<Damage*>::ConstIterator it = damages.begin(); it != end; ++it) {
305 Damage* damage = *it;
306 if (!damage) continue;
307
308 if (damage->type() == Damage::Cell) {
309 CellDamage* cellDamage = static_cast<CellDamage*>(damage);
310 const Region region = cellDamage->region();
311
312 if (cellDamage->changes() & CellDamage::Appearance)
313 d->sheetView->invalidateRegion(region);
314 continue;
315 }
316
317 if (damage->type() == Damage::Sheet) {
318 SheetDamage* sheetDamage = static_cast<SheetDamage*>(damage);
319
320 if (sheetDamage->changes() & SheetDamage::PropertiesChanged)
321 d->sheetView->invalidate();
322 continue;
323 }
324 }
325
326 update();
327 }
328