1 /* This file is part of the KDE project
2 Copyright 2010 Marijn Kruisselbrink <mkruisselbrink@kde.org>
3 Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20
21 // Local
22 #include "Map.h"
23
24 #include <stdlib.h>
25 #include <time.h>
26
27 #include <QTimer>
28
29 #include <kcodecs.h>
30 #include <kcompletion.h>
31
32 #include <KoGlobal.h>
33 #include <KoEmbeddedDocumentSaver.h>
34 #include <KoStyleManager.h>
35 #include <KoParagraphStyle.h>
36 #include <KoUpdater.h>
37 #include <KoProgressUpdater.h>
38
39 #include "ApplicationSettings.h"
40 #include "BindingManager.h"
41 #include "CalculationSettings.h"
42 #include "CellStorage.h"
43 #include "Damages.h"
44 #include "DependencyManager.h"
45 #include "DocBase.h"
46 #include "LoadingInfo.h"
47 #include "Localization.h"
48 #include "NamedAreaManager.h"
49 #include "RecalcManager.h"
50 #include "RowColumnFormat.h"
51 #include "Sheet.h"
52 #include "StyleManager.h"
53 #include "ValueCalc.h"
54 #include "ValueConverter.h"
55 #include "ValueFormatter.h"
56 #include "ValueParser.h"
57
58 // database
59 #include "database/DatabaseManager.h"
60
61 using namespace Calligra::Sheets;
62
63 class Q_DECL_HIDDEN Map::Private
64 {
65 public:
66 DocBase* doc;
67
68 /**
69 * List of all sheets in this map.
70 */
71 QList<Sheet*> lstSheets;
72 QList<Sheet*> lstDeletedSheets;
73
74 // used to give every Sheet a unique default name.
75 int tableId;
76
77 // used to determine the loading progress
78 int overallRowCount;
79 int loadedRowsCounter;
80
81 LoadingInfo* loadingInfo;
82 bool readwrite;
83
84 BindingManager* bindingManager;
85 DatabaseManager* databaseManager;
86 DependencyManager* dependencyManager;
87 NamedAreaManager* namedAreaManager;
88 RecalcManager* recalcManager;
89 StyleManager* styleManager;
90 KoStyleManager* textStyleManager;
91
92 ApplicationSettings* applicationSettings;
93 CalculationSettings* calculationSettings;
94 ValueCalc* calc;
95 ValueConverter* converter;
96 ValueFormatter* formatter;
97 ValueParser* parser;
98
99 // default objects
100 ColumnFormat* defaultColumnFormat;
101 RowFormat* defaultRowFormat;
102
103 QList<Damage*> damages;
104 bool isLoading;
105
106 int syntaxVersion;
107
108 KCompletion listCompletion;
109 };
110
111
Map(DocBase * doc,int syntaxVersion)112 Map::Map(DocBase* doc, int syntaxVersion)
113 : QObject(doc),
114 d(new Private)
115 {
116 setObjectName(QLatin1String("Map")); // necessary for D-Bus
117 d->doc = doc;
118 d->tableId = 1;
119 d->overallRowCount = 0;
120 d->loadedRowsCounter = 0;
121 d->loadingInfo = 0;
122 d->readwrite = true;
123
124 d->bindingManager = new BindingManager(this);
125 d->databaseManager = new DatabaseManager(this);
126 d->dependencyManager = new DependencyManager(this);
127 d->namedAreaManager = new NamedAreaManager(this);
128 d->recalcManager = new RecalcManager(this);
129 d->styleManager = new StyleManager();
130 d->textStyleManager = new KoStyleManager(this);
131 d->applicationSettings = new ApplicationSettings();
132 d->calculationSettings = new CalculationSettings();
133
134 d->parser = new ValueParser(d->calculationSettings);
135 d->converter = new ValueConverter(d->parser);
136 d->calc = new ValueCalc(d->converter);
137 d->formatter = new ValueFormatter(d->converter);
138
139 d->defaultColumnFormat = new ColumnFormat();
140 d->defaultRowFormat = new RowFormat();
141
142 QFont font(KoGlobal::defaultFont());
143 d->defaultRowFormat->setHeight(font.pointSizeF() + 4);
144 d->defaultColumnFormat->setWidth((font.pointSizeF() + 4) * 5);
145
146 d->isLoading = false;
147
148 // default document properties
149 d->syntaxVersion = syntaxVersion;
150
151 connect(this, SIGNAL(sheetAdded(Sheet*)),
152 d->dependencyManager, SLOT(addSheet(Sheet*)));
153 connect(this, SIGNAL(sheetAdded(Sheet*)),
154 d->recalcManager, SLOT(addSheet(Sheet*)));
155 connect(this, SIGNAL(sheetRemoved(Sheet*)),
156 d->dependencyManager, SLOT(removeSheet(Sheet*)));
157 connect(this, SIGNAL(sheetRemoved(Sheet*)),
158 d->recalcManager, SLOT(removeSheet(Sheet*)));
159 connect(this, SIGNAL(sheetRevived(Sheet*)),
160 d->dependencyManager, SLOT(addSheet(Sheet*)));
161 connect(this, SIGNAL(sheetRevived(Sheet*)),
162 d->recalcManager, SLOT(addSheet(Sheet*)));
163 connect(d->namedAreaManager, SIGNAL(namedAreaModified(QString)),
164 d->dependencyManager, SLOT(namedAreaModified(QString)));
165 connect(this, SIGNAL(damagesFlushed(QList<Damage*>)),
166 this, SLOT(handleDamages(QList<Damage*>)));
167 }
168
~Map()169 Map::~Map()
170 {
171 // Because some of the shapes might be using a sheet in this map, delete
172 // all shapes in each sheet before all sheets are deleted together.
173 foreach(Sheet *sheet, d->lstSheets)
174 sheet->deleteShapes();
175 // we have to explicitly delete the Sheets, not let QObject take care of that
176 // as the sheet in its destructor expects the Map to still exist
177 qDeleteAll(d->lstSheets);
178 d->lstSheets.clear();
179
180 deleteLoadingInfo();
181
182 delete d->bindingManager;
183 delete d->databaseManager;
184 delete d->dependencyManager;
185 delete d->namedAreaManager;
186 delete d->recalcManager;
187 delete d->styleManager;
188
189 delete d->parser;
190 delete d->formatter;
191 delete d->converter;
192 delete d->calc;
193 delete d->calculationSettings;
194 delete d->applicationSettings;
195
196 delete d->defaultColumnFormat;
197 delete d->defaultRowFormat;
198
199 delete d;
200 }
201
doc() const202 DocBase* Map::doc() const
203 {
204 return d->doc;
205 }
206
setReadWrite(bool readwrite)207 void Map::setReadWrite(bool readwrite)
208 {
209 d->readwrite = readwrite;
210 }
211
isReadWrite() const212 bool Map::isReadWrite() const
213 {
214 return d->readwrite;
215 }
216
completeLoading(KoStore * store)217 bool Map::completeLoading(KoStore *store)
218 {
219 Q_UNUSED(store);
220
221 QPointer<KoUpdater> dependencyUpdater, recalcUpdater;
222 if (doc() && doc()->progressUpdater()) {
223 dependencyUpdater = doc()->progressUpdater()->startSubtask(1, "Calligra::Sheets::DependencyManager::updateAllDependencies");
224 recalcUpdater = doc()->progressUpdater()->startSubtask(1, "Calligra::Sheets::RecalcManager::recalc");
225 }
226
227 // Initial build of all cell dependencies.
228 d->dependencyManager->updateAllDependencies(this, dependencyUpdater);
229 // Recalc the whole workbook now, since there may be formulas other spreadsheets support,
230 // but Calligra Sheets does not.
231 d->recalcManager->recalcMap(recalcUpdater);
232
233 return true;
234 }
235
completeSaving(KoStore * store,KoXmlWriter * manifestWriter,KoShapeSavingContext * context)236 bool Map::completeSaving(KoStore *store, KoXmlWriter *manifestWriter, KoShapeSavingContext * context)
237 {
238 Q_UNUSED(store);
239 Q_UNUSED(manifestWriter);
240 Q_UNUSED(context);
241 return true;
242 }
243
bindingManager() const244 BindingManager* Map::bindingManager() const
245 {
246 return d->bindingManager;
247 }
248
databaseManager() const249 DatabaseManager* Map::databaseManager() const
250 {
251 return d->databaseManager;
252 }
253
dependencyManager() const254 DependencyManager* Map::dependencyManager() const
255 {
256 return d->dependencyManager;
257 }
258
namedAreaManager() const259 NamedAreaManager* Map::namedAreaManager() const
260 {
261 return d->namedAreaManager;
262 }
263
recalcManager() const264 RecalcManager* Map::recalcManager() const
265 {
266 return d->recalcManager;
267 }
268
styleManager() const269 StyleManager* Map::styleManager() const
270 {
271 return d->styleManager;
272 }
273
textStyleManager() const274 KoStyleManager* Map::textStyleManager() const
275 {
276 return d->textStyleManager;
277 }
278
parser() const279 ValueParser* Map::parser() const
280 {
281 return d->parser;
282 }
283
formatter() const284 ValueFormatter* Map::formatter() const
285 {
286 return d->formatter;
287 }
288
converter() const289 ValueConverter* Map::converter() const
290 {
291 return d->converter;
292 }
293
calc() const294 ValueCalc* Map::calc() const
295 {
296 return d->calc;
297 }
298
defaultColumnFormat() const299 const ColumnFormat* Map::defaultColumnFormat() const
300 {
301 return d->defaultColumnFormat;
302 }
303
defaultRowFormat() const304 const RowFormat* Map::defaultRowFormat() const
305 {
306 return d->defaultRowFormat;
307 }
308
setDefaultColumnWidth(double width)309 void Map::setDefaultColumnWidth(double width)
310 {
311 d->defaultColumnFormat->setWidth(width);
312 }
313
setDefaultRowHeight(double height)314 void Map::setDefaultRowHeight(double height)
315 {
316 d->defaultRowFormat->setHeight(height);
317 }
318
settings() const319 ApplicationSettings* Map::settings() const
320 {
321 return d->applicationSettings;
322 }
323
calculationSettings() const324 CalculationSettings* Map::calculationSettings() const
325 {
326 return d->calculationSettings;
327 }
328
createSheet(const QString & name)329 Sheet* Map::createSheet(const QString& name)
330 {
331 QString sheetName(i18n("Sheet%1", d->tableId++));
332 if ( !name.isEmpty() )
333 sheetName = name;
334 Sheet* sheet = new Sheet(this, sheetName);
335 connect(sheet, SIGNAL(statusMessage(QString,int)),
336 this, SIGNAL(statusMessage(QString,int)));
337 return sheet;
338 }
339
addSheet(Sheet * _sheet)340 void Map::addSheet(Sheet *_sheet)
341 {
342 d->lstSheets.append(_sheet);
343 emit sheetAdded(_sheet);
344 }
345
addNewSheet(const QString & name)346 Sheet *Map::addNewSheet(const QString& name)
347 {
348 Sheet *t = createSheet(name);
349 addSheet(t);
350 return t;
351 }
352
moveSheet(const QString & _from,const QString & _to,bool _before)353 void Map::moveSheet(const QString & _from, const QString & _to, bool _before)
354 {
355 Sheet* sheetfrom = findSheet(_from);
356 Sheet* sheetto = findSheet(_to);
357
358 int from = d->lstSheets.indexOf(sheetfrom) ;
359 int to = d->lstSheets.indexOf(sheetto) ;
360 if (!_before)
361 ++to;
362
363 if (to > (int)d->lstSheets.count()) {
364 d->lstSheets.append(sheetfrom);
365 d->lstSheets.removeAt(from);
366 } else if (from < to) {
367 d->lstSheets.insert(to, sheetfrom);
368 d->lstSheets.removeAt(from);
369 } else {
370 d->lstSheets.removeAt(from);
371 d->lstSheets.insert(to, sheetfrom);
372 }
373 }
374
save(QDomDocument & doc)375 QDomElement Map::save(QDomDocument& doc)
376 {
377 QDomElement spread = doc.documentElement();
378
379 QDomElement locale = static_cast<Localization*>(d->calculationSettings->locale())->save(doc);
380 spread.appendChild(locale);
381
382 QDomElement areaname = d->namedAreaManager->saveXML(doc);
383 spread.appendChild(areaname);
384
385 QDomElement defaults = doc.createElement("defaults");
386 defaults.setAttribute("row-height", QString::number(d->defaultRowFormat->height()));
387 defaults.setAttribute("col-width", QString::number(d->defaultColumnFormat->width()));
388 spread.appendChild(defaults);
389
390 QDomElement s = d->styleManager->save(doc);
391 spread.appendChild(s);
392
393 QDomElement mymap = doc.createElement("map");
394
395 QByteArray password;
396 this->password(password);
397 if (!password.isNull()) {
398 if (password.size() > 0) {
399 QByteArray str = KCodecs::base64Encode(password);
400 mymap.setAttribute("protected", QString(str.data()));
401 } else {
402 mymap.setAttribute("protected", "");
403 }
404 }
405
406 foreach(Sheet* sheet, d->lstSheets) {
407 QDomElement e = sheet->saveXML(doc);
408 if (e.isNull())
409 return e;
410 mymap.appendChild(e);
411 }
412 return mymap;
413 }
414
loadXML(const KoXmlElement & mymap)415 bool Map::loadXML(const KoXmlElement& mymap)
416 {
417 d->isLoading = true;
418 loadingInfo()->setFileFormat(LoadingInfo::NativeFormat);
419 const QString activeSheet = mymap.attribute("activeTable");
420 const QPoint marker(mymap.attribute("markerColumn").toInt(), mymap.attribute("markerRow").toInt());
421 loadingInfo()->setCursorPosition(findSheet(activeSheet), marker);
422 const QPointF offset(mymap.attribute("xOffset").toDouble(), mymap.attribute("yOffset").toDouble());
423 loadingInfo()->setScrollingOffset(findSheet(activeSheet), offset);
424
425 KoXmlNode n = mymap.firstChild();
426 if (n.isNull()) {
427 // We need at least one sheet !
428 doc()->setErrorMessage(i18n("This document has no sheets (tables)."));
429 d->isLoading = false;
430 return false;
431 }
432 while (!n.isNull()) {
433 KoXmlElement e = n.toElement();
434 if (!e.isNull() && e.tagName() == "table") {
435 Sheet *t = addNewSheet();
436 if (!t->loadXML(e)) {
437 d->isLoading = false;
438 return false;
439 }
440 }
441 n = n.nextSibling();
442 }
443
444 loadXmlProtection(mymap);
445
446 if (!activeSheet.isEmpty()) {
447 // Used by View's constructor
448 loadingInfo()->setInitialActiveSheet(findSheet(activeSheet));
449 }
450
451 d->isLoading = false;
452 return true;
453 }
454
findSheet(const QString & _name) const455 Sheet* Map::findSheet(const QString & _name) const
456 {
457 foreach(Sheet* sheet, d->lstSheets) {
458 if (_name.toLower() == sheet->sheetName().toLower())
459 return sheet;
460 }
461 return 0;
462 }
463
nextSheet(Sheet * currentSheet) const464 Sheet * Map::nextSheet(Sheet * currentSheet) const
465 {
466 if (currentSheet == d->lstSheets.last())
467 return currentSheet;
468 int index = 0;
469 foreach(Sheet* sheet, d->lstSheets) {
470 if (sheet == currentSheet)
471 return d->lstSheets.value(++index);
472 ++index;
473 }
474 return 0;
475 }
476
previousSheet(Sheet * currentSheet) const477 Sheet * Map::previousSheet(Sheet * currentSheet) const
478 {
479 if (currentSheet == d->lstSheets.first())
480 return currentSheet;
481 int index = 0;
482 foreach(Sheet* sheet, d->lstSheets) {
483 if (sheet == currentSheet)
484 return d->lstSheets.value(--index);
485 ++index;
486 }
487 return 0;
488 }
489
loadChildren(KoStore * _store)490 bool Map::loadChildren(KoStore * _store)
491 {
492 foreach(Sheet* sheet, d->lstSheets) {
493 if (!sheet->loadChildren(_store))
494 return false;
495 }
496 return true;
497 }
498
removeSheet(Sheet * sheet)499 void Map::removeSheet(Sheet* sheet)
500 {
501 d->lstSheets.removeAll(sheet);
502 d->lstDeletedSheets.append(sheet);
503 d->namedAreaManager->remove(sheet);
504 emit sheetRemoved(sheet);
505 }
506
reviveSheet(Sheet * sheet)507 void Map::reviveSheet(Sheet* sheet)
508 {
509 d->lstDeletedSheets.removeAll(sheet);
510 d->lstSheets.append(sheet);
511 emit sheetRevived(sheet);
512 }
513
514 // FIXME cache this for faster operation
visibleSheets() const515 QStringList Map::visibleSheets() const
516 {
517 QStringList result;
518 foreach(Sheet* sheet, d->lstSheets) {
519 if (!sheet->isHidden())
520 result.append(sheet->sheetName());
521 }
522 return result;
523 }
524
525 // FIXME cache this for faster operation
hiddenSheets() const526 QStringList Map::hiddenSheets() const
527 {
528 QStringList result;
529 foreach(Sheet* sheet, d->lstSheets) {
530 if (sheet->isHidden())
531 result.append(sheet->sheetName());
532 }
533 return result;
534 }
535
sheet(int index) const536 Sheet* Map::sheet(int index) const
537 {
538 return d->lstSheets.value(index);
539 }
540
indexOf(Sheet * sheet) const541 int Map::indexOf(Sheet* sheet) const
542 {
543 return d->lstSheets.indexOf(sheet);
544 }
545
sheetList() const546 QList<Sheet*>& Map::sheetList() const
547 {
548 return d->lstSheets;
549 }
550
count() const551 int Map::count() const
552 {
553 return d->lstSheets.count();
554 }
555
setOverallRowsCounter(int number)556 void Map::setOverallRowsCounter(int number)
557 {
558 d->overallRowCount = number;
559 }
560
increaseLoadedRowsCounter(int number)561 int Map::increaseLoadedRowsCounter(int number)
562 {
563 d->loadedRowsCounter += number;
564 if (d->overallRowCount) {
565 return 100 * d->loadedRowsCounter / d->overallRowCount;
566 }
567 return -1;
568 }
569
isLoading() const570 bool Map::isLoading() const
571 {
572 // The KoDocument state is necessary to avoid damages while importing a file (through a filter).
573 return d->isLoading || (d->doc && d->doc->isLoading());
574 }
575
setLoading(bool l)576 void Map::setLoading(bool l) {
577 d->isLoading = l;
578 }
579
syntaxVersion() const580 int Map::syntaxVersion() const
581 {
582 return d->syntaxVersion;
583 }
584
setSyntaxVersion(int version)585 void Map::setSyntaxVersion(int version)
586 {
587 d->syntaxVersion = version;
588 }
589
loadingInfo() const590 LoadingInfo* Map::loadingInfo() const
591 {
592 if (!d->loadingInfo) {
593 d->loadingInfo = new LoadingInfo();
594 }
595 return d->loadingInfo;
596 }
597
deleteLoadingInfo()598 void Map::deleteLoadingInfo()
599 {
600 delete d->loadingInfo;
601 d->loadingInfo = 0;
602 }
603
stringCompletion()604 KCompletion& Map::stringCompletion()
605 {
606 return d->listCompletion;
607 }
608
addStringCompletion(const QString & stringCompletion)609 void Map::addStringCompletion(const QString &stringCompletion)
610 {
611 if (d->listCompletion.items().contains(stringCompletion) == 0) {
612 d->listCompletion.addItem(stringCompletion);
613 }
614 }
615
addDamage(Damage * damage)616 void Map::addDamage(Damage* damage)
617 {
618 // Do not create a new Damage, if we are in loading process. Check for it before
619 // calling this function. This prevents unnecessary memory allocations (new).
620 // see FIXME in Sheet::setSheetName().
621 // Q_ASSERT(!isLoading());
622 Q_CHECK_PTR(damage);
623
624 #ifndef NDEBUG
625 if (damage->type() == Damage::Cell) {
626 debugSheetsDamage << "Adding\t" << *static_cast<CellDamage*>(damage);
627 } else if (damage->type() == Damage::Sheet) {
628 debugSheetsDamage << "Adding\t" << *static_cast<SheetDamage*>(damage);
629 } else if (damage->type() == Damage::Selection) {
630 debugSheetsDamage << "Adding\t" << *static_cast<SelectionDamage*>(damage);
631 } else {
632 debugSheetsDamage << "Adding\t" << *damage;
633 }
634 #endif
635
636 d->damages.append(damage);
637
638 if (d->damages.count() == 1) {
639 QTimer::singleShot(0, this, SLOT(flushDamages()));
640 }
641 }
642
flushDamages()643 void Map::flushDamages()
644 {
645 // Copy the damages to process. This allows new damages while processing.
646 QList<Damage*> damages = d->damages;
647 d->damages.clear();
648 emit damagesFlushed(damages);
649 qDeleteAll(damages);
650 }
651
handleDamages(const QList<Damage * > & damages)652 void Map::handleDamages(const QList<Damage*>& damages)
653 {
654 Region bindingChangedRegion;
655 Region formulaChangedRegion;
656 Region namedAreaChangedRegion;
657 Region valueChangedRegion;
658 WorkbookDamage::Changes workbookChanges = WorkbookDamage::None;
659
660 QList<Damage*>::ConstIterator end(damages.end());
661 for (QList<Damage*>::ConstIterator it = damages.begin(); it != end; ++it) {
662 Damage* damage = *it;
663
664 if (damage->type() == Damage::Cell) {
665 CellDamage* cellDamage = static_cast<CellDamage*>(damage);
666 debugSheetsDamage << "Processing\t" << *cellDamage;
667 Sheet* const damagedSheet = cellDamage->sheet();
668 const Region& region = cellDamage->region();
669 const CellDamage::Changes changes = cellDamage->changes();
670
671 // TODO Stefan: Detach the style cache from the CellView cache.
672 if ((changes.testFlag(CellDamage::Appearance))) {
673 // Rebuild the style storage cache.
674 damagedSheet->cellStorage()->invalidateStyleCache(); // FIXME more fine-grained
675 }
676 if ((cellDamage->changes() & CellDamage::Binding) &&
677 !workbookChanges.testFlag(WorkbookDamage::Value)) {
678 bindingChangedRegion.add(region, damagedSheet);
679 }
680 if ((cellDamage->changes() & CellDamage::Formula) &&
681 !workbookChanges.testFlag(WorkbookDamage::Formula)) {
682 formulaChangedRegion.add(region, damagedSheet);
683 }
684 if ((cellDamage->changes() & CellDamage::NamedArea) &&
685 !workbookChanges.testFlag(WorkbookDamage::Formula)) {
686 namedAreaChangedRegion.add(region, damagedSheet);
687 }
688 if ((cellDamage->changes() & CellDamage::Value) &&
689 !workbookChanges.testFlag(WorkbookDamage::Value)) {
690 valueChangedRegion.add(region, damagedSheet);
691 }
692 continue;
693 }
694
695 if (damage->type() == Damage::Sheet) {
696 SheetDamage* sheetDamage = static_cast<SheetDamage*>(damage);
697 debugSheetsDamage << "Processing\t" << *sheetDamage;
698 // Sheet* damagedSheet = sheetDamage->sheet();
699
700 if (sheetDamage->changes() & SheetDamage::PropertiesChanged) {
701 }
702 continue;
703 }
704
705 if (damage->type() == Damage::Workbook) {
706 WorkbookDamage* workbookDamage = static_cast<WorkbookDamage*>(damage);
707 debugSheetsDamage << "Processing\t" << *damage;
708
709 workbookChanges |= workbookDamage->changes();
710 if (workbookDamage->changes() & WorkbookDamage::Formula) {
711 formulaChangedRegion.clear();
712 }
713 if (workbookDamage->changes() & WorkbookDamage::Value) {
714 valueChangedRegion.clear();
715 }
716 continue;
717 }
718 // debugSheetsDamage <<"Unhandled\t" << *damage;
719 }
720
721 // Update the named areas.
722 if (!namedAreaChangedRegion.isEmpty()) {
723 d->namedAreaManager->regionChanged(namedAreaChangedRegion);
724 }
725 // First, update the dependencies.
726 if (!formulaChangedRegion.isEmpty()) {
727 d->dependencyManager->regionChanged(formulaChangedRegion);
728 }
729 // Tell the RecalcManager which cells have had a value change.
730 if (!valueChangedRegion.isEmpty()) {
731 d->recalcManager->regionChanged(valueChangedRegion);
732 }
733 if (workbookChanges.testFlag(WorkbookDamage::Formula)) {
734 d->namedAreaManager->updateAllNamedAreas();
735 d->dependencyManager->updateAllDependencies(this);
736 }
737 if (workbookChanges.testFlag(WorkbookDamage::Value)) {
738 d->recalcManager->recalcMap();
739 d->bindingManager->updateAllBindings();
740 }
741 // Update the bindings
742 if (!bindingChangedRegion.isEmpty()) {
743 d->bindingManager->regionChanged(bindingChangedRegion);
744 }
745 }
746
addCommand(KUndo2Command * command)747 void Map::addCommand(KUndo2Command *command)
748 {
749 emit commandAdded(command);
750 }
751
resourceManager() const752 KoDocumentResourceManager* Map::resourceManager() const
753 {
754 if (!doc()) return 0;
755 return doc()->resourceManager();
756 }
757