[Libreoffice-commits] core.git: Branch 'feature/formula-core-rework' - sc/inc sc/source

Kohei Yoshida kohei.yoshida at gmail.com
Thu Jun 27 11:55:25 PDT 2013


 sc/inc/formulacell.hxx              |    9 
 sc/source/core/data/formulacell.cxx |  399 ++++++++++++++++++------------------
 2 files changed, 208 insertions(+), 200 deletions(-)

New commits:
commit f0be3d0ed15179b82910041b827a6313be367a02
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Thu Jun 27 14:57:32 2013 -0400

    Some attempt to clean ScFormulaCell::UpdateReference() a bit.
    
    This method is still a monster, however...
    
    Change-Id: I4aaa2d20c8ae6132a75c7c92c0a1b58882d8a261

diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index b724d02..1f9b960 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -176,11 +176,10 @@ public:
     bool            HasRelNameReference() const;
     bool            HasColRowName() const;
 
-    bool            UpdateReference(UpdateRefMode eUpdateRefMode,
-                                    const ScRange& r,
-                                    SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
-                                    ScDocument* pUndoDoc = NULL,
-                                    const ScAddress* pUndoCellPos = NULL );
+    bool UpdateReference(
+        UpdateRefMode eUpdateRefMode, const ScRange& rRange,
+        SCsCOL nDx, SCsROW nDy, SCsTAB nDz, ScDocument* pUndoDoc = NULL,
+        const ScAddress* pUndoCellPos = NULL );
 
     void            TransposeReference();
     void            UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 96efc40..224bbea 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -46,8 +46,10 @@
 #include "formulagroup.hxx"
 #include "listenercontext.hxx"
 #include "types.hxx"
+#include "scopetools.hxx"
 
 #include <boost/bind.hpp>
+#include <boost/scoped_ptr.hpp>
 
 using namespace formula;
 
@@ -2039,15 +2041,14 @@ bool ScFormulaCell::HasColRowName() const
     return (pCode->GetNextColRowName() != NULL);
 }
 
-bool ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode,
-                                    const ScRange& r,
-                                    SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
-                                    ScDocument* pUndoDoc, const ScAddress* pUndoCellPos )
+bool ScFormulaCell::UpdateReference(
+    UpdateRefMode eUpdateRefMode, const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+    ScDocument* pUndoDoc, const ScAddress* pUndoCellPos )
 {
     bool bCellStateChanged = false;
 
-    SCCOL nCol1 = r.aStart.Col();
-    SCROW nRow1 = r.aStart.Row();
+    SCCOL nCol1 = rRange.aStart.Col();
+    SCROW nRow1 = rRange.aStart.Row();
     SCCOL nCol = aPos.Col();
     SCROW nRow = aPos.Row();
     SCTAB nTab = aPos.Tab();
@@ -2055,15 +2056,21 @@ bool ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode,
     if ( pUndoCellPos )
         aUndoPos = *pUndoCellPos;
     ScAddress aOldPos( aPos );
-    bool bIsInsert = (eUpdateRefMode == URM_INSDEL &&
-                nDx >= 0 && nDy >= 0 && nDz >= 0);
-    if (eUpdateRefMode == URM_INSDEL && r.In( aPos ))
+    bool bIsInsert = (eUpdateRefMode == URM_INSDEL && nDx >= 0 && nDy >= 0 && nDz >= 0);
+
+    if (eUpdateRefMode == URM_INSDEL && rRange.In(aPos))
     {
+        // This formula cell itself is being shifted during cell range
+        // insertion or deletion. Update its position.
         aPos.Move(nDx, nDy, nDz);
         bCellStateChanged = aPos != aOldPos;
     }
-    else if ( r.In( aPos ) )
+    else if (rRange.In(aPos))
     {
+        // The cell is being moved or copied to a new position. I guess the
+        // position has been updated prior to this call?  Determine
+        // its original position before the move which will be used to adjust
+        // relative references later.
         aOldPos.Set( nCol - nDx, nRow - nDy, nTab - nDz );
     }
 
@@ -2072,6 +2079,7 @@ bool ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode,
     bool bOnRefMove = false;
     if ( !pDocument->IsClipOrUndo() )
     {
+        // Check presence of any references or column row names.
         pCode->Reset();
         bHasRefs = (pCode->GetNextReferenceRPN() != NULL);
         if ( !bHasRefs || eUpdateRefMode == URM_COPY )
@@ -2082,218 +2090,219 @@ bool ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode,
         }
         bOnRefMove = pCode->IsRecalcModeOnRefMove();
     }
-    if( bHasRefs || bOnRefMove )
+
+    if (!bHasRefs && !bOnRefMove)
+        // This formula cell contains no references, nor needs recalculating
+        // on reference update. Bail out.
+        return bCellStateChanged;
+
+    boost::scoped_ptr<ScTokenArray> pOldCode;
+    if (pUndoDoc)
+        pOldCode.reset(pCode->Clone());
+
+    ScRangeData* pRangeData = NULL;
+    bool bValChanged = false;
+    bool bRangeModified = false;    // any range, not only shared formula
+    bool bRefSizeChanged = false;
+
+    if (bHasRefs)
     {
-        ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL;
-        ScRangeData* pRangeData;
-        bool bValChanged = false;
-        bool bRangeModified = false;    // any range, not only shared formula
-        bool bRefSizeChanged = false;
-        if ( bHasRefs )
-        {
-            ScCompiler aComp(pDocument, aPos, *pCode);
-            aComp.SetGrammar(pDocument->GetGrammar());
-            pRangeData = aComp.UpdateReference(eUpdateRefMode, aOldPos, r,
-                                             nDx, nDy, nDz,
-                                             bValChanged, bRefSizeChanged);
-            bRangeModified = aComp.HasModifiedRange();
-        }
-        else
-        {
-            bValChanged = false;
-            pRangeData = NULL;
-            bRangeModified = false;
-            bRefSizeChanged = false;
-        }
+        // Update cell or range references.
+        ScCompiler aComp(pDocument, aPos, *pCode);
+        aComp.SetGrammar(pDocument->GetGrammar());
+        pRangeData = aComp.UpdateReference(eUpdateRefMode, aOldPos, rRange,
+                                         nDx, nDy, nDz,
+                                         bValChanged, bRefSizeChanged);
+        bRangeModified = aComp.HasModifiedRange();
+    }
+
+    bCellStateChanged |= bValChanged;
 
-        bCellStateChanged |= bValChanged;
+    if (bOnRefMove)
+        // Cell may reference itself, e.g. ocColumn, ocRow without parameter
+        bOnRefMove = (bValChanged || (aPos != aOldPos));
 
-        if ( bOnRefMove )
-            bOnRefMove = (bValChanged || (aPos != aOldPos));
-            // Cell may reference itself, e.g. ocColumn, ocRow without parameter
+    bool bColRowNameCompile = false;
+    bool bHasRelName = false;
+    bool bNewListening = false;
+    bool bInDeleteUndo = false;
 
-        bool bColRowNameCompile, bHasRelName, bNewListening, bInDeleteUndo;
-        if ( bHasRefs )
+    if (bHasRefs)
+    {
+        // Upon Insert ColRowNames have to be recompiled in case the
+        // insertion occurs right in front of the range.
+        bColRowNameCompile =
+            (eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0));
+
+        if ( bColRowNameCompile )
         {
-            // Upon Insert ColRowNames have to be recompiled in case the
-            // insertion occurs right in front of the range.
-            bColRowNameCompile =
-                (eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0));
-            if ( bColRowNameCompile )
+            bColRowNameCompile = false;
+            ScToken* t;
+            ScRangePairList* pColList = pDocument->GetColNameRanges();
+            ScRangePairList* pRowList = pDocument->GetRowNameRanges();
+            pCode->Reset();
+            while ( !bColRowNameCompile && (t = static_cast<ScToken*>(pCode->GetNextColRowName())) != NULL )
             {
-                bColRowNameCompile = false;
-                ScToken* t;
-                ScRangePairList* pColList = pDocument->GetColNameRanges();
-                ScRangePairList* pRowList = pDocument->GetRowNameRanges();
-                pCode->Reset();
-                while ( !bColRowNameCompile && (t = static_cast<ScToken*>(pCode->GetNextColRowName())) != NULL )
-                {
-                    ScSingleRefData& rRef = t->GetSingleRef();
-                    if ( nDy > 0 && rRef.IsColRel() )
-                    {   // ColName
-                        rRef.CalcAbsIfRel( aPos );
-                        ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
-                        ScRangePair* pR = pColList->Find( aAdr );
-                        if ( pR )
-                        {   // defined
-                            if ( pR->GetRange(1).aStart.Row() == nRow1 )
-                                bColRowNameCompile = true;
-                        }
-                        else
-                        {   // on the fly
-                            if ( rRef.nRow + 1 == nRow1 )
-                                bColRowNameCompile = true;
-                        }
+                ScSingleRefData& rRef = t->GetSingleRef();
+                if ( nDy > 0 && rRef.IsColRel() )
+                {   // ColName
+                    rRef.CalcAbsIfRel( aPos );
+                    ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
+                    ScRangePair* pR = pColList->Find( aAdr );
+                    if ( pR )
+                    {   // defined
+                        if ( pR->GetRange(1).aStart.Row() == nRow1 )
+                            bColRowNameCompile = true;
                     }
-                    if ( nDx > 0 && rRef.IsRowRel() )
-                    {   // RowName
-                        rRef.CalcAbsIfRel( aPos );
-                        ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
-                        ScRangePair* pR = pRowList->Find( aAdr );
-                        if ( pR )
-                        {   // defined
-                            if ( pR->GetRange(1).aStart.Col() == nCol1 )
-                                bColRowNameCompile = true;
-                        }
-                        else
-                        {   // on the fly
-                            if ( rRef.nCol + 1 == nCol1 )
-                                bColRowNameCompile = true;
-                        }
+                    else
+                    {   // on the fly
+                        if ( rRef.nRow + 1 == nRow1 )
+                            bColRowNameCompile = true;
+                    }
+                }
+                if ( nDx > 0 && rRef.IsRowRel() )
+                {   // RowName
+                    rRef.CalcAbsIfRel( aPos );
+                    ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
+                    ScRangePair* pR = pRowList->Find( aAdr );
+                    if ( pR )
+                    {   // defined
+                        if ( pR->GetRange(1).aStart.Col() == nCol1 )
+                            bColRowNameCompile = true;
+                    }
+                    else
+                    {   // on the fly
+                        if ( rRef.nCol + 1 == nCol1 )
+                            bColRowNameCompile = true;
                     }
                 }
             }
-            else if ( eUpdateRefMode == URM_MOVE )
-            {   // Recomplie for Move/D&D when ColRowName was moved or this Cell
-                // points to one and was moved.
-                bColRowNameCompile = bCompile;      // Possibly from Copy ctor
-                if ( !bColRowNameCompile )
+        }
+        else if ( eUpdateRefMode == URM_MOVE )
+        {   // Recomplie for Move/D&D when ColRowName was moved or this Cell
+            // points to one and was moved.
+            bColRowNameCompile = bCompile;      // Possibly from Copy ctor
+            if ( !bColRowNameCompile )
+            {
+                bool bMoved = (aPos != aOldPos);
+                pCode->Reset();
+                ScToken* t = static_cast<ScToken*>(pCode->GetNextColRowName());
+                if ( t && bMoved )
+                    bColRowNameCompile = true;
+                while ( t && !bColRowNameCompile )
                 {
-                    bool bMoved = (aPos != aOldPos);
-                    pCode->Reset();
-                    ScToken* t = static_cast<ScToken*>(pCode->GetNextColRowName());
-                    if ( t && bMoved )
-                        bColRowNameCompile = true;
-                    while ( t && !bColRowNameCompile )
+                    ScSingleRefData& rRef = t->GetSingleRef();
+                    rRef.CalcAbsIfRel( aPos );
+                    if ( rRef.Valid() )
                     {
-                        ScSingleRefData& rRef = t->GetSingleRef();
-                        rRef.CalcAbsIfRel( aPos );
-                        if ( rRef.Valid() )
-                        {
-                            ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
-                            if ( r.In( aAdr ) )
-                                bColRowNameCompile = true;
-                        }
-                        t = static_cast<ScToken*>(pCode->GetNextColRowName());
+                        ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
+                        if ( rRange.In( aAdr ) )
+                            bColRowNameCompile = true;
                     }
+                    t = static_cast<ScToken*>(pCode->GetNextColRowName());
                 }
             }
-            else if ( eUpdateRefMode == URM_COPY && bHasColRowNames && bValChanged )
-            {
-                bColRowNameCompile = true;
-            }
-            ScChangeTrack* pChangeTrack = pDocument->GetChangeTrack();
-            if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
-                bInDeleteUndo = true;
-            else
-                bInDeleteUndo = false;
-            // RelNameRefs are always moved
-            bHasRelName = HasRelNameReference();
-            // Reference changed and new listening needed?
-            // Except in Insert/Delete without specialties.
-            bNewListening = (bRangeModified || pRangeData || bColRowNameCompile
-                    || (bValChanged && (eUpdateRefMode != URM_INSDEL ||
-                            bInDeleteUndo || bRefSizeChanged)) ||
-                    (bHasRelName && eUpdateRefMode != URM_COPY))
-                // #i36299# Don't duplicate action during cut&paste / drag&drop
-                // on a cell in the range moved, start/end listeners is done
-                // via ScDocument::DeleteArea() and ScDocument::CopyFromClip().
-                && !(eUpdateRefMode == URM_MOVE &&
-                        pDocument->IsInsertingFromOtherDoc() && r.In(aPos));
-            if ( bNewListening )
-                EndListeningTo( pDocument, pOld, aOldPos );
         }
-        else
+        else if ( eUpdateRefMode == URM_COPY && bHasColRowNames && bValChanged )
         {
-            bColRowNameCompile = bHasRelName = bNewListening = bInDeleteUndo =
-                false;
+            bColRowNameCompile = true;
         }
 
-        bool bNeedDirty = false;
-        // NeedDirty for changes except for Copy and Move/Insert without RelNames
-        if ( bRangeModified || pRangeData || bColRowNameCompile ||
-                (bValChanged && eUpdateRefMode != URM_COPY &&
-                 (eUpdateRefMode != URM_MOVE || bHasRelName) &&
-                 (!bIsInsert || bHasRelName || bInDeleteUndo ||
-                  bRefSizeChanged)) || bOnRefMove)
-            bNeedDirty = true;
-        else
-            bNeedDirty = false;
-        if (pUndoDoc && (bValChanged || pRangeData || bOnRefMove))
-        {
-            // Copy the cell to aUndoPos, which is its current position in the document,
-            // so this works when UpdateReference is called before moving the cells
-            // (InsertCells/DeleteCells - aPos is changed above) as well as when UpdateReference
-            // is called after moving the cells (MoveBlock/PasteFromClip - aOldPos is changed).
+        ScChangeTrack* pChangeTrack = pDocument->GetChangeTrack();
+        bInDeleteUndo = (pChangeTrack && pChangeTrack->IsInDeleteUndo());
 
-            // If there is already a formula cell in the undo document, don't overwrite it,
-            // the first (oldest) is the important cell.
-            if ( pUndoDoc->GetCellType( aUndoPos ) != CELLTYPE_FORMULA )
-            {
-                ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aUndoPos,
-                        pOld, eTempGrammar, cMatrixFlag );
-                pFCell->aResult.SetToken( NULL);  // to recognize it as changed later (Cut/Paste!)
-                pUndoDoc->SetFormulaCell(aUndoPos, pFCell);
-            }
-        }
-        bValChanged = false;
-        if ( pRangeData )
-        {   // Replace shared formula with own formula
-            pDocument->RemoveFromFormulaTree( this );   // update formula count
-            delete pCode;
-            pCode = pRangeData->GetCode()->Clone();
-            // #i18937# #i110008# call MoveRelWrap, but with the old position
-            ScCompiler::MoveRelWrap(*pCode, pDocument, aOldPos, pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
-            ScCompiler aComp2(pDocument, aPos, *pCode);
-            aComp2.SetGrammar(pDocument->GetGrammar());
-            aComp2.UpdateSharedFormulaReference( eUpdateRefMode, aOldPos, r,
-                nDx, nDy, nDz );
-            bValChanged = true;
-            bNeedDirty = true;
-        }
-        if ( ( bCompile = (bCompile || bValChanged || bRangeModified || bColRowNameCompile) ) != 0 )
+        // RelNameRefs are always moved
+        bHasRelName = HasRelNameReference();
+        // Reference changed and new listening needed?
+        // Except in Insert/Delete without specialties.
+        bNewListening = (bRangeModified || pRangeData || bColRowNameCompile
+                || (bValChanged && (eUpdateRefMode != URM_INSDEL ||
+                        bInDeleteUndo || bRefSizeChanged)) ||
+                (bHasRelName && eUpdateRefMode != URM_COPY))
+            // #i36299# Don't duplicate action during cut&paste / drag&drop
+            // on a cell in the range moved, start/end listeners is done
+            // via ScDocument::DeleteArea() and ScDocument::CopyFromClip().
+            && !(eUpdateRefMode == URM_MOVE &&
+                    pDocument->IsInsertingFromOtherDoc() && rRange.In(aPos));
+
+        if ( bNewListening )
+            EndListeningTo(pDocument, pOldCode.get(), aOldPos);
+    }
+
+    bool bNeedDirty = false;
+    // NeedDirty for changes except for Copy and Move/Insert without RelNames
+    if ( bRangeModified || pRangeData || bColRowNameCompile ||
+            (bValChanged && eUpdateRefMode != URM_COPY &&
+             (eUpdateRefMode != URM_MOVE || bHasRelName) &&
+             (!bIsInsert || bHasRelName || bInDeleteUndo ||
+              bRefSizeChanged)) || bOnRefMove)
+        bNeedDirty = true;
+
+    if (pUndoDoc && (bValChanged || pRangeData || bOnRefMove))
+    {
+        // Copy the cell to aUndoPos, which is its current position in the document,
+        // so this works when UpdateReference is called before moving the cells
+        // (InsertCells/DeleteCells - aPos is changed above) as well as when UpdateReference
+        // is called after moving the cells (MoveBlock/PasteFromClip - aOldPos is changed).
+
+        // If there is already a formula cell in the undo document, don't overwrite it,
+        // the first (oldest) is the important cell.
+        if ( pUndoDoc->GetCellType( aUndoPos ) != CELLTYPE_FORMULA )
         {
-            CompileTokenArray( bNewListening ); // no Listening
-            bNeedDirty = true;
+            ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aUndoPos,
+                    pOldCode.get(), eTempGrammar, cMatrixFlag );
+            pFCell->aResult.SetToken( NULL);  // to recognize it as changed later (Cut/Paste!)
+            pUndoDoc->SetFormulaCell(aUndoPos, pFCell);
         }
-        if ( !bInDeleteUndo )
-        {   // In ChangeTrack Delete-Reject listeners are established in
-            // InsertCol/InsertRow
-            if ( bNewListening )
+    }
+
+    bValChanged = false;
+
+    if ( pRangeData )
+    {   // Replace shared formula with own formula
+        pDocument->RemoveFromFormulaTree( this );   // update formula count
+        delete pCode;
+        pCode = pRangeData->GetCode()->Clone();
+        // #i18937# #i110008# call MoveRelWrap, but with the old position
+        ScCompiler::MoveRelWrap(*pCode, pDocument, aOldPos, pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
+        ScCompiler aComp2(pDocument, aPos, *pCode);
+        aComp2.SetGrammar(pDocument->GetGrammar());
+        aComp2.UpdateSharedFormulaReference( eUpdateRefMode, aOldPos, rRange,
+            nDx, nDy, nDz );
+        bValChanged = true;
+        bNeedDirty = true;
+    }
+
+    if ( ( bCompile = (bCompile || bValChanged || bRangeModified || bColRowNameCompile) ) != 0 )
+    {
+        CompileTokenArray( bNewListening ); // no Listening
+        bNeedDirty = true;
+    }
+
+    if ( !bInDeleteUndo )
+    {   // In ChangeTrack Delete-Reject listeners are established in
+        // InsertCol/InsertRow
+        if ( bNewListening )
+        {
+            if ( eUpdateRefMode == URM_INSDEL )
             {
-                if ( eUpdateRefMode == URM_INSDEL )
-                {
-                    // Inserts/Deletes re-establish listeners after all
-                    // UpdateReference calls.
-                    // All replaced shared formula listeners have to be
-                    // established after an Insert or Delete. Do nothing here.
-                    SetNeedsListening( true);
-                }
-                else
-                    StartListeningTo( pDocument );
+                // Inserts/Deletes re-establish listeners after all
+                // UpdateReference calls.
+                // All replaced shared formula listeners have to be
+                // established after an Insert or Delete. Do nothing here.
+                SetNeedsListening( true);
             }
+            else
+                StartListeningTo( pDocument );
         }
-        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 );
-        }
+    }
 
-        delete pOld;
+    if ( bNeedDirty && (!(eUpdateRefMode == URM_INSDEL && bHasRelName) || pRangeData) )
+    {   // Cut off references, invalid or similar?
+        sc::AutoCalcSwitch(*pDocument, false);
+        SetDirty();
     }
+
     return bCellStateChanged;
 }
 


More information about the Libreoffice-commits mailing list