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

0001 /* This file is part of the KDE project
0002    Copyright 2010 Marijn Kruisselbrink <mkruisselbrink@kde.org>
0003    Copyright (C) 1998, 1999 Torben Weis <weis@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 "Map.h"
0023 
0024 #include <stdlib.h>
0025 #include <time.h>
0026 
0027 #include <QTimer>
0028 
0029 #include <kcodecs.h>
0030 #include <kcompletion.h>
0031 
0032 #include <KoGlobal.h>
0033 #include <KoEmbeddedDocumentSaver.h>
0034 #include <KoStyleManager.h>
0035 #include <KoParagraphStyle.h>
0036 #include <KoUpdater.h>
0037 #include <KoProgressUpdater.h>
0038 
0039 #include "ApplicationSettings.h"
0040 #include "BindingManager.h"
0041 #include "CalculationSettings.h"
0042 #include "CellStorage.h"
0043 #include "Damages.h"
0044 #include "DependencyManager.h"
0045 #include "DocBase.h"
0046 #include "LoadingInfo.h"
0047 #include "Localization.h"
0048 #include "NamedAreaManager.h"
0049 #include "RecalcManager.h"
0050 #include "RowColumnFormat.h"
0051 #include "Sheet.h"
0052 #include "StyleManager.h"
0053 #include "ValueCalc.h"
0054 #include "ValueConverter.h"
0055 #include "ValueFormatter.h"
0056 #include "ValueParser.h"
0057 
0058 // database
0059 #include "database/DatabaseManager.h"
0060 
0061 using namespace Calligra::Sheets;
0062 
0063 class Q_DECL_HIDDEN Map::Private
0064 {
0065 public:
0066     DocBase* doc;
0067 
0068     /**
0069      * List of all sheets in this map.
0070      */
0071     QList<Sheet*> lstSheets;
0072     QList<Sheet*> lstDeletedSheets;
0073 
0074     // used to give every Sheet a unique default name.
0075     int tableId;
0076 
0077     // used to determine the loading progress
0078     int overallRowCount;
0079     int loadedRowsCounter;
0080 
0081     LoadingInfo* loadingInfo;
0082     bool readwrite;
0083 
0084     BindingManager* bindingManager;
0085     DatabaseManager* databaseManager;
0086     DependencyManager* dependencyManager;
0087     NamedAreaManager* namedAreaManager;
0088     RecalcManager* recalcManager;
0089     StyleManager* styleManager;
0090     KoStyleManager* textStyleManager;
0091 
0092     ApplicationSettings* applicationSettings;
0093     CalculationSettings* calculationSettings;
0094     ValueCalc* calc;
0095     ValueConverter* converter;
0096     ValueFormatter* formatter;
0097     ValueParser* parser;
0098 
0099     // default objects
0100     ColumnFormat* defaultColumnFormat;
0101     RowFormat* defaultRowFormat;
0102 
0103     QList<Damage*> damages;
0104     bool isLoading;
0105 
0106     int syntaxVersion;
0107 
0108     KCompletion listCompletion;
0109 };
0110 
0111 
0112 Map::Map(DocBase* doc, int syntaxVersion)
0113         : QObject(doc),
0114         d(new Private)
0115 {
0116     setObjectName(QLatin1String("Map")); // necessary for D-Bus
0117     d->doc = doc;
0118     d->tableId = 1;
0119     d->overallRowCount = 0;
0120     d->loadedRowsCounter = 0;
0121     d->loadingInfo = 0;
0122     d->readwrite = true;
0123 
0124     d->bindingManager = new BindingManager(this);
0125     d->databaseManager = new DatabaseManager(this);
0126     d->dependencyManager = new DependencyManager(this);
0127     d->namedAreaManager = new NamedAreaManager(this);
0128     d->recalcManager = new RecalcManager(this);
0129     d->styleManager = new StyleManager();
0130     d->textStyleManager = new KoStyleManager(this);
0131     d->applicationSettings = new ApplicationSettings();
0132     d->calculationSettings = new CalculationSettings();
0133 
0134     d->parser = new ValueParser(d->calculationSettings);
0135     d->converter = new ValueConverter(d->parser);
0136     d->calc = new ValueCalc(d->converter);
0137     d->formatter = new ValueFormatter(d->converter);
0138 
0139     d->defaultColumnFormat = new ColumnFormat();
0140     d->defaultRowFormat = new RowFormat();
0141 
0142     QFont font(KoGlobal::defaultFont());
0143     d->defaultRowFormat->setHeight(font.pointSizeF() + 4);
0144     d->defaultColumnFormat->setWidth((font.pointSizeF() + 4) * 5);
0145 
0146     d->isLoading = false;
0147 
0148     // default document properties
0149     d->syntaxVersion = syntaxVersion;
0150 
0151     connect(this, SIGNAL(sheetAdded(Sheet*)),
0152             d->dependencyManager, SLOT(addSheet(Sheet*)));
0153     connect(this, SIGNAL(sheetAdded(Sheet*)),
0154             d->recalcManager, SLOT(addSheet(Sheet*)));
0155     connect(this, SIGNAL(sheetRemoved(Sheet*)),
0156             d->dependencyManager, SLOT(removeSheet(Sheet*)));
0157     connect(this, SIGNAL(sheetRemoved(Sheet*)),
0158             d->recalcManager, SLOT(removeSheet(Sheet*)));
0159     connect(this, SIGNAL(sheetRevived(Sheet*)),
0160             d->dependencyManager, SLOT(addSheet(Sheet*)));
0161     connect(this, SIGNAL(sheetRevived(Sheet*)),
0162             d->recalcManager, SLOT(addSheet(Sheet*)));
0163     connect(d->namedAreaManager, SIGNAL(namedAreaModified(QString)),
0164             d->dependencyManager, SLOT(namedAreaModified(QString)));
0165     connect(this, SIGNAL(damagesFlushed(QList<Damage*>)),
0166             this, SLOT(handleDamages(QList<Damage*>)));
0167 }
0168 
0169 Map::~Map()
0170 {
0171     // Because some of the shapes might be using a sheet in this map, delete
0172     // all shapes in each sheet before all sheets are deleted together.
0173     foreach(Sheet *sheet, d->lstSheets)
0174         sheet->deleteShapes();
0175     // we have to explicitly delete the Sheets, not let QObject take care of that
0176     // as the sheet in its destructor expects the Map to still exist
0177     qDeleteAll(d->lstSheets);
0178     d->lstSheets.clear();
0179 
0180     deleteLoadingInfo();
0181 
0182     delete d->bindingManager;
0183     delete d->databaseManager;
0184     delete d->dependencyManager;
0185     delete d->namedAreaManager;
0186     delete d->recalcManager;
0187     delete d->styleManager;
0188 
0189     delete d->parser;
0190     delete d->formatter;
0191     delete d->converter;
0192     delete d->calc;
0193     delete d->calculationSettings;
0194     delete d->applicationSettings;
0195 
0196     delete d->defaultColumnFormat;
0197     delete d->defaultRowFormat;
0198 
0199     delete d;
0200 }
0201 
0202 DocBase* Map::doc() const
0203 {
0204     return d->doc;
0205 }
0206 
0207 void Map::setReadWrite(bool readwrite)
0208 {
0209     d->readwrite = readwrite;
0210 }
0211 
0212 bool Map::isReadWrite() const
0213 {
0214     return d->readwrite;
0215 }
0216 
0217 bool Map::completeLoading(KoStore *store)
0218 {
0219     Q_UNUSED(store);
0220 
0221     QPointer<KoUpdater> dependencyUpdater, recalcUpdater;
0222     if (doc() && doc()->progressUpdater()) {
0223         dependencyUpdater = doc()->progressUpdater()->startSubtask(1, "Calligra::Sheets::DependencyManager::updateAllDependencies");
0224         recalcUpdater = doc()->progressUpdater()->startSubtask(1, "Calligra::Sheets::RecalcManager::recalc");
0225     }
0226 
0227     // Initial build of all cell dependencies.
0228     d->dependencyManager->updateAllDependencies(this, dependencyUpdater);
0229     // Recalc the whole workbook now, since there may be formulas other spreadsheets support,
0230     // but Calligra Sheets does not.
0231     d->recalcManager->recalcMap(recalcUpdater);
0232 
0233     return true;
0234 }
0235 
0236 bool Map::completeSaving(KoStore *store, KoXmlWriter *manifestWriter, KoShapeSavingContext * context)
0237 {
0238     Q_UNUSED(store);
0239     Q_UNUSED(manifestWriter);
0240     Q_UNUSED(context);
0241     return true;
0242 }
0243 
0244 BindingManager* Map::bindingManager() const
0245 {
0246     return d->bindingManager;
0247 }
0248 
0249 DatabaseManager* Map::databaseManager() const
0250 {
0251     return d->databaseManager;
0252 }
0253 
0254 DependencyManager* Map::dependencyManager() const
0255 {
0256     return d->dependencyManager;
0257 }
0258 
0259 NamedAreaManager* Map::namedAreaManager() const
0260 {
0261     return d->namedAreaManager;
0262 }
0263 
0264 RecalcManager* Map::recalcManager() const
0265 {
0266     return d->recalcManager;
0267 }
0268 
0269 StyleManager* Map::styleManager() const
0270 {
0271     return d->styleManager;
0272 }
0273 
0274 KoStyleManager* Map::textStyleManager() const
0275 {
0276     return d->textStyleManager;
0277 }
0278 
0279 ValueParser* Map::parser() const
0280 {
0281     return d->parser;
0282 }
0283 
0284 ValueFormatter* Map::formatter() const
0285 {
0286     return d->formatter;
0287 }
0288 
0289 ValueConverter* Map::converter() const
0290 {
0291     return d->converter;
0292 }
0293 
0294 ValueCalc* Map::calc() const
0295 {
0296     return d->calc;
0297 }
0298 
0299 const ColumnFormat* Map::defaultColumnFormat() const
0300 {
0301     return d->defaultColumnFormat;
0302 }
0303 
0304 const RowFormat* Map::defaultRowFormat() const
0305 {
0306     return d->defaultRowFormat;
0307 }
0308 
0309 void Map::setDefaultColumnWidth(double width)
0310 {
0311     d->defaultColumnFormat->setWidth(width);
0312 }
0313 
0314 void Map::setDefaultRowHeight(double height)
0315 {
0316     d->defaultRowFormat->setHeight(height);
0317 }
0318 
0319 ApplicationSettings* Map::settings() const
0320 {
0321     return d->applicationSettings;
0322 }
0323 
0324 CalculationSettings* Map::calculationSettings() const
0325 {
0326     return d->calculationSettings;
0327 }
0328 
0329 Sheet* Map::createSheet(const QString& name)
0330 {
0331     QString sheetName(i18n("Sheet%1", d->tableId++));
0332     if ( !name.isEmpty() )
0333         sheetName = name;
0334     Sheet* sheet = new Sheet(this, sheetName);
0335     connect(sheet, SIGNAL(statusMessage(QString,int)),
0336             this, SIGNAL(statusMessage(QString,int)));
0337     return sheet;
0338 }
0339 
0340 void Map::addSheet(Sheet *_sheet)
0341 {
0342     d->lstSheets.append(_sheet);
0343     emit sheetAdded(_sheet);
0344 }
0345 
0346 Sheet *Map::addNewSheet(const QString& name)
0347 {
0348     Sheet *t = createSheet(name);
0349     addSheet(t);
0350     return t;
0351 }
0352 
0353 void Map::moveSheet(const QString & _from, const QString & _to, bool _before)
0354 {
0355     Sheet* sheetfrom = findSheet(_from);
0356     Sheet* sheetto = findSheet(_to);
0357 
0358     int from = d->lstSheets.indexOf(sheetfrom) ;
0359     int to = d->lstSheets.indexOf(sheetto) ;
0360     if (!_before)
0361         ++to;
0362 
0363     if (to > (int)d->lstSheets.count()) {
0364         d->lstSheets.append(sheetfrom);
0365         d->lstSheets.removeAt(from);
0366     } else if (from < to) {
0367         d->lstSheets.insert(to, sheetfrom);
0368         d->lstSheets.removeAt(from);
0369     } else {
0370         d->lstSheets.removeAt(from);
0371         d->lstSheets.insert(to, sheetfrom);
0372     }
0373 }
0374 
0375 QDomElement Map::save(QDomDocument& doc)
0376 {
0377     QDomElement spread = doc.documentElement();
0378 
0379     QDomElement locale = static_cast<Localization*>(d->calculationSettings->locale())->save(doc);
0380     spread.appendChild(locale);
0381 
0382     QDomElement areaname = d->namedAreaManager->saveXML(doc);
0383     spread.appendChild(areaname);
0384 
0385     QDomElement defaults = doc.createElement("defaults");
0386     defaults.setAttribute("row-height", QString::number(d->defaultRowFormat->height()));
0387     defaults.setAttribute("col-width", QString::number(d->defaultColumnFormat->width()));
0388     spread.appendChild(defaults);
0389 
0390     QDomElement s = d->styleManager->save(doc);
0391     spread.appendChild(s);
0392 
0393     QDomElement mymap = doc.createElement("map");
0394 
0395     QByteArray password;
0396     this->password(password);
0397     if (!password.isNull()) {
0398         if (password.size() > 0) {
0399             QByteArray str = KCodecs::base64Encode(password);
0400             mymap.setAttribute("protected", QString(str.data()));
0401         } else {
0402             mymap.setAttribute("protected", "");
0403         }
0404     }
0405 
0406     foreach(Sheet* sheet, d->lstSheets) {
0407         QDomElement e = sheet->saveXML(doc);
0408         if (e.isNull())
0409             return e;
0410         mymap.appendChild(e);
0411     }
0412     return mymap;
0413 }
0414 
0415 bool Map::loadXML(const KoXmlElement& mymap)
0416 {
0417     d->isLoading = true;
0418     loadingInfo()->setFileFormat(LoadingInfo::NativeFormat);
0419     const QString activeSheet = mymap.attribute("activeTable");
0420     const QPoint marker(mymap.attribute("markerColumn").toInt(), mymap.attribute("markerRow").toInt());
0421     loadingInfo()->setCursorPosition(findSheet(activeSheet), marker);
0422     const QPointF offset(mymap.attribute("xOffset").toDouble(), mymap.attribute("yOffset").toDouble());
0423     loadingInfo()->setScrollingOffset(findSheet(activeSheet), offset);
0424 
0425     KoXmlNode n = mymap.firstChild();
0426     if (n.isNull()) {
0427         // We need at least one sheet !
0428         doc()->setErrorMessage(i18n("This document has no sheets (tables)."));
0429         d->isLoading = false;
0430         return false;
0431     }
0432     while (!n.isNull()) {
0433         KoXmlElement e = n.toElement();
0434         if (!e.isNull() && e.tagName() == "table") {
0435             Sheet *t = addNewSheet();
0436             if (!t->loadXML(e)) {
0437                 d->isLoading = false;
0438                 return false;
0439             }
0440         }
0441         n = n.nextSibling();
0442     }
0443 
0444     loadXmlProtection(mymap);
0445 
0446     if (!activeSheet.isEmpty()) {
0447         // Used by View's constructor
0448         loadingInfo()->setInitialActiveSheet(findSheet(activeSheet));
0449     }
0450 
0451     d->isLoading = false;
0452     return true;
0453 }
0454 
0455 Sheet* Map::findSheet(const QString & _name) const
0456 {
0457     foreach(Sheet* sheet, d->lstSheets) {
0458         if (_name.toLower() == sheet->sheetName().toLower())
0459             return sheet;
0460     }
0461     return 0;
0462 }
0463 
0464 Sheet * Map::nextSheet(Sheet * currentSheet) const
0465 {
0466     if (currentSheet == d->lstSheets.last())
0467         return currentSheet;
0468     int index = 0;
0469     foreach(Sheet* sheet, d->lstSheets) {
0470         if (sheet == currentSheet)
0471             return d->lstSheets.value(++index);
0472         ++index;
0473     }
0474     return 0;
0475 }
0476 
0477 Sheet * Map::previousSheet(Sheet * currentSheet) const
0478 {
0479     if (currentSheet == d->lstSheets.first())
0480         return currentSheet;
0481     int index = 0;
0482     foreach(Sheet* sheet, d->lstSheets) {
0483         if (sheet  == currentSheet)
0484             return d->lstSheets.value(--index);
0485         ++index;
0486     }
0487     return 0;
0488 }
0489 
0490 bool Map::loadChildren(KoStore * _store)
0491 {
0492     foreach(Sheet* sheet, d->lstSheets) {
0493         if (!sheet->loadChildren(_store))
0494             return false;
0495     }
0496     return true;
0497 }
0498 
0499 void Map::removeSheet(Sheet* sheet)
0500 {
0501     d->lstSheets.removeAll(sheet);
0502     d->lstDeletedSheets.append(sheet);
0503     d->namedAreaManager->remove(sheet);
0504     emit sheetRemoved(sheet);
0505 }
0506 
0507 void Map::reviveSheet(Sheet* sheet)
0508 {
0509     d->lstDeletedSheets.removeAll(sheet);
0510     d->lstSheets.append(sheet);
0511     emit sheetRevived(sheet);
0512 }
0513 
0514 // FIXME cache this for faster operation
0515 QStringList Map::visibleSheets() const
0516 {
0517     QStringList result;
0518     foreach(Sheet* sheet, d->lstSheets) {
0519         if (!sheet->isHidden())
0520             result.append(sheet->sheetName());
0521     }
0522     return result;
0523 }
0524 
0525 // FIXME cache this for faster operation
0526 QStringList Map::hiddenSheets() const
0527 {
0528     QStringList result;
0529     foreach(Sheet* sheet, d->lstSheets) {
0530         if (sheet->isHidden())
0531             result.append(sheet->sheetName());
0532     }
0533     return result;
0534 }
0535 
0536 Sheet* Map::sheet(int index) const
0537 {
0538     return d->lstSheets.value(index);
0539 }
0540 
0541 int Map::indexOf(Sheet* sheet) const
0542 {
0543     return d->lstSheets.indexOf(sheet);
0544 }
0545 
0546 QList<Sheet*>& Map::sheetList() const
0547 {
0548     return d->lstSheets;
0549 }
0550 
0551 int Map::count() const
0552 {
0553     return d->lstSheets.count();
0554 }
0555 
0556 void Map::setOverallRowsCounter(int number)
0557 {
0558     d->overallRowCount = number;
0559 }
0560 
0561 int Map::increaseLoadedRowsCounter(int number)
0562 {
0563     d->loadedRowsCounter += number;
0564     if (d->overallRowCount) {
0565         return 100 * d->loadedRowsCounter / d->overallRowCount;
0566     }
0567     return -1;
0568 }
0569 
0570 bool Map::isLoading() const
0571 {
0572     // The KoDocument state is necessary to avoid damages while importing a file (through a filter).
0573     return d->isLoading || (d->doc && d->doc->isLoading());
0574 }
0575 
0576 void Map::setLoading(bool l) {
0577     d->isLoading = l;
0578 }
0579 
0580 int Map::syntaxVersion() const
0581 {
0582     return d->syntaxVersion;
0583 }
0584 
0585 void Map::setSyntaxVersion(int version)
0586 {
0587     d->syntaxVersion = version;
0588 }
0589 
0590 LoadingInfo* Map::loadingInfo() const
0591 {
0592     if (!d->loadingInfo) {
0593         d->loadingInfo = new LoadingInfo();
0594     }
0595     return d->loadingInfo;
0596 }
0597 
0598 void Map::deleteLoadingInfo()
0599 {
0600     delete d->loadingInfo;
0601     d->loadingInfo = 0;
0602 }
0603 
0604 KCompletion& Map::stringCompletion()
0605 {
0606     return d->listCompletion;
0607 }
0608 
0609 void Map::addStringCompletion(const QString &stringCompletion)
0610 {
0611     if (d->listCompletion.items().contains(stringCompletion) == 0) {
0612         d->listCompletion.addItem(stringCompletion);
0613     }
0614 }
0615 
0616 void Map::addDamage(Damage* damage)
0617 {
0618     // Do not create a new Damage, if we are in loading process. Check for it before
0619     // calling this function. This prevents unnecessary memory allocations (new).
0620     // see FIXME in Sheet::setSheetName().
0621 //     Q_ASSERT(!isLoading());
0622     Q_CHECK_PTR(damage);
0623 
0624 #ifndef NDEBUG
0625     if (damage->type() == Damage::Cell) {
0626         debugSheetsDamage << "Adding\t" << *static_cast<CellDamage*>(damage);
0627     } else if (damage->type() == Damage::Sheet) {
0628         debugSheetsDamage << "Adding\t" << *static_cast<SheetDamage*>(damage);
0629     } else if (damage->type() == Damage::Selection) {
0630         debugSheetsDamage << "Adding\t" << *static_cast<SelectionDamage*>(damage);
0631     } else {
0632         debugSheetsDamage << "Adding\t" << *damage;
0633     }
0634 #endif
0635 
0636     d->damages.append(damage);
0637 
0638     if (d->damages.count() == 1) {
0639         QTimer::singleShot(0, this, SLOT(flushDamages()));
0640     }
0641 }
0642 
0643 void Map::flushDamages()
0644 {
0645     // Copy the damages to process. This allows new damages while processing.
0646     QList<Damage*> damages = d->damages;
0647     d->damages.clear();
0648     emit damagesFlushed(damages);
0649     qDeleteAll(damages);
0650 }
0651 
0652 void Map::handleDamages(const QList<Damage*>& damages)
0653 {
0654     Region bindingChangedRegion;
0655     Region formulaChangedRegion;
0656     Region namedAreaChangedRegion;
0657     Region valueChangedRegion;
0658     WorkbookDamage::Changes workbookChanges = WorkbookDamage::None;
0659 
0660     QList<Damage*>::ConstIterator end(damages.end());
0661     for (QList<Damage*>::ConstIterator it = damages.begin(); it != end; ++it) {
0662         Damage* damage = *it;
0663 
0664         if (damage->type() == Damage::Cell) {
0665             CellDamage* cellDamage = static_cast<CellDamage*>(damage);
0666             debugSheetsDamage << "Processing\t" << *cellDamage;
0667             Sheet* const damagedSheet = cellDamage->sheet();
0668             const Region& region = cellDamage->region();
0669             const CellDamage::Changes changes = cellDamage->changes();
0670 
0671             // TODO Stefan: Detach the style cache from the CellView cache.
0672             if ((changes.testFlag(CellDamage::Appearance))) {
0673                 // Rebuild the style storage cache.
0674                 damagedSheet->cellStorage()->invalidateStyleCache(); // FIXME more fine-grained
0675             }
0676             if ((cellDamage->changes() & CellDamage::Binding) &&
0677                     !workbookChanges.testFlag(WorkbookDamage::Value)) {
0678                 bindingChangedRegion.add(region, damagedSheet);
0679             }
0680             if ((cellDamage->changes() & CellDamage::Formula) &&
0681                     !workbookChanges.testFlag(WorkbookDamage::Formula)) {
0682                 formulaChangedRegion.add(region, damagedSheet);
0683             }
0684             if ((cellDamage->changes() & CellDamage::NamedArea) &&
0685                     !workbookChanges.testFlag(WorkbookDamage::Formula)) {
0686                 namedAreaChangedRegion.add(region, damagedSheet);
0687             }
0688             if ((cellDamage->changes() & CellDamage::Value) &&
0689                     !workbookChanges.testFlag(WorkbookDamage::Value)) {
0690                 valueChangedRegion.add(region, damagedSheet);
0691             }
0692             continue;
0693         }
0694 
0695         if (damage->type() == Damage::Sheet) {
0696             SheetDamage* sheetDamage = static_cast<SheetDamage*>(damage);
0697             debugSheetsDamage << "Processing\t" << *sheetDamage;
0698 //             Sheet* damagedSheet = sheetDamage->sheet();
0699 
0700             if (sheetDamage->changes() & SheetDamage::PropertiesChanged) {
0701             }
0702             continue;
0703         }
0704 
0705         if (damage->type() == Damage::Workbook) {
0706             WorkbookDamage* workbookDamage = static_cast<WorkbookDamage*>(damage);
0707             debugSheetsDamage << "Processing\t" << *damage;
0708 
0709             workbookChanges |= workbookDamage->changes();
0710             if (workbookDamage->changes() & WorkbookDamage::Formula) {
0711                 formulaChangedRegion.clear();
0712             }
0713             if (workbookDamage->changes() & WorkbookDamage::Value) {
0714                 valueChangedRegion.clear();
0715             }
0716             continue;
0717         }
0718 //         debugSheetsDamage <<"Unhandled\t" << *damage;
0719     }
0720 
0721     // Update the named areas.
0722     if (!namedAreaChangedRegion.isEmpty()) {
0723         d->namedAreaManager->regionChanged(namedAreaChangedRegion);
0724     }
0725     // First, update the dependencies.
0726     if (!formulaChangedRegion.isEmpty()) {
0727         d->dependencyManager->regionChanged(formulaChangedRegion);
0728     }
0729     // Tell the RecalcManager which cells have had a value change.
0730     if (!valueChangedRegion.isEmpty()) {
0731         d->recalcManager->regionChanged(valueChangedRegion);
0732     }
0733     if (workbookChanges.testFlag(WorkbookDamage::Formula)) {
0734         d->namedAreaManager->updateAllNamedAreas();
0735         d->dependencyManager->updateAllDependencies(this);
0736     }
0737     if (workbookChanges.testFlag(WorkbookDamage::Value)) {
0738         d->recalcManager->recalcMap();
0739         d->bindingManager->updateAllBindings();
0740     }
0741     // Update the bindings
0742     if (!bindingChangedRegion.isEmpty()) {
0743         d->bindingManager->regionChanged(bindingChangedRegion);
0744     }
0745 }
0746 
0747 void Map::addCommand(KUndo2Command *command)
0748 {
0749     emit commandAdded(command);
0750 }
0751 
0752 KoDocumentResourceManager* Map::resourceManager() const
0753 {
0754     if (!doc()) return 0;
0755     return doc()->resourceManager();
0756 }