/* This file is part of the KDE project Copyright 2010 Marijn Kruisselbrink Copyright 2007, 2009 Stefan Nikolaus This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Local #include "CellStorage.h" #include "CellStorage_p.h" // Qt #ifdef CALLIGRA_SHEETS_MT #include #include #include #endif // Calligra #include // Sheets #include "BindingStorage.h" #include "ConditionsStorage.h" #include "Damages.h" #include "DependencyManager.h" #include "FormulaStorage.h" #include "Map.h" #include "ModelSupport.h" #include "RecalcManager.h" #include "RectStorage.h" #include "RowRepeatStorage.h" #include "Sheet.h" #include "StyleStorage.h" #include "ValidityStorage.h" #include "ValueStorage.h" // commands #include "commands/PointStorageUndoCommand.h" #include "commands/RectStorageUndoCommand.h" #include "commands/StyleStorageUndoCommand.h" // database #include "database/DatabaseStorage.h" #include "database/DatabaseManager.h" Q_DECLARE_METATYPE(QSharedPointer) using namespace Calligra::Sheets; typedef RectStorage NamedAreaStorage; class Q_DECL_HIDDEN CellStorage::Private { public: Private(Sheet* sheet) : sheet(sheet) , bindingStorage(new BindingStorage(sheet->map())) , commentStorage(new CommentStorage(sheet->map())) , conditionsStorage(new ConditionsStorage(sheet->map())) , databaseStorage(new DatabaseStorage(sheet->map())) , formulaStorage(new FormulaStorage()) , fusionStorage(new FusionStorage(sheet->map())) , linkStorage(new LinkStorage()) , matrixStorage(new MatrixStorage(sheet->map())) , namedAreaStorage(new NamedAreaStorage(sheet->map())) , styleStorage(new StyleStorage(sheet->map())) , userInputStorage(new UserInputStorage()) , validityStorage(new ValidityStorage(sheet->map())) , valueStorage(new ValueStorage()) , richTextStorage(new RichTextStorage()) , rowRepeatStorage(new RowRepeatStorage()) , undoData(0) #ifdef CALLIGRA_SHEETS_MT , bigUglyLock(QReadWriteLock::Recursive) #endif {} Private(const Private& other, Sheet* sheet) : sheet(sheet) , bindingStorage(new BindingStorage(*other.bindingStorage)) , commentStorage(new CommentStorage(*other.commentStorage)) , conditionsStorage(new ConditionsStorage(*other.conditionsStorage)) , databaseStorage(new DatabaseStorage(*other.databaseStorage)) , formulaStorage(new FormulaStorage(*other.formulaStorage)) , fusionStorage(new FusionStorage(*other.fusionStorage)) , linkStorage(new LinkStorage(*other.linkStorage)) , matrixStorage(new MatrixStorage(*other.matrixStorage)) , namedAreaStorage(new NamedAreaStorage(*other.namedAreaStorage)) , styleStorage(new StyleStorage(*other.styleStorage)) , userInputStorage(new UserInputStorage(*other.userInputStorage)) , validityStorage(new ValidityStorage(*other.validityStorage)) , valueStorage(new ValueStorage(*other.valueStorage)) , richTextStorage(new RichTextStorage(*other.richTextStorage)) , rowRepeatStorage(new RowRepeatStorage(*other.rowRepeatStorage)) , undoData(0) #ifdef CALLIGRA_SHEETS_MT , bigUglyLock(QReadWriteLock::Recursive) #endif {} ~Private() { delete bindingStorage; delete commentStorage; delete conditionsStorage; delete databaseStorage; delete formulaStorage; delete fusionStorage; delete linkStorage; delete matrixStorage; delete namedAreaStorage; delete styleStorage; delete userInputStorage; delete validityStorage; delete valueStorage; delete richTextStorage; delete rowRepeatStorage; } void createCommand(KUndo2Command *parent) const; Sheet* sheet; BindingStorage* bindingStorage; CommentStorage* commentStorage; ConditionsStorage* conditionsStorage; DatabaseStorage* databaseStorage; FormulaStorage* formulaStorage; FusionStorage* fusionStorage; LinkStorage* linkStorage; MatrixStorage* matrixStorage; NamedAreaStorage* namedAreaStorage; StyleStorage* styleStorage; UserInputStorage* userInputStorage; ValidityStorage* validityStorage; ValueStorage* valueStorage; RichTextStorage* richTextStorage; RowRepeatStorage* rowRepeatStorage; CellStorageUndoData* undoData; #ifdef CALLIGRA_SHEETS_MT QReadWriteLock bigUglyLock; #endif }; void CellStorage::Private::createCommand(KUndo2Command *parent) const { if (!undoData->bindings.isEmpty()) { RectStorageUndoCommand *const command = new RectStorageUndoCommand(sheet->model(), SourceRangeRole, parent); command->add(undoData->bindings); } if (!undoData->comments.isEmpty()) { RectStorageUndoCommand *const command = new RectStorageUndoCommand(sheet->model(), CommentRole, parent); command->add(undoData->comments); } if (!undoData->conditions.isEmpty()) { RectStorageUndoCommand *const command = new RectStorageUndoCommand(sheet->model(), ConditionRole, parent); command->add(undoData->conditions); } if (!undoData->databases.isEmpty()) { RectStorageUndoCommand *const command = new RectStorageUndoCommand(sheet->model(), TargetRangeRole, parent); command->add(undoData->databases); } if (!undoData->formulas.isEmpty()) { PointStorageUndoCommand *const command = new PointStorageUndoCommand(sheet->model(), FormulaRole, parent); command->add(undoData->formulas); } if (!undoData->fusions.isEmpty()) { RectStorageUndoCommand *const command = new RectStorageUndoCommand(sheet->model(), FusionedRangeRole, parent); command->add(undoData->fusions); } if (!undoData->links.isEmpty()) { PointStorageUndoCommand *const command = new PointStorageUndoCommand(sheet->model(), LinkRole, parent); command->add(undoData->links); } if (!undoData->matrices.isEmpty()) { RectStorageUndoCommand *const command = new RectStorageUndoCommand(sheet->model(), LockedRangeRole, parent); command->add(undoData->matrices); } if (!undoData->namedAreas.isEmpty()) { RectStorageUndoCommand *const command = new RectStorageUndoCommand(sheet->model(), NamedAreaRole, parent); command->add(undoData->namedAreas); } if (!undoData->richTexts.isEmpty()) { PointStorageUndoCommand > *const command = new PointStorageUndoCommand >(sheet->model(), RichTextRole, parent); command->add(undoData->richTexts); } if (!undoData->styles.isEmpty()) { StyleStorageUndoCommand *const command = new StyleStorageUndoCommand(styleStorage, parent); command->add(undoData->styles); } if (!undoData->userInputs.isEmpty()) { PointStorageUndoCommand *const command = new PointStorageUndoCommand(sheet->model(), UserInputRole, parent); command->add(undoData->userInputs); } if (!undoData->validities.isEmpty()) { RectStorageUndoCommand *const command = new RectStorageUndoCommand(sheet->model(), ValidityRole, parent); command->add(undoData->validities); } if (!undoData->values.isEmpty()) { PointStorageUndoCommand *const command = new PointStorageUndoCommand(sheet->model(), ValueRole, parent); command->add(undoData->values); } } CellStorage::CellStorage(Sheet* sheet) : QObject(sheet) , d(new Private(sheet)) { } CellStorage::CellStorage(const CellStorage& other) : QObject(other.d->sheet) , d(new Private(*other.d, other.d->sheet)) { } CellStorage::CellStorage(const CellStorage& other, Sheet* sheet) : QObject(sheet) , d(new Private(*other.d, sheet)) { } CellStorage::~CellStorage() { delete d; } Sheet* CellStorage::sheet() const { return d->sheet; } void CellStorage::take(int col, int row) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif Formula oldFormula; QString oldLink; QString oldUserInput; Value oldValue; QSharedPointer oldRichText; oldFormula = d->formulaStorage->take(col, row); oldLink = d->linkStorage->take(col, row); oldUserInput = d->userInputStorage->take(col, row); oldValue = d->valueStorage->take(col, row); oldRichText = d->richTextStorage->take(col, row); if (!d->sheet->map()->isLoading()) { // Trigger a recalculation of the consuming cells. CellDamage::Changes changes = CellDamage:: Binding | CellDamage::Formula | CellDamage::Value; d->sheet->map()->addDamage(new CellDamage(Cell(d->sheet, col, row), changes)); d->rowRepeatStorage->setRowRepeat(row, 1); } // also trigger a relayout of the first non-empty cell to the left of this cell int prevCol; Value v = d->valueStorage->prevInRow(col, row, &prevCol); if (!v.isEmpty()) d->sheet->map()->addDamage(new CellDamage(Cell(d->sheet, prevCol, row), CellDamage::Appearance)); // recording undo? if (d->undoData) { d->undoData->formulas << qMakePair(QPoint(col, row), oldFormula); d->undoData->links << qMakePair(QPoint(col, row), oldLink); d->undoData->userInputs << qMakePair(QPoint(col, row), oldUserInput); d->undoData->values << qMakePair(QPoint(col, row), oldValue); d->undoData->richTexts << qMakePair(QPoint(col, row), oldRichText); } } Binding CellStorage::binding(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->bindingStorage->contains(QPoint(column, row)); } void CellStorage::setBinding(const Region& region, const Binding& binding) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // recording undo? if (d->undoData) d->undoData->bindings << d->bindingStorage->undoData(region); d->bindingStorage->insert(region, binding); } void CellStorage::removeBinding(const Region& region, const Binding& binding) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // recording undo? if (d->undoData) { d->undoData->bindings << d->bindingStorage->undoData(region); } d->bindingStorage->remove(region, binding); } QString CellStorage::comment(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->commentStorage->contains(QPoint(column, row)); } void CellStorage::setComment(const Region& region, const QString& comment) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // recording undo? if (d->undoData) d->undoData->comments << d->commentStorage->undoData(region); d->commentStorage->insert(region, comment); if (!d->sheet->map()->isLoading()) { foreach (const QRect& r, region.rects()) { d->rowRepeatStorage->splitRowRepeat(r.top()); d->rowRepeatStorage->splitRowRepeat(r.bottom()+1); } } } Conditions CellStorage::conditions(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->conditionsStorage->contains(QPoint(column, row)); } void CellStorage::setConditions(const Region& region, Conditions conditions) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // recording undo? if (d->undoData) d->undoData->conditions << d->conditionsStorage->undoData(region); d->conditionsStorage->insert(region, conditions); if (!d->sheet->map()->isLoading()) { foreach (const QRect& r, region.rects()) { d->rowRepeatStorage->splitRowRepeat(r.top()); d->rowRepeatStorage->splitRowRepeat(r.bottom()+1); } } } Database CellStorage::database(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif QPair pair = d->databaseStorage->containedPair(QPoint(column, row)); if (pair.first.isEmpty()) return Database(); if (pair.second.isEmpty()) return Database(); // update the range, which might get changed Database database = pair.second; database.setRange(Region(pair.first.toRect(), d->sheet)); return database; } QList< QPair > CellStorage::databases(const Region& region) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->databaseStorage->intersectingPairs(region); } void CellStorage::setDatabase(const Region& region, const Database& database) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // recording undo? if (d->undoData) d->undoData->databases << d->databaseStorage->undoData(region); d->databaseStorage->insert(region, database); } Formula CellStorage::formula(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->formulaStorage->lookup(column, row, Formula::empty()); } void CellStorage::setFormula(int column, int row, const Formula& formula) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif Formula old = Formula::empty(); if (formula.expression().isEmpty()) old = d->formulaStorage->take(column, row, Formula::empty()); else old = d->formulaStorage->insert(column, row, formula); // formula changed? if (formula != old) { if (!d->sheet->map()->isLoading()) { // trigger an update of the dependencies and a recalculation d->sheet->map()->addDamage(new CellDamage(Cell(d->sheet, column, row), CellDamage::Formula | CellDamage::Value)); d->rowRepeatStorage->setRowRepeat(row, 1); } // recording undo? if (d->undoData) { d->undoData->formulas << qMakePair(QPoint(column, row), old); // Also store the old value, if there wasn't a formula before, // because the new value is calculated later by the damage // processing and is not recorded for undoing. if (old == Formula()) d->undoData->values << qMakePair(QPoint(column, row), value(column, row)); } } } QString CellStorage::link(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->linkStorage->lookup(column, row); } void CellStorage::setLink(int column, int row, const QString& link) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif QString old; if (link.isEmpty()) old = d->linkStorage->take(column, row); else old = d->linkStorage->insert(column, row, link); // recording undo? if (d->undoData && link != old) d->undoData->links << qMakePair(QPoint(column, row), old); if (!d->sheet->map()->isLoading()) d->rowRepeatStorage->setRowRepeat(row, 1); } QString CellStorage::namedArea(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif QPair pair = d->namedAreaStorage->containedPair(QPoint(column, row)); if (pair.first.isEmpty()) return QString(); if (pair.second.isEmpty()) return QString(); return pair.second; } QList< QPair > CellStorage::namedAreas(const Region& region) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->namedAreaStorage->intersectingPairs(region); } void CellStorage::setNamedArea(const Region& region, const QString& namedArea) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // recording undo? if (d->undoData) d->undoData->namedAreas << d->namedAreaStorage->undoData(region); d->namedAreaStorage->insert(region, namedArea); } void CellStorage::removeNamedArea(const Region& region, const QString& namedArea) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // recording undo? if (d->undoData) d->undoData->namedAreas << d->namedAreaStorage->undoData(region); d->namedAreaStorage->remove(region, namedArea); } void CellStorage::emitInsertNamedArea(const Region ®ion, const QString &namedArea) { emit insertNamedArea(region, namedArea); } Style CellStorage::style(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->styleStorage->contains(QPoint(column, row)); } Style CellStorage::style(const QRect& rect) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->styleStorage->contains(rect); } void CellStorage::setStyle(const Region& region, const Style& style) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // recording undo? if (d->undoData) d->undoData->styles << d->styleStorage->undoData(region); d->styleStorage->insert(region, style); if (!d->sheet->map()->isLoading()) { foreach (const QRect& r, region.rects()) { d->rowRepeatStorage->splitRowRepeat(r.top()); d->rowRepeatStorage->splitRowRepeat(r.bottom()+1); } } } void CellStorage::insertSubStyle(const QRect &rect, const SharedSubStyle &subStyle) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif d->styleStorage->insert(rect, subStyle); if (!d->sheet->map()->isLoading()) { d->rowRepeatStorage->splitRowRepeat(rect.top()); d->rowRepeatStorage->splitRowRepeat(rect.bottom()+1); } } QString CellStorage::userInput(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->userInputStorage->lookup(column, row); } void CellStorage::setUserInput(int column, int row, const QString& userInput) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif QString old; if (userInput.isEmpty()) old = d->userInputStorage->take(column, row); else old = d->userInputStorage->insert(column, row, userInput); // recording undo? if (d->undoData && userInput != old) d->undoData->userInputs << qMakePair(QPoint(column, row), old); if (!d->sheet->map()->isLoading()) d->rowRepeatStorage->setRowRepeat(row, 1); } QSharedPointer CellStorage::richText(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->richTextStorage->lookup(column, row); } void CellStorage::setRichText(int column, int row, QSharedPointer text) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif QSharedPointer old; if (text.isNull()) old = d->richTextStorage->take(column, row); else old = d->richTextStorage->insert(column, row, text); // recording undo? if (d->undoData && text != old) d->undoData->richTexts << qMakePair(QPoint(column, row), old); } Validity CellStorage::validity(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->validityStorage->contains(QPoint(column, row)); } void CellStorage::setValidity(const Region& region, Validity validity) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // recording undo? if (d->undoData) d->undoData->validities << d->validityStorage->undoData(region); d->validityStorage->insert(region, validity); if (!d->sheet->map()->isLoading()) { foreach (const QRect& r, region.rects()) { d->rowRepeatStorage->splitRowRepeat(r.top()); d->rowRepeatStorage->splitRowRepeat(r.bottom()+1); } } } Value CellStorage::value(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->valueStorage->lookup(column, row); } Value CellStorage::valueRegion(const Region& region) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif // create a subStorage with adjusted origin return Value(d->valueStorage->subStorage(region, false), region.boundingRect().size()); } void CellStorage::setValue(int column, int row, const Value& value) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // release any lock unlockCells(column, row); Value old; if (value.isEmpty()) old = d->valueStorage->take(column, row); else old = d->valueStorage->insert(column, row, value); // value changed? if (value != old) { if (!d->sheet->map()->isLoading()) { // Always trigger a repainting and a binding update. CellDamage::Changes changes = CellDamage::Appearance | CellDamage::Binding; // Trigger a recalculation of the consuming cells, only if we are not // already in a recalculation process. if (!d->sheet->map()->recalcManager()->isActive()) changes |= CellDamage::Value; d->sheet->map()->addDamage(new CellDamage(Cell(d->sheet, column, row), changes)); // Also trigger a relayouting of the first non-empty cell to the left of this one int prevCol; Value v = d->valueStorage->prevInRow(column, row, &prevCol); if (!v.isEmpty()) d->sheet->map()->addDamage(new CellDamage(Cell(d->sheet, prevCol, row), CellDamage::Appearance)); d->rowRepeatStorage->setRowRepeat(row, 1); } // recording undo? if (d->undoData) d->undoData->values << qMakePair(QPoint(column, row), old); } } bool CellStorage::doesMergeCells(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif const QPair pair = d->fusionStorage->containedPair(QPoint(column, row)); if (pair.first.isNull()) return false; if (pair.second == false) return false; // master cell? if (pair.first.toRect().topLeft() != QPoint(column, row)) return false; return true; } bool CellStorage::isPartOfMerged(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif const QPair pair = d->fusionStorage->containedPair(QPoint(column, row)); if (pair.first.isNull()) return false; if (pair.second == false) return false; // master cell? if (pair.first.toRect().topLeft() == QPoint(column, row)) return false; return true; } void CellStorage::mergeCells(int column, int row, int numXCells, int numYCells) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // Start by unmerging the cells that we merge right now const QPair pair = d->fusionStorage->containedPair(QPoint(column, row)); if (!pair.first.isNull()) d->fusionStorage->insert(Region(pair.first.toRect()), false); // Merge the cells if (numXCells != 0 || numYCells != 0) d->fusionStorage->insert(Region(column, row, numXCells + 1, numYCells + 1), true); if (!d->sheet->map()->isLoading()) d->rowRepeatStorage->setRowRepeat(row, 1); } Cell CellStorage::masterCell(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif const QPair pair = d->fusionStorage->containedPair(QPoint(column, row)); if (pair.first.isNull()) return Cell(d->sheet, column, row); if (pair.second == false) return Cell(d->sheet, column, row); return Cell(d->sheet, pair.first.toRect().topLeft()); } int CellStorage::mergedXCells(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif const QPair pair = d->fusionStorage->containedPair(QPoint(column, row)); if (pair.first.isNull()) return 0; // Not the master cell? if (pair.first.topLeft() != QPoint(column, row)) return 0; return pair.first.toRect().width() - 1; } int CellStorage::mergedYCells(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif const QPair pair = d->fusionStorage->containedPair(QPoint(column, row)); if (pair.first.isNull()) return 0; // Not the master cell? if (pair.first.topLeft() != QPoint(column, row)) return 0; return pair.first.toRect().height() - 1; } QList CellStorage::masterCells(const Region& region) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif const QList > pairs = d->fusionStorage->intersectingPairs(region); if (pairs.isEmpty()) return QList(); QList masterCells; for (int i = 0; i < pairs.count(); ++i) { if (pairs[i].first.isNull()) continue; if (pairs[i].second == false) continue; masterCells.append(Cell(d->sheet, pairs[i].first.toRect().topLeft())); } return masterCells; } bool CellStorage::locksCells(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif const QPair pair = d->matrixStorage->containedPair(QPoint(column, row)); if (pair.first.isNull()) return false; if (pair.second == false) return false; // master cell? if (pair.first.toRect().topLeft() != QPoint(column, row)) return false; return true; } bool CellStorage::isLocked(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif const QPair pair = d->matrixStorage->containedPair(QPoint(column, row)); if (pair.first.isNull()) return false; if (pair.second == false) return false; // master cell? if (pair.first.toRect().topLeft() == QPoint(column, row)) return false; return true; } bool CellStorage::hasLockedCells(const Region& region) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif typedef QPair RectBoolPair; QList > pairs = d->matrixStorage->intersectingPairs(region); foreach (const RectBoolPair& pair, pairs) { if (pair.first.isNull()) continue; if (pair.second == false) continue; // more than just the master cell in the region? const QPoint topLeft = pair.first.toRect().topLeft(); if (pair.first.width() >= 1) { if (region.contains(topLeft + QPoint(1, 0), d->sheet)) return true; } if (pair.first.height() >= 1) { if (region.contains(topLeft + QPoint(0, 1), d->sheet)) return true; } } return false; } void CellStorage::lockCells(const QRect& rect) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // Start by unlocking the cells that we lock right now const QPair pair = d->matrixStorage->containedPair(rect.topLeft()); // FIXME if (!pair.first.isNull()) d->matrixStorage->insert(Region(pair.first.toRect()), false); // Lock the cells if (rect.width() > 1 || rect.height() > 1) d->matrixStorage->insert(Region(rect), true); } void CellStorage::unlockCells(int column, int row) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif const QPair pair = d->matrixStorage->containedPair(QPoint(column, row)); if (pair.first.isNull()) return; if (pair.second == false) return; if (pair.first.toRect().topLeft() != QPoint(column, row)) return; const QRect rect = pair.first.toRect(); d->matrixStorage->insert(Region(rect), false); // clear the values for (int r = rect.top(); r <= rect.bottom(); ++r) { for (int c = rect.left(); c <= rect.right(); ++c) { if (r != rect.top() || c != rect.left()) setValue(c, r, Value()); } } // recording undo? if (d->undoData) d->undoData->matrices << pair; } QRect CellStorage::lockedCells(int column, int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif const QPair pair = d->matrixStorage->containedPair(QPoint(column, row)); if (pair.first.isNull()) return QRect(column, row, 1, 1); if (pair.second == false) return QRect(column, row, 1, 1); if (pair.first.toRect().topLeft() != QPoint(column, row)) return QRect(column, row, 1, 1); return pair.first.toRect(); } void CellStorage::insertColumns(int position, int number) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // Trigger a dependency update of the cells, which have a formula. (old positions) // FIXME Stefan: Would it be better to directly alter the dependency tree? // TODO Stefan: Optimize: Avoid the double creation of the sub-storages, but don't process // formulas, that will get out of bounds after the operation. const Region invalidRegion(QRect(QPoint(position, 1), QPoint(KS_colMax, KS_rowMax)), d->sheet); PointStorage subStorage = d->formulaStorage->subStorage(invalidRegion); Cell cell; for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger an update of the bindings and the named areas. d->sheet->map()->addDamage(new CellDamage(d->sheet, invalidRegion, CellDamage::Binding | CellDamage::NamedArea)); QList< QPair > bindings = d->bindingStorage->insertColumns(position, number); QList< QPair > comments = d->commentStorage->insertColumns(position, number); QList< QPair > conditions = d->conditionsStorage->insertColumns(position, number); QList< QPair > databases = d->databaseStorage->insertColumns(position, number); QVector< QPair > formulas = d->formulaStorage->insertColumns(position, number); QList< QPair > fusions = d->fusionStorage->insertColumns(position, number); QVector< QPair > links = d->linkStorage->insertColumns(position, number); QList< QPair > matrices = d->matrixStorage->insertColumns(position, number); QList< QPair > namedAreas = d->namedAreaStorage->insertColumns(position, number); QList< QPair > styles = d->styleStorage->insertColumns(position, number); QVector< QPair > userInputs = d->userInputStorage->insertColumns(position, number); QVector< QPair > > richTexts = d->richTextStorage->insertColumns(position, number); QList< QPair > validities = d->validityStorage->insertColumns(position, number); QVector< QPair > values = d->valueStorage->insertColumns(position, number); // recording undo? if (d->undoData) { d->undoData->bindings << bindings; d->undoData->comments << comments; d->undoData->conditions << conditions; d->undoData->databases << databases; d->undoData->formulas << formulas; d->undoData->fusions << fusions; d->undoData->links << links; d->undoData->matrices << matrices; d->undoData->namedAreas << namedAreas; d->undoData->styles << styles; d->undoData->userInputs << userInputs; d->undoData->validities << validities; d->undoData->values << values; d->undoData->richTexts << richTexts; } // Trigger a dependency update of the cells, which have a formula. (new positions) subStorage = d->formulaStorage->subStorage(invalidRegion); for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger a recalculation only for the cells, that depend on values in the changed region. Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion); d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value)); } void CellStorage::removeColumns(int position, int number) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // Trigger a dependency update of the cells, which have a formula. (old positions) const Region invalidRegion(QRect(QPoint(position, 1), QPoint(KS_colMax, KS_rowMax)), d->sheet); PointStorage subStorage = d->formulaStorage->subStorage(invalidRegion); Cell cell; for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger an update of the bindings and the named areas. const Region region(QRect(QPoint(position - 1, 1), QPoint(KS_colMax, KS_rowMax)), d->sheet); d->sheet->map()->addDamage(new CellDamage(d->sheet, region, CellDamage::Binding | CellDamage::NamedArea)); QList< QPair > bindings = d->bindingStorage->removeColumns(position, number); QList< QPair > comments = d->commentStorage->removeColumns(position, number); QList< QPair > conditions = d->conditionsStorage->removeColumns(position, number); QList< QPair > databases = d->databaseStorage->removeColumns(position, number); QVector< QPair > formulas = d->formulaStorage->removeColumns(position, number); QList< QPair > fusions = d->fusionStorage->removeColumns(position, number); QVector< QPair > links = d->linkStorage->removeColumns(position, number); QList< QPair > matrices = d->matrixStorage->removeColumns(position, number); QList< QPair > namedAreas = d->namedAreaStorage->removeColumns(position, number); QList< QPair > styles = d->styleStorage->removeColumns(position, number); QVector< QPair > userInputs = d->userInputStorage->removeColumns(position, number); QList< QPair > validities = d->validityStorage->removeColumns(position, number); QVector< QPair > values = d->valueStorage->removeColumns(position, number); QVector< QPair > > richTexts = d->richTextStorage->removeColumns(position, number); // recording undo? if (d->undoData) { d->undoData->bindings << bindings; d->undoData->comments << comments; d->undoData->conditions << conditions; d->undoData->databases << databases; d->undoData->formulas << formulas; d->undoData->fusions << fusions; d->undoData->links << links; d->undoData->matrices << matrices; d->undoData->namedAreas << namedAreas; d->undoData->styles << styles; d->undoData->userInputs << userInputs; d->undoData->validities << validities; d->undoData->values << values; d->undoData->richTexts << richTexts; } // Trigger a dependency update of the cells, which have a formula. (new positions) subStorage = d->formulaStorage->subStorage(invalidRegion); for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger a recalculation only for the cells, that depend on values in the changed region. Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion); d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value)); } void CellStorage::insertRows(int position, int number) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // Trigger a dependency update of the cells, which have a formula. (old positions) const Region invalidRegion(QRect(QPoint(1, position), QPoint(KS_colMax, KS_rowMax)), d->sheet); PointStorage subStorage = d->formulaStorage->subStorage(invalidRegion); Cell cell; for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger an update of the bindings and the named areas. d->sheet->map()->addDamage(new CellDamage(d->sheet, invalidRegion, CellDamage::Binding | CellDamage::NamedArea)); QList< QPair > bindings = d->bindingStorage->insertRows(position, number); QList< QPair > comments = d->commentStorage->insertRows(position, number); QList< QPair > conditions = d->conditionsStorage->insertRows(position, number); QList< QPair > databases = d->databaseStorage->insertRows(position, number); QVector< QPair > formulas = d->formulaStorage->insertRows(position, number); QList< QPair > fusions = d->fusionStorage->insertRows(position, number); QVector< QPair > links = d->linkStorage->insertRows(position, number); QList< QPair > matrices = d->matrixStorage->insertRows(position, number); QList< QPair > namedAreas = d->namedAreaStorage->insertRows(position, number); QList< QPair > styles = d->styleStorage->insertRows(position, number); QVector< QPair > userInputs = d->userInputStorage->insertRows(position, number); QList< QPair > validities = d->validityStorage->insertRows(position, number); QVector< QPair > values = d->valueStorage->insertRows(position, number); QVector< QPair > > richTexts = d->richTextStorage->insertRows(position, number); // recording undo? if (d->undoData) { d->undoData->bindings << bindings; d->undoData->comments << comments; d->undoData->conditions << conditions; d->undoData->databases << databases; d->undoData->formulas << formulas; d->undoData->fusions << fusions; d->undoData->links << links; d->undoData->matrices << matrices; d->undoData->namedAreas << namedAreas; d->undoData->styles << styles; d->undoData->userInputs << userInputs; d->undoData->validities << validities; d->undoData->values << values; d->undoData->richTexts << richTexts; } // Trigger a dependency update of the cells, which have a formula. (new positions) subStorage = d->formulaStorage->subStorage(invalidRegion); for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger a recalculation only for the cells, that depend on values in the changed region. Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion); d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value)); d->rowRepeatStorage->insertRows(position, number); } void CellStorage::removeRows(int position, int number) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // Trigger a dependency update of the cells, which have a formula. (old positions) const Region invalidRegion(QRect(QPoint(1, position), QPoint(KS_colMax, KS_rowMax)), d->sheet); PointStorage subStorage = d->formulaStorage->subStorage(invalidRegion); Cell cell; for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger an update of the bindings and the named areas. const Region region(QRect(QPoint(1, position - 1), QPoint(KS_colMax, KS_rowMax)), d->sheet); d->sheet->map()->addDamage(new CellDamage(d->sheet, region, CellDamage::Binding | CellDamage::NamedArea)); QList< QPair > bindings = d->bindingStorage->removeRows(position, number); QList< QPair > comments = d->commentStorage->removeRows(position, number); QList< QPair > conditions = d->conditionsStorage->removeRows(position, number); QList< QPair > databases = d->databaseStorage->removeRows(position, number); QVector< QPair > formulas = d->formulaStorage->removeRows(position, number); QList< QPair > fusions = d->fusionStorage->removeRows(position, number); QVector< QPair > links = d->linkStorage->removeRows(position, number); QList< QPair > matrices = d->matrixStorage->removeRows(position, number); QList< QPair > namedAreas = d->namedAreaStorage->removeRows(position, number); QList< QPair > styles = d->styleStorage->removeRows(position, number); QVector< QPair > userInputs = d->userInputStorage->removeRows(position, number); QList< QPair > validities = d->validityStorage->removeRows(position, number); QVector< QPair > values = d->valueStorage->removeRows(position, number); QVector< QPair > > richTexts = d->richTextStorage->removeRows(position, number); // recording undo? if (d->undoData) { d->undoData->bindings << bindings; d->undoData->comments << comments; d->undoData->conditions << conditions; d->undoData->databases << databases; d->undoData->formulas << formulas; d->undoData->fusions << fusions; d->undoData->links << links; d->undoData->matrices << matrices; d->undoData->namedAreas << namedAreas; d->undoData->styles << styles; d->undoData->userInputs << userInputs; d->undoData->validities << validities; d->undoData->values << values; d->undoData->richTexts << richTexts; } // Trigger a dependency update of the cells, which have a formula. (new positions) subStorage = d->formulaStorage->subStorage(invalidRegion); for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger a recalculation only for the cells, that depend on values in the changed region. Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion); d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value)); d->rowRepeatStorage->removeRows(position, number); } void CellStorage::removeShiftLeft(const QRect& rect) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // Trigger a dependency update of the cells, which have a formula. (old positions) const Region invalidRegion(QRect(rect.topLeft(), QPoint(KS_colMax, rect.bottom())), d->sheet); PointStorage subStorage = d->formulaStorage->subStorage(invalidRegion); Cell cell; for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger an update of the bindings and the named areas. const Region region(QRect(rect.topLeft() - QPoint(1, 0), QPoint(KS_colMax, rect.bottom())), d->sheet); d->sheet->map()->addDamage(new CellDamage(d->sheet, region, CellDamage::Binding | CellDamage::NamedArea)); QList< QPair > bindings = d->bindingStorage->removeShiftLeft(rect); QList< QPair > comments = d->commentStorage->removeShiftLeft(rect); QList< QPair > conditions = d->conditionsStorage->removeShiftLeft(rect); QList< QPair > databases = d->databaseStorage->removeShiftLeft(rect); QVector< QPair > formulas = d->formulaStorage->removeShiftLeft(rect); QList< QPair > fusions = d->fusionStorage->removeShiftLeft(rect); QVector< QPair > links = d->linkStorage->removeShiftLeft(rect); QList< QPair > matrices = d->matrixStorage->removeShiftLeft(rect); QList< QPair > namedAreas = d->namedAreaStorage->removeShiftLeft(rect); QList< QPair > styles = d->styleStorage->removeShiftLeft(rect); QVector< QPair > userInputs = d->userInputStorage->removeShiftLeft(rect); QList< QPair > validities = d->validityStorage->removeShiftLeft(rect); QVector< QPair > values = d->valueStorage->removeShiftLeft(rect); QVector< QPair > > richTexts = d->richTextStorage->removeShiftLeft(rect); // recording undo? if (d->undoData) { d->undoData->bindings << bindings; d->undoData->comments << comments; d->undoData->conditions << conditions; d->undoData->databases << databases; d->undoData->formulas << formulas; d->undoData->fusions << fusions; d->undoData->links << links; d->undoData->matrices << matrices; d->undoData->namedAreas << namedAreas; d->undoData->styles << styles; d->undoData->userInputs << userInputs; d->undoData->validities << validities; d->undoData->values << values; d->undoData->richTexts << richTexts; } // Trigger a dependency update of the cells, which have a formula. (new positions) subStorage = d->formulaStorage->subStorage(invalidRegion); for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger a recalculation only for the cells, that depend on values in the changed region. Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion); d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value)); d->rowRepeatStorage->removeShiftLeft(rect); } void CellStorage::insertShiftRight(const QRect& rect) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // Trigger a dependency update of the cells, which have a formula. (old positions) const Region invalidRegion(QRect(rect.topLeft(), QPoint(KS_colMax, rect.bottom())), d->sheet); PointStorage subStorage = d->formulaStorage->subStorage(invalidRegion); Cell cell; for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger an update of the bindings and the named areas. d->sheet->map()->addDamage(new CellDamage(d->sheet, invalidRegion, CellDamage::Binding | CellDamage::NamedArea)); QList< QPair > bindings = d->bindingStorage->insertShiftRight(rect); QList< QPair > comments = d->commentStorage->insertShiftRight(rect); QList< QPair > conditions = d->conditionsStorage->insertShiftRight(rect); QList< QPair > databases = d->databaseStorage->insertShiftRight(rect); QVector< QPair > formulas = d->formulaStorage->insertShiftRight(rect); QList< QPair > fusions = d->fusionStorage->insertShiftRight(rect); QVector< QPair > links = d->linkStorage->insertShiftRight(rect); QList< QPair > matrices = d->matrixStorage->insertShiftRight(rect); QList< QPair > namedAreas = d->namedAreaStorage->insertShiftRight(rect); QList< QPair > styles = d->styleStorage->insertShiftRight(rect); QVector< QPair > userInputs = d->userInputStorage->insertShiftRight(rect); QList< QPair > validities = d->validityStorage->insertShiftRight(rect); QVector< QPair > values = d->valueStorage->insertShiftRight(rect); QVector< QPair > > richTexts = d->richTextStorage->insertShiftRight(rect); // recording undo? if (d->undoData) { d->undoData->bindings << bindings; d->undoData->comments << comments; d->undoData->conditions << conditions; d->undoData->databases << databases; d->undoData->formulas << formulas; d->undoData->fusions << fusions; d->undoData->links << links; d->undoData->matrices << matrices; d->undoData->namedAreas << namedAreas; d->undoData->styles << styles; d->undoData->userInputs << userInputs; d->undoData->validities << validities; d->undoData->values << values; d->undoData->richTexts << richTexts; } // Trigger a dependency update of the cells, which have a formula. (new positions) subStorage = d->formulaStorage->subStorage(invalidRegion); for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger a recalculation only for the cells, that depend on values in the changed region. Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion); d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value)); d->rowRepeatStorage->insertShiftRight(rect); } void CellStorage::removeShiftUp(const QRect& rect) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // Trigger a dependency update of the cells, which have a formula. (old positions) const Region invalidRegion(QRect(rect.topLeft(), QPoint(rect.right(), KS_rowMax)), d->sheet); PointStorage subStorage = d->formulaStorage->subStorage(invalidRegion); Cell cell; for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger an update of the bindings and the named areas. const Region region(QRect(rect.topLeft() - QPoint(0, 1), QPoint(rect.right(), KS_rowMax)), d->sheet); d->sheet->map()->addDamage(new CellDamage(d->sheet, region, CellDamage::Binding | CellDamage::NamedArea)); QList< QPair > bindings = d->bindingStorage->removeShiftUp(rect); QList< QPair > comments = d->commentStorage->removeShiftUp(rect); QList< QPair > conditions = d->conditionsStorage->removeShiftUp(rect); QList< QPair > databases = d->databaseStorage->removeShiftUp(rect); QVector< QPair > formulas = d->formulaStorage->removeShiftUp(rect); QList< QPair > fusions = d->fusionStorage->removeShiftUp(rect); QVector< QPair > links = d->linkStorage->removeShiftUp(rect); QList< QPair > matrices = d->matrixStorage->removeShiftUp(rect); QList< QPair > namedAreas = d->namedAreaStorage->removeShiftUp(rect); QList< QPair > styles = d->styleStorage->removeShiftUp(rect); QVector< QPair > userInputs = d->userInputStorage->removeShiftUp(rect); QList< QPair > validities = d->validityStorage->removeShiftUp(rect); QVector< QPair > values = d->valueStorage->removeShiftUp(rect); QVector< QPair > > richTexts = d->richTextStorage->removeShiftUp(rect); // recording undo? if (d->undoData) { d->undoData->bindings << bindings; d->undoData->comments << comments; d->undoData->conditions << conditions; d->undoData->databases << databases; d->undoData->formulas << formulas; d->undoData->fusions << fusions; d->undoData->links << links; d->undoData->matrices << matrices; d->undoData->namedAreas << namedAreas; d->undoData->styles << styles; d->undoData->userInputs << userInputs; d->undoData->validities << validities; d->undoData->values << values; d->undoData->richTexts << richTexts; } // Trigger a dependency update of the cells, which have a formula. (new positions) subStorage = d->formulaStorage->subStorage(invalidRegion); for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger a recalculation only for the cells, that depend on values in the changed region. Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion); d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value)); d->rowRepeatStorage->removeShiftUp(rect); } void CellStorage::insertShiftDown(const QRect& rect) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // Trigger a dependency update of the cells, which have a formula. (old positions) const Region invalidRegion(QRect(rect.topLeft(), QPoint(rect.right(), KS_rowMax)), d->sheet); PointStorage subStorage = d->formulaStorage->subStorage(invalidRegion); Cell cell; for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger an update of the bindings and the named areas. d->sheet->map()->addDamage(new CellDamage(d->sheet, invalidRegion, CellDamage::Binding | CellDamage::NamedArea)); QList< QPair > bindings = d->bindingStorage->insertShiftDown(rect); QList< QPair > comments = d->commentStorage->insertShiftDown(rect); QList< QPair > conditions = d->conditionsStorage->insertShiftDown(rect); QList< QPair > databases = d->databaseStorage->insertShiftDown(rect); QVector< QPair > formulas = d->formulaStorage->insertShiftDown(rect); QList< QPair > fusions = d->fusionStorage->insertShiftDown(rect); QVector< QPair > links = d->linkStorage->insertShiftDown(rect); QList< QPair > matrices = d->matrixStorage->insertShiftDown(rect); QList< QPair > namedAreas = d->namedAreaStorage->insertShiftDown(rect); QList< QPair > styles = d->styleStorage->insertShiftDown(rect); QVector< QPair > userInputs = d->userInputStorage->insertShiftDown(rect); QList< QPair > validities = d->validityStorage->insertShiftDown(rect); QVector< QPair > values = d->valueStorage->insertShiftDown(rect); QVector< QPair > > richTexts = d->richTextStorage->insertShiftDown(rect); // recording undo? if (d->undoData) { d->undoData->bindings << bindings; d->undoData->comments << comments; d->undoData->conditions << conditions; d->undoData->databases << databases; d->undoData->formulas << formulas; d->undoData->fusions << fusions; d->undoData->links << links; d->undoData->matrices << matrices; d->undoData->namedAreas << namedAreas; d->undoData->styles << styles; d->undoData->userInputs << userInputs; d->undoData->validities << validities; d->undoData->values << values; d->undoData->richTexts << richTexts; } // Trigger a dependency update of the cells, which have a formula. (new positions) subStorage = d->formulaStorage->subStorage(invalidRegion); for (int i = 0; i < subStorage.count(); ++i) { cell = Cell(d->sheet, subStorage.col(i), subStorage.row(i)); d->sheet->map()->addDamage(new CellDamage(cell, CellDamage::Formula)); } // Trigger a recalculation only for the cells, that depend on values in the changed region. Region providers = d->sheet->map()->dependencyManager()->reduceToProvidingRegion(invalidRegion); d->sheet->map()->addDamage(new CellDamage(d->sheet, providers, CellDamage::Value)); d->rowRepeatStorage->insertShiftDown(rect); } Cell CellStorage::firstInColumn(int col, Visiting visiting) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif Q_UNUSED(visiting); int newRow = 0; int tmpRow = 0; d->formulaStorage->firstInColumn(col, &tmpRow); newRow = tmpRow; d->valueStorage->firstInColumn(col, &tmpRow); if (tmpRow) newRow = newRow ? qMin(newRow, tmpRow) : tmpRow; if (!newRow) return Cell(); return Cell(d->sheet, col, newRow); } Cell CellStorage::firstInRow(int row, Visiting visiting) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif int newCol = 0; int tmpCol = 0; d->formulaStorage->firstInRow(row, &tmpCol); newCol = tmpCol; d->valueStorage->firstInRow(row, &tmpCol); if (tmpCol) newCol = newCol ? qMin(newCol, tmpCol) : tmpCol; if (visiting == VisitAll) { tmpCol = d->styleStorage->firstColumnIndexInRow(row); if (tmpCol) newCol = newCol ? qMin(newCol, tmpCol) : tmpCol; } if (!newCol) return Cell(); return Cell(d->sheet, newCol, row); } Cell CellStorage::lastInColumn(int col, Visiting visiting) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif Q_UNUSED(visiting); int newRow = 0; int tmpRow = 0; d->formulaStorage->lastInColumn(col, &tmpRow); newRow = tmpRow; d->valueStorage->lastInColumn(col, &tmpRow); newRow = qMax(newRow, tmpRow); if (!newRow) return Cell(); return Cell(d->sheet, col, newRow); } Cell CellStorage::lastInRow(int row, Visiting visiting) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif Q_UNUSED(visiting); int newCol = 0; int tmpCol = 0; d->formulaStorage->lastInRow(row, &tmpCol); newCol = tmpCol; d->valueStorage->lastInRow(row, &tmpCol); newCol = qMax(newCol, tmpCol); if (!newCol) return Cell(); return Cell(d->sheet, newCol, row); } Cell CellStorage::nextInColumn(int col, int row, Visiting visiting) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif Q_UNUSED(visiting); int newRow = 0; int tmpRow = 0; d->formulaStorage->nextInColumn(col, row, &tmpRow); newRow = tmpRow; d->valueStorage->nextInColumn(col, row, &tmpRow); if (tmpRow) newRow = newRow ? qMin(newRow, tmpRow) : tmpRow; if (!newRow) return Cell(); return Cell(d->sheet, col, newRow); } Cell CellStorage::nextInRow(int col, int row, Visiting visiting) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif int newCol = 0; int tmpCol = 0; d->formulaStorage->nextInRow(col, row, &tmpCol); newCol = tmpCol; d->valueStorage->nextInRow(col, row, &tmpCol); if (tmpCol) newCol = newCol ? qMin(newCol, tmpCol) : tmpCol; if (visiting == VisitAll) { tmpCol = d->styleStorage->nextColumnIndexInRow(col, row); if (tmpCol) newCol = newCol ? qMin(newCol, tmpCol) : tmpCol; } if (!newCol) return Cell(); return Cell(d->sheet, newCol, row); } Cell CellStorage::prevInColumn(int col, int row, Visiting visiting) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif Q_UNUSED(visiting); int newRow = 0; int tmpRow = 0; d->formulaStorage->prevInColumn(col, row, &tmpRow); newRow = tmpRow; d->valueStorage->prevInColumn(col, row, &tmpRow); newRow = qMax(newRow, tmpRow); if (!newRow) return Cell(); return Cell(d->sheet, col, newRow); } Cell CellStorage::prevInRow(int col, int row, Visiting visiting) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif Q_UNUSED(visiting); int newCol = 0; int tmpCol = 0; d->formulaStorage->prevInRow(col, row, &tmpCol); newCol = tmpCol; d->valueStorage->prevInRow(col, row, &tmpCol); newCol = qMax(newCol, tmpCol); if (!newCol) return Cell(); return Cell(d->sheet, newCol, row); } int CellStorage::columns(bool includeStyles) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif int max = 0; max = qMax(max, d->commentStorage->usedArea().right()); max = qMax(max, d->conditionsStorage->usedArea().right()); max = qMax(max, d->fusionStorage->usedArea().right()); if (includeStyles) max = qMax(max, d->styleStorage->usedArea().right()); max = qMax(max, d->validityStorage->usedArea().right()); max = qMax(max, d->formulaStorage->columns()); max = qMax(max, d->linkStorage->columns()); max = qMax(max, d->valueStorage->columns()); // don't include bindings cause the bindingStorage does only listen to all cells in the sheet. //max = qMax(max, d->bindingStorage->usedArea().right()); return max; } int CellStorage::rows(bool includeStyles) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif int max = 0; max = qMax(max, d->commentStorage->usedArea().bottom()); max = qMax(max, d->conditionsStorage->usedArea().bottom()); max = qMax(max, d->fusionStorage->usedArea().bottom()); if (includeStyles) max = qMax(max, d->styleStorage->usedArea().bottom()); max = qMax(max, d->validityStorage->usedArea().bottom()); max = qMax(max, d->formulaStorage->rows()); max = qMax(max, d->linkStorage->rows()); max = qMax(max, d->valueStorage->rows()); // don't include bindings cause the bindingStorage does only listen to all cells in the sheet. //max = qMax(max, d->bindingStorage->usedArea().bottom()); return max; } CellStorage CellStorage::subStorage(const Region& region) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif CellStorage subStorage(d->sheet); *subStorage.d->formulaStorage = d->formulaStorage->subStorage(region); *subStorage.d->linkStorage = d->linkStorage->subStorage(region); *subStorage.d->valueStorage = d->valueStorage->subStorage(region); return subStorage; } const BindingStorage* CellStorage::bindingStorage() const { return d->bindingStorage; } const CommentStorage* CellStorage::commentStorage() const { return d->commentStorage; } const ConditionsStorage* CellStorage::conditionsStorage() const { return d->conditionsStorage; } const FormulaStorage* CellStorage::formulaStorage() const { return d->formulaStorage; } const FusionStorage* CellStorage::fusionStorage() const { return d->fusionStorage; } const LinkStorage* CellStorage::linkStorage() const { return d->linkStorage; } const StyleStorage* CellStorage::styleStorage() const { return d->styleStorage; } const UserInputStorage* CellStorage::userInputStorage() const { return d->userInputStorage; } const ValidityStorage* CellStorage::validityStorage() const { return d->validityStorage; } const ValueStorage* CellStorage::valueStorage() const { return d->valueStorage; } void CellStorage::startUndoRecording() { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // If undoData is not null, the recording wasn't stopped. // Should not happen, hence this assertion. Q_ASSERT(d->undoData == 0); d->undoData = new CellStorageUndoData(); } void CellStorage::stopUndoRecording(KUndo2Command *parent) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif // If undoData is null, the recording wasn't started. // Should not happen, hence this assertion. Q_ASSERT(d->undoData != 0); // append sub-commands to the parent command d->createCommand(parent); // needs d->undoData for (int i = 0; i < d->undoData->namedAreas.count(); ++i) { emit namedAreaRemoved(d->undoData->namedAreas[i].second); } delete d->undoData; d->undoData = 0; } void CellStorage::loadConditions(const QList >& conditions) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif d->conditionsStorage->load(conditions); } void CellStorage::loadStyles(const QList > &styles) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif d->styleStorage->load(styles); } void CellStorage::invalidateStyleCache() { d->styleStorage->invalidateCache(); } int CellStorage::rowRepeat(int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->rowRepeatStorage->rowRepeat(row); } int CellStorage::firstIdenticalRow(int row) const { #ifdef CALLIGRA_SHEETS_MT QReadLocker rl(&d->bigUglyLock); #endif return d->rowRepeatStorage->firstIdenticalRow(row); } void CellStorage::setRowsRepeated(int row, int count) { #ifdef CALLIGRA_SHEETS_MT QWriteLocker(&d->bigUglyLock); #endif d->rowRepeatStorage->setRowRepeat(row, count); }