From 1bfbe2a44021ca4ae6716caa39fc8a375914be5c Mon Sep 17 00:00:00 2001 From: Dennis Francis Date: Sat, 4 May 2019 21:49:44 +0530 Subject: [PATCH] tdf#99938 : Allow batch of formula-cells to be written... using a single undo document from ScMovingAverageDialog rather than write tons of formula-cells to the document one by one thus creating that many number of undo docs unnecessarily. Change-Id: I2528e0ab47f83e0c5ea40c73d00db5af14f656e0 Reviewed-on: https://gerrit.libreoffice.org/71823 Tested-by: Jenkins Reviewed-by: Eike Rathke --- sc/inc/cellvalues.hxx | 2 + sc/source/core/data/cellvalues.cxx | 24 +++++++++- .../ui/StatisticsDialogs/MovingAverageDialog.cxx | 8 ++-- .../TableFillingAndNavigationTools.cxx | 22 +++++++++ sc/source/ui/docshell/docfunc.cxx | 55 ++++++++++++++++++++++ .../ui/inc/TableFillingAndNavigationTools.hxx | 1 + sc/source/ui/inc/docfunc.hxx | 3 +- sc/source/ui/inc/undocell.hxx | 2 + sc/source/ui/undo/undocell2.cxx | 6 +++ 9 files changed, 117 insertions(+), 6 deletions(-) diff --git a/sc/inc/cellvalues.hxx b/sc/inc/cellvalues.hxx index 431239835271..4b877c661a1e 100644 --- a/sc/inc/cellvalues.hxx +++ b/sc/inc/cellvalues.hxx @@ -15,6 +15,7 @@ #include class ScColumn; +class ScFormulaCell; namespace svl { @@ -63,6 +64,7 @@ public: void swapNonEmpty( ScColumn& rCol ); void assign( const std::vector& rVals ); + void assign( const std::vector& rVals ); size_t size() const; diff --git a/sc/source/core/data/cellvalues.cxx b/sc/source/core/data/cellvalues.cxx index 83c01a9080ca..290dc0d091a9 100644 --- a/sc/source/core/data/cellvalues.cxx +++ b/sc/source/core/data/cellvalues.cxx @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -98,6 +99,25 @@ void CellValues::assign( const std::vector& rVals ) mpImpl->maCellTextAttrs.set(0, aDefaults.begin(), aDefaults.end()); } +void CellValues::assign( const std::vector& rVals ) +{ + std::vector aCopyVals(rVals.size()); + size_t nIdx = 0; + for (const auto* pCell : rVals) + { + aCopyVals[nIdx] = pCell->Clone(); + ++nIdx; + } + + mpImpl->maCells.resize(aCopyVals.size()); + mpImpl->maCells.set(0, aCopyVals.begin(), aCopyVals.end()); + + // Set default text attributes. + std::vector aDefaults(rVals.size(), CellTextAttr()); + mpImpl->maCellTextAttrs.resize(rVals.size()); + mpImpl->maCellTextAttrs.set(0, aDefaults.begin(), aDefaults.end()); +} + size_t CellValues::size() const { assert(mpImpl->maCells.size() == mpImpl->maCellTextAttrs.size()); @@ -154,7 +174,7 @@ void CellValues::copyCellsTo( ScColumn& rCol, SCROW nRow ) const const CellStoreType& rSrc = mpImpl->maCells; // Caller must ensure the destination is long enough. - assert(rSrc.size() + static_cast(nRow) < rDest.size()); + assert(rSrc.size() + static_cast(nRow) <= rDest.size()); SCROW nCurRow = nRow; CellStoreType::iterator itPos = rDest.begin(); @@ -219,7 +239,7 @@ void CellValues::copyCellTextAttrsTo( ScColumn& rCol, SCROW nRow ) const const CellTextAttrStoreType& rSrc = mpImpl->maCellTextAttrs; // Caller must ensure the destination is long enough. - assert(rSrc.size() + static_cast(nRow) < rDest.size()); + assert(rSrc.size() + static_cast(nRow) <= rDest.size()); SCROW nCurRow = nRow; CellTextAttrStoreType::iterator itPos = rDest.begin(); diff --git a/sc/source/ui/StatisticsDialogs/MovingAverageDialog.cxx b/sc/source/ui/StatisticsDialogs/MovingAverageDialog.cxx index 4f4d5960e199..4d59e28336c7 100644 --- a/sc/source/ui/StatisticsDialogs/MovingAverageDialog.cxx +++ b/sc/source/ui/StatisticsDialogs/MovingAverageDialog.cxx @@ -75,6 +75,7 @@ ScRange ScMovingAverageDialog::ApplyOutput(ScDocShell* pDocShell) output.nextRow(); DataCellIterator aDataCellIterator = pIterator->iterateCells(); + std::vector aFormulas; for (; aDataCellIterator.hasNext(); aDataCellIterator.next()) { @@ -98,14 +99,15 @@ ScRange ScMovingAverageDialog::ApplyOutput(ScDocShell* pDocShell) { aTemplate.setTemplate("=AVERAGE(%RANGE%)"); aTemplate.applyRange("%RANGE%", ScRange(aIntervalStart, aIntervalEnd)); - output.writeFormula(aTemplate.getTemplate()); + aFormulas.push_back(aTemplate.getTemplate()); } else { - output.writeFormula("=#N/A"); + aFormulas.push_back("=#N/A"); } - output.nextRow(); } + + output.writeFormulas(aFormulas); output.nextColumn(); } return ScRange(output.mMinimumAddress, output.mMaximumAddress); diff --git a/sc/source/ui/StatisticsDialogs/TableFillingAndNavigationTools.cxx b/sc/source/ui/StatisticsDialogs/TableFillingAndNavigationTools.cxx index 15936bc2d518..f793417f04a7 100644 --- a/sc/source/ui/StatisticsDialogs/TableFillingAndNavigationTools.cxx +++ b/sc/source/ui/StatisticsDialogs/TableFillingAndNavigationTools.cxx @@ -163,6 +163,28 @@ void AddressWalkerWriter::writeFormula(const OUString& aFormula) new ScFormulaCell(mpDocument, mCurrentAddress, aFormula, meGrammar), true); } +void AddressWalkerWriter::writeFormulas(const std::vector& rFormulas) +{ + size_t nLength = rFormulas.size(); + if (!nLength) + return; + + const size_t nMaxLen = MAXROW - mCurrentAddress.Row() + 1; + // If not done already, trim the length to fit. + if (nLength > nMaxLen) + nLength = nMaxLen; + + std::vector aFormulaCells(nLength); + ScAddress aAddr(mCurrentAddress); + for (size_t nIdx = 0; nIdx < nLength; ++nIdx) + { + aFormulaCells[nIdx] = new ScFormulaCell(mpDocument, aAddr, rFormulas[nIdx], meGrammar); + aAddr.IncRow(1); + } + + mpDocShell->GetDocFunc().SetFormulaCells(mCurrentAddress, aFormulaCells, true); +} + void AddressWalkerWriter::writeMatrixFormula(const OUString& aFormula, SCCOL nCols, SCROW nRows) { ScRange aRange; diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx index 1df41fa5903c..a5a61830f0fc 100644 --- a/sc/source/ui/docshell/docfunc.cxx +++ b/sc/source/ui/docshell/docfunc.cxx @@ -1023,6 +1023,61 @@ bool ScDocFunc::SetFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell, boo return true; } +bool ScDocFunc::SetFormulaCells( const ScAddress& rPos, std::vector& rCells, bool bInteraction ) +{ + const size_t nLength = rCells.size(); + if (rPos.Row() + nLength - 1 > MAXROW) + // out of bound + return false; + + ScRange aRange(rPos); + aRange.aEnd.IncRow(nLength - 1); + + ScDocShellModificator aModificator( rDocShell ); + ScDocument& rDoc = rDocShell.GetDocument(); + bool bUndo = rDoc.IsUndoEnabled(); + + std::unique_ptr pUndoObj; + if (bUndo) + { + pUndoObj.reset(new sc::UndoSetCells(&rDocShell, rPos)); + rDoc.TransferCellValuesTo(rPos, nLength, pUndoObj->GetOldValues()); + } + + rDoc.SetFormulaCells(rPos, rCells); + + // For performance reasons API calls may disable calculation while + // operating and recalculate once when done. If through user interaction + // and AutoCalc is disabled, calculate the formula (without its + // dependencies) once so the result matches the current document's content. + if (bInteraction && !rDoc.GetAutoCalc()) + { + for (auto* pCell : rCells) + { + // calculate just the cell once and set Dirty again + pCell->Interpret(); + pCell->SetDirtyVar(); + rDoc.PutInFormulaTree( pCell); + } + } + + if (bUndo) + { + pUndoObj->SetNewValues(rCells); + SfxUndoManager* pUndoMgr = rDocShell.GetUndoManager(); + pUndoMgr->AddUndoAction(std::move(pUndoObj)); + } + + rDocShell.PostPaint(aRange, PaintPartFlags::Grid); + aModificator.SetDocumentModified(); + + // #103934#; notify editline and cell in edit mode + if (!bInteraction) + NotifyInputHandler( rPos ); + + return true; +} + void ScDocFunc::NotifyInputHandler( const ScAddress& rPos ) { ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); diff --git a/sc/source/ui/inc/TableFillingAndNavigationTools.hxx b/sc/source/ui/inc/TableFillingAndNavigationTools.hxx index dd5cdcae1e51..d1d75d248c94 100644 --- a/sc/source/ui/inc/TableFillingAndNavigationTools.hxx +++ b/sc/source/ui/inc/TableFillingAndNavigationTools.hxx @@ -80,6 +80,7 @@ public: formula::FormulaGrammar::Grammar eGrammar ); void writeFormula(const OUString& aFormula); + void writeFormulas(const std::vector& rFormulas); void writeMatrixFormula(const OUString& aFormula, SCCOL nCols = 1, SCROW nRows = 1); void writeString(const OUString& aString); void writeString(const char* aCharArray); diff --git a/sc/source/ui/inc/docfunc.hxx b/sc/source/ui/inc/docfunc.hxx index 28da723907a3..bf07e230cea8 100644 --- a/sc/source/ui/inc/docfunc.hxx +++ b/sc/source/ui/inc/docfunc.hxx @@ -104,10 +104,11 @@ public: bool SetStringOrEditCell( const ScAddress& rPos, const OUString& rStr, bool bInteraction ); /** - * This method takes ownership of the formula cell instance. The caller + * Below two methods take ownership of the formula cell instance(s). The caller * must not delete it after passing it to this call. */ bool SetFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell, bool bInteraction ); + bool SetFormulaCells( const ScAddress& rPos, std::vector& rCells, bool bInteraction ); void PutData( const ScAddress& rPos, ScEditEngineDefaulter& rEngine, bool bApi ); bool SetCellText( const ScAddress& rPos, const OUString& rText, bool bInterpret, bool bEnglish, bool bApi, diff --git a/sc/source/ui/inc/undocell.hxx b/sc/source/ui/inc/undocell.hxx index 6eb30ee3ff40..c62ea7205304 100644 --- a/sc/source/ui/inc/undocell.hxx +++ b/sc/source/ui/inc/undocell.hxx @@ -32,6 +32,7 @@ class ScDocShell; class ScPatternAttr; class ScRangeName; +class ScFormulaCell; class ScUndoCursorAttr: public ScSimpleUndo { @@ -361,6 +362,7 @@ public: CellValues& GetOldValues() { return maOldValues;} void SetNewValues( const std::vector& rVals ); + void SetNewValues( const std::vector& rVals ); }; } // namespace sc diff --git a/sc/source/ui/undo/undocell2.cxx b/sc/source/ui/undo/undocell2.cxx index da7c2ddaa0f1..2222afa4224c 100644 --- a/sc/source/ui/undo/undocell2.cxx +++ b/sc/source/ui/undo/undocell2.cxx @@ -11,6 +11,7 @@ #include #include #include +#include namespace sc { @@ -60,6 +61,11 @@ void UndoSetCells::SetNewValues( const std::vector& rVals ) maNewValues.assign(rVals); } +void UndoSetCells::SetNewValues( const std::vector& rVals ) +{ + maNewValues.assign(rVals); +} + } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- 2.11.4.GIT