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:

Reply via email to