sc/inc/formulacell.hxx | 1 sc/qa/unit/ucalc.cxx | 75 +++++++++++++++++++++++++++++++++--- sc/qa/unit/ucalc.hxx | 2 sc/source/core/data/column.cxx | 31 +++++++++----- sc/source/core/data/formulacell.cxx | 44 ++++++++++++++++++++- 5 files changed, 133 insertions(+), 20 deletions(-)
New commits: commit ff89c120f5f5036c3792b9cfc3f0329de3ac0a43 Author: Michael Meeks <michael.me...@collabora.com> Date: Fri Mar 14 16:31:59 2014 +0000 fdo#72741 - write unit test for in formula group swapping. Change-Id: I9da62b026b40b08784415e0421556946646d25e2 diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index cfc94e0..e1e9529 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -4525,10 +4525,8 @@ void Test::testFindAreaPosColRight() void Test::testSortWithFormulaRefs() { ScDocument* pDoc = getDocShell().GetDocument(); - OUString aTabName1("List1"); - OUString aTabName2("List2"); - pDoc->InsertTab(0, aTabName1); - pDoc->InsertTab(1, aTabName2); + pDoc->InsertTab(0, "List1"); + pDoc->InsertTab(1, "List2"); const char* aFormulaData[6] = { "=IF($List1.A2<>\"\",$List1.A2,\"\")", @@ -4627,8 +4625,7 @@ void Test::testSortWithStrings() void Test::testSort() { - OUString aTabName1("test1"); - m_pDoc->InsertTab(0, aTabName1); + m_pDoc->InsertTab(0, "test1"); ScRange aDataRange; ScAddress aPos(0,0,0); @@ -4717,6 +4714,72 @@ void Test::testSort() m_pDoc->DeleteTab(0); } +void Test::testSortInFormulaGroup() +{ + static struct { + SCCOL nCol; + SCROW nRow; + const char *pData; + } aEntries[] = { + { 0, 0, "3" }, { 1, 0, "=A1" }, + { 0, 1, "1" }, { 1, 1, "=A2" }, + { 0, 2, "20" }, { 1, 2, "=A3" }, + { 0, 3, "10" }, { 1, 3, "=A4+1" }, // swap across groups + { 0, 4, "2" }, { 1, 4, "=A5+1" }, + { 0, 5, "101" }, { 1, 5, "=A6" }, // swap inside contiguious group + { 0, 6, "100" }, { 1, 6, "=A7" }, + { 0, 7, "102" }, { 1, 7, "=A8" }, + { 0, 8, "104" }, { 1, 8, "=A9" }, + { 0, 9, "103" }, { 1, 9, "=A10" }, + }; + + m_pDoc->InsertTab(0, "sorttest"); + + for ( SCROW i = 0; i < (SCROW) SAL_N_ELEMENTS( aEntries ); ++i ) + m_pDoc->SetString( aEntries[i].nCol, aEntries[i].nRow, 0, + OUString::createFromAscii( aEntries[i].pData) ); + + ScSortParam aSortData; + aSortData.nCol1 = 0; + aSortData.nCol2 = 1; + aSortData.nRow1 = 0; + aSortData.nRow2 = 9; + aSortData.maKeyState[0].bDoSort = true; + aSortData.maKeyState[0].nField = 0; + aSortData.maKeyState[0].bAscending = true; + + m_pDoc->Sort(0, aSortData, false, NULL); + + static struct { + SCCOL nCol; + SCROW nRow; + double fValue; + } aResults[] = { + { 0, 0, 1.0 }, { 1, 0, 1.0 }, + { 0, 1, 2.0 }, { 1, 1, 3.0 }, + { 0, 2, 3.0 }, { 1, 2, 3.0 }, + { 0, 3, 10.0 }, { 1, 3, 11.0 }, + { 0, 4, 20.0 }, { 1, 4, 20.0 }, + { 0, 5, 100.0 }, { 1, 5, 100.0 }, + { 0, 6, 101.0 }, { 1, 6, 101.0 }, + { 0, 7, 102.0 }, { 1, 7, 102.0 }, + { 0, 8, 103.0 }, { 1, 8, 103.0 }, + { 0, 9, 104.0 }, { 1, 9, 104.0 }, + }; + + for ( SCROW i = 0; i < (SCROW) SAL_N_ELEMENTS( aEntries ); ++i ) + { + double val = m_pDoc->GetValue( aEntries[i].nCol, aEntries[i].nRow, 0 ); +// fprintf(stderr, "value at %d %d is %g = %g\n", +// (int)aResults[i].nRow, (int)aResults[i].nCol, +// val, aResults[i].fValue); + CPPUNIT_ASSERT_MESSAGE("Mis-matching value after sort.", + rtl::math::approxEqual(val, aResults[i].fValue)); + } + + m_pDoc->DeleteTab( 0 ); +} + void Test::testShiftCells() { m_pDoc->InsertTab(0, "foo"); diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx index 68f5bc4..8c3ec8f 100644 --- a/sc/qa/unit/ucalc.hxx +++ b/sc/qa/unit/ucalc.hxx @@ -315,6 +315,7 @@ public: void testSort(); void testSortWithFormulaRefs(); void testSortWithStrings(); + void testSortInFormulaGroup(); void testShiftCells(); void testNoteBasic(); @@ -460,6 +461,7 @@ public: CPPUNIT_TEST(testSort); CPPUNIT_TEST(testSortWithFormulaRefs); CPPUNIT_TEST(testSortWithStrings); + CPPUNIT_TEST(testSortInFormulaGroup); CPPUNIT_TEST(testShiftCells); CPPUNIT_TEST(testNoteBasic); CPPUNIT_TEST(testNoteDeleteRow); commit 0698c49ccdbf62dd84d3f9c5d25ee039f4fff722 Author: Michael Meeks <michael.me...@collabora.com> Date: Fri Mar 14 14:26:02 2014 +0000 fdo#72741 - swap values only inside a formula group. Speeds up sorting large ranges containing formula groups by a computational order or two: can sort 1 million rows of =A1 in sub 10s Change-Id: I729c801e68154986956b1726e1c35ef973cc4248 diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index f2bc36c..9b47046 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -203,6 +203,7 @@ public: void SetDirtyAfterLoad(); void ResetTableOpDirtyVar(); void SetTableOpDirty(); + bool SwapWithinGroup( ScFormulaCell *pSwap ); bool IsDirtyOrInTableOpDirty() const; bool GetDirty() const; void ResetDirty(); diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 1fa7120..2e9192d 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -871,18 +871,25 @@ void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2) std::advance(itf1, aPos1.second); std::advance(itf2, aPos2.second); - // TODO: Find out a way to adjust references without cloning new instances. - boost::scoped_ptr<ScFormulaCell> pOld1(*itf1); - boost::scoped_ptr<ScFormulaCell> pOld2(*itf2); - DetachFormulaCell(aPos1, **itf1); - DetachFormulaCell(aPos2, **itf2); - ScFormulaCell* pNew1 = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *pOld2); - ScFormulaCell* pNew2 = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *pOld1); - *itf1 = pNew1; - *itf2 = pNew2; - - ActivateNewFormulaCell(aPos1, *pNew1); - ActivateNewFormulaCell(aPos2, *pNew2); + // Is it an identical formula in the same group - if so, + // take a shortcut to swap the result data: + if(!(*itf1)->SwapWithinGroup(*itf2)) + { + // otherwise we need to really move the formula & + // re-write dependencies etc. + boost::scoped_ptr<ScFormulaCell> pOld1(*itf1); + boost::scoped_ptr<ScFormulaCell> pOld2(*itf2); + + DetachFormulaCell(aPos1, **itf1); + DetachFormulaCell(aPos2, **itf2); + ScFormulaCell* pNew1 = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *pOld2); + ScFormulaCell* pNew2 = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *pOld1); + *itf1 = pNew1; + *itf2 = pNew2; + + ActivateNewFormulaCell(aPos1, *pNew1); + ActivateNewFormulaCell(aPos2, *pNew2); + } } break; default: diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 9bbc75d..957d8b2 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -1977,15 +1977,55 @@ void ScFormulaCell::SetTableOpDirty() } } - bool ScFormulaCell::IsDirtyOrInTableOpDirty() const { return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp()); } +/** Exchange formulae cell result data inside a formula + group if possible. Return true if both Formula cells + are inside the same formula group and the data has + been successfully exchanged; otherwise false - leaving + the formulae untouched. + */ +bool ScFormulaCell::SwapWithinGroup( ScFormulaCell *pSwap ) +{ + if (!mxGroup || // ungrouped + mxGroup != pSwap->mxGroup) + return false; + + if (pDocument != pSwap->pDocument || + nSeenInIteration != pSwap->nSeenInIteration || + eTempGrammar != pSwap->eTempGrammar || + cMatrixFlag != pSwap->cMatrixFlag || + nFormatType != pSwap->nFormatType || + bDirty != pSwap->bDirty || + bChanged != pSwap->bChanged || + bRunning != pSwap->bRunning || + bCompile != pSwap->bCompile || + bSubTotal != pSwap->bSubTotal || + bIsIterCell != pSwap->bIsIterCell || + bInChangeTrack != pSwap->bInChangeTrack || + bTableOpDirty != pSwap->bTableOpDirty || + bNeedListening != pSwap->bNeedListening || + mbNeedsNumberFormat != pSwap->mbNeedsNumberFormat || + mbPostponedDirty != pSwap->mbPostponedDirty + ) + return false; // we are paranoid for good reason. + + // retain aPos as is. + + // swap result value + ScFormulaResult aTemp(aResult); + aResult = pSwap->aResult; + pSwap->aResult.Assign(aTemp); + + return true; +} + void ScFormulaCell::SetResultDouble( double n ) { - aResult.SetDouble( n); + aResult.SetDouble(n); } void ScFormulaCell::SetResultToken( const formula::FormulaToken* pToken ) _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits