sc/inc/column.hxx | 1 sc/inc/formulacell.hxx | 1 sc/inc/table.hxx | 1 sc/inc/tokenarray.hxx | 22 +++- sc/qa/unit/ucalc.cxx | 174 ++++++++++++++++++++---------------- sc/source/core/data/column.cxx | 22 ++++ sc/source/core/data/documen2.cxx | 1 sc/source/core/data/formulacell.cxx | 15 ++- sc/source/core/data/table4.cxx | 6 + sc/source/core/tool/token.cxx | 28 ++++- 10 files changed, 180 insertions(+), 91 deletions(-)
New commits: commit 5caec58dd46320c66f902146d0d14f6e4737d9a8 Author: Tomaž Vajngerl <[email protected]> AuthorDate: Sat Feb 28 00:22:24 2026 +0900 Commit: Miklos Vajna <[email protected]> CommitDate: Mon Mar 2 14:57:45 2026 +0100 sc: Fix backward reference when copying a sheet When extending the test for Overwrite content I also added a case to check a backwards tab reference (referencing a tab that precedes the current one). This extends the test for CopyTab, but surprisingly it failed. In a copied tab, it is needed to adjust the relative tab references, as they still need to point to the same tab, but because the reference is relative, the actual value needs to change (for example from index -1 to -2). This mechanism was missing. This combines the work for OverwriteContent and extends the method AdjustRelativeTabRefs so it can be used for both. This also adds a new sc::CopyTabMode enum to denote if we are adjusting a tab that is inserted or an existing one. Tests were adjusted with the relevant use cases. Change-Id: Ie32d0ceac34525ccaf13aed8fb9630ae42d4225e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200674 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index a6eb2015e77c..acf7cf8abe5a 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -608,6 +608,7 @@ public: bool GetDataEntries( SCROW nRow, std::set<ScTypedStrData>& 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 c11fcea7efe5..0a479961984c 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -318,6 +318,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 9a8d5cf37390..40a1df4fc798 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -1340,6 +1340,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 e2c4fdb7bdcd..ec63c5fd643d 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -7352,19 +7352,22 @@ CPPUNIT_TEST_FIXTURE(Test, testOverwriteContent) 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<std::vector<OUString>> 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) @@ -7373,7 +7376,7 @@ 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]); } } } @@ -7381,115 +7384,134 @@ CPPUNIT_TEST_FIXTURE(Test, testCopyTabContent) // 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<SCTAB>(4), m_pDoc->GetTableCount()); + 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))); - // Tab3 value shifted from index 2 to index 3 - CPPUNIT_ASSERT_EQUAL(66.0, m_pDoc->GetValue(ScAddress(0, 0, 3))); + 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))); - // 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))); + 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 } - // The copy Tab1_2 (tab index 1) should have the same data as Tab1 + // Copy Tab1 to index 2 - Tab1_2 + m_pDoc->CopyTab(1, 2); + CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB>(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/column.cxx b/sc/source/core/data/column.cxx index 1b6db61f6afa..b12c26491d22 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -2612,6 +2612,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; @@ -3042,6 +3058,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/documen2.cxx b/sc/source/core/data/documen2.cxx index 0cb0ec300fc6..7fd9d40a3025 100644 --- a/sc/source/core/data/documen2.cxx +++ b/sc/source/core/data/documen2.cxx @@ -911,6 +911,7 @@ void sc::TableContentCopier::performCopy(const ScMarkData* pOnlyMarked, 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/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 2bed434ae623..c27304d59ee8 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -851,8 +851,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()); } } @@ -3706,6 +3705,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 c42f3d798f3a..6a7623dd315e 100644 --- a/sc/source/core/data/table4.cxx +++ b/sc/source/core/data/table4.cxx @@ -3073,6 +3073,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 3d17fee21ffa..66e770943e30 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -2703,8 +2703,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, nRPN, true); for (size_t j=0; j<2; ++j) { @@ -2721,17 +2738,14 @@ void ScTokenArray::AdjustRelativeTabRefs( SCTAB nDelta ) case svDoubleRef: { ScComplexRefData& rRef = *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 = *p->GetSingleRef(); - if (rRef.IsTabRel() && rRef.Tab() != 0) - rRef.IncTab(-nDelta); + adjustRelativeTabRef(rRef, nOldTab, nNewTab, bInsertedTab); break; } default:
