sc/inc/refupdatecontext.hxx | 8 + sc/inc/tokenarray.hxx | 16 +++ sc/qa/unit/ucalc_formula.cxx | 156 ++++++++++++++++++++++++++++++- sc/source/core/data/formulacell.cxx | 10 - sc/source/core/data/refupdatecontext.cxx | 2 sc/source/core/tool/token.cxx | 46 +++++++++ 6 files changed, 228 insertions(+), 10 deletions(-)
New commits: commit ecafe509fc7aeeb19f88c4c74a7095c205c903cc Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Thu Jul 18 15:57:10 2013 -0400 Correctly update references on cell insertion/deletion. Change-Id: Ie7499f1f589cd384c4e2421dc81d3c1f02e4a53e diff --git a/sc/inc/refupdatecontext.hxx b/sc/inc/refupdatecontext.hxx index 80fdd74..7192ec7 100644 --- a/sc/inc/refupdatecontext.hxx +++ b/sc/inc/refupdatecontext.hxx @@ -43,6 +43,14 @@ struct RefUpdateContext bool hasDelta() const; }; +struct RefUpdateResult +{ + bool mbValueChanged; + bool mbRangeSizeModified; + + RefUpdateResult(); +}; + } #endif diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx index 9f0c463..fe6204c 100644 --- a/sc/inc/tokenarray.hxx +++ b/sc/inc/tokenarray.hxx @@ -27,6 +27,13 @@ #include "calcmacros.hxx" #include <formula/tokenarray.hxx> +namespace sc { + +struct RefUpdateContext; +struct RefUpdateResult; + +} + struct ScRawToken; struct ScSingleRefData; struct ScComplexRefData; @@ -113,6 +120,15 @@ public: */ void AdjustAbsoluteRefs( const ScDocument* pOldDoc, const ScAddress& rOldPos, const ScAddress& rNewPos, bool bRangeName = false, bool bCheckCopyArea = false ); + /** + * Adjust all references in response to shifting of cells during cell + * insertion and deletion. + * + * @param rCxt context that stores details of shifted region. + * @param rOldPos old cell position prior to shifting. + */ + sc::RefUpdateResult AdjustReferenceOnShift( const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos ); + #if DEBUG_FORMULA_COMPILER void Dump() const; #endif diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index f74231a..e17d4c6 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -1852,7 +1852,6 @@ bool ScFormulaCell::GetMatrixOrigin( ScAddress& rPos ) const } break; } - fprintf(stdout, "ScFormulaCell::GetMatrixOrigin: failed\n"); return false; } @@ -2274,12 +2273,9 @@ bool ScFormulaCell::UpdateReferenceOnShift( if (bHasRefs) { // Update cell or range references. - ScCompiler aComp(pDocument, aPos, *pCode); - aComp.SetGrammar(pDocument->GetGrammar()); - aComp.UpdateReference( - URM_INSDEL, aOldPos, rCxt.maRange, rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, - bValChanged, bRefSizeChanged); - bRangeModified = aComp.HasModifiedRange(); + sc::RefUpdateResult aRes = pCode->AdjustReferenceOnShift(rCxt, aOldPos); + bRangeModified = aRes.mbRangeSizeModified; + bValChanged = aRes.mbValueChanged; } bCellStateChanged |= bValChanged; diff --git a/sc/source/core/data/refupdatecontext.cxx b/sc/source/core/data/refupdatecontext.cxx index a5c8616..72dadf0 100644 --- a/sc/source/core/data/refupdatecontext.cxx +++ b/sc/source/core/data/refupdatecontext.cxx @@ -19,6 +19,8 @@ bool RefUpdateContext::hasDelta() const return (mnColDelta > 0 || mnRowDelta > 0 || mnTabDelta > 0); } +RefUpdateResult::RefUpdateResult() : mbValueChanged(false), mbRangeSizeModified(false) {} + } diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index 3447432..56d4ddc 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -37,6 +37,7 @@ #include "rangeseq.hxx" #include "externalrefmgr.hxx" #include "document.hxx" +#include "refupdatecontext.hxx" using ::std::vector; @@ -2216,6 +2217,51 @@ void ScTokenArray::AdjustAbsoluteRefs( const ScDocument* pOldDoc, const ScAddres } } +sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos ) +{ + sc::RefUpdateResult aRes; + ScAddress aNewPos = rOldPos; + bool bCellShifted = rCxt.maRange.In(rOldPos); + if (bCellShifted) + aNewPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta); + + FormulaToken** p = pCode; + FormulaToken** pEnd = p + static_cast<size_t>(nLen); + for (; p != pEnd; ++p) + { + ScToken* pToken = static_cast<ScToken*>(*p); + switch (pToken->GetType()) + { + case svSingleRef: + { + ScSingleRefData& rRef = pToken->GetSingleRef(); + ScAddress aAbs = rRef.toAbs(rOldPos); + + if (rCxt.maRange.In(aAbs)) + aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta); + + rRef.SetAddress(aAbs, aNewPos); + } + break; + case svDoubleRef: + { + ScComplexRefData& rRef = pToken->GetDoubleRef(); + ScRange aAbs = rRef.toAbs(rOldPos); + + if (rCxt.maRange.In(aAbs)) + aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta); + + rRef.SetRange(aAbs, aNewPos); + } + break; + default: + ; + } + } + + return aRes; +} + #if DEBUG_FORMULA_COMPILER void ScTokenArray::Dump() const { commit 779e01640c280e96bf837c2e2762ed8fd093c45a Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Thu Jul 18 15:56:37 2013 -0400 More test on reference updates. Change-Id: Icf0222ee08157836e3119a2c67b320a14d4be8bd diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx index 4954d88..134d23c 100644 --- a/sc/qa/unit/ucalc_formula.cxx +++ b/sc/qa/unit/ucalc_formula.cxx @@ -206,7 +206,7 @@ void Test::testFormulaRefUpdate() sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on. - m_pDoc->SetValue(ScAddress(0,0,0), 2.0); + m_pDoc->SetValue(ScAddress(0,0,0), 2.0); // A1 m_pDoc->SetString(ScAddress(2,2,0), "=A1"); // C3 m_pDoc->SetString(ScAddress(2,3,0), "=$A$1"); // C4 @@ -240,9 +240,159 @@ void Test::testFormulaRefUpdate() if (!checkFormula(*m_pDoc, aPos, "$A$1")) CPPUNIT_FAIL("Wrong formula in C4."); - m_pDoc->DeleteTab(0); + // Insert 2 rows at row 1 to shift all of A1 and C3:C4 down. + m_pDoc->InsertRow(ScRange(0,0,0,MAXCOL,1,0)); + + aPos = ScAddress(2,4,0); + if (!checkFormula(*m_pDoc, aPos, "A3")) + CPPUNIT_FAIL("Wrong formula in C5."); + + aPos = ScAddress(2,5,0); + if (!checkFormula(*m_pDoc, aPos, "$A$3")) + CPPUNIT_FAIL("Wrong formula in C6."); + + // Delete 2 rows at row 1 to shift them back. + m_pDoc->DeleteRow(ScRange(0,0,0,MAXCOL,1,0)); + + aPos = ScAddress(2,2,0); + if (!checkFormula(*m_pDoc, aPos, "A1")) + CPPUNIT_FAIL("Wrong formula in C3."); + + aPos = ScAddress(2,3,0); + if (!checkFormula(*m_pDoc, aPos, "$A$1")) + CPPUNIT_FAIL("Wrong formula in C4."); + + // Insert 3 columns at column B. to shift C3:C4 to F3:F4. + m_pDoc->InsertCol(ScRange(1,0,0,3,MAXROW,0)); + + aPos = ScAddress(5,2,0); + if (!checkFormula(*m_pDoc, aPos, "A1")) + CPPUNIT_FAIL("Wrong formula in F3."); + + aPos = ScAddress(5,3,0); + if (!checkFormula(*m_pDoc, aPos, "$A$1")) + CPPUNIT_FAIL("Wrong formula in F4."); + + // Delete columns B:D to shift them back. + m_pDoc->DeleteCol(ScRange(1,0,0,3,MAXROW,0)); + + aPos = ScAddress(2,2,0); + if (!checkFormula(*m_pDoc, aPos, "A1")) + CPPUNIT_FAIL("Wrong formula in C3."); + + aPos = ScAddress(2,3,0); + if (!checkFormula(*m_pDoc, aPos, "$A$1")) + CPPUNIT_FAIL("Wrong formula in C4."); + + // Insert cells over A1:A3 to only shift A1 down to A4. + m_pDoc->InsertRow(ScRange(0,0,0,0,2,0)); + + aPos = ScAddress(2,2,0); + if (!checkFormula(*m_pDoc, aPos, "A4")) + CPPUNIT_FAIL("Wrong formula in C3."); + + aPos = ScAddress(2,3,0); + if (!checkFormula(*m_pDoc, aPos, "$A$4")) + CPPUNIT_FAIL("Wrong formula in C4."); - CPPUNIT_ASSERT_MESSAGE("All looks good!", false); + // .. and back. + m_pDoc->DeleteRow(ScRange(0,0,0,0,2,0)); + + aPos = ScAddress(2,2,0); + if (!checkFormula(*m_pDoc, aPos, "A1")) + CPPUNIT_FAIL("Wrong formula in C3."); + + aPos = ScAddress(2,3,0); + if (!checkFormula(*m_pDoc, aPos, "$A$1")) + CPPUNIT_FAIL("Wrong formula in C4."); + + // Clear all and start over. + clearRange(m_pDoc, ScRange(0,0,0,10,10,0)); + + // Fill B2:C3 with values. + m_pDoc->SetValue(ScAddress(1,1,0), 1); + m_pDoc->SetValue(ScAddress(1,2,0), 2); + m_pDoc->SetValue(ScAddress(2,1,0), 3); + m_pDoc->SetValue(ScAddress(2,2,0), 4); + + m_pDoc->SetString(ScAddress(0,5,0), "=SUM(B2:C3)"); + m_pDoc->SetString(ScAddress(0,6,0), "=SUM($B$2:$C$3)"); + + aPos = ScAddress(0,5,0); + if (!checkFormula(*m_pDoc, aPos, "SUM(B2:C3)")) + CPPUNIT_FAIL("Wrong formula in A6."); + + aPos = ScAddress(0,6,0); + if (!checkFormula(*m_pDoc, aPos, "SUM($B$2:$C$3)")) + CPPUNIT_FAIL("Wrong formula in A7."); + + // Insert a row at row 1. + m_pDoc->InsertRow(ScRange(0,0,0,MAXCOL,0,0)); + + aPos = ScAddress(0,6,0); + if (!checkFormula(*m_pDoc, aPos, "SUM(B3:C4)")) + CPPUNIT_FAIL("Wrong formula in A7."); + + aPos = ScAddress(0,7,0); + if (!checkFormula(*m_pDoc, aPos, "SUM($B$3:$C$4)")) + CPPUNIT_FAIL("Wrong formula in A8."); + + // ... and back. + m_pDoc->DeleteRow(ScRange(0,0,0,MAXCOL,0,0)); + + aPos = ScAddress(0,5,0); + if (!checkFormula(*m_pDoc, aPos, "SUM(B2:C3)")) + CPPUNIT_FAIL("Wrong formula in A6."); + + aPos = ScAddress(0,6,0); + if (!checkFormula(*m_pDoc, aPos, "SUM($B$2:$C$3)")) + CPPUNIT_FAIL("Wrong formula in A7."); + + // Insert columns B:C to shift only the value range. + m_pDoc->InsertCol(ScRange(1,0,0,2,MAXROW,0)); + + aPos = ScAddress(0,5,0); + if (!checkFormula(*m_pDoc, aPos, "SUM(D2:E3)")) + CPPUNIT_FAIL("Wrong formula in A6."); + + aPos = ScAddress(0,6,0); + if (!checkFormula(*m_pDoc, aPos, "SUM($D$2:$E$3)")) + CPPUNIT_FAIL("Wrong formula in A7."); + + // ... and back. + m_pDoc->DeleteCol(ScRange(1,0,0,2,MAXROW,0)); + + aPos = ScAddress(0,5,0); + if (!checkFormula(*m_pDoc, aPos, "SUM(B2:C3)")) + CPPUNIT_FAIL("Wrong formula in A6."); + + aPos = ScAddress(0,6,0); + if (!checkFormula(*m_pDoc, aPos, "SUM($B$2:$C$3)")) + CPPUNIT_FAIL("Wrong formula in A7."); + + // Insert rows 5:6 to shift the formula cells only. + m_pDoc->InsertRow(ScRange(0,4,0,MAXCOL,5,0)); + + aPos = ScAddress(0,7,0); + if (!checkFormula(*m_pDoc, aPos, "SUM(B2:C3)")) + CPPUNIT_FAIL("Wrong formula in A8."); + + aPos = ScAddress(0,8,0); + if (!checkFormula(*m_pDoc, aPos, "SUM($B$2:$C$3)")) + CPPUNIT_FAIL("Wrong formula in A9."); + + // ... and back. + m_pDoc->DeleteRow(ScRange(0,4,0,MAXCOL,5,0)); + + aPos = ScAddress(0,5,0); + if (!checkFormula(*m_pDoc, aPos, "SUM(B2:C3)")) + CPPUNIT_FAIL("Wrong formula in A6."); + + aPos = ScAddress(0,6,0); + if (!checkFormula(*m_pDoc, aPos, "SUM($B$2:$C$3)")) + CPPUNIT_FAIL("Wrong formula in A7."); + + m_pDoc->DeleteTab(0); } void Test::testFuncSUM() _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits