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 <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/202020
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
(cherry picked from commit ad7c05c27c177a105418337771ed182dd11f23ba)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205410
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Tomaž Vajngerl
2026-05-20 17:06:14 +02:00
committed by Xisco Fauli
parent fbedd28a4c
commit 5cefed66bc
10 changed files with 185 additions and 96 deletions
+1
View File
@@ -597,6 +597,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;
+1
View File
@@ -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);
+1
View File
@@ -1329,6 +1329,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;
+16 -6
View File
@@ -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.
+103 -81
View File
@@ -7579,19 +7579,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)
@@ -7600,123 +7603,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<SCTAB>(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<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);
+22
View File
@@ -2627,6 +2627,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;
@@ -3057,6 +3073,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;
+1
View File
@@ -925,6 +925,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();
}
+13 -2
View File
@@ -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());
}
}
@@ -3727,6 +3726,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())
+6
View File
@@ -2789,6 +2789,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
{
+21 -7
View File
@@ -2682,8 +2682,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)
{
@@ -2700,17 +2717,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: