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

Kohei Yoshida kohei.yoshida at gmail.com
Tue Jul 23 19:31:12 PDT 2013


 sc/inc/tokenarray.hxx               |    3 +
 sc/qa/unit/ucalc.hxx                |    2 
 sc/qa/unit/ucalc_formula.cxx        |   73 ++++++++++++++++++++++++++++++++++++
 sc/source/core/data/formulacell.cxx |   22 ++++------
 sc/source/core/tool/token.cxx       |   52 +++++++++++++++++++++++++
 5 files changed, 139 insertions(+), 13 deletions(-)

New commits:
commit a62b7f10ec1fddd7d2bd6517dec75a617aaa12be
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Jul 23 22:33:27 2013 -0400

    Re-implement adjusting of references on move.
    
    Change-Id: I52a8b78ed072eb6bcd86b4f80936a869046cbc4d

diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index 5ff7da0..2ae6c90 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -129,6 +129,9 @@ public:
      */
     sc::RefUpdateResult AdjustReferenceOnShift( const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos );
 
+    sc::RefUpdateResult AdjustReferenceOnMove(
+        const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos, const ScAddress& rNewPos );
+
     /**
      * Adjust all references on sheet deletion.
      *
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 63d2c9b..725c5d9 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2365,7 +2365,6 @@ bool ScFormulaCell::UpdateReferenceOnMove(
         aOldPos.Set(aPos.Col() - rCxt.mnColDelta, aPos.Row() - rCxt.mnRowDelta, aPos.Tab() - rCxt.mnTabDelta);
     }
 
-
     // Check presence of any references or column row names.
     pCode->Reset();
     bool bHasRefs = (pCode->GetNextReferenceRPN() != NULL);
@@ -2389,22 +2388,19 @@ bool ScFormulaCell::UpdateReferenceOnMove(
         pOldCode.reset(pCode->Clone());
 
     bool bValChanged = false;
-    bool bRangeModified = false;    // any range, not only shared formula
+    bool bRefModified = false;
     bool bRefSizeChanged = false;
 
     if (bHasRefs)
     {
         // Update cell or range references.
-        ScCompiler aComp(pDocument, aPos, *pCode);
-        aComp.SetGrammar(pDocument->GetGrammar());
-        aComp.UpdateReference(
-            URM_MOVE, aOldPos, rCxt.maRange,
-            rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta,
-            bValChanged, bRefSizeChanged);
-        bRangeModified = aComp.HasModifiedRange();
+        sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMove(rCxt, aOldPos, aPos);
+        bRefModified = aRes.mbReferenceModified;
+        bValChanged = aRes.mbValueChanged;
     }
 
-    bCellStateChanged |= bValChanged;
+    if (bValChanged || bRefModified)
+        bCellStateChanged = true;
 
     if (bOnRefMove)
         // Cell may reference itself, e.g. ocColumn, ocRow without parameter
@@ -2429,7 +2425,7 @@ bool ScFormulaCell::UpdateReferenceOnMove(
         bHasRelName = HasRelNameReference();
         // Reference changed and new listening needed?
         // Except in Insert/Delete without specialties.
-        bNewListening = (bRangeModified || bColRowNameCompile
+        bNewListening = (bRefModified || bColRowNameCompile
                 || bValChanged || bHasRelName)
             // #i36299# Don't duplicate action during cut&paste / drag&drop
             // on a cell in the range moved, start/end listeners is done
@@ -2442,7 +2438,7 @@ bool ScFormulaCell::UpdateReferenceOnMove(
 
     bool bNeedDirty = false;
     // NeedDirty for changes except for Copy and Move/Insert without RelNames
-    if ( bRangeModified || bColRowNameCompile ||
+    if ( bRefModified || bColRowNameCompile ||
          (bValChanged && bHasRelName && (bHasRelName || bInDeleteUndo || bRefSizeChanged)) || bOnRefMove)
         bNeedDirty = true;
 
@@ -2451,7 +2447,7 @@ bool ScFormulaCell::UpdateReferenceOnMove(
 
     bValChanged = false;
 
-    if ( ( bCompile = (bCompile || bValChanged || bRangeModified || bColRowNameCompile) ) != 0 )
+    if ( ( bCompile = (bCompile || bValChanged || bRefModified || bColRowNameCompile) ) != 0 )
     {
         CompileTokenArray( bNewListening ); // no Listening
         bNeedDirty = true;
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 64beedf..b783525 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2472,6 +2472,58 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateCon
     return aRes;
 }
 
+sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMove(
+    const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos, const ScAddress& rNewPos )
+{
+    // When moving, the range is the destination range. We need to use the old
+    // range prior to the move for hit analysis.
+    ScRange aOldRange = rCxt.maRange;
+    aOldRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta);
+
+    sc::RefUpdateResult aRes;
+
+    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);
+                if (aOldRange.In(aAbs))
+                {
+                    aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
+                    aRes.mbReferenceModified = true;
+                }
+
+                rRef.SetAddress(aAbs, rNewPos);
+            }
+            break;
+            case svDoubleRef:
+            {
+                ScToken* pToken = static_cast<ScToken*>(*p);
+                ScComplexRefData& rRef = pToken->GetDoubleRef();
+                ScRange aAbs = rRef.toAbs(rOldPos);
+                if (aOldRange.In(aAbs))
+                {
+                    aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
+                    aRes.mbReferenceModified = true;
+                }
+
+                rRef.SetRange(aAbs, rNewPos);
+            }
+            break;
+            default:
+                ;
+        }
+    }
+
+    return aRes;
+}
+
 namespace {
 
 bool adjustSingleRef( ScSingleRefData& rRef, SCTAB nDelPos, SCTAB nSheets, const ScAddress& rOldPos, const ScAddress& rNewPos )
commit 9e304c34daae3dd8e9b7813138b5028b91819002
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Jul 23 22:29:48 2013 -0400

    Add test for moving the formula cells that reference stationary range.
    
    Change-Id: I6f996e4c8535371c57c9d43012baa6118160f834

diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index 69b0374..ebf74e7 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -884,6 +884,29 @@ void Test::testFormulaRefUpdateMove()
     if (!checkFormula(*m_pDoc, ScAddress(0,11,0), "$D$6"))
         CPPUNIT_FAIL("Wrong formula.");
 
+    // Move A9:A12 to B10:B13.
+    bMoved = rFunc.MoveBlock(ScRange(0,8,0,0,11,0), ScAddress(1,9,0), true, false, false, false);
+    CPPUNIT_ASSERT_MESSAGE("Failed to move A9:A12 to B10:B13", bMoved);
+
+    // The results of these formula cells should still stay the same.
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(1,9,0));
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(1,10,0));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(1,11,0));
+    CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(1,12,0));
+
+    // Displayed formulas should stay the same since the referenced range hasn't moved.
+    if (!checkFormula(*m_pDoc, ScAddress(1,9,0), "SUM(D4:D6)"))
+        CPPUNIT_FAIL("Wrong formula.");
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,10,0), "SUM($D$4:$D$6)"))
+        CPPUNIT_FAIL("Wrong formula.");
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,11,0), "D5"))
+        CPPUNIT_FAIL("Wrong formula.");
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,12,0), "$D$6"))
+        CPPUNIT_FAIL("Wrong formula.");
+
     m_pDoc->DeleteTab(0);
 }
 
commit a38c2df3c20c3a3e8585b610635b751269793bf3
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Jul 23 18:59:34 2013 -0400

    Add starter test for reference update on range move.
    
    This currently fails.
    
    Change-Id: I83cdcb6ed9620079664ff35375a0457b0c9bcea0

diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index ac17bd9..5a1d0ae 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -89,6 +89,7 @@ public:
     void testFormulaRefUpdate();
     void testFormulaRefUpdateRange();
     void testFormulaRefUpdateSheets();
+    void testFormulaRefUpdateMove();
     void testFuncCOLUMN();
     void testFuncROW();
     void testFuncSUM();
@@ -280,6 +281,7 @@ public:
     CPPUNIT_TEST(testFormulaRefUpdate);
     CPPUNIT_TEST(testFormulaRefUpdateRange);
     CPPUNIT_TEST(testFormulaRefUpdateSheets);
+    CPPUNIT_TEST(testFormulaRefUpdateMove);
     CPPUNIT_TEST(testFuncCOLUMN);
     CPPUNIT_TEST(testFuncROW);
     CPPUNIT_TEST(testFuncSUM);
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index c651b6d..69b0374 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -18,6 +18,8 @@
 #include "formulacell.hxx"
 #include "inputopt.hxx"
 #include "scmod.hxx"
+#include "docsh.hxx"
+#include "docfunc.hxx"
 
 #include <boost/scoped_ptr.hpp>
 
@@ -837,6 +839,54 @@ void Test::testFormulaRefUpdateSheets()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testFormulaRefUpdateMove()
+{
+    m_pDoc->InsertTab(0, "Sheet1");
+
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+
+    // Set value to B4:B6.
+    m_pDoc->SetValue(ScAddress(1,3,0), 1);
+    m_pDoc->SetValue(ScAddress(1,4,0), 2);
+    m_pDoc->SetValue(ScAddress(1,5,0), 3);
+
+    // Set formulas to A9:A12 that references B4:B6.
+    m_pDoc->SetString(ScAddress(0,8,0), "=SUM(B4:B6)");
+    m_pDoc->SetString(ScAddress(0,9,0), "=SUM($B$4:$B$6)");
+    m_pDoc->SetString(ScAddress(0,10,0), "=B5");
+    m_pDoc->SetString(ScAddress(0,11,0), "=$B$6");
+
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(0,8,0));
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(0,9,0));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(0,10,0));
+    CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(0,11,0));
+
+    // Move B4:B6 to D4 (two columsn to the right).
+    ScDocFunc& rFunc = getDocShell().GetDocFunc();
+    bool bMoved = rFunc.MoveBlock(ScRange(1,3,0,1,5,0), ScAddress(3,3,0), true, false, false, false);
+    CPPUNIT_ASSERT_MESSAGE("Failed to move B4:B6.", bMoved);
+
+    // The results of the formula cells that reference the moved range should remain the same.
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(0,8,0));
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(0,9,0));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(0,10,0));
+    CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(0,11,0));
+
+    if (!checkFormula(*m_pDoc, ScAddress(0,8,0), "SUM(D4:D6)"))
+        CPPUNIT_FAIL("Wrong formula.");
+
+    if (!checkFormula(*m_pDoc, ScAddress(0,9,0), "SUM($D$4:$D$6)"))
+        CPPUNIT_FAIL("Wrong formula.");
+
+    if (!checkFormula(*m_pDoc, ScAddress(0,10,0), "D5"))
+        CPPUNIT_FAIL("Wrong formula.");
+
+    if (!checkFormula(*m_pDoc, ScAddress(0,11,0), "$D$6"))
+        CPPUNIT_FAIL("Wrong formula.");
+
+    m_pDoc->DeleteTab(0);
+}
+
 void Test::testFuncCOLUMN()
 {
     m_pDoc->InsertTab(0, "Formula");


More information about the Libreoffice-commits mailing list