From 20b7476142f75b49d10a75e48429a94cff0cec32 Mon Sep 17 00:00:00 2001 From: Eike Rathke Date: Thu, 23 Jan 2014 22:40:16 +0100 Subject: resolved fdo#71598 postpone SetDirty during Insert/Delete ... until after all listeners are re-established. Change-Id: I9f6036d4bcc9206191959a88ed5439b9860ca268 --- sc/inc/column.hxx | 2 +- sc/inc/formulacell.hxx | 3 +++ sc/inc/table.hxx | 6 +++--- sc/source/core/data/column.cxx | 8 ++++---- sc/source/core/data/document.cxx | 30 ++++++++++++++++-------------- sc/source/core/data/formulacell.cxx | 36 ++++++++++++++++++++++-------------- sc/source/core/data/table2.cxx | 4 ++-- 7 files changed, 51 insertions(+), 38 deletions(-) diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index afe9f6abe828..3127cf49334c 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -445,7 +445,7 @@ public: void MoveListeners( SvtBroadcaster& rSource, SCROW nDestRow ); void StartAllListeners(); void StartNeededListeners(); // only for cells where NeedsListening()==true - void SetRelNameDirty(); + void SetDirtyIfPostponed(); void BroadcastRecalcOnRefMove(); void CompileDBFormula(); diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index dbb52e45b107..68c620cd67c8 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -121,6 +121,7 @@ private: bool bTableOpDirty : 1; // Dirty flag for TableOp bool bNeedListening : 1; // Listeners need to be re-established after UpdateReference bool mbNeedsNumberFormat : 1; // set the calculated number format as hard number format + bool mbPostponedDirty : 1; // if cell needs to be set dirty later enum ScInterpretTailParameter { @@ -371,6 +372,8 @@ public: SCROW GetSharedLength() const; ScTokenArray* GetSharedCode(); const ScTokenArray* GetSharedCode() const; + + bool IsPostponedDirty() const; }; #endif diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 19dbb00d01be..f7d338953e6a 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -882,10 +882,10 @@ public: void StartNeededListeners(); /** - * Mark dirty those formula cells that has named ranges with relative - * references. + * Mark formula cells dirty that have the mbPostponedDirty flag set or + * contain named ranges with relative references. */ - void SetRelNameDirty(); + void SetDirtyIfPostponed(); /** * Broadcast dirty formula cells that contain functions such as CELL(), diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index aafb3149abc0..007e9e317cf2 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -2806,11 +2806,11 @@ struct SetDirtyAfterLoadHandler } }; -struct SetRelNameDirtyHandler +struct SetDirtyIfPostponedHandler { void operator() (size_t /*nRow*/, ScFormulaCell* pCell) { - if (pCell->HasRelNameReference()) + if (pCell->IsPostponedDirty() || pCell->HasRelNameReference()) pCell->SetDirty(); } }; @@ -3144,10 +3144,10 @@ public: } -void ScColumn::SetRelNameDirty() +void ScColumn::SetDirtyIfPostponed() { sc::AutoCalcSwitch aSwitch(*pDocument, false); - SetRelNameDirtyHandler aFunc; + SetDirtyIfPostponedHandler aFunc; sc::ProcessFormula(maCells, aFunc); } diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 4d45f565ffaf..7a4cbf06fa09 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -1167,12 +1167,12 @@ struct StartNeededListenersHandler : std::unary_function } }; -struct SetRelNameDirtyHandler : std::unary_function +struct SetDirtyIfPostponedHandler : std::unary_function { void operator() (ScTable* p) { if (p) - p->SetRelNameDirty(); + p->SetDirtyIfPostponed(); } }; @@ -1262,12 +1262,13 @@ bool ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab, for (; it != maTabs.end(); ++it) if (*it) (*it)->StartNeededListeners(); - // at least all cells using range names pointing relative - // to the moved range must recalculate + // At least all cells using range names pointing relative to the + // moved range must be recalculated, and all cells marked postponed + // dirty. it = maTabs.begin(); for (; it != maTabs.end(); ++it) if (*it) - (*it)->SetRelNameDirty(); + (*it)->SetDirtyIfPostponed(); std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler()); } @@ -1357,12 +1358,12 @@ void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab, for (; it != maTabs.end(); ++it) if (*it) (*it)->StartNeededListeners(); - // at least all cells using range names pointing relative - // to the moved range must recalculate + // At least all cells using range names pointing relative to the moved + // range must be recalculated, and all cells marked postponed dirty. it = maTabs.begin(); for (; it != maTabs.end(); ++it) if (*it) - (*it)->SetRelNameDirty(); + (*it)->SetDirtyIfPostponed(); std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler()); } @@ -1464,9 +1465,10 @@ bool ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab, { // Listeners have been removed in UpdateReference std::for_each(maTabs.begin(), maTabs.end(), StartNeededListenersHandler()); - // at least all cells using range names pointing relative to the - // moved range must recalculate. - std::for_each(maTabs.begin(), maTabs.end(), SetRelNameDirtyHandler()); + // At least all cells using range names pointing relative to the + // moved range must be recalculated, and all cells marked postponed + // dirty. + std::for_each(maTabs.begin(), maTabs.end(), SetDirtyIfPostponedHandler()); // Cells containing functions such as CELL, COLUMN or ROW may have // changed their values on relocation. Broadcast them. std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler()); @@ -1556,12 +1558,12 @@ void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTA for (; it != maTabs.end(); ++it) if (*it) (*it)->StartNeededListeners(); - // at least all cells using range names pointing relative - // to the moved range must recalculate + // At least all cells using range names pointing relative to the moved + // range must be recalculated, and all cells marked postponed dirty. it = maTabs.begin(); for (; it != maTabs.end(); ++it) if (*it) - (*it)->SetRelNameDirty(); + (*it)->SetDirtyIfPostponed(); std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler()); } diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 14ccad41bca4..75f01d2e11dd 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -503,6 +503,7 @@ ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos ) : bTableOpDirty(false), bNeedListening(false), mbNeedsNumberFormat(false), + mbPostponedDirty(false), aPos(rPos) { } @@ -531,6 +532,7 @@ ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, bTableOpDirty( false ), bNeedListening( false ), mbNeedsNumberFormat( false ), + mbPostponedDirty(false), aPos( rPos ) { Compile( rFormula, true, eGrammar ); // bNoListening, Insert does that @@ -562,6 +564,7 @@ ScFormulaCell::ScFormulaCell( bTableOpDirty( false ), bNeedListening( false ), mbNeedsNumberFormat( false ), + mbPostponedDirty(false), aPos( rPos ) { assert(pArray); // Never pass a NULL pointer here. @@ -610,6 +613,7 @@ ScFormulaCell::ScFormulaCell( bTableOpDirty( false ), bNeedListening( false ), mbNeedsNumberFormat( false ), + mbPostponedDirty(false), aPos( rPos ) { // RPN array generation @@ -657,6 +661,7 @@ ScFormulaCell::ScFormulaCell( bTableOpDirty( false ), bNeedListening( false ), mbNeedsNumberFormat( false ), + mbPostponedDirty(false), aPos( rPos ) { if (bSubTotal) @@ -685,6 +690,7 @@ ScFormulaCell::ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, cons bTableOpDirty( false ), bNeedListening( false ), mbNeedsNumberFormat( false ), + mbPostponedDirty(false), aPos( rPos ) { pCode = rCell.pCode->Clone(); @@ -891,7 +897,7 @@ void ScFormulaCell::GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows ) } bool ScFormulaCell::GetDirty() const { return bDirty; } -void ScFormulaCell::ResetDirty() { bDirty = false; } +void ScFormulaCell::ResetDirty() { bDirty = bTableOpDirty = mbPostponedDirty = false; } bool ScFormulaCell::NeedsListening() const { return bNeedListening; } void ScFormulaCell::SetNeedsListening( bool bVar ) { bNeedListening = bVar; } void ScFormulaCell::SetNeedNumberFormat( bool bVal ) { mbNeedsNumberFormat = bVal; } @@ -1290,8 +1296,7 @@ void ScFormulaCell::Interpret() // If one cell didn't converge, all cells of this // circular dependency don't, no matter whether // single cells did. - pIterCell->bDirty = false; - pIterCell->bTableOpDirty = false; + pIterCell->ResetDirty(); pIterCell->aResult.SetResultError( errNoConvergence); pIterCell->bChanged = true; } @@ -1448,8 +1453,7 @@ void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam ) if( p->GetError() && p->GetError() != errCircularReference) { - bDirty = false; - bTableOpDirty = false; + ResetDirty(); bChanged = true; } if (eTailParam == SCITP_FROM_ITERATION && IsDirtyOrInTableOpDirty()) @@ -1472,8 +1476,7 @@ void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam ) if (nSeenInIteration > 1 || pDocument->GetDocOptions().GetIterCount() == 1) { - bDirty = false; - bTableOpDirty = false; + ResetDirty(); } } } @@ -1574,8 +1577,7 @@ void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam ) } if (eTailParam == SCITP_NORMAL) { - bDirty = false; - bTableOpDirty = false; + ResetDirty(); } if( aResult.GetMatrix() ) { @@ -1654,8 +1656,7 @@ void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam ) { // Cells with compiler errors should not be marked dirty forever OSL_ENSURE( pCode->GetCodeError(), "no RPN code und no errors ?!?!" ); - bDirty = false; - bTableOpDirty = false; + ResetDirty(); } } @@ -1757,7 +1758,7 @@ void ScFormulaCell::SetDirty( bool bDirtyFlag ) // by Scenario and Copy Block From Clip. // If unconditional required Formula tracking is set before SetDirty // bDirty = false, eg in CompileTokenArray - if ( !bDirty || !pDocument->IsInFormulaTree( this ) ) + if ( !bDirty || mbPostponedDirty || !pDocument->IsInFormulaTree( this ) ) { if( bDirtyFlag ) SetDirtyVar(); @@ -1774,6 +1775,7 @@ void ScFormulaCell::SetDirty( bool bDirtyFlag ) void ScFormulaCell::SetDirtyVar() { bDirty = true; + mbPostponedDirty = false; if (mxGroup && mxGroup->meCalcState == sc::GroupCalcRunning) mxGroup->meCalcState = sc::GroupCalcEnabled; @@ -2566,8 +2568,9 @@ bool ScFormulaCell::UpdateReferenceOnShift( if (bNeedDirty && !bHasRelName) { // Cut off references, invalid or similar? - sc::AutoCalcSwitch(*pDocument, false); - SetDirty(); + // Postpone SetDirty() until all listeners have been re-established in + // Inserts/Deletes. + mbPostponedDirty = true; } return bCellStateChanged; @@ -3862,4 +3865,9 @@ const ScTokenArray* ScFormulaCell::GetSharedCode() const return mxGroup ? mxGroup->mpCode : NULL; } +bool ScFormulaCell::IsPostponedDirty() const +{ + return mbPostponedDirty; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 27233f77c94e..f96d913b2cc5 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -1670,12 +1670,12 @@ void ScTable::SetDirtyAfterLoad() } -void ScTable::SetRelNameDirty() +void ScTable::SetDirtyIfPostponed() { bool bOldAutoCalc = pDocument->GetAutoCalc(); pDocument->SetAutoCalc( false ); // Mehrfachberechnungen vermeiden for (SCCOL i=0; i<=MAXCOL; i++) - aCol[i].SetRelNameDirty(); + aCol[i].SetDirtyIfPostponed(); pDocument->SetAutoCalc( bOldAutoCalc ); } -- cgit v1.2.3