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

Kohei Yoshida kohei.yoshida at gmail.com
Thu Jul 25 18:19:38 PDT 2013


 sc/inc/tokenarray.hxx               |    2 
 sc/qa/unit/ucalc_formula.cxx        |   50 ++++++++++++++++++++++++
 sc/source/core/data/formulacell.cxx |   34 +++++-----------
 sc/source/core/tool/token.cxx       |   73 ++++++++++++++++++++++++++++++++++++
 4 files changed, 136 insertions(+), 23 deletions(-)

New commits:
commit 60e9f263676c3c10cc0fcfbfc6f80c895f289e9c
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Thu Jul 25 21:19:51 2013 -0400

    Re-implement sheet reference adjustment on sheet move.
    
    Change-Id: I24e93e0bbc51c7f9a1f1ea0c126a1399ace84a9e

diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index 1e8ced1..b3fb5ef 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -145,6 +145,8 @@ public:
 
     bool AdjustReferenceOnInsertedTab( SCTAB nInsPos, SCTAB nSheets, const ScAddress& rOldPos );
 
+    void AdjustReferenceOnMovedTab( SCTAB nOldPos, SCTAB nNewPos, const ScAddress& rOldPos );
+
 #if DEBUG_FORMULA_COMPILER
     void Dump() const;
 #endif
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index 531d1d3..a8a54d3 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -813,6 +813,36 @@ void Test::testFormulaRefUpdateSheets()
     if (!checkFormula(*m_pDoc, ScAddress(1,2,2), "SUM($Sheet1.$B$2:$C$3)"))
         CPPUNIT_FAIL("Wrong formula in Sheet2.B3.");
 
+    // Move the last sheet (Sheet2) to the first position.
+    m_pDoc->MoveTab(2, 0);
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "SUM(Sheet1.B2:C3)"))
+        CPPUNIT_FAIL("Wrong formula in Sheet2.B2.");
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "SUM($Sheet1.$B$2:$C$3)"))
+        CPPUNIT_FAIL("Wrong formula in Sheet2.B3.");
+
+    // Move back.
+    m_pDoc->MoveTab(0, 2);
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,1,2), "SUM(Sheet1.B2:C3)"))
+        CPPUNIT_FAIL("Wrong formula in Sheet2.B2.");
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,2,2), "SUM($Sheet1.$B$2:$C$3)"))
+        CPPUNIT_FAIL("Wrong formula in Sheet2.B3.");
+
+    // Move the "Temp" sheet to the last position.
+    m_pDoc->MoveTab(1, 2);
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,1,1), "SUM(Sheet1.B2:C3)"))
+        CPPUNIT_FAIL("Wrong formula in Sheet2.B2.");
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,2,1), "SUM($Sheet1.$B$2:$C$3)"))
+        CPPUNIT_FAIL("Wrong formula in Sheet2.B3.");
+
+    // Move back.
+    m_pDoc->MoveTab(2, 1);
+
     // Delete the temporary sheet.
     m_pDoc->DeleteTab(1);
 
@@ -848,6 +878,26 @@ void Test::testFormulaRefUpdateSheets()
     if (!checkFormula(*m_pDoc, ScAddress(1,2,1), "SUM($Sheet1.$B$2:$C$3)"))
         CPPUNIT_FAIL("Wrong formula in Sheet2.B3.");
 
+    // Append a bunch of sheets.
+    m_pDoc->InsertTab(2, "Temp1");
+    m_pDoc->InsertTab(3, "Temp2");
+    m_pDoc->InsertTab(4, "Temp3");
+
+    // Move these tabs around. This shouldn't affects the first 2 sheets.
+    m_pDoc->MoveTab(2, 4);
+    m_pDoc->MoveTab(3, 2);
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,1,1), "SUM(Sheet1.B2:C3)"))
+        CPPUNIT_FAIL("Wrong formula in Sheet2.B2.");
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,2,1), "SUM($Sheet1.$B$2:$C$3)"))
+        CPPUNIT_FAIL("Wrong formula in Sheet2.B3.");
+
+    // Delete the temp sheets.
+    m_pDoc->DeleteTab(4);
+    m_pDoc->DeleteTab(3);
+    m_pDoc->DeleteTab(2);
+
     // Delete Sheet1.
     m_pDoc->DeleteTab(0);
     m_pDoc->GetName(0, aName);
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index c6fb301..b20fa0c 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2598,31 +2598,19 @@ bool ScFormulaCell::UpdateDeleteTab(SCTAB nTable, bool /*bIsMove*/, SCTAB nSheet
 void ScFormulaCell::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
 {
     pCode->Reset();
-    if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
+    if (!pCode->GetNextReferenceRPN() || pDocument->IsClipOrUndo())
     {
-        EndListeningTo( pDocument );
-        // SetTab _after_ EndListeningTo und _before_ Compiler UpdateMoveTab !
-        aPos.SetTab( nTabNo );
-        ScRangeData* pRangeData;
-        ScCompiler aComp(pDocument, aPos, *pCode);
-        aComp.SetGrammar(pDocument->GetGrammar());
-        pRangeData = aComp.UpdateMoveTab( nOldPos, nNewPos, false );
-        if (pRangeData) // Exchange Shared Formula with real Formula
-        {
-            pDocument->RemoveFromFormulaTree( this );   // update formula count
-            delete pCode;
-            pCode = pRangeData->GetCode()->Clone();
-            ScCompiler aComp2(pDocument, aPos, *pCode);
-            aComp2.SetGrammar(pDocument->GetGrammar());
-            aComp2.CompileTokenArray();
-            aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
-            aComp2.UpdateMoveTab( nOldPos, nNewPos, true );
-            bCompile = true;
-        }
-        // no StartListeningTo because pTab[nTab] not yet correct!
+        aPos.SetTab(nTabNo);
+        return;
     }
-    else
-        aPos.SetTab( nTabNo );
+
+    EndListeningTo(pDocument);
+    ScAddress aOldPos = aPos;
+    // SetTab _after_ EndListeningTo und _before_ Compiler UpdateMoveTab !
+    aPos.SetTab(nTabNo);
+
+    // no StartListeningTo because pTab[nTab] not yet correct!
+    pCode->AdjustReferenceOnMovedTab(nOldPos, nNewPos, aOldPos);
 }
 
 void ScFormulaCell::UpdateInsertTabAbs(SCTAB nTable)
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index e5381aa..79bdfa3 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2660,6 +2660,79 @@ bool ScTokenArray::AdjustReferenceOnInsertedTab( SCTAB nInsPos, SCTAB nSheets, c
     return bRefChanged;
 }
 
+namespace {
+
+void adjustTabOnMove( ScAddress& rPos, SCTAB nOldPos, SCTAB nNewPos )
+{
+    // Sheets below the lower bound or above the uppper bound will not change.
+    SCTAB nLowerBound = std::min(nOldPos, nNewPos);
+    SCTAB nUpperBound = std::max(nOldPos, nNewPos);
+
+    if (rPos.Tab() < nLowerBound || nUpperBound < rPos.Tab())
+        // Outside the boundary. Nothing to adjust.
+        return;
+
+    if (rPos.Tab() == nOldPos)
+    {
+        rPos.SetTab(nNewPos);
+        return;
+    }
+
+    // It's somewhere in between.
+    if (nOldPos < nNewPos)
+    {
+        // Moving a sheet to the right. The rest of the sheets shifts to the left.
+        rPos.IncTab(-1);
+    }
+    else
+    {
+        // Moving a sheet to the left. The rest of the sheets shifts to the right.
+        rPos.IncTab();
+    }
+}
+
+}
+
+void ScTokenArray::AdjustReferenceOnMovedTab( SCTAB nOldPos, SCTAB nNewPos, const ScAddress& rOldPos )
+{
+    if (nOldPos == nNewPos)
+        return;
+
+    ScAddress aNewPos = rOldPos;
+    adjustTabOnMove(aNewPos, nOldPos, nNewPos);
+
+    FormulaToken** p = pCode;
+    FormulaToken** pEnd = p + static_cast<size_t>(nLen);
+    for (; p != pEnd; ++p)
+    {
+        switch ((*p)->GetType())
+        {
+            case svSingleRef:
+            {
+                ScToken* pToken = static_cast<ScToken*>(*p);
+                ScSingleRefData& rRef = pToken->GetSingleRef();
+                ScAddress aAbs = rRef.toAbs(rOldPos);
+                adjustTabOnMove(aAbs, nOldPos, nNewPos);
+                rRef.SetAddress(aAbs, aNewPos);
+
+            }
+            break;
+            case svDoubleRef:
+            {
+                ScToken* pToken = static_cast<ScToken*>(*p);
+                ScComplexRefData& rRef = pToken->GetDoubleRef();
+                ScRange aAbs = rRef.toAbs(rOldPos);
+                adjustTabOnMove(aAbs.aStart, nOldPos, nNewPos);
+                adjustTabOnMove(aAbs.aEnd, nOldPos, nNewPos);
+                rRef.SetRange(aAbs, aNewPos);
+            }
+            break;
+            default:
+                ;
+        }
+    }
+}
+
 #if DEBUG_FORMULA_COMPILER
 void ScTokenArray::Dump() const
 {


More information about the Libreoffice-commits mailing list