summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2016-03-19 00:22:40 +0100
committerEike Rathke <erack@redhat.com>2016-03-19 01:47:05 +0100
commitb86b97e54590872fc0ea85fbea22c2d00d241181 (patch)
treea4f150c1fd604f66ea88f4ed871a540c00bcc871 /sc
parenta4d300f559c4c5704133c01efa6fbcd9193a16c8 (diff)
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
Diffstat (limited to 'sc')
-rw-r--r--sc/inc/rangenam.hxx6
-rw-r--r--sc/inc/tokenarray.hxx5
-rw-r--r--sc/qa/unit/ucalc.cxx56
-rw-r--r--sc/source/core/data/formulacell.cxx12
-rw-r--r--sc/source/core/tool/rangenam.cxx4
-rw-r--r--sc/source/core/tool/token.cxx48
6 files changed, 115 insertions, 16 deletions
diff --git a/sc/inc/rangenam.hxx b/sc/inc/rangenam.hxx
index 2a15ec87c413..8e9e75303d51 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 e4953466d81e..ac3c332e5278 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 476ba3eb5ee3..98e5bad035d1 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 9ef82e4834b1..f91dc213a1f2 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 830980c9ca66..15b7f6b17383 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 3d82694c3a9e..7a47d69b1424 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 )