sc/inc/column.hxx                   |    2 
 sc/inc/document.hxx                 |    4 
 sc/inc/global.hxx                   |    9 +
 sc/inc/table.hxx                    |    3 
 sc/inc/tokenarray.hxx               |    7 +
 sc/qa/unit/ucalc.cxx                |  199 +++++++++++++++++++++++++++++++-----
 sc/source/core/data/column.cxx      |    8 -
 sc/source/core/data/documen2.cxx    |  155 +++++++++++++++++++---------
 sc/source/core/data/document.cxx    |   10 -
 sc/source/core/data/formulacell.cxx |    6 +
 sc/source/core/data/table2.cxx      |    4 
 sc/source/core/tool/token.cxx       |   38 ++++++
 12 files changed, 357 insertions(+), 88 deletions(-)

New commits:
commit 54d971bc0b527a3f2679f558fecb9f253a50e387
Author:     Tomaž Vajngerl <[email protected]>
AuthorDate: Fri Feb 27 18:09:18 2026 +0900
Commit:     Miklos Vajna <[email protected]>
CommitDate: Mon Mar 2 09:17:22 2026 +0100

    sc: Fix cross-tab references when using OverwriteContent
    
    When we overwrite the content of a tab, we need to handle the
    cross-tab references in the document, or the formulas will refer
    to the wrong tab.
    
    Introduce TableContentCopier, which handles copying content
    for CopyTab and OverwriteContent. The class is needed so we
    don't duplicate almost the same algorithm and still keep the
    code readable.
    
    Add a new AdjustCrossSheetRefs flag to ScCloneFlags to handle
    the cross-tab references.
    
    Expose ScCloneFlags as a parameter in ScTable::CopyToTable, which
    makes it possible to set the new flag from the outside. Previously
    a bool was used, which was converted to a ScCloneFlags value.
    
    Change-Id: I8d5886b03c68421f78fc57c42af6ead493eab5b9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200619
    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 22e3ad1e284c..a6eb2015e77c 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -378,7 +378,7 @@ public:
     void CopyToColumn(
         sc::CopyToDocContext& rCxt, SCROW nRow1, SCROW nRow2, 
InsertDeleteFlags nFlags, bool bMarked,
         ScColumn& rColumn, const ScMarkData* pMarkData = nullptr, bool bAsLink 
= false,
-        bool bGlobalNamesToLocal = false ) const;
+        ScCloneFlags nCloneFlags = ScCloneFlags::Default ) const;
 
     void UndoToColumn(
         sc::CopyToDocContext& rCxt, SCROW nRow1, SCROW nRow2, 
InsertDeleteFlags nFlags, bool bMarked,
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index c68d550fddfd..81244baa0536 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -234,6 +234,8 @@ namespace sc {
 
 typedef std::map<OUString, BitmapEx> IconSetBitmapMap;
 
+class TableContentCopier;
+
 }
 
 namespace com::sun::star {
@@ -368,6 +370,7 @@ friend class ScColumn;
 friend struct ScRefCellValue;
 friend class ScDocumentImport;
 friend class sc::EditTextIterator;
+friend class sc::TableContentCopier;
 friend struct ScMutationGuard;
 friend struct ScMutationDisable;
 
@@ -1071,7 +1074,6 @@ public:
     bool                        MoveTab( SCTAB nOldPos, SCTAB nNewPos, 
ScProgress* pProgress = nullptr );
     SC_DLLPUBLIC bool           CopyTab( SCTAB nOldPos, SCTAB nNewPos, const 
ScMarkData* pOnlyMarked = nullptr );
 
-    void CopyContent(SCTAB nSourceTabNo, SCTAB nTargetTabNo, const ScMarkData* 
pOnlyMarked, sc::RefUpdateInsertTabContext& rContext);
     bool OverwriteContent(SCTAB nSourceTabNo, SCTAB nTargetTabNo);
 
     SC_DLLPUBLIC bool      TransferTab(ScDocument& rSrcDoc, SCTAB nSrcPos, 
SCTAB nDestPos,
diff --git a/sc/inc/global.hxx b/sc/inc/global.hxx
index 6e986267c8a6..4692dc791220 100644
--- a/sc/inc/global.hxx
+++ b/sc/inc/global.hxx
@@ -263,11 +263,16 @@ enum class ScCloneFlags{
 
 /** If set, global named expressions will be converted to sheet-local named
     expressions. */
-    NamesToLocal   = 0x0004
+    NamesToLocal   = 0x0004,
+
+    /** If set, cross-sheet references will be adjusted during copying to
+    compensate for the difference of the tab index between source and
+    destination cells. */
+    AdjustCrossSheetRefs = 0x0008
 };
 namespace o3tl
 {
-    template<> struct typed_flags<ScCloneFlags> : is_typed_flags<ScCloneFlags, 
0x0007> {};
+    template<> struct typed_flags<ScCloneFlags> : is_typed_flags<ScCloneFlags, 
0x000f> {};
 }
 
 enum CellType
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 92a6e76d4bbd..9a8d5cf37390 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -288,6 +288,7 @@ friend class sc::ColumnSpanSet;
 friend class sc::RangeColumnSpanSet;
 friend class sc::EditTextIterator;
 friend class sc::FormulaGroupAreaListener;
+friend class sc::TableContentCopier;
 
 public:
                 ScTable( ScDocument& rDoc, SCTAB nNewTab, const OUString& 
rNewName,
@@ -584,7 +585,7 @@ public:
         sc::CopyToDocContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, 
SCROW nRow2,
         InsertDeleteFlags nFlags, bool bMarked, ScTable* pDestTab,
         const ScMarkData* pMarkData, bool bAsLink, bool bColRowFlags,
-        bool bGlobalNamesToLocal, bool bCopyCaptions );
+        ScCloneFlags nCloneFlags, bool bCopyCaptions );
 
     void CopyCaptionsToTable( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW 
nRow2, ScTable* pDestTab, bool bCloneCaption );
 
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index 08938553ea4f..13d3230a9700 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -151,6 +151,13 @@ 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);
+
     /** 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 c793d093b5a5..70227e300eb9 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -7151,56 +7151,203 @@ CPPUNIT_TEST_FIXTURE(Test, 
testDocumentModelAccessor_getDocumentCurrencies)
 
 CPPUNIT_TEST_FIXTURE(Test, testOverwriteContent)
 {
-    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 table 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"C1"_ustr, u"C2"_ustr, u"C3"_ustr },
-        {  u"7"_ustr,  u"1"_ustr,  u"A"_ustr },
-        {  u"3"_ustr,  u"2"_ustr,   u""_ustr },
-        {  u"2"_ustr,  u"4"_ustr,  u"B"_ustr },
-        {  u"4"_ustr,  u"3"_ustr,  u"B"_ustr }
+        { 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 }, // 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
     };
 
-    // Populate cells.
     for (size_t i = 0; i < aData.size(); ++i)
     {
         for (size_t j = 0; j < aData[0].size(); ++j)
         {
             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();
 
-    CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(0, 1, 0)));
-    CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(0, 1, 1)));
+    // Verify Tab1 values and formulas before overwrite
+    {
+        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))); // 
A3-2=2
+        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
+    }
+
+    // Tab2 should be empty
     CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(0, 1, 2)));
+    CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(1, 2, 2)));
+    CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(2, 3, 2)));
 
-    m_pDoc->OverwriteContent(0, 1);
+    // Overwrite Tab2 with Tab1 content
+    m_pDoc->OverwriteContent(1, 2);
 
-    CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(0, 1, 0)));
-    CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(0, 1, 1)));
-    CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(0, 1, 2)));
+    // Tab1 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(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)));
+    }
+
+    // Tab2 values should match Tab1 and the formulas adjusted if needed
+    {
+        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->SetString(0, 1, 0, u"9.0"_ustr);
+    // Check Tab2 formulas were copied correctly
+    {
+        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));
+    }
 
-    CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(0, 1, 0)));
-    CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(0, 1, 1)));
-    CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(0, 1, 2)));
+    // Change Tab1 and see if it affects Tab2
+    m_pDoc->SetValue(ScAddress(0, 1, 1), 10.0); // 7 -> 10
+    m_pDoc->CalcAll();
 
+    // Check Tab 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(15.0, m_pDoc->GetValue(ScAddress(2, 1, 1)));
+        CPPUNIT_ASSERT_EQUAL(66.0, m_pDoc->GetValue(ScAddress(2, 2, 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)));
+    }
 
-    m_pDoc->OverwriteContent(0, 1);
+    // Check Tab 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)));
+    }
 
-    CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(0, 1, 0)));
-    CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(0, 1, 1)));
-    CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(0, 1, 2)));
+    // Overwrite Tab2 again with updated Tab1
+    m_pDoc->OverwriteContent(1, 2);
 
-    m_pDoc->DeleteTab(0);
-    m_pDoc->DeleteTab(1);
+    // Check Tab 2
+    {
+        CPPUNIT_ASSERT_EQUAL(10.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(15.0, m_pDoc->GetValue(ScAddress(2, 1, 2)));
+        CPPUNIT_ASSERT_EQUAL(66.0, m_pDoc->GetValue(ScAddress(2, 2, 2)));
+        CPPUNIT_ASSERT_EQUAL(24.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 formulas are still the same
+    {
+        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));
+    }
+
+    m_pDoc->DeleteTab(3);
     m_pDoc->DeleteTab(2);
+    m_pDoc->DeleteTab(1);
+    m_pDoc->DeleteTab(0);
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 15060d98c1b3..1b6db61f6afa 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -1349,14 +1349,14 @@ class CopyByCloneHandler
 
 public:
     CopyByCloneHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, 
sc::ColumnBlockPosition* pDestPos,
-            InsertDeleteFlags nCopyFlags, svl::SharedStringPool* 
pSharedStringPool, bool bGlobalNamesToLocal) :
+            InsertDeleteFlags nCopyFlags, svl::SharedStringPool* 
pSharedStringPool, ScCloneFlags nCloneFlags) :
         mrSrcCol(rSrcCol),
         mrDestCol(rDestCol),
         mpDestPos(pDestPos),
         mpSharedStringPool(pSharedStringPool),
         mnCopyFlags(nCopyFlags),
         meListenType(sc::SingleCellListening),
-        mnFormulaCellCloneFlags(bGlobalNamesToLocal ? 
ScCloneFlags::NamesToLocal : ScCloneFlags::Default)
+        mnFormulaCellCloneFlags(nCloneFlags)
     {
         if (mpDestPos)
             maDestPos = *mpDestPos;
@@ -1522,7 +1522,7 @@ public:
 void ScColumn::CopyToColumn(
     sc::CopyToDocContext& rCxt,
     SCROW nRow1, SCROW nRow2, InsertDeleteFlags nFlags, bool bMarked, 
ScColumn& rColumn,
-    const ScMarkData* pMarkData, bool bAsLink, bool bGlobalNamesToLocal) const
+    const ScMarkData* pMarkData, bool bAsLink, ScCloneFlags nCloneFlags) const
 {
     if (bMarked)
     {
@@ -1579,7 +1579,7 @@ void ScColumn::CopyToColumn(
             (GetDoc().GetPool() != rColumn.GetDoc().GetPool()) ?
             &rColumn.GetDoc().GetSharedStringPool() : nullptr;
         CopyByCloneHandler aFunc(*this, rColumn, 
rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags,
-                pSharedStringPool, bGlobalNamesToLocal);
+                pSharedStringPool, nCloneFlags);
         aFunc.setStartListening(rCxt.isStartListening());
         sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
     }
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index a3d3d5939cb3..0cb0ec300fc6 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -820,66 +820,110 @@ bool ScDocument::MoveTab( SCTAB nOldPos, SCTAB nNewPos, 
ScProgress* pProgress )
     return bValid;
 }
 
-void ScDocument::CopyContent(SCTAB nSourceTabNo, SCTAB nTargetTabNo, const 
ScMarkData* pOnlyMarked, sc::RefUpdateInsertTabContext& rContext)
+namespace sc
 {
-    SetNoListening( true );     // not yet at CopyToTable/Insert
+
+class TableContentCopier
+{
+    ScDocument& mrDoc;
+    const SCTAB mnSourceTabNo;
+    const SCTAB mnTargetTabNo;
+    ScTable* const mpSourceTab;
+    ScTable* const mpTargetTab;
+public:
+    TableContentCopier(ScDocument& rDoc,
+        SCTAB nSourceTabNo, SCTAB nTargetTabNo);
+
+    ~TableContentCopier();
+
+    void performCopy(const ScMarkData* pOnlyMarked, ScCloneFlags nCloneFlags,
+        SCTAB nPreviousSourceTabNo = -1);
+    void updateReferencesAfterTabInsertion(RefUpdateInsertTabContext& 
rContext);
+    void recompileTargetFormulas();
+};
+
+} // namespace sc
+
+sc::TableContentCopier::TableContentCopier(ScDocument& rDoc,
+    SCTAB nSourceTabNo, SCTAB nTargetTabNo)
+    : mrDoc(rDoc)
+    , mnSourceTabNo(nSourceTabNo)
+    , mnTargetTabNo(nTargetTabNo)
+    , mpSourceTab(mrDoc.FetchTable(nSourceTabNo))
+    , mpTargetTab(mrDoc.FetchTable(nTargetTabNo))
+{
+}
+
+void sc::TableContentCopier::performCopy(const ScMarkData* pOnlyMarked,
+    ScCloneFlags nCloneFlags, SCTAB nPreviousSourceTabNo)
+{
+    if (nPreviousSourceTabNo < 0)
+        nPreviousSourceTabNo = mnSourceTabNo;
 
     const bool bGlobalNamesToLocal = true;
-    const SCTAB nRealOldPos = (nTargetTabNo < nSourceTabNo) ? nSourceTabNo - 1 
: nSourceTabNo;
-    const ScRangeName* pNames = GetRangeName( nSourceTabNo);
+    const ScRangeName* pNames = mrDoc.GetRangeName(mnSourceTabNo);
     if (pNames)
-        pNames->CopyUsedNames( nSourceTabNo, nRealOldPos, nTargetTabNo, *this, 
*this, bGlobalNamesToLocal);
-    GetRangeName()->CopyUsedNames( -1, nRealOldPos, nTargetTabNo, *this, 
*this, bGlobalNamesToLocal);
-
-    sc::CopyToDocContext aCopyDocCxt(*this);
-    pDBCollection->CopyToTable(nSourceTabNo, nTargetTabNo);
-    maTabs[nSourceTabNo]->CopyToTable(aCopyDocCxt, 0, 0, MaxCol(), MaxRow(), 
InsertDeleteFlags::ALL,
-            (pOnlyMarked != nullptr), maTabs[nTargetTabNo].get(), pOnlyMarked,
-            false /*bAsLink*/, true /*bColRowFlags*/, bGlobalNamesToLocal, 
false /*bCopyCaptions*/ );
-    maTabs[nTargetTabNo]->SetTabBgColor(maTabs[nSourceTabNo]->GetTabBgColor());
-
-    SCTAB nDz = nTargetTabNo - nSourceTabNo;
-    sc::RefUpdateContext aRefContext(*this);
+        pNames->CopyUsedNames(mnSourceTabNo, nPreviousSourceTabNo, 
mnTargetTabNo, mrDoc, mrDoc, bGlobalNamesToLocal);
+    mrDoc.GetRangeName()->CopyUsedNames(-1, nPreviousSourceTabNo, 
mnTargetTabNo, mrDoc, mrDoc, bGlobalNamesToLocal);
+
+    sc::CopyToDocContext aCopyDocCxt(mrDoc);
+    if (mrDoc.pDBCollection)
+        mrDoc.pDBCollection->CopyToTable(mnSourceTabNo, mnTargetTabNo);
+    mpSourceTab->CopyToTable(aCopyDocCxt, 0, 0, mrDoc.MaxCol(), 
mrDoc.MaxRow(), InsertDeleteFlags::ALL,
+            (pOnlyMarked != nullptr), mpTargetTab, pOnlyMarked,
+            false /*bAsLink*/, true /*bColRowFlags*/, nCloneFlags, false 
/*bCopyCaptions*/);
+    mpTargetTab->SetTabBgColor(mpSourceTab->GetTabBgColor());
+
+    SCTAB nDz = mnTargetTabNo - mnSourceTabNo;
+    sc::RefUpdateContext aRefContext(mrDoc);
     aRefContext.meMode = URM_COPY;
-    aRefContext.maRange = ScRange(0, 0, nTargetTabNo, MaxCol(), MaxRow(), 
nTargetTabNo);
+    aRefContext.maRange = ScRange(0, 0, mnTargetTabNo, mrDoc.MaxCol(), 
mrDoc.MaxRow(), mnTargetTabNo);
     aRefContext.mnTabDelta = nDz;
-    maTabs[nTargetTabNo]->UpdateReference(aRefContext);
-
-    maTabs[nTargetTabNo]->UpdateInsertTabAbs(nTargetTabNo); // move all 
paragraphs up by one!!
-    maTabs[nSourceTabNo]->UpdateInsertTab(rContext);
-
-    maTabs[nSourceTabNo]->UpdateCompile();
-    maTabs[nTargetTabNo]->UpdateCompile( true ); //  maybe already compiled in 
Clone, but used names need recompilation
-    SetNoListening( false );
-    sc::StartListeningContext aSLCxt(*this);
-    maTabs[nSourceTabNo]->StartListeners(aSLCxt, true);
-    maTabs[nTargetTabNo]->StartListeners(aSLCxt, true);
+    mpTargetTab->UpdateReference(aRefContext);
 
     sc::SetFormulaDirtyContext aFormulaDirtyCxt;
-    SetAllFormulasDirty(aFormulaDirtyCxt);
+    mrDoc.SetAllFormulasDirty(aFormulaDirtyCxt);
 
-    if (mpDrawLayer) //  Skip cloning Note caption object
+    if (mrDoc.mpDrawLayer) //  Skip cloning Note caption object
         // page is already created in ScTable ctor
-        mpDrawLayer->ScCopyPage( static_cast<sal_uInt16>(nSourceTabNo), 
static_cast<sal_uInt16>(nTargetTabNo) );
+        mrDoc.mpDrawLayer->ScCopyPage( static_cast<sal_uInt16>(mnSourceTabNo), 
static_cast<sal_uInt16>(mnTargetTabNo) );
 
-    if (pDPCollection)
-        pDPCollection->CopyToTab(nSourceTabNo, nTargetTabNo);
+    if (mrDoc.pDPCollection)
+        mrDoc.pDPCollection->CopyToTab(mnSourceTabNo, mnTargetTabNo);
 
-    maTabs[nTargetTabNo]->SetPageStyle( maTabs[nSourceTabNo]->GetPageStyle() );
-    maTabs[nTargetTabNo]->SetPendingRowHeights( 
maTabs[nSourceTabNo]->IsPendingRowHeights() );
+    mpTargetTab->SetPageStyle( mpSourceTab->GetPageStyle() );
+    mpTargetTab->SetPendingRowHeights( mpSourceTab->IsPendingRowHeights() );
 
     // Copy the custom print range if exists.
-    maTabs[nTargetTabNo]->CopyPrintRange(*maTabs[nSourceTabNo]);
+    mpTargetTab->CopyPrintRange(*mpSourceTab);
 
     // Copy the RTL settings
-    maTabs[nTargetTabNo]->SetLayoutRTL(maTabs[nSourceTabNo]->IsLayoutRTL());
-    maTabs[nTargetTabNo]->SetLoadingRTL(maTabs[nSourceTabNo]->IsLoadingRTL());
+    mpTargetTab->SetLayoutRTL(mpSourceTab->IsLayoutRTL());
+    mpTargetTab->SetLoadingRTL(mpSourceTab->IsLoadingRTL());
 
     // Finally copy the note captions, which need
-    // 1. the updated source ScColumn::nTab members if nTargetTabNo <= 
nSourceTabNo
+    // 1. the updated source ScColumn::nTab members if the target tab is 
before the source tab
     // 2. row heights and column widths of the destination
     // 3. RTL settings of the destination
-    maTabs[nSourceTabNo]->CopyCaptionsToTable( 0, 0, MaxCol(), MaxRow(), 
maTabs[nTargetTabNo].get(), true /*bCloneCaption*/);
+    mpSourceTab->CopyCaptionsToTable( 0, 0, mrDoc.MaxCol(), mrDoc.MaxRow(), 
mpTargetTab, true /*bCloneCaption*/);
+}
+
+void 
sc::TableContentCopier::updateReferencesAfterTabInsertion(sc::RefUpdateInsertTabContext&
 rContext)
+{
+    mpTargetTab->UpdateInsertTabAbs(mnTargetTabNo);
+    mpSourceTab->UpdateInsertTab(rContext);
+    mpSourceTab->UpdateCompile();
+}
+
+void sc::TableContentCopier::recompileTargetFormulas()
+{
+    //  maybe already compiled in Clone, but used names need recompilation
+    mpTargetTab->UpdateCompile(true);
+}
+
+sc::TableContentCopier::~TableContentCopier()
+{
+    recompileTargetFormulas();
 }
 
 bool ScDocument::OverwriteContent(SCTAB nSourceTabNo, SCTAB nTargetTabNo)
@@ -889,14 +933,21 @@ bool ScDocument::OverwriteContent(SCTAB nSourceTabNo, 
SCTAB nTargetTabNo)
 
     if (pSourceTable && pTargetTable)
     {
+        sc::AutoCalcSwitch aACSwitch(*this, false);
+        SetNoListening(true);
         pTargetTable->DeleteArea(0, 0, MaxCol(), MaxRow(), 
InsertDeleteFlags::ALL);
 
-        sc::AutoCalcSwitch aACSwitch(*this, false);
-        sc::RefUpdateInsertTabContext aContext(*this, nTargetTabNo, 1);
-        CopyContent(nSourceTabNo, nTargetTabNo, nullptr, aContext);
+        {
+            sc::TableContentCopier aHandler(*this, nSourceTabNo, nTargetTabNo);
+            aHandler.performCopy(nullptr, ScCloneFlags::NamesToLocal | 
ScCloneFlags::AdjustCrossSheetRefs);
+        }
+
+        SetNoListening(false);
+        sc::StartListeningContext aSLCxt(*this);
+        maTabs[nTargetTabNo]->StartListeners(aSLCxt, true);
         return true;
     }
-    return false;
+    return true;
 }
 
 
@@ -983,7 +1034,19 @@ bool ScDocument::CopyTab( SCTAB nOldPos, SCTAB nNewPos, 
const ScMarkData* pOnlyM
 
     if (bValid)
     {
-        CopyContent(nOldPos, nNewPos, pOnlyMarked, aCxt);
+        SetNoListening(true);
+
+        SCTAB nPreviousSourceTabNo = (nNewPos < nOldPos) ? nOldPos - 1 : 
nOldPos;
+        {
+            sc::TableContentCopier aHandler(*this, nOldPos, nNewPos);
+            aHandler.performCopy(pOnlyMarked, ScCloneFlags::NamesToLocal, 
nPreviousSourceTabNo);
+            aHandler.updateReferencesAfterTabInsertion(aCxt);
+        }
+
+        SetNoListening(false);
+        sc::StartListeningContext aSLCxt(*this);
+        maTabs[nOldPos]->StartListeners(aSLCxt, true);
+        maTabs[nNewPos]->StartListeners(aSLCxt, true);
     }
 
     return bValid;
@@ -1059,7 +1122,7 @@ bool ScDocument::TransferTab( ScDocument& rSrcDoc, SCTAB 
nSrcPos,
                 rSrcDoc.maTabs[nSrcPos]->CopyToTable(aCxt, 0, 0, MaxCol(), 
MaxRow(),
                         ( bResultsOnly ? InsertDeleteFlags::ALL & 
~InsertDeleteFlags::FORMULA : InsertDeleteFlags::ALL),
                         false, maTabs[nDestPos].get(), /*pMarkData*/nullptr, 
/*bAsLink*/false, /*bColRowFlags*/true,
-                        /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true );
+                        ScCloneFlags::Default, /*bCopyCaptions*/true );
             }
         }
         maTabs[nDestPos]->SetTabNo(nDestPos);
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index ebd41484f18a..a81bc70fa83a 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2173,7 +2173,7 @@ void ScDocument::CopyToDocument(const ScRange& rRange,
         pTab->CopyToTable(
             aCxt, aNewRange.aStart.Col(), aNewRange.aStart.Row(), 
aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
             nFlags, bOnlyMarked, pDestTab, pMarks, false, bColRowFlags,
-            /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true);
+            ScCloneFlags::Default, /*bCopyCaptions*/true);
     }
 
     rDestDoc.StartAllListeners(aNewRange);
@@ -3380,12 +3380,12 @@ void ScDocument::FillTab( const ScRange& rSrcArea, 
const ScMarkData& rMark,
                     maTabs[i]->CopyToTable(aMixCxt, nStartCol,nStartRow, 
nEndCol,nEndRow,
                                            InsertDeleteFlags::CONTENTS, false, 
pMixDoc->maTabs[i].get(),
                                            /*pMarkData*/nullptr, 
/*bAsLink*/false, /*bColRowFlags*/true,
-                                           /*bGlobalNamesToLocal*/false, 
/*bCopyCaptions*/true );
+                                           ScCloneFlags::Default, 
/*bCopyCaptions*/true );
                 }
                 maTabs[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, 
nDelFlags);
                 pSourceTable->CopyToTable(aCxt, nStartCol,nStartRow, 
nEndCol,nEndRow,
                                              nFlags, false, maTabs[i].get(), 
nullptr, bAsLink,
-                                             /*bColRowFlags*/true, 
/*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true );
+                                             /*bColRowFlags*/true, 
ScCloneFlags::Default, /*bCopyCaptions*/true );
 
                 if (bDoMix)
                     maTabs[i]->MixData(aMixDocCxt, nStartCol,nStartRow, 
nEndCol,nEndRow,
@@ -3445,14 +3445,14 @@ void ScDocument::FillTabMarked( SCTAB nSrcTab, const 
ScMarkData& rMark,
                     sc::CopyToDocContext aMixCxt(*pMixDoc);
                     maTabs[i]->CopyToTable(aMixCxt, nStartCol,nStartRow, 
nEndCol,nEndRow,
                                            InsertDeleteFlags::CONTENTS, true, 
pMixDoc->maTabs[i].get(), &rMark,
-                                           /*bAsLink*/false, 
/*bColRowFlags*/true, /*bGlobalNamesToLocal*/false,
+                                           /*bAsLink*/false, 
/*bColRowFlags*/true, ScCloneFlags::Default,
                                            /*bCopyCaptions*/true );
                 }
 
                 maTabs[i]->DeleteSelection( nDelFlags, rMark );
                 pSourceTable->CopyToTable(aCxt, nStartCol,nStartRow, 
nEndCol,nEndRow,
                                              nFlags, true, maTabs[i].get(), 
&rMark, bAsLink,
-                                             /*bColRowFlags*/true, 
/*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true );
+                                             /*bColRowFlags*/true, 
ScCloneFlags::Default, /*bCopyCaptions*/true );
 
                 if (bDoMix)
                     maTabs[i]->MixMarked(aMixDocCxt, rMark, nFunction, 
bSkipEmpty, pMixDoc->maTabs[i].get());
diff --git a/sc/source/core/data/formulacell.cxx 
b/sc/source/core/data/formulacell.cxx
index 16c585fe5364..2bed434ae623 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -848,6 +848,12 @@ ScFormulaCell::ScFormulaCell(const ScFormulaCell& rCell, 
ScDocument& rDoc, const
         }
 
         pCode->AdjustAbsoluteRefs( rCell.rDocument, rCell.aPos, aPos, 
bCopyBetweenDocs );
+
+        if ((nCloneFlags & ScCloneFlags::AdjustCrossSheetRefs) != 
ScCloneFlags::Default)
+        {
+            SCTAB nDelta = aPos.Tab() - rCell.aPos.Tab();
+            pCode->AdjustRelativeTabRefs(nDelta);
+        }
     }
 
     if (!rDocument.IsClipOrUndo())
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 57550e926c4e..00e898afda35 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -1337,7 +1337,7 @@ void ScTable::StartListeningFormulaCells(
 void ScTable::CopyToTable(
     sc::CopyToDocContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW 
nRow2,
     InsertDeleteFlags nFlags, bool bMarked, ScTable* pDestTab, const 
ScMarkData* pMarkData,
-    bool bAsLink, bool bColRowFlags, bool bGlobalNamesToLocal, bool 
bCopyCaptions )
+    bool bAsLink, bool bColRowFlags, ScCloneFlags nCloneFlags, bool 
bCopyCaptions )
 {
     if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
         return;
@@ -1377,7 +1377,7 @@ void ScTable::CopyToTable(
         pDestTab->CreateColumnIfNotExists(ClampToAllocatedColumns(nCol2)); // 
avoid repeated resizing
         for (SCCOL i = nCol1; i <= ClampToAllocatedColumns(nCol2); i++)
             aCol[i].CopyToColumn(rCxt, nRow1, nRow2, bToUndoDoc ? nFlags : 
nTempFlags, bMarked,
-                                 pDestTab->CreateColumnIfNotExists(i), 
pMarkData, bAsLink, bGlobalNamesToLocal);
+                                 pDestTab->CreateColumnIfNotExists(i), 
pMarkData, bAsLink, nCloneFlags);
         // tdf#154044: Restore from the default column data
         if (bFromUndoDoc && (nFlags & InsertDeleteFlags::ATTRIB) && nCol2 >= 
aCol.size())
         {
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index eb9ba6c1db50..3d17fee21ffa 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2703,6 +2703,44 @@ void ScTokenArray::AdjustAbsoluteRefs( const ScDocument& 
rOldDoc, const ScAddres
     }
 }
 
+void ScTokenArray::AdjustRelativeTabRefs( SCTAB nDelta )
+{
+    TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN, true);
+    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();
+                    if (rRef.Ref1.IsTabRel() && rRef.Ref1.Tab() != 0)
+                        rRef.Ref1.IncTab(-nDelta);
+                    if (rRef.Ref2.IsTabRel() && rRef.Ref2.Tab() != 0)
+                        rRef.Ref2.IncTab(-nDelta);
+                    break;
+                }
+                case svSingleRef:
+                {
+                    ScSingleRefData& rRef = *p->GetSingleRef();
+                    if (rRef.IsTabRel() && rRef.Tab() != 0)
+                        rRef.IncTab(-nDelta);
+                    break;
+                }
+                default:
+                    break;
+            }
+        }
+    }
+}
+
 void ScTokenArray::AdjustSheetLocalNameReferences( SCTAB nOldTab, SCTAB 
nNewTab )
 {
     TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN, false);

Reply via email to