From b99a2691484e9b0533530ad4f02e15ad4031b74b 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. (cherry picked from commit 20b7476142f75b49d10a75e48429a94cff0cec32) Conflicts: sc/inc/formulacell.hxx sc/inc/table.hxx sc/source/core/data/column.cxx sc/source/core/data/document.cxx sc/source/core/data/formulacell.cxx Backported. Change-Id: I9f6036d4bcc9206191959a88ed5439b9860ca268 Reviewed-on: https://gerrit.libreoffice.org/7624 Reviewed-by: Michael Meeks Tested-by: Michael Meeks --- sc/inc/column.hxx | 2 +- sc/inc/formulacell.hxx | 5 ++++- sc/inc/table.hxx | 7 ++++++- sc/source/core/data/column.cxx | 4 ++-- sc/source/core/data/document.cxx | 26 +++++++++++++----------- sc/source/core/data/formulacell.cxx | 40 +++++++++++++++++++++---------------- sc/source/core/data/table2.cxx | 4 ++-- 7 files changed, 52 insertions(+), 36 deletions(-) (limited to 'sc') diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 1dd462d1b7b4..83ccf09589d3 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -446,7 +446,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 747d67f977d6..fd4af058f41d 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -90,6 +90,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 { @@ -149,7 +150,7 @@ public: void SetTableOpDirty(); bool IsDirtyOrInTableOpDirty() const; bool GetDirty() const { return bDirty; } - void ResetDirty() { bDirty = false; } + void ResetDirty() { bDirty = bTableOpDirty = mbPostponedDirty = false; } bool NeedsListening() const { return bNeedListening; } void SetNeedsListening( bool bVar ) { bNeedListening = bVar; } void SetNeedNumberFormat( bool bVal ) { mbNeedsNumberFormat = bVal; } @@ -304,6 +305,8 @@ public: void EndListeningTo( ScDocument* pDoc, ScTokenArray* pArr = NULL, ScAddress aPos = ScAddress() ); void EndListeningTo( sc::EndListeningContext& rCxt ); + + bool IsPostponedDirty() const { return mbPostponedDirty; } }; #endif diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 20b0ed7bda67..7f95d7f58bdd 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -853,6 +853,12 @@ public: void DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, SCCOL nCol, SCROW nRow1, SCROW nRow2 ); bool HasBroadcaster( SCCOL nCol ) const; + /** + * Mark formula cells dirty that have the mbPostponedDirty flag set or + * contain named ranges with relative references. + */ + void SetDirtyIfPostponed(); + /** * Broadcast dirty formula cells that contain functions such as CELL(), * COLUMN() or ROW() which may change its value on move. @@ -961,7 +967,6 @@ private: void EndListening( sc::EndListeningContext& rCxt, SCCOL nCol, SCROW nRow, SvtListener& rListener ); void StartAllListeners(); void StartNeededListeners(); // only for cells where NeedsListening()==TRUE - void SetRelNameDirty(); void SetLoadingMedium(bool bLoading); diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 305eeb50caaa..984633ce454b 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -2168,14 +2168,14 @@ void ScColumn::SetDirtyAfterLoad() } -void ScColumn::SetRelNameDirty() +void ScColumn::SetDirtyIfPostponed() { bool bOldAutoCalc = pDocument->GetAutoCalc(); pDocument->SetAutoCalc( false ); // no multiple recalculation for (SCSIZE i=0; iGetCellType() == CELLTYPE_FORMULA && p->HasRelNameReference() ) + if( p->GetCellType() == CELLTYPE_FORMULA && (p->IsPostponedDirty() || p->HasRelNameReference()) ) p->SetDirty(); } pDocument->SetAutoCalc( bOldAutoCalc ); diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 02d6e21e35bc..6369388f159b 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -1200,12 +1200,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(); // Cells containing functions such as CELL, COLUMN or ROW may have // changed their values on relocation. Broadcast them. @@ -1295,12 +1296,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(); // Cells containing functions such as CELL, COLUMN or ROW may have // changed their values on relocation. Broadcast them. @@ -1404,12 +1405,13 @@ bool ScDocument::InsertCol( SCROW nStartRow, 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(); // Cells containing functions such as CELL, COLUMN or ROW may have // changed their values on relocation. Broadcast them. @@ -1497,12 +1499,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(); // Cells containing functions such as CELL, COLUMN or ROW may have // changed their values on relocation. Broadcast them. diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index b75bdcc08f06..5ebf9b337fbc 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -414,6 +414,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 @@ -448,6 +449,7 @@ ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, bTableOpDirty( false ), bNeedListening( false ), mbNeedsNumberFormat( false ), + mbPostponedDirty(false), aPos( rPos ) { // UPN-Array generation @@ -494,6 +496,7 @@ ScFormulaCell::ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, cons bTableOpDirty( false ), bNeedListening( false ), mbNeedsNumberFormat( false ), + mbPostponedDirty(false), aPos( rPos ) { pCode = rCell.pCode->Clone(); @@ -1094,8 +1097,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; pDocument->SetTextWidth(pIterCell->aPos, TEXTWIDTH_DIRTY); @@ -1251,8 +1253,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()) @@ -1275,8 +1276,7 @@ void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam ) if (nSeenInIteration > 1 || pDocument->GetDocOptions().GetIterCount() == 1) { - bDirty = false; - bTableOpDirty = false; + ResetDirty(); } } } @@ -1377,8 +1377,7 @@ void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam ) } if (eTailParam == SCITP_NORMAL) { - bDirty = false; - bTableOpDirty = false; + ResetDirty(); } if( aResult.GetMatrix() ) { @@ -1460,9 +1459,8 @@ void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam ) else { // Cells with compiler errors should not be marked dirty forever - OSL_ENSURE( pCode->GetCodeError(), "no UPN-Code und no errors ?!?!" ); - bDirty = false; - bTableOpDirty = false; + OSL_ENSURE( pCode->GetCodeError(), "no RPN code und no errors ?!?!" ); + ResetDirty(); } } @@ -1546,7 +1544,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(); @@ -1563,6 +1561,7 @@ void ScFormulaCell::SetDirty( bool bDirtyFlag ) void ScFormulaCell::SetDirtyVar() { bDirty = true; + mbPostponedDirty = false; // mark the sheet of this cell to be calculated //#FIXME do we need to revert this remnant of old fake vba events? pDocument->AddCalculateTable( aPos.Tab() ); } @@ -2293,11 +2292,18 @@ bool ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode, } if ( bNeedDirty && (!(eUpdateRefMode == URM_INSDEL && bHasRelName) || pRangeData) ) { // Cut off references, invalid or similar? - bool bOldAutoCalc = pDocument->GetAutoCalc(); - // No Interpret in SubMinimalRecalc because of eventual wrong reference - pDocument->SetAutoCalc( false ); - SetDirty(); - pDocument->SetAutoCalc( bOldAutoCalc ); + if (eUpdateRefMode == URM_INSDEL) + { + mbPostponedDirty = true; + } + else + { + bool bOldAutoCalc = pDocument->GetAutoCalc(); + // No Interpret in SubMinimalRecalc because of eventual wrong reference + pDocument->SetAutoCalc( false ); + SetDirty(); + pDocument->SetAutoCalc( bOldAutoCalc ); + } } delete pOld; diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 6c530d350e1a..821ab9261c76 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