[Libreoffice-commits] core.git: 2 commits - sc/inc sc/qa sc/source

Kohei Yoshida kohei.yoshida at collabora.com
Tue Mar 25 19:38:24 PDT 2014


 sc/inc/tokenarray.hxx               |    2 
 sc/qa/unit/ucalc.hxx                |    2 
 sc/qa/unit/ucalc_formula.cxx        |   80 +++++++++++++++++++++
 sc/source/core/data/column.cxx      |   15 +++-
 sc/source/core/data/formulacell.cxx |    2 
 sc/source/core/tool/token.cxx       |  135 ++++++++++++++++++++++++------------
 6 files changed, 190 insertions(+), 46 deletions(-)

New commits:
commit 003a27a14d5cf65fe0b528b6d6015e37a64dbb8e
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Mar 25 22:34:18 2014 -0400

    fdo#74322: Handle moving of named ranges correctly.
    
    But named ranges are adjusted if and only if the references are absolute.
    
    Change-Id: I6c5287b413884b045f1a798c6c6683aa17863f24

diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index eb68997..e8b96cc 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -163,6 +163,8 @@ public:
      */
     sc::RefUpdateResult AdjustReferenceInName( const sc::RefUpdateContext& rCxt, const ScAddress& rPos );
 
+    sc::RefUpdateResult AdjustReferenceInMovedName( const sc::RefUpdateContext& rCxt, const ScAddress& rPos );
+
     /**
      * Adjust all references on sheet deletion.
      *
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 5c196a0..e08766e 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -2537,8 +2537,21 @@ class UpdateRefOnNonCopy : std::unary_function<FormulaGroup, void>
             bRecalcOnMove = aPos != aOldPos;
 
         sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMove(*mpCxt, aOldPos, aPos);
-        if (aRes.mbReferenceModified || bRecalcOnMove)
+
+        if (aRes.mbReferenceModified || aRes.mbNameModified || bRecalcOnMove)
         {
+            sc::AutoCalcSwitch(mpCxt->mrDoc, false);
+
+            if (aRes.mbNameModified)
+            {
+                // We need to re-compile the token array when a range name is
+                // modified, to correctly reflect the new references in the
+                // name.
+                ScCompiler aComp(&mpCxt->mrDoc, aPos, *pCode);
+                aComp.SetGrammar(mpCxt->mrDoc.GetGrammar());
+                aComp.CompileTokenArray();
+            }
+
             // Perform end-listening, start-listening, and dirtying on all
             // formula cells in the group.
 
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 320a2c2..b4b3ddf 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2833,7 +2833,7 @@ bool ScFormulaCell::UpdateReferenceOnMove(
     {
         // Update cell or range references.
         sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMove(rCxt, aOldPos, aPos);
-        bRefModified = aRes.mbReferenceModified;
+        bRefModified = aRes.mbReferenceModified || aRes.mbNameModified;
         bValChanged = aRes.mbValueChanged;
     }
 
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index f1982bd..e2a0fdb 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2634,6 +2634,19 @@ bool expandRangeByEdge( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, co
     return false;
 }
 
+bool isNameModified( const sc::UpdatedRangeNames& rUpdatedNames, SCTAB nOldTab, const formula::FormulaToken& rToken )
+{
+    if (rToken.GetOpCode() != ocName)
+        return false;
+
+    SCTAB nTab = -1;
+    if (!rToken.IsGlobal())
+        nTab = nOldTab;
+
+    // Check if this named expression has been modified.
+    return rUpdatedNames.isNameUpdated(nTab, rToken.GetIndex());
+}
+
 }
 
 sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos )
@@ -2772,17 +2785,8 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateCon
             break;
             case svIndex:
             {
-                const formula::FormulaToken* pToken = *p;
-                if (pToken->GetOpCode() == ocName)
-                {
-                    SCTAB nTab = -1;
-                    if (!pToken->IsGlobal())
-                        nTab = rOldPos.Tab();
-
-                    // Check if this named expression has been modified.
-                    if (rCxt.maUpdatedNames.isNameUpdated(nTab, pToken->GetIndex()))
-                        aRes.mbNameModified = true;
-                }
+                if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **p))
+                    aRes.mbNameModified = true;
             }
             break;
             default:
@@ -2837,6 +2841,12 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMove(
                 rRef.SetRange(aAbs, rNewPos);
             }
             break;
+            case svIndex:
+            {
+                if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **p))
+                    aRes.mbNameModified = true;
+            }
+            break;
             default:
                 ;
         }
@@ -2967,6 +2977,9 @@ bool adjustDoubleRefInName(
 sc::RefUpdateResult ScTokenArray::AdjustReferenceInName(
     const sc::RefUpdateContext& rCxt, const ScAddress& rPos )
 {
+    if (rCxt.meMode == URM_MOVE)
+        return AdjustReferenceInMovedName(rCxt, rPos);
+
     sc::RefUpdateResult aRes;
 
     FormulaToken** p = pCode;
@@ -3029,6 +3042,67 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceInName(
     return aRes;
 }
 
+sc::RefUpdateResult ScTokenArray::AdjustReferenceInMovedName( const sc::RefUpdateContext& rCxt, const ScAddress& rPos )
+{
+    // When moving, the range is the destination range.
+    ScRange aOldRange = rCxt.maRange;
+    aOldRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta);
+
+    // In a named expression, we'll move the reference only when the reference
+    // is entirely absolute.
+
+    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();
+                if (rRef.IsColRel() || rRef.IsRowRel() || rRef.IsTabRel())
+                    continue;
+
+                ScAddress aAbs = rRef.toAbs(rPos);
+                if (aOldRange.In(aAbs))
+                {
+                    aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
+                    aRes.mbReferenceModified = true;
+                }
+
+                rRef.SetAddress(aAbs, rPos);
+            }
+            break;
+            case svDoubleRef:
+            {
+                ScToken* pToken = static_cast<ScToken*>(*p);
+                ScComplexRefData& rRef = pToken->GetDoubleRef();
+                if (rRef.Ref1.IsColRel() || rRef.Ref1.IsRowRel() || rRef.Ref1.IsTabRel() ||
+                    rRef.Ref2.IsColRel() || rRef.Ref2.IsRowRel() || rRef.Ref2.IsTabRel())
+                    continue;
+
+                ScRange aAbs = rRef.toAbs(rPos);
+                if (aOldRange.In(aAbs))
+                {
+                    aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
+                    aRes.mbReferenceModified = true;
+                }
+
+                rRef.SetRange(aAbs, rPos);
+            }
+            break;
+            default:
+                ;
+        }
+    }
+
+    return aRes;
+}
+
 namespace {
 
 bool adjustSingleRefOnDeletedTab( ScSingleRefData& rRef, SCTAB nDelPos, SCTAB nSheets, const ScAddress& rOldPos, const ScAddress& rNewPos )
@@ -3112,17 +3186,8 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnDeletedTab( sc::RefUpdateDele
             break;
             case svIndex:
             {
-                const formula::FormulaToken* pToken = *p;
-                if (pToken->GetOpCode() == ocName)
-                {
-                    SCTAB nTab = -1;
-                    if (!pToken->IsGlobal())
-                        nTab = rOldPos.Tab();
-
-                    // Check if this named expression has been modified.
-                    if (rCxt.maUpdatedNames.isNameUpdated(nTab, pToken->GetIndex()))
-                        aRes.mbNameModified = true;
-                }
+                if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **p))
+                    aRes.mbNameModified = true;
             }
             break;
             default:
@@ -3165,17 +3230,8 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnInsertedTab( sc::RefUpdateIns
             break;
             case svIndex:
             {
-                const formula::FormulaToken* pToken = *p;
-                if (pToken->GetOpCode() == ocName)
-                {
-                    SCTAB nTab = -1;
-                    if (!pToken->IsGlobal())
-                        nTab = rOldPos.Tab();
-
-                    // Check if this named expression has been modified.
-                    if (rCxt.maUpdatedNames.isNameUpdated(nTab, pToken->GetIndex()))
-                        aRes.mbNameModified = true;
-                }
+                if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **p))
+                    aRes.mbNameModified = true;
             }
             break;
             default:
@@ -3239,17 +3295,8 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMovedTab( sc::RefUpdateMoveTa
             break;
             case svIndex:
             {
-                const formula::FormulaToken* pToken = *p;
-                if (pToken->GetOpCode() == ocName)
-                {
-                    SCTAB nTab = -1;
-                    if (!pToken->IsGlobal())
-                        nTab = rOldPos.Tab();
-
-                    // Check if this named expression has been modified.
-                    if (rCxt.maUpdatedNames.isNameUpdated(nTab, pToken->GetIndex()))
-                        aRes.mbNameModified = true;
-                }
+                if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **p))
+                    aRes.mbNameModified = true;
             }
             break;
             default:
commit 3edc49d11765372fa54c52b71b49bf52675f4dda
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Mar 25 22:33:03 2014 -0400

    fdo#74322: Write unit test for this first.
    
    Change-Id: If16a93ee371e9a4e0d0992fd0a62a4623fc284ab

diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 7c1c67c..9579918 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -121,6 +121,7 @@ public:
     void testFormulaRefUpdateMove();
     void testFormulaRefUpdateMoveUndo();
     void testFormulaRefUpdateNamedExpression();
+    void testFormulaRefUpdateNamedExpressionMove();
     void testFormulaRefUpdateNamedExpressionExpandRef();
     void testMultipleOperations();
     void testFuncCOLUMN();
@@ -367,6 +368,7 @@ public:
     CPPUNIT_TEST(testFormulaRefUpdateMove);
     CPPUNIT_TEST(testFormulaRefUpdateMoveUndo);
     CPPUNIT_TEST(testFormulaRefUpdateNamedExpression);
+    CPPUNIT_TEST(testFormulaRefUpdateNamedExpressionMove);
     CPPUNIT_TEST(testFormulaRefUpdateNamedExpressionExpandRef);
     CPPUNIT_TEST(testMultipleOperations);
     CPPUNIT_TEST(testFuncCOLUMN);
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index 718ece7..4544ac6 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -1818,6 +1818,86 @@ void Test::testFormulaRefUpdateNamedExpression()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testFormulaRefUpdateNamedExpressionMove()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+
+    m_pDoc->InsertTab(0, "Test");
+
+    // Set values to B2:B4.
+    m_pDoc->SetValue(ScAddress(1,1,0), 1.0);
+    m_pDoc->SetValue(ScAddress(1,2,0), 2.0);
+    m_pDoc->SetValue(ScAddress(1,3,0), 3.0);
+
+    // Set named range for B2:B4.
+    bool bInserted = m_pDoc->InsertNewRangeName("MyRange", ScAddress(0,0,0), "$Test.$B$2:$B$4");
+    CPPUNIT_ASSERT(bInserted);
+
+    // Set formula in A10.
+    m_pDoc->SetString(ScAddress(0,9,0), "=SUM(MyRange)");
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,9,0)));
+
+    ScRangeData* pData = m_pDoc->GetRangeName()->findByUpperName("MYRANGE");
+    CPPUNIT_ASSERT(pData);
+    OUString aSymbol;
+    pData->GetSymbol(aSymbol, m_pDoc->GetGrammar());
+    CPPUNIT_ASSERT_EQUAL(OUString("$Test.$B$2:$B$4"), aSymbol);
+
+    // Move B2:B4 to D3.
+    ScDocFunc& rFunc = getDocShell().GetDocFunc();
+    bool bMoved = rFunc.MoveBlock(ScRange(1,1,0,1,3,0), ScAddress(3,2,0), true, true, false, true);
+    CPPUNIT_ASSERT(bMoved);
+
+    // The named range should have moved as well.
+    pData->GetSymbol(aSymbol, m_pDoc->GetGrammar());
+    CPPUNIT_ASSERT_EQUAL(OUString("$Test.$D$3:$D$5"), aSymbol);
+
+    // The value of A10 should remain unchanged.
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,9,0)));
+
+    SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
+    CPPUNIT_ASSERT(pUndoMgr);
+
+    // Undo and check.
+    pUndoMgr->Undo();
+
+    pData = m_pDoc->GetRangeName()->findByUpperName("MYRANGE");
+    CPPUNIT_ASSERT(pData);
+    pData->GetSymbol(aSymbol, m_pDoc->GetGrammar());
+    CPPUNIT_ASSERT_EQUAL(OUString("$Test.$B$2:$B$4"), aSymbol);
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,9,0)));
+
+    // Redo and check.
+    pUndoMgr->Redo();
+
+    pData = m_pDoc->GetRangeName()->findByUpperName("MYRANGE");
+    CPPUNIT_ASSERT(pData);
+    pData->GetSymbol(aSymbol, m_pDoc->GetGrammar());
+    CPPUNIT_ASSERT_EQUAL(OUString("$Test.$D$3:$D$5"), aSymbol);
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,9,0)));
+
+    // Undo again to bring it back to the initial condition, and clear the undo buffer.
+    pUndoMgr->Undo();
+    pUndoMgr->Clear();
+
+    // Add an identical formula to A11 and make a formula group over A10:A11.
+    m_pDoc->SetString(ScAddress(0,10,0), "=SUM(MyRange)");
+    ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(0,9,0));
+    CPPUNIT_ASSERT(pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(9), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
+
+    // Move B2:B4 to D3 again.
+    bMoved = rFunc.MoveBlock(ScRange(1,1,0,1,3,0), ScAddress(3,2,0), true, true, false, true);
+    CPPUNIT_ASSERT(bMoved);
+
+    // Values of A10 and A11 should remain the same.
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,9,0)));
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,10,0)));
+
+    m_pDoc->DeleteTab(0);
+}
+
 void Test::testFormulaRefUpdateNamedExpressionExpandRef()
 {
     m_pDoc->InsertTab(0, "Test");


More information about the Libreoffice-commits mailing list