sc/inc/tokenarray.hxx | 3 + sc/qa/unit/ucalc.hxx | 2 sc/qa/unit/ucalc_formula.cxx | 73 ++++++++++++++++++++++++++++++++++++ sc/source/core/data/formulacell.cxx | 22 ++++------ sc/source/core/tool/token.cxx | 52 +++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 13 deletions(-)
New commits: commit a62b7f10ec1fddd7d2bd6517dec75a617aaa12be Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Tue Jul 23 22:33:27 2013 -0400 Re-implement adjusting of references on move. Change-Id: I52a8b78ed072eb6bcd86b4f80936a869046cbc4d diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx index 5ff7da0..2ae6c90 100644 --- a/sc/inc/tokenarray.hxx +++ b/sc/inc/tokenarray.hxx @@ -129,6 +129,9 @@ public: */ sc::RefUpdateResult AdjustReferenceOnShift( const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos ); + sc::RefUpdateResult AdjustReferenceOnMove( + const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos, const ScAddress& rNewPos ); + /** * Adjust all references on sheet deletion. * diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 63d2c9b..725c5d9 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -2365,7 +2365,6 @@ bool ScFormulaCell::UpdateReferenceOnMove( aOldPos.Set(aPos.Col() - rCxt.mnColDelta, aPos.Row() - rCxt.mnRowDelta, aPos.Tab() - rCxt.mnTabDelta); } - // Check presence of any references or column row names. pCode->Reset(); bool bHasRefs = (pCode->GetNextReferenceRPN() != NULL); @@ -2389,22 +2388,19 @@ bool ScFormulaCell::UpdateReferenceOnMove( pOldCode.reset(pCode->Clone()); bool bValChanged = false; - bool bRangeModified = false; // any range, not only shared formula + bool bRefModified = false; bool bRefSizeChanged = false; if (bHasRefs) { // Update cell or range references. - ScCompiler aComp(pDocument, aPos, *pCode); - aComp.SetGrammar(pDocument->GetGrammar()); - aComp.UpdateReference( - URM_MOVE, aOldPos, rCxt.maRange, - rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, - bValChanged, bRefSizeChanged); - bRangeModified = aComp.HasModifiedRange(); + sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMove(rCxt, aOldPos, aPos); + bRefModified = aRes.mbReferenceModified; + bValChanged = aRes.mbValueChanged; } - bCellStateChanged |= bValChanged; + if (bValChanged || bRefModified) + bCellStateChanged = true; if (bOnRefMove) // Cell may reference itself, e.g. ocColumn, ocRow without parameter @@ -2429,7 +2425,7 @@ bool ScFormulaCell::UpdateReferenceOnMove( bHasRelName = HasRelNameReference(); // Reference changed and new listening needed? // Except in Insert/Delete without specialties. - bNewListening = (bRangeModified || bColRowNameCompile + bNewListening = (bRefModified || bColRowNameCompile || bValChanged || bHasRelName) // #i36299# Don't duplicate action during cut&paste / drag&drop // on a cell in the range moved, start/end listeners is done @@ -2442,7 +2438,7 @@ bool ScFormulaCell::UpdateReferenceOnMove( bool bNeedDirty = false; // NeedDirty for changes except for Copy and Move/Insert without RelNames - if ( bRangeModified || bColRowNameCompile || + if ( bRefModified || bColRowNameCompile || (bValChanged && bHasRelName && (bHasRelName || bInDeleteUndo || bRefSizeChanged)) || bOnRefMove) bNeedDirty = true; @@ -2451,7 +2447,7 @@ bool ScFormulaCell::UpdateReferenceOnMove( bValChanged = false; - if ( ( bCompile = (bCompile || bValChanged || bRangeModified || bColRowNameCompile) ) != 0 ) + if ( ( bCompile = (bCompile || bValChanged || bRefModified || bColRowNameCompile) ) != 0 ) { CompileTokenArray( bNewListening ); // no Listening bNeedDirty = true; diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index 64beedf..b783525 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -2472,6 +2472,58 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateCon return aRes; } +sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMove( + const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos, const ScAddress& rNewPos ) +{ + // When moving, the range is the destination range. We need to use the old + // range prior to the move for hit analysis. + ScRange aOldRange = rCxt.maRange; + aOldRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta); + + sc::RefUpdateResult aRes; + + 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); + if (aOldRange.In(aAbs)) + { + aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta); + aRes.mbReferenceModified = true; + } + + rRef.SetAddress(aAbs, rNewPos); + } + break; + case svDoubleRef: + { + ScToken* pToken = static_cast<ScToken*>(*p); + ScComplexRefData& rRef = pToken->GetDoubleRef(); + ScRange aAbs = rRef.toAbs(rOldPos); + if (aOldRange.In(aAbs)) + { + aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta); + aRes.mbReferenceModified = true; + } + + rRef.SetRange(aAbs, rNewPos); + } + break; + default: + ; + } + } + + return aRes; +} + namespace { bool adjustSingleRef( ScSingleRefData& rRef, SCTAB nDelPos, SCTAB nSheets, const ScAddress& rOldPos, const ScAddress& rNewPos ) commit 9e304c34daae3dd8e9b7813138b5028b91819002 Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Tue Jul 23 22:29:48 2013 -0400 Add test for moving the formula cells that reference stationary range. Change-Id: I6f996e4c8535371c57c9d43012baa6118160f834 diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx index 69b0374..ebf74e7 100644 --- a/sc/qa/unit/ucalc_formula.cxx +++ b/sc/qa/unit/ucalc_formula.cxx @@ -884,6 +884,29 @@ void Test::testFormulaRefUpdateMove() if (!checkFormula(*m_pDoc, ScAddress(0,11,0), "$D$6")) CPPUNIT_FAIL("Wrong formula."); + // Move A9:A12 to B10:B13. + bMoved = rFunc.MoveBlock(ScRange(0,8,0,0,11,0), ScAddress(1,9,0), true, false, false, false); + CPPUNIT_ASSERT_MESSAGE("Failed to move A9:A12 to B10:B13", bMoved); + + // The results of these formula cells should still stay the same. + CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(1,9,0)); + CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(1,10,0)); + CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(1,11,0)); + CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(1,12,0)); + + // Displayed formulas should stay the same since the referenced range hasn't moved. + if (!checkFormula(*m_pDoc, ScAddress(1,9,0), "SUM(D4:D6)")) + CPPUNIT_FAIL("Wrong formula."); + + if (!checkFormula(*m_pDoc, ScAddress(1,10,0), "SUM($D$4:$D$6)")) + CPPUNIT_FAIL("Wrong formula."); + + if (!checkFormula(*m_pDoc, ScAddress(1,11,0), "D5")) + CPPUNIT_FAIL("Wrong formula."); + + if (!checkFormula(*m_pDoc, ScAddress(1,12,0), "$D$6")) + CPPUNIT_FAIL("Wrong formula."); + m_pDoc->DeleteTab(0); } commit a38c2df3c20c3a3e8585b610635b751269793bf3 Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Tue Jul 23 18:59:34 2013 -0400 Add starter test for reference update on range move. This currently fails. Change-Id: I83cdcb6ed9620079664ff35375a0457b0c9bcea0 diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx index ac17bd9..5a1d0ae 100644 --- a/sc/qa/unit/ucalc.hxx +++ b/sc/qa/unit/ucalc.hxx @@ -89,6 +89,7 @@ public: void testFormulaRefUpdate(); void testFormulaRefUpdateRange(); void testFormulaRefUpdateSheets(); + void testFormulaRefUpdateMove(); void testFuncCOLUMN(); void testFuncROW(); void testFuncSUM(); @@ -280,6 +281,7 @@ public: CPPUNIT_TEST(testFormulaRefUpdate); CPPUNIT_TEST(testFormulaRefUpdateRange); CPPUNIT_TEST(testFormulaRefUpdateSheets); + CPPUNIT_TEST(testFormulaRefUpdateMove); CPPUNIT_TEST(testFuncCOLUMN); CPPUNIT_TEST(testFuncROW); CPPUNIT_TEST(testFuncSUM); diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx index c651b6d..69b0374 100644 --- a/sc/qa/unit/ucalc_formula.cxx +++ b/sc/qa/unit/ucalc_formula.cxx @@ -18,6 +18,8 @@ #include "formulacell.hxx" #include "inputopt.hxx" #include "scmod.hxx" +#include "docsh.hxx" +#include "docfunc.hxx" #include <boost/scoped_ptr.hpp> @@ -837,6 +839,54 @@ void Test::testFormulaRefUpdateSheets() m_pDoc->DeleteTab(0); } +void Test::testFormulaRefUpdateMove() +{ + m_pDoc->InsertTab(0, "Sheet1"); + + sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on. + + // Set value to B4:B6. + m_pDoc->SetValue(ScAddress(1,3,0), 1); + m_pDoc->SetValue(ScAddress(1,4,0), 2); + m_pDoc->SetValue(ScAddress(1,5,0), 3); + + // Set formulas to A9:A12 that references B4:B6. + m_pDoc->SetString(ScAddress(0,8,0), "=SUM(B4:B6)"); + m_pDoc->SetString(ScAddress(0,9,0), "=SUM($B$4:$B$6)"); + m_pDoc->SetString(ScAddress(0,10,0), "=B5"); + m_pDoc->SetString(ScAddress(0,11,0), "=$B$6"); + + CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(0,8,0)); + CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(0,9,0)); + CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(0,10,0)); + CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(0,11,0)); + + // Move B4:B6 to D4 (two columsn to the right). + ScDocFunc& rFunc = getDocShell().GetDocFunc(); + bool bMoved = rFunc.MoveBlock(ScRange(1,3,0,1,5,0), ScAddress(3,3,0), true, false, false, false); + CPPUNIT_ASSERT_MESSAGE("Failed to move B4:B6.", bMoved); + + // The results of the formula cells that reference the moved range should remain the same. + CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(0,8,0)); + CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(0,9,0)); + CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(0,10,0)); + CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(0,11,0)); + + if (!checkFormula(*m_pDoc, ScAddress(0,8,0), "SUM(D4:D6)")) + CPPUNIT_FAIL("Wrong formula."); + + if (!checkFormula(*m_pDoc, ScAddress(0,9,0), "SUM($D$4:$D$6)")) + CPPUNIT_FAIL("Wrong formula."); + + if (!checkFormula(*m_pDoc, ScAddress(0,10,0), "D5")) + CPPUNIT_FAIL("Wrong formula."); + + if (!checkFormula(*m_pDoc, ScAddress(0,11,0), "$D$6")) + CPPUNIT_FAIL("Wrong formula."); + + m_pDoc->DeleteTab(0); +} + void Test::testFuncCOLUMN() { m_pDoc->InsertTab(0, "Formula"); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits