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

0001 /* This file is part of the KDE project
0002    Copyright 2010 Marijn Kruisselbrink <mkruisselbrink@kde.org>
0003    Copyright 2007, 2009 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
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 "CellStorage.h"
0023 #include "CellStorage_p.h"
0024 
0025 // Qt
0026 #ifdef CALLIGRA_SHEETS_MT
0027 #include <QReadWriteLock>
0028 #include <QReadLocker>
0029 #include <QWriteLocker>
0030 #endif
0031 
0032 // Calligra
0033 #include <KoXmlWriter.h>
0034 
0035 // Sheets
0036 #include "BindingStorage.h"
0037 #include "ConditionsStorage.h"
0038 #include "Damages.h"
0039 #include "DependencyManager.h"
0040 #include "FormulaStorage.h"
0041 #include "Map.h"
0042 #include "ModelSupport.h"
0043 #include "RecalcManager.h"
0044 #include "RectStorage.h"
0045 #include "RowRepeatStorage.h"
0046 #include "Sheet.h"
0047 #include "StyleStorage.h"
0048 #include "ValidityStorage.h"
0049 #include "ValueStorage.h"
0050 
0051 // commands
0052 #include "commands/PointStorageUndoCommand.h"
0053 #include "commands/RectStorageUndoCommand.h"
0054 #include "commands/StyleStorageUndoCommand.h"
0055 
0056 // database
0057 #include "database/DatabaseStorage.h"
0058 #include "database/DatabaseManager.h"
0059 
0060 Q_DECLARE_METATYPE(QSharedPointer<QTextDocument>)
0061 
0062 using namespace Calligra::Sheets;
0063 
0064 typedef RectStorage<QString> NamedAreaStorage;
0065 
0066 class Q_DECL_HIDDEN CellStorage::Private
0067 {
0068 public:
0069     Private(Sheet* sheet)
0070             : sheet(sheet)
0071             , bindingStorage(new BindingStorage(sheet->map()))
0072             , commentStorage(new CommentStorage(sheet->map()))
0073             , conditionsStorage(new ConditionsStorage(sheet->map()))
0074             , databaseStorage(new DatabaseStorage(sheet->map()))
0075             , formulaStorage(new FormulaStorage())
0076             , fusionStorage(new FusionStorage(sheet->map()))
0077             , linkStorage(new LinkStorage())
0078             , matrixStorage(new MatrixStorage(sheet->map()))
0079             , namedAreaStorage(new NamedAreaStorage(sheet->map()))
0080             , styleStorage(new StyleStorage(sheet->map()))
0081             , userInputStorage(new UserInputStorage())
0082             , validityStorage(new ValidityStorage(sheet->map()))
0083             , valueStorage(new ValueStorage())
0084             , richTextStorage(new RichTextStorage())
0085             , rowRepeatStorage(new RowRepeatStorage())
0086             , undoData(0)
0087 #ifdef CALLIGRA_SHEETS_MT
0088             , bigUglyLock(QReadWriteLock::Recursive)
0089 #endif
0090     {}
0091 
0092     Private(const Private& other, Sheet* sheet)
0093             : sheet(sheet)
0094             , bindingStorage(new BindingStorage(*other.bindingStorage))
0095             , commentStorage(new CommentStorage(*other.commentStorage))
0096             , conditionsStorage(new ConditionsStorage(*other.conditionsStorage))
0097             , databaseStorage(new DatabaseStorage(*other.databaseStorage))
0098             , formulaStorage(new FormulaStorage(*other.formulaStorage))
0099             , fusionStorage(new FusionStorage(*other.fusionStorage))
0100             , linkStorage(new LinkStorage(*other.linkStorage))
0101             , matrixStorage(new MatrixStorage(*other.matrixStorage))
0102             , namedAreaStorage(new NamedAreaStorage(*other.namedAreaStorage))
0103             , styleStorage(new StyleStorage(*other.styleStorage))
0104             , userInputStorage(new UserInputStorage(*other.userInputStorage))
0105             , validityStorage(new ValidityStorage(*other.validityStorage))
0106             , valueStorage(new ValueStorage(*other.valueStorage))
0107             , richTextStorage(new RichTextStorage(*other.richTextStorage))
0108             , rowRepeatStorage(new RowRepeatStorage(*other.rowRepeatStorage))
0109             , undoData(0)
0110 #ifdef CALLIGRA_SHEETS_MT
0111             , bigUglyLock(QReadWriteLock::Recursive)
0112 #endif
0113     {}
0114 
0115     ~Private() {
0116         delete bindingStorage;
0117         delete commentStorage;
0118         delete conditionsStorage;
0119         delete databaseStorage;
0120         delete formulaStorage;
0121         delete fusionStorage;
0122         delete linkStorage;
0123         delete matrixStorage;
0124         delete namedAreaStorage;
0125         delete styleStorage;
0126         delete userInputStorage;
0127         delete validityStorage;
0128         delete valueStorage;
0129         delete richTextStorage;
0130         delete rowRepeatStorage;
0131     }
0132 
0133     void createCommand(KUndo2Command *parent) const;
0134 
0135     Sheet*                  sheet;
0136     BindingStorage*         bindingStorage;
0137     CommentStorage*         commentStorage;
0138     ConditionsStorage*      conditionsStorage;
0139     DatabaseStorage*        databaseStorage;
0140     FormulaStorage*         formulaStorage;
0141     FusionStorage*          fusionStorage;
0142     LinkStorage*            linkStorage;
0143     MatrixStorage*          matrixStorage;
0144     NamedAreaStorage*       namedAreaStorage;
0145     StyleStorage*           styleStorage;
0146     UserInputStorage*       userInputStorage;
0147     ValidityStorage*        validityStorage;
0148     ValueStorage*           valueStorage;
0149     RichTextStorage*        richTextStorage;
0150     RowRepeatStorage*       rowRepeatStorage;
0151     CellStorageUndoData*    undoData;
0152 
0153 #ifdef CALLIGRA_SHEETS_MT
0154     QReadWriteLock bigUglyLock;
0155 #endif
0156 };
0157 
0158 void CellStorage::Private::createCommand(KUndo2Command *parent) const
0159 {
0160     if (!undoData->bindings.isEmpty()) {
0161         RectStorageUndoCommand<Binding> *const command
0162         = new RectStorageUndoCommand<Binding>(sheet->model(), SourceRangeRole, parent);
0163         command->add(undoData->bindings);
0164     }
0165     if (!undoData->comments.isEmpty()) {
0166         RectStorageUndoCommand<QString> *const command
0167         = new RectStorageUndoCommand<QString>(sheet->model(), CommentRole, parent);
0168         command->add(undoData->comments);
0169     }
0170     if (!undoData->conditions.isEmpty()) {
0171         RectStorageUndoCommand<Conditions> *const command
0172         = new RectStorageUndoCommand<Conditions>(sheet->model(), ConditionRole, parent);
0173         command->add(undoData->conditions);
0174     }
0175     if (!undoData->databases.isEmpty()) {
0176         RectStorageUndoCommand<Database> *const command
0177         = new RectStorageUndoCommand<Database>(sheet->model(), TargetRangeRole, parent);
0178         command->add(undoData->databases);
0179     }
0180     if (!undoData->formulas.isEmpty()) {
0181         PointStorageUndoCommand<Formula> *const command
0182         = new PointStorageUndoCommand<Formula>(sheet->model(), FormulaRole, parent);
0183         command->add(undoData->formulas);
0184     }
0185     if (!undoData->fusions.isEmpty()) {
0186         RectStorageUndoCommand<bool> *const command
0187         = new RectStorageUndoCommand<bool>(sheet->model(), FusionedRangeRole, parent);
0188         command->add(undoData->fusions);
0189     }
0190     if (!undoData->links.isEmpty()) {
0191         PointStorageUndoCommand<QString> *const command
0192         = new PointStorageUndoCommand<QString>(sheet->model(), LinkRole, parent);
0193         command->add(undoData->links);
0194     }
0195     if (!undoData->matrices.isEmpty()) {
0196         RectStorageUndoCommand<bool> *const command
0197         = new RectStorageUndoCommand<bool>(sheet->model(), LockedRangeRole, parent);
0198         command->add(undoData->matrices);
0199     }
0200     if (!undoData->namedAreas.isEmpty()) {
0201         RectStorageUndoCommand<QString> *const command
0202         = new RectStorageUndoCommand<QString>(sheet->model(), NamedAreaRole, parent);
0203         command->add(undoData->namedAreas);
0204     }
0205     if (!undoData->richTexts.isEmpty()) {
0206         PointStorageUndoCommand<QSharedPointer<QTextDocument> > *const command
0207         = new PointStorageUndoCommand<QSharedPointer<QTextDocument> >(sheet->model(), RichTextRole, parent);
0208         command->add(undoData->richTexts);
0209     }
0210     if (!undoData->styles.isEmpty()) {
0211         StyleStorageUndoCommand *const command
0212         = new StyleStorageUndoCommand(styleStorage, parent);
0213         command->add(undoData->styles);
0214     }
0215     if (!undoData->userInputs.isEmpty()) {
0216         PointStorageUndoCommand<QString> *const command
0217         = new PointStorageUndoCommand<QString>(sheet->model(), UserInputRole, parent);
0218         command->add(undoData->userInputs);
0219     }
0220     if (!undoData->validities.isEmpty()) {
0221         RectStorageUndoCommand<Validity> *const command
0222         = new RectStorageUndoCommand<Validity>(sheet->model(), ValidityRole, parent);
0223         command->add(undoData->validities);
0224     }
0225     if (!undoData->values.isEmpty()) {
0226         PointStorageUndoCommand<Value> *const command
0227         = new PointStorageUndoCommand<Value>(sheet->model(), ValueRole, parent);
0228         command->add(undoData->values);
0229     }
0230 }
0231 
0232 
0233 CellStorage::CellStorage(Sheet* sheet)
0234         : QObject(sheet)
0235         , d(new Private(sheet))
0236 {
0237 }
0238 
0239 CellStorage::CellStorage(const CellStorage& other)
0240         : QObject(other.d->sheet)
0241         , d(new Private(*other.d, other.d->sheet))
0242 {
0243 }
0244 
0245 CellStorage::CellStorage(const CellStorage& other, Sheet* sheet)
0246         : QObject(sheet)
0247         , d(new Private(*other.d, sheet))
0248 {
0249 }
0250 
0251 CellStorage::~CellStorage()
0252 {
0253     delete d;
0254 }
0255 
0256 Sheet* CellStorage::sheet() const
0257 {
0258     return d->sheet;
0259 }
0260 
0261 void CellStorage::take(int col, int row)
0262 {
0263 #ifdef CALLIGRA_SHEETS_MT
0264     QWriteLocker(&d->bigUglyLock);
0265 #endif
0266 
0267     Formula oldFormula;
0268     QString oldLink;
0269     QString oldUserInput;
0270     Value oldValue;
0271     QSharedPointer<QTextDocument> oldRichText;
0272 
0273     oldFormula = d->formulaStorage->take(col, row);
0274     oldLink = d->linkStorage->take(col, row);
0275     oldUserInput = d->userInputStorage->take(col, row);
0276     oldValue = d->valueStorage->take(col, row);
0277     oldRichText = d->richTextStorage->take(col, row);
0278 
0279     if (!d->sheet->map()->isLoading()) {
0280         // Trigger a recalculation of the consuming cells.
0281         CellDamage::Changes changes = CellDamage:: Binding | CellDamage::Formula | CellDamage::Value;
0282         d->sheet->map()->addDamage(new CellDamage(Cell(d->sheet, col, row), changes));
0283 
0284         d->rowRepeatStorage->setRowRepeat(row, 1);
0285     }
0286     // also trigger a relayout of the first non-empty cell to the left of this cell
0287     int prevCol;
0288     Value v = d->valueStorage->prevInRow(col, row, &prevCol);
0289     if (!v.isEmpty())
0290         d->sheet->map()->addDamage(new CellDamage(Cell(d->sheet, prevCol, row), CellDamage::Appearance));
0291 
0292 
0293     // recording undo?
0294     if (d->undoData) {
0295         d->undoData->formulas   << qMakePair(QPoint(col, row), oldFormula);
0296         d->undoData->links      << qMakePair(QPoint(col, row), oldLink);
0297         d->undoData->userInputs << qMakePair(QPoint(col, row), oldUserInput);
0298         d->undoData->values     << qMakePair(QPoint(col, row), oldValue);
0299         d->undoData->richTexts  << qMakePair(QPoint(col, row), oldRichText);
0300     }
0301 }
0302 
0303 Binding CellStorage::binding(int column, int row) const
0304 {
0305 #ifdef CALLIGRA_SHEETS_MT
0306     QReadLocker rl(&d->bigUglyLock);
0307 #endif
0308     return d->bindingStorage->contains(QPoint(column, row));
0309 }
0310 
0311 void CellStorage::setBinding(const Region& region, const Binding& binding)
0312 {
0313 #ifdef CALLIGRA_SHEETS_MT
0314     QWriteLocker(&d->bigUglyLock);
0315 #endif
0316     // recording undo?
0317     if (d->undoData)
0318         d->undoData->bindings << d->bindingStorage->undoData(region);
0319 
0320     d->bindingStorage->insert(region, binding);
0321 }
0322 
0323 void CellStorage::removeBinding(const Region& region, const Binding& binding)
0324 {
0325 #ifdef CALLIGRA_SHEETS_MT
0326     QWriteLocker(&d->bigUglyLock);
0327 #endif
0328     // recording undo?
0329     if (d->undoData) {
0330         d->undoData->bindings << d->bindingStorage->undoData(region);
0331     }
0332     d->bindingStorage->remove(region, binding);
0333 }
0334 
0335 QString CellStorage::comment(int column, int row) const
0336 {
0337 #ifdef CALLIGRA_SHEETS_MT
0338     QReadLocker rl(&d->bigUglyLock);
0339 #endif
0340     return d->commentStorage->contains(QPoint(column, row));
0341 }
0342 
0343 void CellStorage::setComment(const Region& region, const QString& comment)
0344 {
0345 #ifdef CALLIGRA_SHEETS_MT
0346     QWriteLocker(&d->bigUglyLock);
0347 #endif
0348     // recording undo?
0349     if (d->undoData)
0350         d->undoData->comments << d->commentStorage->undoData(region);
0351 
0352     d->commentStorage->insert(region, comment);
0353     if (!d->sheet->map()->isLoading()) {
0354         foreach (const QRect& r, region.rects()) {
0355             d->rowRepeatStorage->splitRowRepeat(r.top());
0356             d->rowRepeatStorage->splitRowRepeat(r.bottom()+1);
0357         }
0358     }
0359 }
0360 
0361 Conditions CellStorage::conditions(int column, int row) const
0362 {
0363 #ifdef CALLIGRA_SHEETS_MT
0364     QReadLocker rl(&d->bigUglyLock);
0365 #endif
0366     return d->conditionsStorage->contains(QPoint(column, row));
0367 }
0368 
0369 void CellStorage::setConditions(const Region& region, Conditions conditions)
0370 {
0371 #ifdef CALLIGRA_SHEETS_MT
0372     QWriteLocker(&d->bigUglyLock);
0373 #endif
0374     // recording undo?
0375     if (d->undoData)
0376         d->undoData->conditions << d->conditionsStorage->undoData(region);
0377 
0378     d->conditionsStorage->insert(region, conditions);
0379     if (!d->sheet->map()->isLoading()) {
0380         foreach (const QRect& r, region.rects()) {
0381             d->rowRepeatStorage->splitRowRepeat(r.top());
0382             d->rowRepeatStorage->splitRowRepeat(r.bottom()+1);
0383         }
0384     }
0385 }
0386 
0387 Database CellStorage::database(int column, int row) const
0388 {
0389 #ifdef CALLIGRA_SHEETS_MT
0390     QReadLocker rl(&d->bigUglyLock);
0391 #endif
0392     QPair<QRectF, Database> pair = d->databaseStorage->containedPair(QPoint(column, row));
0393     if (pair.first.isEmpty())
0394         return Database();
0395     if (pair.second.isEmpty())
0396         return Database();
0397     // update the range, which might get changed
0398     Database database = pair.second;
0399     database.setRange(Region(pair.first.toRect(), d->sheet));
0400     return database;
0401 }
0402 
0403 QList< QPair<QRectF, Database> > CellStorage::databases(const Region& region) const
0404 {
0405 #ifdef CALLIGRA_SHEETS_MT
0406     QReadLocker rl(&d->bigUglyLock);
0407 #endif
0408     return d->databaseStorage->intersectingPairs(region);
0409 }
0410 
0411 void CellStorage::setDatabase(const Region& region, const Database& database)
0412 {
0413 #ifdef CALLIGRA_SHEETS_MT
0414     QWriteLocker(&d->bigUglyLock);
0415 #endif
0416     // recording undo?
0417     if (d->undoData)
0418         d->undoData->databases << d->databaseStorage->undoData(region);
0419 
0420     d->databaseStorage->insert(region, database);
0421 }
0422 
0423 Formula CellStorage::formula(int column, int row) const
0424 {
0425 #ifdef CALLIGRA_SHEETS_MT
0426     QReadLocker rl(&d->bigUglyLock);
0427 #endif
0428     return d->formulaStorage->lookup(column, row, Formula::empty());
0429 }
0430 
0431 void CellStorage::setFormula(int column, int row, const Formula& formula)
0432 {
0433 #ifdef CALLIGRA_SHEETS_MT
0434     QWriteLocker(&d->bigUglyLock);
0435 #endif
0436     Formula old = Formula::empty();
0437     if (formula.expression().isEmpty())
0438         old = d->formulaStorage->take(column, row, Formula::empty());
0439     else
0440         old = d->formulaStorage->insert(column, row, formula);
0441 
0442     // formula changed?
0443     if (formula != old) {
0444         if (!d->sheet->map()->isLoading()) {
0445             // trigger an update of the dependencies and a recalculation
0446             d->sheet->map()->addDamage(new CellDamage(Cell(d->sheet, column, row), CellDamage::Formula | CellDamage::Value));
0447             d->rowRepeatStorage->setRowRepeat(row, 1);
0448         }
0449         // recording undo?
0450         if (d->undoData) {
0451             d->undoData->formulas << qMakePair(QPoint(column, row), old);
0452             // Also store the old value, if there wasn't a formula before,
0453             // because the new value is calculated later by the damage
0454             // processing and is not recorded for undoing.
0455             if (old == Formula())
0456                 d->undoData->values << qMakePair(QPoint(column, row), value(column, row));
0457         }
0458     }
0459 }
0460 
0461 QString CellStorage::link(int column, int row) const
0462 {
0463 #ifdef CALLIGRA_SHEETS_MT
0464     QReadLocker rl(&d->bigUglyLock);
0465 #endif
0466     return d->linkStorage->lookup(column, row);
0467 }
0468 
0469 void CellStorage::setLink(int column, int row, const QString& link)
0470 {
0471 #ifdef CALLIGRA_SHEETS_MT
0472     QWriteLocker(&d->bigUglyLock);
0473 #endif
0474     QString old;
0475     if (link.isEmpty())
0476         old = d->linkStorage->take(column, row);
0477     else
0478         old = d->linkStorage->insert(column, row, link);
0479 
0480     // recording undo?
0481     if (d->undoData && link != old)
0482         d->undoData->links << qMakePair(QPoint(column, row), old);
0483     if (!d->sheet->map()->isLoading())
0484         d->rowRepeatStorage->setRowRepeat(row, 1);
0485 }
0486 
0487 QString CellStorage::namedArea(int column, int row) const
0488 {
0489 #ifdef CALLIGRA_SHEETS_MT
0490     QReadLocker rl(&d->bigUglyLock);
0491 #endif
0492     QPair<QRectF, QString> pair = d->namedAreaStorage->containedPair(QPoint(column, row));
0493     if (pair.first.isEmpty())
0494         return QString();
0495     if (pair.second.isEmpty())
0496         return QString();
0497     return pair.second;
0498 }
0499 
0500 QList< QPair<QRectF, QString> > CellStorage::namedAreas(const Region& region) const
0501 {
0502 #ifdef CALLIGRA_SHEETS_MT
0503     QReadLocker rl(&d->bigUglyLock);
0504 #endif
0505     return d->namedAreaStorage->intersectingPairs(region);
0506 }
0507 
0508 void CellStorage::setNamedArea(const Region& region, const QString& namedArea)
0509 {
0510 #ifdef CALLIGRA_SHEETS_MT
0511     QWriteLocker(&d->bigUglyLock);
0512 #endif
0513     // recording undo?
0514     if (d->undoData)
0515         d->undoData->namedAreas << d->namedAreaStorage->undoData(region);
0516 
0517     d->namedAreaStorage->insert(region, namedArea);
0518 }
0519 
0520 void CellStorage::removeNamedArea(const Region& region, const QString& namedArea)
0521 {
0522 #ifdef CALLIGRA_SHEETS_MT
0523     QWriteLocker(&d->bigUglyLock);
0524 #endif
0525     // recording undo?
0526     if (d->undoData)
0527         d->undoData->namedAreas << d->namedAreaStorage->undoData(region);
0528 
0529     d->namedAreaStorage->remove(region, namedArea);
0530 }
0531 
0532 
0533 void CellStorage::emitInsertNamedArea(const Region &region, const QString &namedArea)
0534 {
0535     emit insertNamedArea(region, namedArea);
0536 }
0537 
0538 Style CellStorage::style(int column, int row) const
0539 {
0540 #ifdef CALLIGRA_SHEETS_MT
0541     QReadLocker rl(&d->bigUglyLock);
0542 #endif
0543     return d->styleStorage->contains(QPoint(column, row));
0544 }
0545 
0546 Style CellStorage::style(const QRect& rect) const
0547 {
0548 #ifdef CALLIGRA_SHEETS_MT
0549     QReadLocker rl(&d->bigUglyLock);
0550 #endif
0551     return d->styleStorage->contains(rect);
0552 }
0553 
0554 void CellStorage::setStyle(const Region& region, const Style& style)
0555 {
0556 #ifdef CALLIGRA_SHEETS_MT
0557     QWriteLocker(&d->bigUglyLock);
0558 #endif
0559     // recording undo?
0560     if (d->undoData)
0561         d->undoData->styles << d->styleStorage->undoData(region);
0562 
0563     d->styleStorage->insert(region, style);
0564     if (!d->sheet->map()->isLoading()) {
0565         foreach (const QRect& r, region.rects()) {
0566             d->rowRepeatStorage->splitRowRepeat(r.top());
0567             d->rowRepeatStorage->splitRowRepeat(r.bottom()+1);
0568         }
0569     }
0570 }
0571 
0572 void CellStorage::insertSubStyle(const QRect &rect, const SharedSubStyle &subStyle)
0573 {
0574 #ifdef CALLIGRA_SHEETS_MT
0575     QWriteLocker(&d->bigUglyLock);
0576 #endif
0577     d->styleStorage->insert(rect, subStyle);
0578     if (!d->sheet->map()->isLoading()) {
0579         d->rowRepeatStorage->splitRowRepeat(rect.top());
0580         d->rowRepeatStorage->splitRowRepeat(rect.bottom()+1);
0581     }
0582 }
0583 
0584 QString CellStorage::userInput(int column, int row) const
0585 {
0586 #ifdef CALLIGRA_SHEETS_MT
0587     QReadLocker rl(&d->bigUglyLock);
0588 #endif
0589     return d->userInputStorage->lookup(column, row);
0590 }
0591 
0592 void CellStorage::setUserInput(int column, int row, const QString& userInput)
0593 {
0594 #ifdef CALLIGRA_SHEETS_MT
0595     QWriteLocker(&d->bigUglyLock);
0596 #endif
0597     QString old;
0598     if (userInput.isEmpty())
0599         old = d->userInputStorage->take(column, row);
0600     else
0601         old = d->userInputStorage->insert(column, row, userInput);
0602 
0603     // recording undo?
0604     if (d->undoData && userInput != old)
0605         d->undoData->userInputs << qMakePair(QPoint(column, row), old);
0606     if (!d->sheet->map()->isLoading())
0607         d->rowRepeatStorage->setRowRepeat(row, 1);
0608 }
0609 
0610 QSharedPointer<QTextDocument> CellStorage::richText(int column, int row) const
0611 {
0612 #ifdef CALLIGRA_SHEETS_MT
0613     QReadLocker rl(&d->bigUglyLock);
0614 #endif
0615     return d->richTextStorage->lookup(column, row);
0616 }
0617 
0618 void CellStorage::setRichText(int column, int row, QSharedPointer<QTextDocument> text)
0619 {
0620 #ifdef CALLIGRA_SHEETS_MT
0621     QWriteLocker(&d->bigUglyLock);
0622 #endif
0623     QSharedPointer<QTextDocument> old;
0624     if (text.isNull())
0625         old = d->richTextStorage->take(column, row);
0626     else
0627         old = d->richTextStorage->insert(column, row, text);
0628 
0629     // recording undo?
0630     if (d->undoData && text != old)
0631         d->undoData->richTexts << qMakePair(QPoint(column, row), old);
0632 }
0633 
0634 Validity CellStorage::validity(int column, int row) const
0635 {
0636 #ifdef CALLIGRA_SHEETS_MT
0637     QReadLocker rl(&d->bigUglyLock);
0638 #endif
0639     return d->validityStorage->contains(QPoint(column, row));
0640 }
0641 
0642 void CellStorage::setValidity(const Region& region, Validity validity)
0643 {
0644 #ifdef CALLIGRA_SHEETS_MT
0645     QWriteLocker(&d->bigUglyLock);
0646 #endif
0647     // recording undo?
0648     if (d->undoData)
0649         d->undoData->validities << d->validityStorage->undoData(region);
0650 
0651     d->validityStorage->insert(region, validity);
0652     if (!d->sheet->map()->isLoading()) {
0653         foreach (const QRect& r, region.rects()) {
0654             d->rowRepeatStorage->splitRowRepeat(r.top());
0655             d->rowRepeatStorage->splitRowRepeat(r.bottom()+1);
0656         }
0657     }
0658 }
0659 
0660 Value CellStorage::value(int column, int row) const
0661 {
0662 #ifdef CALLIGRA_SHEETS_MT
0663     QReadLocker rl(&d->bigUglyLock);
0664 #endif
0665     return d->valueStorage->lookup(column, row);
0666 }
0667 
0668 Value CellStorage::valueRegion(const Region& region) const
0669 {
0670 #ifdef CALLIGRA_SHEETS_MT
0671     QReadLocker rl(&d->bigUglyLock);
0672 #endif
0673     // create a subStorage with adjusted origin
0674     return Value(d->valueStorage->subStorage(region, false), region.boundingRect().size());
0675 }
0676 
0677 void CellStorage::setValue(int column, int row, const Value& value)
0678 {
0679 #ifdef CALLIGRA_SHEETS_MT
0680     QWriteLocker(&d->bigUglyLock);
0681 #endif
0682     // release any lock
0683     unlockCells(column, row);
0684 
0685     Value old;
0686     if (value.isEmpty())
0687         old = d->valueStorage->take(column, row);
0688     else
0689         old = d->valueStorage->insert(column, row, value);
0690 
0691     // value changed?
0692     if (value != old) {
0693         if (!d->sheet->map()->isLoading()) {
0694             // Always trigger a repainting and a binding update.
0695             CellDamage::Changes changes = CellDamage::Appearance | CellDamage::Binding;
0696             // Trigger a recalculation of the consuming cells, only if we are not
0697             // already in a recalculation process.
0698             if (!d->sheet->map()->recalcManager()->isActive())
0699                 changes |= CellDamage::Value;
0700             d->sheet->map()->addDamage(new CellDamage(Cell(d->sheet, column, row), changes));
0701             // Also trigger a relayouting of the first non-empty cell to the left of this one
0702             int prevCol;
0703             Value v = d->valueStorage->prevInRow(column, row, &prevCol);
0704             if (!v.isEmpty())
0705                 d->sheet->map()->addDamage(new CellDamage(Cell(d->sheet, prevCol, row), CellDamage::Appearance));
0706             d->rowRepeatStorage->setRowRepeat(row, 1);
0707         }
0708         // recording undo?
0709         if (d->undoData)
0710             d->undoData->values << qMakePair(QPoint(column, row), old);
0711     }
0712 }
0713 
0714 bool CellStorage::doesMergeCells(int column, int row) const
0715 {
0716 #ifdef CALLIGRA_SHEETS_MT
0717     QReadLocker rl(&d->bigUglyLock);
0718 #endif
0719     const QPair<QRectF, bool> pair = d->fusionStorage->containedPair(QPoint(column, row));
0720     if (pair.first.isNull())
0721         return false;
0722     if (pair.second == false)
0723         return false;
0724     // master cell?
0725     if (pair.first.toRect().topLeft() != QPoint(column, row))
0726         return false;
0727     return true;
0728 }
0729 
0730 bool CellStorage::isPartOfMerged(int column, int row) const
0731 {
0732 #ifdef CALLIGRA_SHEETS_MT
0733     QReadLocker rl(&d->bigUglyLock);
0734 #endif
0735     const QPair<QRectF, bool> pair = d->fusionStorage->containedPair(QPoint(column, row));
0736     if (pair.first.isNull())
0737         return false;
0738     if (pair.second == false)
0739         return false;
0740     // master cell?
0741     if (pair.first.toRect().topLeft() == QPoint(column, row))
0742         return false;
0743     return true;
0744 }
0745 
0746 void CellStorage::mergeCells(int column, int row, int numXCells, int numYCells)
0747 {
0748 #ifdef CALLIGRA_SHEETS_MT
0749     QWriteLocker(&d->bigUglyLock);
0750 #endif
0751     // Start by unmerging the cells that we merge right now
0752     const QPair<QRectF, bool> pair = d->fusionStorage->containedPair(QPoint(column, row));
0753     if (!pair.first.isNull())
0754         d->fusionStorage->insert(Region(pair.first.toRect()), false);
0755     // Merge the cells
0756     if (numXCells != 0 || numYCells != 0)
0757         d->fusionStorage->insert(Region(column, row, numXCells + 1, numYCells + 1), true);
0758     if (!d->sheet->map()->isLoading())
0759         d->rowRepeatStorage->setRowRepeat(row, 1);
0760 }
0761 
0762 Cell CellStorage::masterCell(int column, int row) const
0763 {
0764 #ifdef CALLIGRA_SHEETS_MT
0765     QReadLocker rl(&d->bigUglyLock);
0766 #endif
0767     const QPair<QRectF, bool> pair = d->fusionStorage->containedPair(QPoint(column, row));
0768     if (pair.first.isNull())
0769         return Cell(d->sheet, column, row);
0770     if (pair.second == false)
0771         return Cell(d->sheet, column, row);
0772     return Cell(d->sheet, pair.first.toRect().topLeft());
0773 }
0774 
0775 int CellStorage::mergedXCells(int column, int row) const
0776 {
0777 #ifdef CALLIGRA_SHEETS_MT
0778     QReadLocker rl(&d->bigUglyLock);
0779 #endif
0780     const QPair<QRectF, bool> pair = d->fusionStorage->containedPair(QPoint(column, row));
0781     if (pair.first.isNull())
0782         return 0;
0783     // Not the master cell?
0784     if (pair.first.topLeft() != QPoint(column, row))
0785         return 0;
0786     return pair.first.toRect().width() - 1;
0787 }
0788 
0789 int CellStorage::mergedYCells(int column, int row) const
0790 {
0791 #ifdef CALLIGRA_SHEETS_MT
0792     QReadLocker rl(&d->bigUglyLock);
0793 #endif
0794     const QPair<QRectF, bool> pair = d->fusionStorage->containedPair(QPoint(column, row));
0795     if (pair.first.isNull())
0796         return 0;
0797     // Not the master cell?
0798     if (pair.first.topLeft() != QPoint(column, row))
0799         return 0;
0800     return pair.first.toRect().height() - 1;
0801 }
0802 
0803 QList<Cell> CellStorage::masterCells(const Region& region) const
0804 {
0805 #ifdef CALLIGRA_SHEETS_MT
0806     QReadLocker rl(&d->bigUglyLock);
0807 #endif
0808     const QList<QPair<QRectF, bool> > pairs = d->fusionStorage->intersectingPairs(region);
0809     if (pairs.isEmpty())
0810         return QList<Cell>();
0811     QList<Cell> masterCells;
0812     for (int i = 0; i < pairs.count(); ++i) {
0813         if (pairs[i].first.isNull())
0814             continue;
0815         if (pairs[i].second == false)
0816             continue;
0817         masterCells.append(Cell(d->sheet, pairs[i].first.toRect().topLeft()));
0818     }
0819     return masterCells;
0820 }
0821 
0822 bool CellStorage::locksCells(int column, int row) const
0823 {
0824 #ifdef CALLIGRA_SHEETS_MT
0825     QReadLocker rl(&d->bigUglyLock);
0826 #endif
0827     const QPair<QRectF, bool> pair = d->matrixStorage->containedPair(QPoint(column, row));
0828     if (pair.first.isNull())
0829         return false;
0830     if (pair.second == false)
0831         return false;
0832     // master cell?
0833     if (pair.first.toRect().topLeft() != QPoint(column, row))
0834         return false;
0835     return true;
0836 }
0837 
0838 bool CellStorage::isLocked(int column, int row) const
0839 {
0840 #ifdef CALLIGRA_SHEETS_MT
0841     QReadLocker rl(&d->bigUglyLock);
0842 #endif
0843     const QPair<QRectF, bool> pair = d->matrixStorage->containedPair(QPoint(column, row));
0844     if (pair.first.isNull())
0845         return false;
0846     if (pair.second == false)
0847         return false;
0848     // master cell?
0849     if (pair.first.toRect().topLeft() == QPoint(column, row))
0850         return false;
0851     return true;
0852 }
0853 
0854 bool CellStorage::hasLockedCells(const Region& region) const
0855 {
0856 #ifdef CALLIGRA_SHEETS_MT
0857     QReadLocker rl(&d->bigUglyLock);
0858 #endif
0859     typedef QPair<QRectF, bool> RectBoolPair;
0860     QList<QPair<QRectF, bool> > pairs = d->matrixStorage->intersectingPairs(region);
0861     foreach (const RectBoolPair& pair, pairs) {
0862         if (pair.first.isNull())
0863             continue;
0864         if (pair.second == false)
0865             continue;
0866         // more than just the master cell in the region?
0867         const QPoint topLeft = pair.first.toRect().topLeft();
0868         if (pair.first.width() >= 1) {
0869             if (region.contains(topLeft + QPoint(1, 0), d->sheet))
0870                 return true;
0871         }
0872         if (pair.first.height() >= 1) {
0873             if (region.contains(topLeft + QPoint(0, 1), d->sheet))
0874                 return true;
0875         }
0876     }
0877     return false;
0878 }
0879 
0880 void CellStorage::lockCells(const QRect& rect)
0881 {
0882 #ifdef CALLIGRA_SHEETS_MT
0883     QWriteLocker(&d->bigUglyLock);
0884 #endif
0885     // Start by unlocking the cells that we lock right now
0886     const QPair<QRectF, bool> pair = d->matrixStorage->containedPair(rect.topLeft());  // FIXME
0887     if (!pair.first.isNull())
0888         d->matrixStorage->insert(Region(pair.first.toRect()), false);
0889     // Lock the cells
0890     if (rect.width() > 1 || rect.height() > 1)
0891         d->matrixStorage->insert(Region(rect), true);
0892 }
0893 
0894 void CellStorage::unlockCells(int column, int row)
0895 {
0896 #ifdef CALLIGRA_SHEETS_MT
0897     QWriteLocker(&d->bigUglyLock);
0898 #endif
0899     const QPair<QRectF, bool> pair = d->matrixStorage->containedPair(QPoint(column, row));
0900     if (pair.first.isNull())
0901         return;
0902     if (pair.second == false)
0903         return;
0904     if (pair.first.toRect().topLeft() != QPoint(column, row))
0905         return;
0906     const QRect rect = pair.first.toRect();
0907     d->matrixStorage->insert(Region(rect), false);
0908     // clear the values
0909     for (int r = rect.top(); r <= rect.bottom(); ++r) {
0910         for (int c = rect.left(); c <= rect.right(); ++c) {
0911             if (r != rect.top() || c != rect.left())
0912                 setValue(c, r, Value());
0913         }
0914     }
0915     // recording undo?
0916     if (d->undoData)
0917         d->undoData->matrices << pair;
0918 }
0919 
0920 QRect CellStorage::lockedCells(int column, int row) const
0921 {
0922 #ifdef CALLIGRA_SHEETS_MT
0923     QReadLocker rl(&d->bigUglyLock);
0924 #endif
0925     const QPair<QRectF, bool> pair = d->matrixStorage->containedPair(QPoint(column, row));
0926     if (pair.first.isNull())
0927         return QRect(column, row, 1, 1);
0928     if (pair.second == false)
0929         return QRect(column, row, 1, 1);
0930     if (pair.first.toRect().topLeft() != QPoint(column, row))
0931         return QRect(column, row, 1, 1);
0932     return pair.first.toRect();
0933 }
0934 
0935 void CellStorage::insertColumns(int position, int number)
0936 {
0937 #ifdef CALLIGRA_SHEETS_MT
0938     QWriteLocker(&d->bigUglyLock);
0939 #endif
0940     // Trigger a dependency update of the cells, which have a formula. (old positions)
0941     // FIXME Stefan: Would it be better to directly alter the dependency tree?
0942     // TODO Stefan: Optimize: Avoid the double creation of the sub-storages, but don't process
0943     //              formulas, that will get out of bounds after the operation.
0944     const Region invalidRegion(QRect(QPoint(position, 1), QPoint(KS_colMax, KS_rowMax)), d->sheet);
0945     PointStorage<Formula> subStorage = d->formulaStorage->subStorage(invalidRegion);
0946     Cell cell;
0947     for (int i = 0; i < subStorage.count(); ++i) {
0948         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
0949         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
0950     }
0951     // Trigger an update of the bindings and the named areas.
0952     d->sheet->map()->addDamage(new CellDamage(d->sheet, invalidRegion, CellDamage::Binding | CellDamage::NamedArea));
0953 
0954     QList< QPair<QRectF, Binding> > bindings = d->bindingStorage->insertColumns(position, number);
0955     QList< QPair<QRectF, QString> > comments = d->commentStorage->insertColumns(position, number);
0956     QList< QPair<QRectF, Conditions> > conditions = d->conditionsStorage->insertColumns(position, number);
0957     QList< QPair<QRectF, Database> > databases = d->databaseStorage->insertColumns(position, number);
0958     QVector< QPair<QPoint, Formula> > formulas = d->formulaStorage->insertColumns(position, number);
0959     QList< QPair<QRectF, bool> > fusions = d->fusionStorage->insertColumns(position, number);
0960     QVector< QPair<QPoint, QString> > links = d->linkStorage->insertColumns(position, number);
0961     QList< QPair<QRectF, bool> > matrices = d->matrixStorage->insertColumns(position, number);
0962     QList< QPair<QRectF, QString> > namedAreas = d->namedAreaStorage->insertColumns(position, number);
0963     QList< QPair<QRectF, SharedSubStyle> > styles = d->styleStorage->insertColumns(position, number);
0964     QVector< QPair<QPoint, QString> > userInputs = d->userInputStorage->insertColumns(position, number);
0965     QVector< QPair<QPoint, QSharedPointer<QTextDocument> > > richTexts = d->richTextStorage->insertColumns(position, number);
0966     QList< QPair<QRectF, Validity> > validities = d->validityStorage->insertColumns(position, number);
0967     QVector< QPair<QPoint, Value> > values = d->valueStorage->insertColumns(position, number);
0968     // recording undo?
0969     if (d->undoData) {
0970         d->undoData->bindings   << bindings;
0971         d->undoData->comments   << comments;
0972         d->undoData->conditions << conditions;
0973         d->undoData->databases  << databases;
0974         d->undoData->formulas   << formulas;
0975         d->undoData->fusions    << fusions;
0976         d->undoData->links      << links;
0977         d->undoData->matrices   << matrices;
0978         d->undoData->namedAreas << namedAreas;
0979         d->undoData->styles     << styles;
0980         d->undoData->userInputs << userInputs;
0981         d->undoData->validities << validities;
0982         d->undoData->values     << values;
0983         d->undoData->richTexts  << richTexts;
0984     }
0985 
0986     // Trigger a dependency update of the cells, which have a formula. (new positions)
0987     subStorage = d->formulaStorage->subStorage(invalidRegion);
0988     for (int i = 0; i < subStorage.count(); ++i) {
0989         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
0990         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
0991     }
0992     // Trigger a recalculation only for the cells, that depend on values in the changed region.
0993     Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion);
0994     d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value));
0995 }
0996 
0997 void CellStorage::removeColumns(int position, int number)
0998 {
0999 #ifdef CALLIGRA_SHEETS_MT
1000     QWriteLocker(&d->bigUglyLock);
1001 #endif
1002     // Trigger a dependency update of the cells, which have a formula. (old positions)
1003     const Region invalidRegion(QRect(QPoint(position, 1), QPoint(KS_colMax, KS_rowMax)), d->sheet);
1004     PointStorage<Formula> subStorage = d->formulaStorage->subStorage(invalidRegion);
1005     Cell cell;
1006     for (int i = 0; i < subStorage.count(); ++i) {
1007         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
1008         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
1009     }
1010     // Trigger an update of the bindings and the named areas.
1011     const Region region(QRect(QPoint(position - 1, 1), QPoint(KS_colMax, KS_rowMax)), d->sheet);
1012     d->sheet->map()->addDamage(new CellDamage(d->sheet, region, CellDamage::Binding | CellDamage::NamedArea));
1013 
1014     QList< QPair<QRectF, Binding> > bindings = d->bindingStorage->removeColumns(position, number);
1015     QList< QPair<QRectF, QString> > comments = d->commentStorage->removeColumns(position, number);
1016     QList< QPair<QRectF, Conditions> > conditions = d->conditionsStorage->removeColumns(position, number);
1017     QList< QPair<QRectF, Database> > databases = d->databaseStorage->removeColumns(position, number);
1018     QVector< QPair<QPoint, Formula> > formulas = d->formulaStorage->removeColumns(position, number);
1019     QList< QPair<QRectF, bool> > fusions = d->fusionStorage->removeColumns(position, number);
1020     QVector< QPair<QPoint, QString> > links = d->linkStorage->removeColumns(position, number);
1021     QList< QPair<QRectF, bool> > matrices = d->matrixStorage->removeColumns(position, number);
1022     QList< QPair<QRectF, QString> > namedAreas = d->namedAreaStorage->removeColumns(position, number);
1023     QList< QPair<QRectF, SharedSubStyle> > styles = d->styleStorage->removeColumns(position, number);
1024     QVector< QPair<QPoint, QString> > userInputs = d->userInputStorage->removeColumns(position, number);
1025     QList< QPair<QRectF, Validity> > validities = d->validityStorage->removeColumns(position, number);
1026     QVector< QPair<QPoint, Value> > values = d->valueStorage->removeColumns(position, number);
1027     QVector< QPair<QPoint, QSharedPointer<QTextDocument> > > richTexts = d->richTextStorage->removeColumns(position, number);
1028     // recording undo?
1029     if (d->undoData) {
1030         d->undoData->bindings   << bindings;
1031         d->undoData->comments   << comments;
1032         d->undoData->conditions << conditions;
1033         d->undoData->databases  << databases;
1034         d->undoData->formulas   << formulas;
1035         d->undoData->fusions    << fusions;
1036         d->undoData->links      << links;
1037         d->undoData->matrices   << matrices;
1038         d->undoData->namedAreas << namedAreas;
1039         d->undoData->styles     << styles;
1040         d->undoData->userInputs << userInputs;
1041         d->undoData->validities << validities;
1042         d->undoData->values     << values;
1043         d->undoData->richTexts  << richTexts;
1044     }
1045 
1046     // Trigger a dependency update of the cells, which have a formula. (new positions)
1047     subStorage = d->formulaStorage->subStorage(invalidRegion);
1048     for (int i = 0; i < subStorage.count(); ++i) {
1049         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
1050         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
1051     }
1052     // Trigger a recalculation only for the cells, that depend on values in the changed region.
1053     Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion);
1054     d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value));
1055 }
1056 
1057 void CellStorage::insertRows(int position, int number)
1058 {
1059 #ifdef CALLIGRA_SHEETS_MT
1060     QWriteLocker(&d->bigUglyLock);
1061 #endif
1062     // Trigger a dependency update of the cells, which have a formula. (old positions)
1063     const Region invalidRegion(QRect(QPoint(1, position), QPoint(KS_colMax, KS_rowMax)), d->sheet);
1064     PointStorage<Formula> subStorage = d->formulaStorage->subStorage(invalidRegion);
1065     Cell cell;
1066     for (int i = 0; i < subStorage.count(); ++i) {
1067         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
1068         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
1069     }
1070     // Trigger an update of the bindings and the named areas.
1071     d->sheet->map()->addDamage(new CellDamage(d->sheet, invalidRegion, CellDamage::Binding | CellDamage::NamedArea));
1072 
1073     QList< QPair<QRectF, Binding> > bindings = d->bindingStorage->insertRows(position, number);
1074     QList< QPair<QRectF, QString> > comments = d->commentStorage->insertRows(position, number);
1075     QList< QPair<QRectF, Conditions> > conditions = d->conditionsStorage->insertRows(position, number);
1076     QList< QPair<QRectF, Database> > databases = d->databaseStorage->insertRows(position, number);
1077     QVector< QPair<QPoint, Formula> > formulas = d->formulaStorage->insertRows(position, number);
1078     QList< QPair<QRectF, bool> > fusions = d->fusionStorage->insertRows(position, number);
1079     QVector< QPair<QPoint, QString> > links = d->linkStorage->insertRows(position, number);
1080     QList< QPair<QRectF, bool> > matrices = d->matrixStorage->insertRows(position, number);
1081     QList< QPair<QRectF, QString> > namedAreas = d->namedAreaStorage->insertRows(position, number);
1082     QList< QPair<QRectF, SharedSubStyle> > styles = d->styleStorage->insertRows(position, number);
1083     QVector< QPair<QPoint, QString> > userInputs = d->userInputStorage->insertRows(position, number);
1084     QList< QPair<QRectF, Validity> > validities = d->validityStorage->insertRows(position, number);
1085     QVector< QPair<QPoint, Value> > values = d->valueStorage->insertRows(position, number);
1086     QVector< QPair<QPoint, QSharedPointer<QTextDocument> > > richTexts = d->richTextStorage->insertRows(position, number);
1087     // recording undo?
1088     if (d->undoData) {
1089         d->undoData->bindings   << bindings;
1090         d->undoData->comments   << comments;
1091         d->undoData->conditions << conditions;
1092         d->undoData->databases  << databases;
1093         d->undoData->formulas   << formulas;
1094         d->undoData->fusions    << fusions;
1095         d->undoData->links      << links;
1096         d->undoData->matrices   << matrices;
1097         d->undoData->namedAreas << namedAreas;
1098         d->undoData->styles     << styles;
1099         d->undoData->userInputs << userInputs;
1100         d->undoData->validities << validities;
1101         d->undoData->values     << values;
1102         d->undoData->richTexts  << richTexts;
1103     }
1104 
1105     // Trigger a dependency update of the cells, which have a formula. (new positions)
1106     subStorage = d->formulaStorage->subStorage(invalidRegion);
1107     for (int i = 0; i < subStorage.count(); ++i) {
1108         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
1109         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
1110     }
1111     // Trigger a recalculation only for the cells, that depend on values in the changed region.
1112     Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion);
1113     d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value));
1114 
1115     d->rowRepeatStorage->insertRows(position, number);
1116 }
1117 
1118 void CellStorage::removeRows(int position, int number)
1119 {
1120 #ifdef CALLIGRA_SHEETS_MT
1121     QWriteLocker(&d->bigUglyLock);
1122 #endif
1123     // Trigger a dependency update of the cells, which have a formula. (old positions)
1124     const Region invalidRegion(QRect(QPoint(1, position), QPoint(KS_colMax, KS_rowMax)), d->sheet);
1125     PointStorage<Formula> subStorage = d->formulaStorage->subStorage(invalidRegion);
1126     Cell cell;
1127     for (int i = 0; i < subStorage.count(); ++i) {
1128         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
1129         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
1130     }
1131     // Trigger an update of the bindings and the named areas.
1132     const Region region(QRect(QPoint(1, position - 1), QPoint(KS_colMax, KS_rowMax)), d->sheet);
1133     d->sheet->map()->addDamage(new CellDamage(d->sheet, region, CellDamage::Binding | CellDamage::NamedArea));
1134 
1135     QList< QPair<QRectF, Binding> > bindings = d->bindingStorage->removeRows(position, number);
1136     QList< QPair<QRectF, QString> > comments = d->commentStorage->removeRows(position, number);
1137     QList< QPair<QRectF, Conditions> > conditions = d->conditionsStorage->removeRows(position, number);
1138     QList< QPair<QRectF, Database> > databases = d->databaseStorage->removeRows(position, number);
1139     QVector< QPair<QPoint, Formula> > formulas = d->formulaStorage->removeRows(position, number);
1140     QList< QPair<QRectF, bool> > fusions = d->fusionStorage->removeRows(position, number);
1141     QVector< QPair<QPoint, QString> > links = d->linkStorage->removeRows(position, number);
1142     QList< QPair<QRectF, bool> > matrices = d->matrixStorage->removeRows(position, number);
1143     QList< QPair<QRectF, QString> > namedAreas = d->namedAreaStorage->removeRows(position, number);
1144     QList< QPair<QRectF, SharedSubStyle> > styles = d->styleStorage->removeRows(position, number);
1145     QVector< QPair<QPoint, QString> > userInputs = d->userInputStorage->removeRows(position, number);
1146     QList< QPair<QRectF, Validity> > validities = d->validityStorage->removeRows(position, number);
1147     QVector< QPair<QPoint, Value> > values = d->valueStorage->removeRows(position, number);
1148     QVector< QPair<QPoint, QSharedPointer<QTextDocument> > > richTexts = d->richTextStorage->removeRows(position, number);
1149     // recording undo?
1150     if (d->undoData) {
1151         d->undoData->bindings   << bindings;
1152         d->undoData->comments   << comments;
1153         d->undoData->conditions << conditions;
1154         d->undoData->databases  << databases;
1155         d->undoData->formulas   << formulas;
1156         d->undoData->fusions    << fusions;
1157         d->undoData->links      << links;
1158         d->undoData->matrices   << matrices;
1159         d->undoData->namedAreas << namedAreas;
1160         d->undoData->styles     << styles;
1161         d->undoData->userInputs << userInputs;
1162         d->undoData->validities << validities;
1163         d->undoData->values     << values;
1164         d->undoData->richTexts  << richTexts;
1165     }
1166 
1167     // Trigger a dependency update of the cells, which have a formula. (new positions)
1168     subStorage = d->formulaStorage->subStorage(invalidRegion);
1169     for (int i = 0; i < subStorage.count(); ++i) {
1170         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
1171         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
1172     }
1173     // Trigger a recalculation only for the cells, that depend on values in the changed region.
1174     Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion);
1175     d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value));
1176 
1177     d->rowRepeatStorage->removeRows(position, number);
1178 }
1179 
1180 void CellStorage::removeShiftLeft(const QRect& rect)
1181 {
1182 #ifdef CALLIGRA_SHEETS_MT
1183     QWriteLocker(&d->bigUglyLock);
1184 #endif
1185     // Trigger a dependency update of the cells, which have a formula. (old positions)
1186     const Region invalidRegion(QRect(rect.topLeft(), QPoint(KS_colMax, rect.bottom())), d->sheet);
1187     PointStorage<Formula> subStorage = d->formulaStorage->subStorage(invalidRegion);
1188     Cell cell;
1189     for (int i = 0; i < subStorage.count(); ++i) {
1190         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
1191         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
1192     }
1193     // Trigger an update of the bindings and the named areas.
1194     const Region region(QRect(rect.topLeft() - QPoint(1, 0), QPoint(KS_colMax, rect.bottom())), d->sheet);
1195     d->sheet->map()->addDamage(new CellDamage(d->sheet, region, CellDamage::Binding | CellDamage::NamedArea));
1196 
1197     QList< QPair<QRectF, Binding> > bindings = d->bindingStorage->removeShiftLeft(rect);
1198     QList< QPair<QRectF, QString> > comments = d->commentStorage->removeShiftLeft(rect);
1199     QList< QPair<QRectF, Conditions> > conditions = d->conditionsStorage->removeShiftLeft(rect);
1200     QList< QPair<QRectF, Database> > databases = d->databaseStorage->removeShiftLeft(rect);
1201     QVector< QPair<QPoint, Formula> > formulas = d->formulaStorage->removeShiftLeft(rect);
1202     QList< QPair<QRectF, bool> > fusions = d->fusionStorage->removeShiftLeft(rect);
1203     QVector< QPair<QPoint, QString> > links = d->linkStorage->removeShiftLeft(rect);
1204     QList< QPair<QRectF, bool> > matrices = d->matrixStorage->removeShiftLeft(rect);
1205     QList< QPair<QRectF, QString> > namedAreas = d->namedAreaStorage->removeShiftLeft(rect);
1206     QList< QPair<QRectF, SharedSubStyle> > styles = d->styleStorage->removeShiftLeft(rect);
1207     QVector< QPair<QPoint, QString> > userInputs = d->userInputStorage->removeShiftLeft(rect);
1208     QList< QPair<QRectF, Validity> > validities = d->validityStorage->removeShiftLeft(rect);
1209     QVector< QPair<QPoint, Value> > values = d->valueStorage->removeShiftLeft(rect);
1210     QVector< QPair<QPoint, QSharedPointer<QTextDocument> > > richTexts = d->richTextStorage->removeShiftLeft(rect);
1211     // recording undo?
1212     if (d->undoData) {
1213         d->undoData->bindings   << bindings;
1214         d->undoData->comments   << comments;
1215         d->undoData->conditions << conditions;
1216         d->undoData->databases  << databases;
1217         d->undoData->formulas   << formulas;
1218         d->undoData->fusions    << fusions;
1219         d->undoData->links      << links;
1220         d->undoData->matrices   << matrices;
1221         d->undoData->namedAreas << namedAreas;
1222         d->undoData->styles     << styles;
1223         d->undoData->userInputs << userInputs;
1224         d->undoData->validities << validities;
1225         d->undoData->values     << values;
1226         d->undoData->richTexts  << richTexts;
1227     }
1228 
1229     // Trigger a dependency update of the cells, which have a formula. (new positions)
1230     subStorage = d->formulaStorage->subStorage(invalidRegion);
1231     for (int i = 0; i < subStorage.count(); ++i) {
1232         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
1233         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
1234     }
1235     // Trigger a recalculation only for the cells, that depend on values in the changed region.
1236     Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion);
1237     d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value));
1238 
1239     d->rowRepeatStorage->removeShiftLeft(rect);
1240 }
1241 
1242 void CellStorage::insertShiftRight(const QRect& rect)
1243 {
1244 #ifdef CALLIGRA_SHEETS_MT
1245     QWriteLocker(&d->bigUglyLock);
1246 #endif
1247     // Trigger a dependency update of the cells, which have a formula. (old positions)
1248     const Region invalidRegion(QRect(rect.topLeft(), QPoint(KS_colMax, rect.bottom())), d->sheet);
1249     PointStorage<Formula> subStorage = d->formulaStorage->subStorage(invalidRegion);
1250     Cell cell;
1251     for (int i = 0; i < subStorage.count(); ++i) {
1252         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
1253         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
1254     }
1255     // Trigger an update of the bindings and the named areas.
1256     d->sheet->map()->addDamage(new CellDamage(d->sheet, invalidRegion, CellDamage::Binding | CellDamage::NamedArea));
1257 
1258     QList< QPair<QRectF, Binding> > bindings = d->bindingStorage->insertShiftRight(rect);
1259     QList< QPair<QRectF, QString> > comments = d->commentStorage->insertShiftRight(rect);
1260     QList< QPair<QRectF, Conditions> > conditions = d->conditionsStorage->insertShiftRight(rect);
1261     QList< QPair<QRectF, Database> > databases = d->databaseStorage->insertShiftRight(rect);
1262     QVector< QPair<QPoint, Formula> > formulas = d->formulaStorage->insertShiftRight(rect);
1263     QList< QPair<QRectF, bool> > fusions = d->fusionStorage->insertShiftRight(rect);
1264     QVector< QPair<QPoint, QString> > links = d->linkStorage->insertShiftRight(rect);
1265     QList< QPair<QRectF, bool> > matrices = d->matrixStorage->insertShiftRight(rect);
1266     QList< QPair<QRectF, QString> > namedAreas = d->namedAreaStorage->insertShiftRight(rect);
1267     QList< QPair<QRectF, SharedSubStyle> > styles = d->styleStorage->insertShiftRight(rect);
1268     QVector< QPair<QPoint, QString> > userInputs = d->userInputStorage->insertShiftRight(rect);
1269     QList< QPair<QRectF, Validity> > validities = d->validityStorage->insertShiftRight(rect);
1270     QVector< QPair<QPoint, Value> > values = d->valueStorage->insertShiftRight(rect);
1271     QVector< QPair<QPoint, QSharedPointer<QTextDocument> > > richTexts = d->richTextStorage->insertShiftRight(rect);
1272     // recording undo?
1273     if (d->undoData) {
1274         d->undoData->bindings   << bindings;
1275         d->undoData->comments   << comments;
1276         d->undoData->conditions << conditions;
1277         d->undoData->databases  << databases;
1278         d->undoData->formulas   << formulas;
1279         d->undoData->fusions    << fusions;
1280         d->undoData->links      << links;
1281         d->undoData->matrices   << matrices;
1282         d->undoData->namedAreas << namedAreas;
1283         d->undoData->styles     << styles;
1284         d->undoData->userInputs << userInputs;
1285         d->undoData->validities << validities;
1286         d->undoData->values     << values;
1287         d->undoData->richTexts  << richTexts;
1288     }
1289 
1290     // Trigger a dependency update of the cells, which have a formula. (new positions)
1291     subStorage = d->formulaStorage->subStorage(invalidRegion);
1292     for (int i = 0; i < subStorage.count(); ++i) {
1293         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
1294         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
1295     }
1296     // Trigger a recalculation only for the cells, that depend on values in the changed region.
1297     Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion);
1298     d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value));
1299 
1300     d->rowRepeatStorage->insertShiftRight(rect);
1301 }
1302 
1303 void CellStorage::removeShiftUp(const QRect& rect)
1304 {
1305 #ifdef CALLIGRA_SHEETS_MT
1306     QWriteLocker(&d->bigUglyLock);
1307 #endif
1308     // Trigger a dependency update of the cells, which have a formula. (old positions)
1309     const Region invalidRegion(QRect(rect.topLeft(), QPoint(rect.right(), KS_rowMax)), d->sheet);
1310     PointStorage<Formula> subStorage = d->formulaStorage->subStorage(invalidRegion);
1311     Cell cell;
1312     for (int i = 0; i < subStorage.count(); ++i) {
1313         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
1314         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
1315     }
1316     // Trigger an update of the bindings and the named areas.
1317     const Region region(QRect(rect.topLeft() - QPoint(0, 1), QPoint(rect.right(), KS_rowMax)), d->sheet);
1318     d->sheet->map()->addDamage(new CellDamage(d->sheet, region, CellDamage::Binding | CellDamage::NamedArea));
1319 
1320     QList< QPair<QRectF, Binding> > bindings = d->bindingStorage->removeShiftUp(rect);
1321     QList< QPair<QRectF, QString> > comments = d->commentStorage->removeShiftUp(rect);
1322     QList< QPair<QRectF, Conditions> > conditions = d->conditionsStorage->removeShiftUp(rect);
1323     QList< QPair<QRectF, Database> > databases = d->databaseStorage->removeShiftUp(rect);
1324     QVector< QPair<QPoint, Formula> > formulas = d->formulaStorage->removeShiftUp(rect);
1325     QList< QPair<QRectF, bool> > fusions = d->fusionStorage->removeShiftUp(rect);
1326     QVector< QPair<QPoint, QString> > links = d->linkStorage->removeShiftUp(rect);
1327     QList< QPair<QRectF, bool> > matrices = d->matrixStorage->removeShiftUp(rect);
1328     QList< QPair<QRectF, QString> > namedAreas = d->namedAreaStorage->removeShiftUp(rect);
1329     QList< QPair<QRectF, SharedSubStyle> > styles = d->styleStorage->removeShiftUp(rect);
1330     QVector< QPair<QPoint, QString> > userInputs = d->userInputStorage->removeShiftUp(rect);
1331     QList< QPair<QRectF, Validity> > validities = d->validityStorage->removeShiftUp(rect);
1332     QVector< QPair<QPoint, Value> > values = d->valueStorage->removeShiftUp(rect);
1333     QVector< QPair<QPoint, QSharedPointer<QTextDocument> > > richTexts = d->richTextStorage->removeShiftUp(rect);
1334     // recording undo?
1335     if (d->undoData) {
1336         d->undoData->bindings   << bindings;
1337         d->undoData->comments   << comments;
1338         d->undoData->conditions << conditions;
1339         d->undoData->databases  << databases;
1340         d->undoData->formulas   << formulas;
1341         d->undoData->fusions    << fusions;
1342         d->undoData->links      << links;
1343         d->undoData->matrices   << matrices;
1344         d->undoData->namedAreas << namedAreas;
1345         d->undoData->styles     << styles;
1346         d->undoData->userInputs << userInputs;
1347         d->undoData->validities << validities;
1348         d->undoData->values     << values;
1349         d->undoData->richTexts  << richTexts;
1350     }
1351 
1352     // Trigger a dependency update of the cells, which have a formula. (new positions)
1353     subStorage = d->formulaStorage->subStorage(invalidRegion);
1354     for (int i = 0; i < subStorage.count(); ++i) {
1355         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
1356         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
1357     }
1358     // Trigger a recalculation only for the cells, that depend on values in the changed region.
1359     Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion);
1360     d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value));
1361 
1362     d->rowRepeatStorage->removeShiftUp(rect);
1363 }
1364 
1365 void CellStorage::insertShiftDown(const QRect& rect)
1366 {
1367 #ifdef CALLIGRA_SHEETS_MT
1368     QWriteLocker(&d->bigUglyLock);
1369 #endif
1370     // Trigger a dependency update of the cells, which have a formula. (old positions)
1371     const Region invalidRegion(QRect(rect.topLeft(), QPoint(rect.right(), KS_rowMax)), d->sheet);
1372     PointStorage<Formula> subStorage = d->formulaStorage->subStorage(invalidRegion);
1373     Cell cell;
1374     for (int i = 0; i < subStorage.count(); ++i) {
1375         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
1376         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
1377     }
1378     // Trigger an update of the bindings and the named areas.
1379     d->sheet->map()->addDamage(new CellDamage(d->sheet, invalidRegion, CellDamage::Binding | CellDamage::NamedArea));
1380 
1381     QList< QPair<QRectF, Binding> > bindings = d->bindingStorage->insertShiftDown(rect);
1382     QList< QPair<QRectF, QString> > comments = d->commentStorage->insertShiftDown(rect);
1383     QList< QPair<QRectF, Conditions> > conditions = d->conditionsStorage->insertShiftDown(rect);
1384     QList< QPair<QRectF, Database> > databases = d->databaseStorage->insertShiftDown(rect);
1385     QVector< QPair<QPoint, Formula> > formulas = d->formulaStorage->insertShiftDown(rect);
1386     QList< QPair<QRectF, bool> > fusions = d->fusionStorage->insertShiftDown(rect);
1387     QVector< QPair<QPoint, QString> > links = d->linkStorage->insertShiftDown(rect);
1388     QList< QPair<QRectF, bool> > matrices = d->matrixStorage->insertShiftDown(rect);
1389     QList< QPair<QRectF, QString> > namedAreas = d->namedAreaStorage->insertShiftDown(rect);
1390     QList< QPair<QRectF, SharedSubStyle> > styles = d->styleStorage->insertShiftDown(rect);
1391     QVector< QPair<QPoint, QString> > userInputs = d->userInputStorage->insertShiftDown(rect);
1392     QList< QPair<QRectF, Validity> > validities = d->validityStorage->insertShiftDown(rect);
1393     QVector< QPair<QPoint, Value> > values = d->valueStorage->insertShiftDown(rect);
1394     QVector< QPair<QPoint, QSharedPointer<QTextDocument> > > richTexts = d->richTextStorage->insertShiftDown(rect);
1395     // recording undo?
1396     if (d->undoData) {
1397         d->undoData->bindings   << bindings;
1398         d->undoData->comments   << comments;
1399         d->undoData->conditions << conditions;
1400         d->undoData->databases  << databases;
1401         d->undoData->formulas   << formulas;
1402         d->undoData->fusions    << fusions;
1403         d->undoData->links      << links;
1404         d->undoData->matrices   << matrices;
1405         d->undoData->namedAreas << namedAreas;
1406         d->undoData->styles     << styles;
1407         d->undoData->userInputs << userInputs;
1408         d->undoData->validities << validities;
1409         d->undoData->values     << values;
1410         d->undoData->richTexts  << richTexts;
1411     }
1412 
1413     // Trigger a dependency update of the cells, which have a formula. (new positions)
1414     subStorage = d->formulaStorage->subStorage(invalidRegion);
1415     for (int i = 0; i < subStorage.count(); ++i) {
1416         cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i));
1417         d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula));
1418     }
1419     // Trigger a recalculation only for the cells, that depend on values in the changed region.
1420     Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion);
1421     d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value));
1422 
1423     d->rowRepeatStorage->insertShiftDown(rect);
1424 }
1425 
1426 Cell CellStorage::firstInColumn(int col, Visiting visiting) const
1427 {
1428 #ifdef CALLIGRA_SHEETS_MT
1429     QReadLocker rl(&d->bigUglyLock);
1430 #endif
1431     Q_UNUSED(visiting);
1432 
1433     int newRow = 0;
1434     int tmpRow = 0;
1435     d->formulaStorage->firstInColumn(col, &tmpRow);
1436     newRow = tmpRow;
1437     d->valueStorage->firstInColumn(col, &tmpRow);
1438     if (tmpRow)
1439         newRow = newRow ? qMin(newRow, tmpRow) : tmpRow;
1440     if (!newRow)
1441         return Cell();
1442     return Cell(d->sheet, col, newRow);
1443 }
1444 
1445 Cell CellStorage::firstInRow(int row, Visiting visiting) const
1446 {
1447 #ifdef CALLIGRA_SHEETS_MT
1448     QReadLocker rl(&d->bigUglyLock);
1449 #endif
1450     int newCol = 0;
1451     int tmpCol = 0;
1452     d->formulaStorage->firstInRow(row, &tmpCol);
1453     newCol = tmpCol;
1454     d->valueStorage->firstInRow(row, &tmpCol);
1455     if (tmpCol)
1456         newCol = newCol ? qMin(newCol, tmpCol) : tmpCol;
1457     if (visiting == VisitAll) {
1458         tmpCol = d->styleStorage->firstColumnIndexInRow(row);
1459         if (tmpCol)
1460             newCol = newCol ? qMin(newCol, tmpCol) : tmpCol;
1461     }
1462     if (!newCol)
1463         return Cell();
1464     return Cell(d->sheet, newCol, row);
1465 }
1466 
1467 Cell CellStorage::lastInColumn(int col, Visiting visiting) const
1468 {
1469 #ifdef CALLIGRA_SHEETS_MT
1470     QReadLocker rl(&d->bigUglyLock);
1471 #endif
1472     Q_UNUSED(visiting);
1473     int newRow = 0;
1474     int tmpRow = 0;
1475     d->formulaStorage->lastInColumn(col, &tmpRow);
1476     newRow = tmpRow;
1477     d->valueStorage->lastInColumn(col, &tmpRow);
1478     newRow = qMax(newRow, tmpRow);
1479     if (!newRow)
1480         return Cell();
1481     return Cell(d->sheet, col, newRow);
1482 }
1483 
1484 Cell CellStorage::lastInRow(int row, Visiting visiting) const
1485 {
1486 #ifdef CALLIGRA_SHEETS_MT
1487     QReadLocker rl(&d->bigUglyLock);
1488 #endif
1489     Q_UNUSED(visiting);
1490     int newCol = 0;
1491     int tmpCol = 0;
1492     d->formulaStorage->lastInRow(row, &tmpCol);
1493     newCol = tmpCol;
1494     d->valueStorage->lastInRow(row, &tmpCol);
1495     newCol = qMax(newCol, tmpCol);
1496     if (!newCol)
1497         return Cell();
1498     return Cell(d->sheet, newCol, row);
1499 }
1500 
1501 Cell CellStorage::nextInColumn(int col, int row, Visiting visiting) const
1502 {
1503 #ifdef CALLIGRA_SHEETS_MT
1504     QReadLocker rl(&d->bigUglyLock);
1505 #endif
1506     Q_UNUSED(visiting);
1507     int newRow = 0;
1508     int tmpRow = 0;
1509     d->formulaStorage->nextInColumn(col, row, &tmpRow);
1510     newRow = tmpRow;
1511     d->valueStorage->nextInColumn(col, row, &tmpRow);
1512     if (tmpRow)
1513         newRow = newRow ? qMin(newRow, tmpRow) : tmpRow;
1514     if (!newRow)
1515         return Cell();
1516     return Cell(d->sheet, col, newRow);
1517 }
1518 
1519 Cell CellStorage::nextInRow(int col, int row, Visiting visiting) const
1520 {
1521 #ifdef CALLIGRA_SHEETS_MT
1522     QReadLocker rl(&d->bigUglyLock);
1523 #endif
1524     int newCol = 0;
1525     int tmpCol = 0;
1526     d->formulaStorage->nextInRow(col, row, &tmpCol);
1527     newCol = tmpCol;
1528     d->valueStorage->nextInRow(col, row, &tmpCol);
1529     if (tmpCol)
1530         newCol = newCol ? qMin(newCol, tmpCol) : tmpCol;
1531     if (visiting == VisitAll) {
1532         tmpCol = d->styleStorage->nextColumnIndexInRow(col, row);
1533         if (tmpCol)
1534             newCol = newCol ? qMin(newCol, tmpCol) : tmpCol;
1535     }
1536     if (!newCol)
1537         return Cell();
1538     return Cell(d->sheet, newCol, row);
1539 }
1540 
1541 Cell CellStorage::prevInColumn(int col, int row, Visiting visiting) const
1542 {
1543 #ifdef CALLIGRA_SHEETS_MT
1544     QReadLocker rl(&d->bigUglyLock);
1545 #endif
1546     Q_UNUSED(visiting);
1547     int newRow = 0;
1548     int tmpRow = 0;
1549     d->formulaStorage->prevInColumn(col, row, &tmpRow);
1550     newRow = tmpRow;
1551     d->valueStorage->prevInColumn(col, row, &tmpRow);
1552     newRow = qMax(newRow, tmpRow);
1553     if (!newRow)
1554         return Cell();
1555     return Cell(d->sheet, col, newRow);
1556 }
1557 
1558 Cell CellStorage::prevInRow(int col, int row, Visiting visiting) const
1559 {
1560 #ifdef CALLIGRA_SHEETS_MT
1561     QReadLocker rl(&d->bigUglyLock);
1562 #endif
1563     Q_UNUSED(visiting);
1564     int newCol = 0;
1565     int tmpCol = 0;
1566     d->formulaStorage->prevInRow(col, row, &tmpCol);
1567     newCol = tmpCol;
1568     d->valueStorage->prevInRow(col, row, &tmpCol);
1569     newCol = qMax(newCol, tmpCol);
1570     if (!newCol)
1571         return Cell();
1572     return Cell(d->sheet, newCol, row);
1573 }
1574 
1575 int CellStorage::columns(bool includeStyles) const
1576 {
1577 #ifdef CALLIGRA_SHEETS_MT
1578     QReadLocker rl(&d->bigUglyLock);
1579 #endif
1580     int max = 0;
1581     max = qMax(max, d->commentStorage->usedArea().right());
1582     max = qMax(max, d->conditionsStorage->usedArea().right());
1583     max = qMax(max, d->fusionStorage->usedArea().right());
1584     if (includeStyles) max = qMax(max, d->styleStorage->usedArea().right());
1585     max = qMax(max, d->validityStorage->usedArea().right());
1586     max = qMax(max, d->formulaStorage->columns());
1587     max = qMax(max, d->linkStorage->columns());
1588     max = qMax(max, d->valueStorage->columns());
1589 
1590     // don't include bindings cause the bindingStorage does only listen to all cells in the sheet.
1591     //max = qMax(max, d->bindingStorage->usedArea().right());
1592 
1593     return max;
1594 }
1595 
1596 int CellStorage::rows(bool includeStyles) const
1597 {
1598 #ifdef CALLIGRA_SHEETS_MT
1599     QReadLocker rl(&d->bigUglyLock);
1600 #endif
1601     int max = 0;
1602     max = qMax(max, d->commentStorage->usedArea().bottom());
1603     max = qMax(max, d->conditionsStorage->usedArea().bottom());
1604     max = qMax(max, d->fusionStorage->usedArea().bottom());
1605     if (includeStyles) max = qMax(max, d->styleStorage->usedArea().bottom());
1606     max = qMax(max, d->validityStorage->usedArea().bottom());
1607     max = qMax(max, d->formulaStorage->rows());
1608     max = qMax(max, d->linkStorage->rows());
1609     max = qMax(max, d->valueStorage->rows());
1610 
1611     // don't include bindings cause the bindingStorage does only listen to all cells in the sheet.
1612     //max = qMax(max, d->bindingStorage->usedArea().bottom());
1613 
1614     return max;
1615 }
1616 
1617 CellStorage CellStorage::subStorage(const Region& region) const
1618 {
1619 #ifdef CALLIGRA_SHEETS_MT
1620     QReadLocker rl(&d->bigUglyLock);
1621 #endif
1622     CellStorage subStorage(d->sheet);
1623     *subStorage.d->formulaStorage = d->formulaStorage->subStorage(region);
1624     *subStorage.d->linkStorage = d->linkStorage->subStorage(region);
1625     *subStorage.d->valueStorage = d->valueStorage->subStorage(region);
1626     return subStorage;
1627 }
1628 
1629 const BindingStorage* CellStorage::bindingStorage() const
1630 {
1631     return d->bindingStorage;
1632 }
1633 
1634 const CommentStorage* CellStorage::commentStorage() const
1635 {
1636     return d->commentStorage;
1637 }
1638 
1639 const ConditionsStorage* CellStorage::conditionsStorage() const
1640 {
1641     return d->conditionsStorage;
1642 }
1643 
1644 const FormulaStorage* CellStorage::formulaStorage() const
1645 {
1646     return d->formulaStorage;
1647 }
1648 
1649 const FusionStorage* CellStorage::fusionStorage() const
1650 {
1651     return d->fusionStorage;
1652 }
1653 
1654 const LinkStorage* CellStorage::linkStorage() const
1655 {
1656     return d->linkStorage;
1657 }
1658 
1659 const StyleStorage* CellStorage::styleStorage() const
1660 {
1661     return d->styleStorage;
1662 }
1663 
1664 const UserInputStorage* CellStorage::userInputStorage() const
1665 {
1666     return d->userInputStorage;
1667 }
1668 
1669 const ValidityStorage* CellStorage::validityStorage() const
1670 {
1671     return d->validityStorage;
1672 }
1673 
1674 const ValueStorage* CellStorage::valueStorage() const
1675 {
1676     return d->valueStorage;
1677 }
1678 
1679 void CellStorage::startUndoRecording()
1680 {
1681 #ifdef CALLIGRA_SHEETS_MT
1682     QWriteLocker(&d->bigUglyLock);
1683 #endif
1684     // If undoData is not null, the recording wasn't stopped.
1685     // Should not happen, hence this assertion.
1686     Q_ASSERT(d->undoData == 0);
1687     d->undoData = new CellStorageUndoData();
1688 }
1689 
1690 void CellStorage::stopUndoRecording(KUndo2Command *parent)
1691 {
1692 #ifdef CALLIGRA_SHEETS_MT
1693     QWriteLocker(&d->bigUglyLock);
1694 #endif
1695     // If undoData is null, the recording wasn't started.
1696     // Should not happen, hence this assertion.
1697     Q_ASSERT(d->undoData != 0);
1698     // append sub-commands to the parent command
1699     d->createCommand(parent); // needs d->undoData
1700     for (int i = 0; i < d->undoData->namedAreas.count(); ++i) {
1701         emit namedAreaRemoved(d->undoData->namedAreas[i].second);
1702     }
1703     delete d->undoData;
1704     d->undoData = 0;
1705 }
1706 
1707 void CellStorage::loadConditions(const QList<QPair<QRegion, Conditions> >& conditions)
1708 {
1709 #ifdef CALLIGRA_SHEETS_MT
1710     QWriteLocker(&d->bigUglyLock);
1711 #endif
1712     d->conditionsStorage->load(conditions);
1713 }
1714 
1715 void CellStorage::loadStyles(const QList<QPair<QRegion, Style> > &styles)
1716 {
1717 #ifdef CALLIGRA_SHEETS_MT
1718     QWriteLocker(&d->bigUglyLock);
1719 #endif
1720     d->styleStorage->load(styles);
1721 }
1722 
1723 void CellStorage::invalidateStyleCache()
1724 {
1725     d->styleStorage->invalidateCache();
1726 }
1727 
1728 int CellStorage::rowRepeat(int row) const
1729 {
1730 #ifdef CALLIGRA_SHEETS_MT
1731     QReadLocker rl(&d->bigUglyLock);
1732 #endif
1733     return d->rowRepeatStorage->rowRepeat(row);
1734 }
1735 
1736 int CellStorage::firstIdenticalRow(int row) const
1737 {
1738 #ifdef CALLIGRA_SHEETS_MT
1739     QReadLocker rl(&d->bigUglyLock);
1740 #endif
1741     return d->rowRepeatStorage->firstIdenticalRow(row);
1742 }
1743 
1744 void CellStorage::setRowsRepeated(int row, int count)
1745 {
1746 #ifdef CALLIGRA_SHEETS_MT
1747     QWriteLocker(&d->bigUglyLock);
1748 #endif
1749     d->rowRepeatStorage->setRowRepeat(row, count);
1750 }