diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index ff85dd634e88..5ffa042b0a71 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -600,6 +600,7 @@ public: bool GetDataEntries( SCROW nRow, std::set& rStrings) const; void UpdateInsertTabAbs(SCTAB nNewPos); + void AdjustRelativeTabRefs(SCTAB nOldTab, SCTAB nNewTab, sc::TargetTabState eMode); bool TestTabRefAbs(SCTAB nTable) const; bool GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& rData) const; diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index 94bfe00c742b..df9115de5abb 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -326,6 +326,7 @@ public: void UpdateInsertTab( const sc::RefUpdateInsertTabContext& rCxt ); void UpdateInsertTabAbs(SCTAB nTable); + void AdjustRelativeTabRefs(SCTAB nOldTab, SCTAB nNewTab, sc::TargetTabState eMode); void UpdateDeleteTab( const sc::RefUpdateDeleteTabContext& rCxt ); void UpdateMoveTab( const sc::RefUpdateMoveTabContext& rCxt, SCTAB nTabNo ); bool TestTabRefAbs(SCTAB nTable); diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 5aa29ae03e68..135bcb149083 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -1326,6 +1326,7 @@ private: void FillFormula( const ScFormulaCell* pSrcCell, SCCOL nDestCol, SCROW nDestRow, bool bLast ); void UpdateInsertTabAbs(SCTAB nNewPos); + void AdjustRelativeTabRefs(SCTAB nOldTab, SCTAB nNewTab, sc::TargetTabState eMode); bool GetNextSpellingCell(SCCOL& rCol, SCROW& rRow, bool bInSel, const ScMarkData& rMark) const; bool GetNextMarkedCell( SCCOL& rCol, SCROW& rRow, const ScMarkData& rMark ) const; diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx index 13d3230a9700..a43a577ac64e 100644 --- a/sc/inc/tokenarray.hxx +++ b/sc/inc/tokenarray.hxx @@ -39,6 +39,13 @@ struct RefUpdateResult; struct TokenStringContext; class ColRowReorderMapType; +/** If the target tab was inserted, or an existing tab was used. */ +enum class TargetTabState +{ + Existing, + Inserted, +}; + } struct ScRawToken; @@ -151,12 +158,15 @@ public: */ void AdjustAbsoluteRefs( const ScDocument& rOldDoc, const ScAddress& rOldPos, const ScAddress& rNewPos, bool bCheckCopyArea ); - /** Adjust relative tab references when copying a formula between tabs when - overwriting a tab. Non-zero relative tab offsets are decremented by - input delta value so they still resolve to the original target sheet - from the new position. Same-sheet relative refs with offset 0 are left - unchanged. */ - void AdjustRelativeTabRefs(SCTAB nDelta); + /** Adjust relative tab references when copying a formula to a new table. + Non-zero relative tab offsets are recalculated so they still resolve + to the original target sheet from the new position. Same-sheet + relative refs (offset 0) are not modified. + If the target tab was newly inserted, the references pointing to + tabs at or after the insertion point are additionally shifted by + one. */ + void AdjustRelativeTabRefs(SCTAB nOldTab, SCTAB nNewTab, + sc::TargetTabState eMode = sc::TargetTabState::Existing); /** When copying a sheet-local named expression, move sheet references that point to the originating sheet to point to the new sheet instead. diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index c57ff746722f..6d49fedd9142 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -7923,19 +7923,22 @@ CPPUNIT_TEST_FIXTURE(Test, testAutoFilterFlagsAfterColumnDeleteUndoRedo) CPPUNIT_TEST_FIXTURE(Test, testCopyTabContent) { - m_pDoc->InsertTab(0, u"Tab1"_ustr); - m_pDoc->InsertTab(1, u"Tab2"_ustr); - m_pDoc->InsertTab(2, u"Tab3"_ustr); + m_pDoc->InsertTab(0, u"Tab0"_ustr); + m_pDoc->InsertTab(1, u"Tab1"_ustr); + m_pDoc->InsertTab(2, u"Tab2"_ustr); + m_pDoc->InsertTab(3, u"Tab3"_ustr); - // For cross-sheet formula checking - m_pDoc->SetValue(ScAddress(0, 0, 2), 66.0); + // For cross-sheet formula checking (forward and backward) + m_pDoc->SetValue(ScAddress(0, 0, 0), 99.0); // Tab0.A1 + m_pDoc->SetValue(ScAddress(0, 0, 3), 66.0); // Tab3.A1 std::vector> aData = { { u"Column 1"_ustr, u"Column 2"_ustr, u"Column 3"_ustr }, { u"7"_ustr, u"A"_ustr, u"=A2+5"_ustr }, - { u"=2+2"_ustr, u"C"_ustr, u"=Tab3.A1"_ustr }, - { u"=A3-2"_ustr, u"D"_ustr, u"=SUM(A2:A5)"_ustr }, - { u"3"_ustr, u"B"_ustr, u"=C3-60"_ustr } + { u"=2+2"_ustr, u"C"_ustr, u"=Tab3.A1"_ustr }, // forward cross-tab reference + { u"=A3-2"_ustr, u"D"_ustr, u"=SUM(A2:A6)"_ustr }, + { u"3"_ustr, u"B"_ustr, u"=C3-60"_ustr }, + { u"5"_ustr, u"E"_ustr, u"=Tab0.A1"_ustr }, // backward cross-tab reference }; for (size_t i = 0; i < aData.size(); ++i) @@ -7944,123 +7947,142 @@ CPPUNIT_TEST_FIXTURE(Test, testCopyTabContent) { if (!aData[i][j].isEmpty()) { - m_pDoc->SetString(j, i, 0, aData[i][j]); + m_pDoc->SetString(j, i, 1, aData[i][j]); } } } m_pDoc->CalcAll(); // Verify Tab1 values and formulas before copy - { - CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(0, 1, 0))); - CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0, 2, 0))); - CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0, 3, 0))); - CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0, 4, 0))); - - CPPUNIT_ASSERT_EQUAL(u"A"_ustr, m_pDoc->GetString(ScAddress(1, 1, 0))); - CPPUNIT_ASSERT_EQUAL(u"C"_ustr, m_pDoc->GetString(ScAddress(1, 2, 0))); - CPPUNIT_ASSERT_EQUAL(u"D"_ustr, m_pDoc->GetString(ScAddress(1, 3, 0))); - CPPUNIT_ASSERT_EQUAL(u"B"_ustr, m_pDoc->GetString(ScAddress(1, 4, 0))); - - CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(2, 1, 0))); - CPPUNIT_ASSERT_EQUAL(66.0, m_pDoc->GetValue(ScAddress(2, 2, 0))); - CPPUNIT_ASSERT_EQUAL(16.0, m_pDoc->GetValue(ScAddress(2, 3, 0))); - CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(2, 4, 0))); - } - - // Copy Tab1 to index 1 - Tab1_2 - m_pDoc->CopyTab(0, 1); - CPPUNIT_ASSERT_EQUAL(static_cast(4), m_pDoc->GetTableCount()); - - // Tab3 value shifted from index 2 to index 3 - CPPUNIT_ASSERT_EQUAL(66.0, m_pDoc->GetValue(ScAddress(0, 0, 3))); - - // Tab1 (tab index 0) should be unchanged - { - CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(0, 1, 0))); - CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0, 2, 0))); - CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0, 3, 0))); - CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0, 4, 0))); - - CPPUNIT_ASSERT_EQUAL(u"A"_ustr, m_pDoc->GetString(ScAddress(1, 1, 0))); - CPPUNIT_ASSERT_EQUAL(u"C"_ustr, m_pDoc->GetString(ScAddress(1, 2, 0))); - CPPUNIT_ASSERT_EQUAL(u"D"_ustr, m_pDoc->GetString(ScAddress(1, 3, 0))); - CPPUNIT_ASSERT_EQUAL(u"B"_ustr, m_pDoc->GetString(ScAddress(1, 4, 0))); - - CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(2, 1, 0))); - CPPUNIT_ASSERT_EQUAL(66.0, m_pDoc->GetValue(ScAddress(2, 2, 0))); - CPPUNIT_ASSERT_EQUAL(16.0, m_pDoc->GetValue(ScAddress(2, 3, 0))); - CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(2, 4, 0))); - } - - // The copy Tab1_2 (tab index 1) should have the same data as Tab1 { CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(0, 1, 1))); CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0, 2, 1))); CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0, 3, 1))); CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0, 4, 1))); + CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(0, 5, 1))); CPPUNIT_ASSERT_EQUAL(u"A"_ustr, m_pDoc->GetString(ScAddress(1, 1, 1))); CPPUNIT_ASSERT_EQUAL(u"C"_ustr, m_pDoc->GetString(ScAddress(1, 2, 1))); CPPUNIT_ASSERT_EQUAL(u"D"_ustr, m_pDoc->GetString(ScAddress(1, 3, 1))); CPPUNIT_ASSERT_EQUAL(u"B"_ustr, m_pDoc->GetString(ScAddress(1, 4, 1))); + CPPUNIT_ASSERT_EQUAL(u"E"_ustr, m_pDoc->GetString(ScAddress(1, 5, 1))); + + CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(2, 1, 1))); // =A2+5=12 + CPPUNIT_ASSERT_EQUAL(66.0, m_pDoc->GetValue(ScAddress(2, 2, 1))); // =Tab3.A1 + CPPUNIT_ASSERT_EQUAL(21.0, m_pDoc->GetValue(ScAddress(2, 3, 1))); // =SUM(A2:A6) + CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(2, 4, 1))); // =C3-60 + CPPUNIT_ASSERT_EQUAL(99.0, m_pDoc->GetValue(ScAddress(2, 5, 1))); // =Tab0.A1 + } + + // Copy Tab1 to index 2 - Tab1_2 + m_pDoc->CopyTab(1, 2); + CPPUNIT_ASSERT_EQUAL(static_cast(5), m_pDoc->GetTableCount()); + + // Tab3 value shifted from index 3 to index 4 + CPPUNIT_ASSERT_EQUAL(66.0, m_pDoc->GetValue(ScAddress(0, 0, 4))); + // Tab0 value stays at index 0 + CPPUNIT_ASSERT_EQUAL(99.0, m_pDoc->GetValue(ScAddress(0, 0, 0))); + + // Tab1 (tab index 1) should be unchanged + { + CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(0, 1, 1))); + CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0, 2, 1))); + CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0, 3, 1))); + CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0, 4, 1))); + CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(0, 5, 1))); + + CPPUNIT_ASSERT_EQUAL(u"A"_ustr, m_pDoc->GetString(ScAddress(1, 1, 1))); + CPPUNIT_ASSERT_EQUAL(u"C"_ustr, m_pDoc->GetString(ScAddress(1, 2, 1))); + CPPUNIT_ASSERT_EQUAL(u"D"_ustr, m_pDoc->GetString(ScAddress(1, 3, 1))); + CPPUNIT_ASSERT_EQUAL(u"B"_ustr, m_pDoc->GetString(ScAddress(1, 4, 1))); + CPPUNIT_ASSERT_EQUAL(u"E"_ustr, m_pDoc->GetString(ScAddress(1, 5, 1))); CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(2, 1, 1))); CPPUNIT_ASSERT_EQUAL(66.0, m_pDoc->GetValue(ScAddress(2, 2, 1))); - CPPUNIT_ASSERT_EQUAL(16.0, m_pDoc->GetValue(ScAddress(2, 3, 1))); + CPPUNIT_ASSERT_EQUAL(21.0, m_pDoc->GetValue(ScAddress(2, 3, 1))); CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(2, 4, 1))); + CPPUNIT_ASSERT_EQUAL(99.0, m_pDoc->GetValue(ScAddress(2, 5, 1))); + } + + // The copy Tab1_2 (tab index 2) should have the same data as Tab1 + { + CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(0, 1, 2))); + CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0, 2, 2))); + CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0, 3, 2))); + CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0, 4, 2))); + CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(0, 5, 2))); + + CPPUNIT_ASSERT_EQUAL(u"A"_ustr, m_pDoc->GetString(ScAddress(1, 1, 2))); + CPPUNIT_ASSERT_EQUAL(u"C"_ustr, m_pDoc->GetString(ScAddress(1, 2, 2))); + CPPUNIT_ASSERT_EQUAL(u"D"_ustr, m_pDoc->GetString(ScAddress(1, 3, 2))); + CPPUNIT_ASSERT_EQUAL(u"B"_ustr, m_pDoc->GetString(ScAddress(1, 4, 2))); + CPPUNIT_ASSERT_EQUAL(u"E"_ustr, m_pDoc->GetString(ScAddress(1, 5, 2))); + + CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(2, 1, 2))); + CPPUNIT_ASSERT_EQUAL(66.0, m_pDoc->GetValue(ScAddress(2, 2, 2))); + CPPUNIT_ASSERT_EQUAL(21.0, m_pDoc->GetValue(ScAddress(2, 3, 2))); + CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(2, 4, 2))); + CPPUNIT_ASSERT_EQUAL(99.0, m_pDoc->GetValue(ScAddress(2, 5, 2))); } // Check the formulas in Tab1_2 { - CPPUNIT_ASSERT_EQUAL(u"=2+2"_ustr, m_pDoc->GetFormula(0, 2, 1)); - CPPUNIT_ASSERT_EQUAL(u"=A3-2"_ustr, m_pDoc->GetFormula(0, 3, 1)); - CPPUNIT_ASSERT_EQUAL(u"=A2+5"_ustr, m_pDoc->GetFormula(2, 1, 1)); - CPPUNIT_ASSERT_EQUAL(u"='Tab3'.A1"_ustr, m_pDoc->GetFormula(2, 2, 1)); - CPPUNIT_ASSERT_EQUAL(u"=SUM(A2:A5)"_ustr, m_pDoc->GetFormula(2, 3, 1)); - CPPUNIT_ASSERT_EQUAL(u"=C3-60"_ustr, m_pDoc->GetFormula(2, 4, 1)); + CPPUNIT_ASSERT_EQUAL(u"=2+2"_ustr, m_pDoc->GetFormula(0, 2, 2)); + CPPUNIT_ASSERT_EQUAL(u"=A3-2"_ustr, m_pDoc->GetFormula(0, 3, 2)); + CPPUNIT_ASSERT_EQUAL(u"=A2+5"_ustr, m_pDoc->GetFormula(2, 1, 2)); + CPPUNIT_ASSERT_EQUAL(u"='Tab3'.A1"_ustr, m_pDoc->GetFormula(2, 2, 2)); + CPPUNIT_ASSERT_EQUAL(u"=SUM(A2:A6)"_ustr, m_pDoc->GetFormula(2, 3, 2)); + CPPUNIT_ASSERT_EQUAL(u"=C3-60"_ustr, m_pDoc->GetFormula(2, 4, 2)); + CPPUNIT_ASSERT_EQUAL(u"=Tab0.A1"_ustr, m_pDoc->GetFormula(2, 5, 2)); } // Change Tab1 and verify the copy is independent - m_pDoc->SetValue(ScAddress(0, 1, 0), 10.0); // 7 -> 10 + m_pDoc->SetValue(ScAddress(0, 1, 1), 10.0); // 7 -> 10 m_pDoc->CalcAll(); // Tab1 should be changed { - CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(0, 1, 0))); - CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0, 2, 0))); - CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0, 3, 0))); - CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0, 4, 0))); - - CPPUNIT_ASSERT_EQUAL(u"A"_ustr, m_pDoc->GetString(ScAddress(1, 1, 0))); - CPPUNIT_ASSERT_EQUAL(u"C"_ustr, m_pDoc->GetString(ScAddress(1, 2, 0))); - CPPUNIT_ASSERT_EQUAL(u"D"_ustr, m_pDoc->GetString(ScAddress(1, 3, 0))); - CPPUNIT_ASSERT_EQUAL(u"B"_ustr, m_pDoc->GetString(ScAddress(1, 4, 0))); - - CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc->GetValue(ScAddress(2, 1, 0))); - CPPUNIT_ASSERT_EQUAL(66.0, m_pDoc->GetValue(ScAddress(2, 2, 0))); - CPPUNIT_ASSERT_EQUAL(19.0, m_pDoc->GetValue(ScAddress(2, 3, 0))); - CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(2, 4, 0))); - } - - // No change in Tab1_2 - { - CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(0, 1, 1))); + CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(0, 1, 1))); CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0, 2, 1))); CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0, 3, 1))); CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0, 4, 1))); + CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(0, 5, 1))); CPPUNIT_ASSERT_EQUAL(u"A"_ustr, m_pDoc->GetString(ScAddress(1, 1, 1))); CPPUNIT_ASSERT_EQUAL(u"C"_ustr, m_pDoc->GetString(ScAddress(1, 2, 1))); CPPUNIT_ASSERT_EQUAL(u"D"_ustr, m_pDoc->GetString(ScAddress(1, 3, 1))); CPPUNIT_ASSERT_EQUAL(u"B"_ustr, m_pDoc->GetString(ScAddress(1, 4, 1))); + CPPUNIT_ASSERT_EQUAL(u"E"_ustr, m_pDoc->GetString(ScAddress(1, 5, 1))); - CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(2, 1, 1))); + CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc->GetValue(ScAddress(2, 1, 1))); CPPUNIT_ASSERT_EQUAL(66.0, m_pDoc->GetValue(ScAddress(2, 2, 1))); - CPPUNIT_ASSERT_EQUAL(16.0, m_pDoc->GetValue(ScAddress(2, 3, 1))); + CPPUNIT_ASSERT_EQUAL(24.0, m_pDoc->GetValue(ScAddress(2, 3, 1))); // =SUM(A2:A6)=10+4+2+3+5 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(2, 4, 1))); + CPPUNIT_ASSERT_EQUAL(99.0, m_pDoc->GetValue(ScAddress(2, 5, 1))); } + // No change in Tab1_2 + { + CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(0, 1, 2))); + CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0, 2, 2))); + CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0, 3, 2))); + CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0, 4, 2))); + CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(0, 5, 2))); + + CPPUNIT_ASSERT_EQUAL(u"A"_ustr, m_pDoc->GetString(ScAddress(1, 1, 2))); + CPPUNIT_ASSERT_EQUAL(u"C"_ustr, m_pDoc->GetString(ScAddress(1, 2, 2))); + CPPUNIT_ASSERT_EQUAL(u"D"_ustr, m_pDoc->GetString(ScAddress(1, 3, 2))); + CPPUNIT_ASSERT_EQUAL(u"B"_ustr, m_pDoc->GetString(ScAddress(1, 4, 2))); + CPPUNIT_ASSERT_EQUAL(u"E"_ustr, m_pDoc->GetString(ScAddress(1, 5, 2))); + + CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(2, 1, 2))); + CPPUNIT_ASSERT_EQUAL(66.0, m_pDoc->GetValue(ScAddress(2, 2, 2))); + CPPUNIT_ASSERT_EQUAL(21.0, m_pDoc->GetValue(ScAddress(2, 3, 2))); + CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(2, 4, 2))); + CPPUNIT_ASSERT_EQUAL(99.0, m_pDoc->GetValue(ScAddress(2, 5, 2))); + } + + m_pDoc->DeleteTab(4); m_pDoc->DeleteTab(3); m_pDoc->DeleteTab(2); m_pDoc->DeleteTab(1); diff --git a/sc/source/core/data/TableContentCopier.cxx b/sc/source/core/data/TableContentCopier.cxx index 4a9fdb5701b8..6a4a35d74351 100644 --- a/sc/source/core/data/TableContentCopier.cxx +++ b/sc/source/core/data/TableContentCopier.cxx @@ -91,6 +91,7 @@ void sc::TableContentCopier::updateReferencesAfterTabInsertion( sc::RefUpdateInsertTabContext& rContext) { mpTargetTab->UpdateInsertTabAbs(mnTargetTabNo); + mpTargetTab->AdjustRelativeTabRefs(mnSourceTabNo, mnTargetTabNo, sc::TargetTabState::Inserted); mpSourceTab->UpdateInsertTab(rContext); mpSourceTab->UpdateCompile(); } diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index ca183f17312f..8bcb8f94bc23 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -2634,6 +2634,22 @@ public: } }; +/** For adjusting relative tab references. */ +class RelativeTabRefUpdater +{ + SCTAB mnOldTab; + SCTAB mnNewTab; + sc::TargetTabState meMode; +public: + RelativeTabRefUpdater(SCTAB nOldTab, SCTAB nNewTab, sc::TargetTabState eMode) : + mnOldTab(nOldTab), mnNewTab(nNewTab), meMode(eMode) {} + + void operator() (size_t /*nRow*/, ScFormulaCell* pCell) + { + pCell->AdjustRelativeTabRefs(mnOldTab, mnNewTab, meMode); + } +}; + class UsedRangeNameFinder { sc::UpdatedRangeNames& mrIndexes; @@ -3064,6 +3080,12 @@ void ScColumn::UpdateInsertTabAbs(SCTAB nNewPos) CellStorageModified(); } +void ScColumn::AdjustRelativeTabRefs(SCTAB nOldTab, SCTAB nNewTab, sc::TargetTabState eMode) +{ + RelativeTabRefUpdater aFunc(nOldTab, nNewTab, eMode); + sc::ProcessFormula(maCells, aFunc); +} + void ScColumn::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nTabNo ) { nTab = nTabNo; diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index b46ae3fe7cea..9096748d4566 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -895,8 +895,7 @@ ScFormulaCell::ScFormulaCell(const ScFormulaCell& rCell, ScDocument& rDoc, const if ((nCloneFlags & ScCloneFlags::AdjustCrossSheetRefs) != ScCloneFlags::Default) { - SCTAB nDelta = aPos.Tab() - rCell.aPos.Tab(); - pCode->AdjustRelativeTabRefs(nDelta); + pCode->AdjustRelativeTabRefs(rCell.aPos.Tab(), aPos.Tab()); } } @@ -4185,6 +4184,18 @@ void ScFormulaCell::UpdateInsertTabAbs(SCTAB nTable) } } +void ScFormulaCell::AdjustRelativeTabRefs(SCTAB nOldTab, SCTAB nNewTab, sc::TargetTabState eMode) +{ + if (rDocument.IsClipOrUndo()) + return; + + bool bAdjustCode = !mxGroup || mxGroup->mpTopCell == this; + if (!bAdjustCode) + return; + + pCode->AdjustRelativeTabRefs(nOldTab, nNewTab, eMode); +} + bool ScFormulaCell::TestTabRefAbs(SCTAB nTable) { if (rDocument.IsClipOrUndo()) diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx index 1ee138c98d28..ad4be97da919 100644 --- a/sc/source/core/data/table4.cxx +++ b/sc/source/core/data/table4.cxx @@ -2756,6 +2756,12 @@ void ScTable::UpdateInsertTabAbs(SCTAB nTable) aCol[i].UpdateInsertTabAbs(nTable); } +void ScTable::AdjustRelativeTabRefs(SCTAB nOldTab, SCTAB nNewTab, sc::TargetTabState eMode) +{ + for (SCCOL i=0; i < aCol.size(); i++) + aCol[i].AdjustRelativeTabRefs(nOldTab, nNewTab, eMode); +} + bool ScTable::GetNextSpellingCell(SCCOL& rCol, SCROW& rRow, bool bInSel, const ScMarkData& rMark) const { diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index 1d8e594b3805..c14c757bfa15 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -2627,8 +2627,25 @@ void ScTokenArray::AdjustAbsoluteRefs( const ScDocument& rOldDoc, const ScAddres } } -void ScTokenArray::AdjustRelativeTabRefs( SCTAB nDelta ) +namespace { + +void adjustRelativeTabRef(ScSingleRefData& rRef, SCTAB nOldTab, SCTAB nNewTab, bool bInsertedTab) +{ + if (!rRef.IsTabRel() || rRef.Tab() == 0) + return; + SCTAB nAbsTarget = nOldTab + rRef.Tab(); + if (bInsertedTab && nAbsTarget >= nNewTab) + nAbsTarget++; + SCTAB nNewOffset = nAbsTarget - nNewTab; + rRef.IncTab(nNewOffset - rRef.Tab()); +} + +} // anonymous namespace + +void ScTokenArray::AdjustRelativeTabRefs(SCTAB nOldTab, SCTAB nNewTab, sc::TargetTabState eMode) +{ + const bool bInsertedTab = (eMode == sc::TargetTabState::Inserted); TokenPointers aPtrs( pCode.get(), nLen, pRPN.get(), nRPN, true); for (size_t j=0; j<2; ++j) { @@ -2645,17 +2662,14 @@ void ScTokenArray::AdjustRelativeTabRefs( SCTAB nDelta ) case svDoubleRef: { ScComplexRefData& rRef = static_cast(p)->GetDoubleRef(); - if (rRef.Ref1.IsTabRel() && rRef.Ref1.Tab() != 0) - rRef.Ref1.IncTab(-nDelta); - if (rRef.Ref2.IsTabRel() && rRef.Ref2.Tab() != 0) - rRef.Ref2.IncTab(-nDelta); + adjustRelativeTabRef(rRef.Ref1, nOldTab, nNewTab, bInsertedTab); + adjustRelativeTabRef(rRef.Ref2, nOldTab, nNewTab, bInsertedTab); break; } case svSingleRef: { ScSingleRefData& rRef = static_cast(p)->GetSingleRef(); - if (rRef.IsTabRel() && rRef.Tab() != 0) - rRef.IncTab(-nDelta); + adjustRelativeTabRef(rRef, nOldTab, nNewTab, bInsertedTab); break; } default: