Kaydet (Commit) 407a6774 authored tarafından Kohei Yoshida's avatar Kohei Yoshida

Re-implement sheet reference adjustment on sheet move.

Change-Id: I24e93e0bbc51c7f9a1f1ea0c126a1399ace84a9e
üst 11e64bb4
......@@ -145,6 +145,8 @@ public:
bool AdjustReferenceOnInsertedTab( SCTAB nInsPos, SCTAB nSheets, const ScAddress& rOldPos );
void AdjustReferenceOnMovedTab( SCTAB nOldPos, SCTAB nNewPos, const ScAddress& rOldPos );
#if DEBUG_FORMULA_COMPILER
void Dump() const;
#endif
......
......@@ -813,6 +813,36 @@ void Test::testFormulaRefUpdateSheets()
if (!checkFormula(*m_pDoc, ScAddress(1,2,2), "SUM($Sheet1.$B$2:$C$3)"))
CPPUNIT_FAIL("Wrong formula in Sheet2.B3.");
// Move the last sheet (Sheet2) to the first position.
m_pDoc->MoveTab(2, 0);
if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "SUM(Sheet1.B2:C3)"))
CPPUNIT_FAIL("Wrong formula in Sheet2.B2.");
if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "SUM($Sheet1.$B$2:$C$3)"))
CPPUNIT_FAIL("Wrong formula in Sheet2.B3.");
// Move back.
m_pDoc->MoveTab(0, 2);
if (!checkFormula(*m_pDoc, ScAddress(1,1,2), "SUM(Sheet1.B2:C3)"))
CPPUNIT_FAIL("Wrong formula in Sheet2.B2.");
if (!checkFormula(*m_pDoc, ScAddress(1,2,2), "SUM($Sheet1.$B$2:$C$3)"))
CPPUNIT_FAIL("Wrong formula in Sheet2.B3.");
// Move the "Temp" sheet to the last position.
m_pDoc->MoveTab(1, 2);
if (!checkFormula(*m_pDoc, ScAddress(1,1,1), "SUM(Sheet1.B2:C3)"))
CPPUNIT_FAIL("Wrong formula in Sheet2.B2.");
if (!checkFormula(*m_pDoc, ScAddress(1,2,1), "SUM($Sheet1.$B$2:$C$3)"))
CPPUNIT_FAIL("Wrong formula in Sheet2.B3.");
// Move back.
m_pDoc->MoveTab(2, 1);
// Delete the temporary sheet.
m_pDoc->DeleteTab(1);
......@@ -848,6 +878,26 @@ void Test::testFormulaRefUpdateSheets()
if (!checkFormula(*m_pDoc, ScAddress(1,2,1), "SUM($Sheet1.$B$2:$C$3)"))
CPPUNIT_FAIL("Wrong formula in Sheet2.B3.");
// Append a bunch of sheets.
m_pDoc->InsertTab(2, "Temp1");
m_pDoc->InsertTab(3, "Temp2");
m_pDoc->InsertTab(4, "Temp3");
// Move these tabs around. This shouldn't affects the first 2 sheets.
m_pDoc->MoveTab(2, 4);
m_pDoc->MoveTab(3, 2);
if (!checkFormula(*m_pDoc, ScAddress(1,1,1), "SUM(Sheet1.B2:C3)"))
CPPUNIT_FAIL("Wrong formula in Sheet2.B2.");
if (!checkFormula(*m_pDoc, ScAddress(1,2,1), "SUM($Sheet1.$B$2:$C$3)"))
CPPUNIT_FAIL("Wrong formula in Sheet2.B3.");
// Delete the temp sheets.
m_pDoc->DeleteTab(4);
m_pDoc->DeleteTab(3);
m_pDoc->DeleteTab(2);
// Delete Sheet1.
m_pDoc->DeleteTab(0);
m_pDoc->GetName(0, aName);
......
......@@ -2598,31 +2598,19 @@ bool ScFormulaCell::UpdateDeleteTab(SCTAB nTable, bool /*bIsMove*/, SCTAB nSheet
void ScFormulaCell::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
{
pCode->Reset();
if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
if (!pCode->GetNextReferenceRPN() || pDocument->IsClipOrUndo())
{
EndListeningTo( pDocument );
// SetTab _after_ EndListeningTo und _before_ Compiler UpdateMoveTab !
aPos.SetTab( nTabNo );
ScRangeData* pRangeData;
ScCompiler aComp(pDocument, aPos, *pCode);
aComp.SetGrammar(pDocument->GetGrammar());
pRangeData = aComp.UpdateMoveTab( nOldPos, nNewPos, false );
if (pRangeData) // Exchange Shared Formula with real Formula
{
pDocument->RemoveFromFormulaTree( this ); // update formula count
delete pCode;
pCode = pRangeData->GetCode()->Clone();
ScCompiler aComp2(pDocument, aPos, *pCode);
aComp2.SetGrammar(pDocument->GetGrammar());
aComp2.CompileTokenArray();
aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
aComp2.UpdateMoveTab( nOldPos, nNewPos, true );
bCompile = true;
}
// no StartListeningTo because pTab[nTab] not yet correct!
aPos.SetTab(nTabNo);
return;
}
else
aPos.SetTab( nTabNo );
EndListeningTo(pDocument);
ScAddress aOldPos = aPos;
// SetTab _after_ EndListeningTo und _before_ Compiler UpdateMoveTab !
aPos.SetTab(nTabNo);
// no StartListeningTo because pTab[nTab] not yet correct!
pCode->AdjustReferenceOnMovedTab(nOldPos, nNewPos, aOldPos);
}
void ScFormulaCell::UpdateInsertTabAbs(SCTAB nTable)
......
......@@ -2660,6 +2660,79 @@ bool ScTokenArray::AdjustReferenceOnInsertedTab( SCTAB nInsPos, SCTAB nSheets, c
return bRefChanged;
}
namespace {
void adjustTabOnMove( ScAddress& rPos, SCTAB nOldPos, SCTAB nNewPos )
{
// Sheets below the lower bound or above the uppper bound will not change.
SCTAB nLowerBound = std::min(nOldPos, nNewPos);
SCTAB nUpperBound = std::max(nOldPos, nNewPos);
if (rPos.Tab() < nLowerBound || nUpperBound < rPos.Tab())
// Outside the boundary. Nothing to adjust.
return;
if (rPos.Tab() == nOldPos)
{
rPos.SetTab(nNewPos);
return;
}
// It's somewhere in between.
if (nOldPos < nNewPos)
{
// Moving a sheet to the right. The rest of the sheets shifts to the left.
rPos.IncTab(-1);
}
else
{
// Moving a sheet to the left. The rest of the sheets shifts to the right.
rPos.IncTab();
}
}
}
void ScTokenArray::AdjustReferenceOnMovedTab( SCTAB nOldPos, SCTAB nNewPos, const ScAddress& rOldPos )
{
if (nOldPos == nNewPos)
return;
ScAddress aNewPos = rOldPos;
adjustTabOnMove(aNewPos, nOldPos, nNewPos);
FormulaToken** p = pCode;
FormulaToken** pEnd = p + static_cast<size_t>(nLen);
for (; p != pEnd; ++p)
{
switch ((*p)->GetType())
{
case svSingleRef:
{
ScToken* pToken = static_cast<ScToken*>(*p);
ScSingleRefData& rRef = pToken->GetSingleRef();
ScAddress aAbs = rRef.toAbs(rOldPos);
adjustTabOnMove(aAbs, nOldPos, nNewPos);
rRef.SetAddress(aAbs, aNewPos);
}
break;
case svDoubleRef:
{
ScToken* pToken = static_cast<ScToken*>(*p);
ScComplexRefData& rRef = pToken->GetDoubleRef();
ScRange aAbs = rRef.toAbs(rOldPos);
adjustTabOnMove(aAbs.aStart, nOldPos, nNewPos);
adjustTabOnMove(aAbs.aEnd, nOldPos, nNewPos);
rRef.SetRange(aAbs, aNewPos);
}
break;
default:
;
}
}
}
#if DEBUG_FORMULA_COMPILER
void ScTokenArray::Dump() const
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment