sc/inc/rangenam.hxx                 |    6 +++
 sc/inc/tokenarray.hxx               |    5 +++
 sc/qa/unit/ucalc.cxx                |   56 ++++++++++++++++++++++++++++--------
 sc/source/core/data/formulacell.cxx |   12 +++++++
 sc/source/core/tool/rangenam.cxx    |    4 +-
 sc/source/core/tool/token.cxx       |   48 ++++++++++++++++++++++++++++++
 6 files changed, 115 insertions(+), 16 deletions(-)

New commits:
commit b86b97e54590872fc0ea85fbea22c2d00d241181
Author: Eike Rathke <er...@redhat.com>
Date:   Sat Mar 19 00:22:40 2016 +0100

    adjust sheet references when copying sheet-local named expressions
    
    ... so references to the local sheet point to the new scope's local
    sheet and not to the originating sheet.
    
    Change-Id: I7f33f4e9b379ec01d6c2587e92ffe851892fc32d

diff --git a/sc/inc/rangenam.hxx b/sc/inc/rangenam.hxx
index 2a15ec8..8e9e753 100644
--- a/sc/inc/rangenam.hxx
+++ b/sc/inc/rangenam.hxx
@@ -94,7 +94,11 @@ public:
                                  const OUString& rName,
                                  const ScAddress& rTarget );
                                 // rTarget is ABSPOS jump label
-                    ScRangeData(const ScRangeData& rScRangeData, ScDocument* 
pDocument = nullptr);
+
+    /* Exact copy, not recompiled, no other index (!), nothing.. except if
+     * pDocument or pPos are passed, those values are assigned instead of the
+     * copies. */
+    ScRangeData( const ScRangeData& rScRangeData, ScDocument* pDocument = 
nullptr, const ScAddress* pPos = nullptr );
 
     SC_DLLPUBLIC ~ScRangeData();
 
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index e495346..ac3c332 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -136,6 +136,11 @@ public:
      */
     void AdjustAbsoluteRefs( const ScDocument* pOldDoc, const ScAddress& 
rOldPos, const ScAddress& rNewPos, bool bRangeName = false, bool bCheckCopyArea 
= false );
 
+    /** When copying a sheet-local named expression, move sheet references that
+        point to the originating sheet to point to the new sheet instead.
+     */
+    void AdjustSheetLocalNameReferences( SCTAB nOldTab, SCTAB nNewTab );
+
     /**
      * Adjust all references in response to shifting of cells during cell
      * insertion and deletion.
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 476ba3e..98e5bad 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -3292,23 +3292,29 @@ void Test::testCopyPaste()
     ScAddress aAdr (0, 0, 0);
 
     //create some range names, local and global
-    ScRangeData* pLocal1 = new ScRangeData(m_pDoc, OUString("local1"), aAdr);
-    ScRangeData* pLocal2 = new ScRangeData(m_pDoc, OUString("local2"), aAdr);
-    ScRangeData* pGlobal = new ScRangeData(m_pDoc, OUString("global"), aAdr);
+    ScRangeData* pLocal1 = new ScRangeData( m_pDoc, "local1", aAdr);
+    ScRangeData* pLocal2 = new ScRangeData( m_pDoc, "local2", aAdr);
+    ScRangeData* pLocal3 = new ScRangeData( m_pDoc, "local3", "$Sheet1.$A$1");
+    ScRangeData* pLocal4 = new ScRangeData( m_pDoc, "local4", "Sheet1.$A$1");
+    ScRangeData* pLocal5 = new ScRangeData( m_pDoc, "local5", "$A$1"); // 
implicit relative sheet reference
+    ScRangeData* pGlobal = new ScRangeData( m_pDoc, "global", aAdr);
     ScRangeName* pGlobalRangeName = new ScRangeName();
     pGlobalRangeName->insert(pGlobal);
     ScRangeName* pLocalRangeName1 = new ScRangeName();
     pLocalRangeName1->insert(pLocal1);
     pLocalRangeName1->insert(pLocal2);
+    pLocalRangeName1->insert(pLocal3);
+    pLocalRangeName1->insert(pLocal4);
+    pLocalRangeName1->insert(pLocal5);
     m_pDoc->SetRangeName(pGlobalRangeName);
     m_pDoc->SetRangeName(0, pLocalRangeName1);
 
     // Add formula to B1.
-    OUString aFormulaString("=local1+global+SUM($C$1:$D$4)");
+    OUString 
aFormulaString("=local1+global+SUM($C$1:$D$4)+local3+local4+local5");
     m_pDoc->SetString(1, 0, 0, aFormulaString);
 
     double fValue = m_pDoc->GetValue(ScAddress(1,0,0));
-    ASSERT_DOUBLES_EQUAL_MESSAGE("formula should return 8", fValue, 8);
+    ASSERT_DOUBLES_EQUAL_MESSAGE("formula should return 11", fValue, 11);
 
     // add notes to A1:C1
     ScAddress aAdrA1 (0, 0, 0); // empty cell content
@@ -3339,23 +3345,49 @@ void Test::testCopyPaste()
 
     //check values after copying
     OUString aString;
-    fValue = m_pDoc->GetValue(ScAddress(1,1,1));
     m_pDoc->GetFormula(1,1,1, aString);
-    ASSERT_DOUBLES_EQUAL_MESSAGE("copied formula should return 2", 2.0, 
fValue);
     CPPUNIT_ASSERT_EQUAL_MESSAGE("formula string was not copied correctly", 
aString, aFormulaString);
+    // Only the global range points to Sheet1.A1, all copied sheet-local ranges
+    // to Sheet2.A1 that is empty, hence the result is 1, not 2.
+    fValue = m_pDoc->GetValue(ScAddress(1,1,1));
+    ASSERT_DOUBLES_EQUAL_MESSAGE("copied formula should return 1", 1.0, 
fValue);
     fValue = m_pDoc->GetValue(ScAddress(0,1,1));
     ASSERT_DOUBLES_EQUAL_MESSAGE("copied value should be 1", 1.0, fValue);
 
+    ScRange aSheet2A1(0,0,1,0,0,1);
+
     //check local range name after copying
     pLocal1 = m_pDoc->GetRangeName(1)->findByUpperName(OUString("LOCAL1"));
     CPPUNIT_ASSERT_MESSAGE("local range name 1 should be copied", pLocal1);
     ScRange aRangeLocal1;
-    bool bIsValidRef = pLocal1->IsValidReference(aRangeLocal1);
-    CPPUNIT_ASSERT_MESSAGE("local range name 1 should be valid", bIsValidRef);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("local range 1 should still point to 
Sheet1.A1",ScRange(0,0,0,0,0,0), aRangeLocal1);
+    bool bIsValidRef1 = pLocal1->IsValidReference(aRangeLocal1);
+    CPPUNIT_ASSERT_MESSAGE("local range name 1 should be valid", bIsValidRef1);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("local range 1 should now point to 
Sheet2.A1", aSheet2A1, aRangeLocal1);
+
     pLocal2 = m_pDoc->GetRangeName(1)->findByUpperName(OUString("LOCAL2"));
     CPPUNIT_ASSERT_MESSAGE("local2 should not be copied", pLocal2 == nullptr);
 
+    pLocal3 = m_pDoc->GetRangeName(1)->findByUpperName(OUString("LOCAL3"));
+    CPPUNIT_ASSERT_MESSAGE("local range name 3 should be copied", pLocal3);
+    ScRange aRangeLocal3;
+    bool bIsValidRef3 = pLocal3->IsValidReference(aRangeLocal3);
+    CPPUNIT_ASSERT_MESSAGE("local range name 3 should be valid", bIsValidRef3);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("local range 3 should now point to 
Sheet2.A1", aSheet2A1, aRangeLocal3);
+
+    pLocal4 = m_pDoc->GetRangeName(1)->findByUpperName(OUString("LOCAL4"));
+    CPPUNIT_ASSERT_MESSAGE("local range name 4 should be copied", pLocal4);
+    ScRange aRangeLocal4;
+    bool bIsValidRef4 = pLocal4->IsValidReference(aRangeLocal4);
+    CPPUNIT_ASSERT_MESSAGE("local range name 4 should be valid", bIsValidRef4);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("local range 4 should now point to 
Sheet2.A1", aSheet2A1, aRangeLocal4);
+
+    pLocal5 = m_pDoc->GetRangeName(1)->findByUpperName(OUString("LOCAL5"));
+    CPPUNIT_ASSERT_MESSAGE("local range name 5 should be copied", pLocal5);
+    ScRange aRangeLocal5;
+    bool bIsValidRef5 = pLocal5->IsValidReference(aRangeLocal5);
+    CPPUNIT_ASSERT_MESSAGE("local range name 5 should be valid", bIsValidRef5);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("local range 5 should now point to 
Sheet2.A1", aSheet2A1, aRangeLocal5);
+
     // check notes after copying
     CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.A2", 
m_pDoc->HasNote(ScAddress(0, 1, 1)));
     CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.B2", 
m_pDoc->HasNote(ScAddress(1, 1, 1)));
@@ -3379,11 +3411,11 @@ void Test::testCopyPaste()
 
     pUndo->Redo();
     fValue = m_pDoc->GetValue(ScAddress(1,1,1));
-    ASSERT_DOUBLES_EQUAL_MESSAGE("formula should return 2 after redo", fValue, 
2);
+    ASSERT_DOUBLES_EQUAL_MESSAGE("formula should return 1 after redo", 1.0, 
fValue);
     aString = m_pDoc->GetString(2, 1, 1);
     CPPUNIT_ASSERT_EQUAL_MESSAGE("Cell Sheet2.C2 should contain: test", 
OUString("test"), aString);
     m_pDoc->GetFormula(1,1,1, aString);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Formula should be correct again", aString, 
aFormulaString);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Formula should be correct again", 
aFormulaString, aString);
 
     CPPUNIT_ASSERT_MESSAGE("After Redo, there should be a note on Sheet2.A2", 
m_pDoc->HasNote(ScAddress(0, 1, 1)));
     CPPUNIT_ASSERT_MESSAGE("After Redo, there should be a note on Sheet2.B2", 
m_pDoc->HasNote(ScAddress(1, 1, 1)));
diff --git a/sc/source/core/data/formulacell.cxx 
b/sc/source/core/data/formulacell.cxx
index 9ef82e4..f91dc21 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -475,13 +475,23 @@ void adjustRangeName(formula::FormulaToken* pToken, 
ScDocument& rNewDoc, const S
     //if no range name was found copy it
     if (!pRangeData)
     {
+        ScAddress aRangePos( pOldRangeData->GetPos());
         if (nOldSheet < 0)
+        {
             nNewSheet = -1;
+        }
         else
+        {
             nNewSheet = aNewPos.Tab();
-        pRangeData = new ScRangeData(*pOldRangeData, &rNewDoc);
+            aRangePos.SetTab( nNewSheet);
+        }
+        pRangeData = new ScRangeData(*pOldRangeData, &rNewDoc, &aRangePos);
         pRangeData->SetIndex(0);    // needed for insert to assign a new index
         ScTokenArray* pRangeNameToken = pRangeData->GetCode();
+        if (bSameDoc && nNewSheet >= 0)
+        {
+            pRangeNameToken->AdjustSheetLocalNameReferences( nOldSheet, 
nNewSheet);
+        }
         if (!bSameDoc)
         {
             pRangeNameToken->ReadjustAbsolute3DReferences(pOldDoc, &rNewDoc, 
pRangeData->GetPos(), true);
diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx
index 830980c..15b7f6b 100644
--- a/sc/source/core/tool/rangenam.cxx
+++ b/sc/source/core/tool/rangenam.cxx
@@ -126,11 +126,11 @@ ScRangeData::ScRangeData( ScDocument* pDok,
         eType |= RT_ABSPOS;
 }
 
-ScRangeData::ScRangeData(const ScRangeData& rScRangeData, ScDocument* 
pDocument) :
+ScRangeData::ScRangeData(const ScRangeData& rScRangeData, ScDocument* 
pDocument, const ScAddress* pPos) :
     aName   (rScRangeData.aName),
     aUpperName  (rScRangeData.aUpperName),
     pCode       (rScRangeData.pCode ? rScRangeData.pCode->Clone() : new 
ScTokenArray()),   // make real copy (not copy-ctor)
-    aPos        (rScRangeData.aPos),
+    aPos        (pPos ? *pPos : rScRangeData.aPos),
     eType       (rScRangeData.eType),
     pDoc        (pDocument ? pDocument : rScRangeData.pDoc),
     eTempGrammar(rScRangeData.eTempGrammar),
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 3d82694..7a47d69 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2480,6 +2480,54 @@ void ScTokenArray::AdjustAbsoluteRefs( const ScDocument* 
pOldDoc, const ScAddres
     }
 }
 
+void ScTokenArray::AdjustSheetLocalNameReferences( SCTAB nOldTab, SCTAB 
nNewTab )
+{
+    TokenPointers aPtrs( pCode, nLen, pRPN, nRPN, false);
+    for (size_t j=0; j<2; ++j)
+    {
+        FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
+        FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
+        for (; pp != pEnd; ++pp)
+        {
+            FormulaToken* p = aPtrs.getHandledToken(j,pp);
+            if (!p)
+                continue;
+
+            switch ( p->GetType() )
+            {
+                case svDoubleRef :
+                    {
+                        ScComplexRefData& rRef = *p->GetDoubleRef();
+                        ScSingleRefData& rRef2 = rRef.Ref2;
+                        ScSingleRefData& rRef1 = rRef.Ref1;
+
+                        if (!rRef1.IsTabRel() && rRef1.Tab() == nOldTab)
+                            rRef1.SetAbsTab( nNewTab);
+                        if (!rRef2.IsTabRel() && rRef2.Tab() == nOldTab)
+                            rRef2.SetAbsTab( nNewTab);
+                        if (!rRef1.IsTabRel() && !rRef2.IsTabRel() && 
rRef1.Tab() > rRef2.Tab())
+                        {
+                            SCTAB nTab = rRef1.Tab();
+                            rRef1.SetAbsTab( rRef2.Tab());
+                            rRef2.SetAbsTab( nTab);
+                        }
+                    }
+                    break;
+                case svSingleRef :
+                    {
+                        ScSingleRefData& rRef = *p->GetSingleRef();
+
+                        if (!rRef.IsTabRel() && rRef.Tab() == nOldTab)
+                            rRef.SetAbsTab( nNewTab);
+                    }
+                    break;
+                default:
+                    ;
+            }
+        }
+    }
+}
+
 namespace {
 
 ScRange getSelectedRange( const sc::RefUpdateContext& rCxt )
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to