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 <michael.meeks@collabora.com>
Tested-by: Michael Meeks <michael.meeks@collabora.com>
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 1dd462d..83ccf09 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 747d67f..fd4af05 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 20b0ed7..7f95d7f 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -854,6 +854,12 @@ public:
    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 305eeb5..984633c 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; i<maItems.size(); i++)
    {
        ScFormulaCell* p = (ScFormulaCell*) maItems[i].pCell;
        if( p->GetCellType() == 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 02d6e21..6369388 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 b75bdcc..5ebf9b3 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 6c530d3..821ab92 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 );
}