sc/inc/column.hxx | 2 sc/qa/unit/ucalc.cxx | 129 ++++++++++++++++++++++++-- sc/source/core/data/column.cxx | 110 +++++++++++++++------- sc/source/core/data/column2.cxx | 4 sc/source/core/data/column3.cxx | 173 +++++++++++++++++++++++++----------- sc/source/core/data/formulacell.cxx | 3 6 files changed, 322 insertions(+), 99 deletions(-)
New commits: commit 3caaac486fbe9a575e602c54f418483cf9dedded Author: Kohei Yoshida <[email protected]> Date: Mon Jul 8 13:50:23 2013 -0400 Remove this marker. Change-Id: Iab8695f579abb009f12aa76f4e161f106527f493 diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 89d26c1..e7e98f8 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -2293,7 +2293,6 @@ bool ScColumn::UpdateReference( } UpdateRefOnNonCopy aHandler(nCol, nTab, rRange, nDx, nDy, nDz, eUpdateRefMode, pUndoDoc); - FormulaCellsUndecided(0, MAXROW); sc::ProcessFormula(maCells, aHandler); return aHandler.isUpdated(); } commit 9e874bc0854cab345da8df0a64442c6c4fe04824 Author: Kohei Yoshida <[email protected]> Date: Mon Jul 8 13:48:07 2013 -0400 Adjust formula grouping in InsertRow(). Change-Id: I82723a30edc361b627246b66d21dc04cd639caa6 diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index 96221cf..5ea6597 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -6447,8 +6447,20 @@ void Test::testSharedFormulas() CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow()); CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength()); - m_pDoc->DeleteTab(0); + // Insert 2 rows at row 4, to split it into B2:B3 and B6:B7. + m_pDoc->InsertRow(ScRange(0,3,0,MAXCOL,4,0)); + pFC = m_pDoc->GetFormulaCell(aPos); + CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength()); + aPos.SetRow(5); + pFC = m_pDoc->GetFormulaCell(aPos); + CPPUNIT_ASSERT_MESSAGE("B6 should be a formula cell.", pFC); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength()); + + m_pDoc->DeleteTab(0); } namespace { diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 6f87a93..89d26c1 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -2273,6 +2273,25 @@ bool ScColumn::UpdateReference( return aHandler.isUpdated(); } + bool bThisColShifted = (rRange.aStart.Tab() <= nTab && nTab <= rRange.aEnd.Tab() && rRange.aStart.Col() <= nCol && nCol <= rRange.aEnd.Col()); + if (bThisColShifted) + { + // Cells in this column is being shifted. Split formula grouping at + // the top and bottom boundaries before they get shifted. + SCROW nSplitPos = rRange.aStart.Row(); + if (ValidRow(nSplitPos)) + { + sc::CellStoreType::position_type aPos = maCells.position(nSplitPos); + SplitFormulaCellGroup(aPos); + nSplitPos = rRange.aEnd.Row() + 1; + if (ValidRow(nSplitPos)) + { + aPos = maCells.position(aPos.first, nSplitPos); + SplitFormulaCellGroup(aPos); + } + } + } + UpdateRefOnNonCopy aHandler(nCol, nTab, rRange, nDx, nDy, nDz, eUpdateRefMode, pUndoDoc); FormulaCellsUndecided(0, MAXROW); sc::ProcessFormula(maCells, aHandler); diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index e146f4a..b693502 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -2099,6 +2099,9 @@ bool ScFormulaCell::UpdateReference( // This formula cell itself is being shifted during cell range // insertion or deletion. Update its position. aPos.Move(nDx, nDy, nDz); + if (xGroup && xGroup->mnStart == aOldPos.Row()) + xGroup->mnStart += nDy; + bCellStateChanged = aPos != aOldPos; } else if (rRange.In(aPos)) commit 48aece30a2cdde4b9bea4146e9868e0bfdaab448 Author: Kohei Yoshida <[email protected]> Date: Mon Jul 8 11:48:00 2013 -0400 Add test for re-grouping of formulas in DeleteRow(). Change-Id: Iea7fafedc2a5f1549a701d1fa768c127e3236246 diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index f04726f..96221cf 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -6438,6 +6438,15 @@ void Test::testSharedFormulas() CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow()); CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength()); + // Delete rows 4:8 and shift row 9 and below up to row 4. This should + // re-merge the two into a group of B2:B5. + m_pDoc->DeleteRow(ScRange(0,3,0,MAXCOL,7,0)); + aPos.SetRow(1); + pFC = m_pDoc->GetFormulaCell(aPos); + CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength()); + m_pDoc->DeleteTab(0); } commit e72e5a33505ad3b756b3a73975d223eb9565f441 Author: Kohei Yoshida <[email protected]> Date: Mon Jul 8 10:15:27 2013 -0400 Re-group formula cells in DeleteRow(). Change-Id: Ic67af048baa55cf1aee118ec741f140831127a95 diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index 0667d38..3c35b80 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -296,9 +296,14 @@ void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize ) maCells.erase(nStartRow, nEndRow); maCells.resize(MAXROWCOUNT); + // Get the position again after the container change. + aPos = maCells.position(nStartRow); + // Shift the formula cell positions below the start row. ShiftFormulaPosHandler aShiftFormulaFunc; - sc::ProcessFormula(maCells.begin(), maCells, nStartRow, MAXROW, aShiftFormulaFunc); + sc::ProcessFormula(aPos.first, maCells, nStartRow, MAXROW, aShiftFormulaFunc); + + JoinFormulaCellAbove(aPos); // Single cell broadcasts on deleted cells. BroadcastCells(aDeleteRowsFunc.getNonEmptyRows()); @@ -307,7 +312,6 @@ void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize ) maCellTextAttrs.erase(nStartRow, nEndRow); maCellTextAttrs.resize(MAXROWCOUNT); - RegroupFormulaCells(nStartRow); CellStorageModified(); if (!bShiftCells) @@ -598,8 +602,6 @@ void ScColumn::JoinFormulaCellAbove( const sc::CellStoreType::position_type& aPo // cell is not a formula cell. return; - SCROW nRow = aPos.first->position + aPos.second; - ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1); ScFormulaCell& rCell = *sc::formula_block::at(*aPos.first->data, aPos.second); sc::CellStoreType::position_type aPosPrev = aPos; commit 547e939d0226bb7e62705f2171a58aa77aa5d3da Author: Kohei Yoshida <[email protected]> Date: Thu Jul 4 02:17:03 2013 -0400 More on regrouping of formula cells. Change-Id: Icd3403e759841dce351c932ea8915ba9819e5a29 diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index c36b804..6704fb4 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -498,6 +498,8 @@ public: */ void SplitFormulaCellGroup( const sc::CellStoreType::position_type& aPos ) const; + void JoinFormulaCellAbove( const sc::CellStoreType::position_type& aPos ) const; + /** * Regroup formula cells for the entire column. */ diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 3a74780..6f87a93 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -2127,13 +2127,29 @@ void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol) sc::SingleColumnSpanSet::SpansType aRanges; aNonEmpties.getSpans(aRanges); + // Split the formula grouping at the top and bottom boundaries. + sc::CellStoreType::position_type aPos = maCells.position(nStartRow); + SplitFormulaCellGroup(aPos); + aPos = maCells.position(aPos.first, nEndRow+1); + SplitFormulaCellGroup(aPos); + + // Do the same with the destination column. + aPos = rCol.maCells.position(nStartRow); + rCol.SplitFormulaCellGroup(aPos); + aPos = rCol.maCells.position(aPos.first, nEndRow+1); + rCol.SplitFormulaCellGroup(aPos); + // Move the broadcasters to the destination column. maBroadcasters.transfer(nStartRow, nEndRow, rCol.maBroadcasters, nStartRow); maCells.transfer(nStartRow, nEndRow, rCol.maCells, nStartRow); maCellTextAttrs.transfer(nStartRow, nEndRow, rCol.maCellTextAttrs, nStartRow); - RegroupFormulaCells(nStartRow, nEndRow); - rCol.RegroupFormulaCells(nStartRow, nEndRow); + // Re-group transferred formula cells. + aPos = rCol.maCells.position(nStartRow); + rCol.JoinFormulaCellAbove(aPos); + aPos = rCol.maCells.position(aPos.first, nEndRow+1); + rCol.JoinFormulaCellAbove(aPos); + CellStorageModified(); rCol.CellStorageModified(); @@ -2267,31 +2283,47 @@ namespace { class UpdateTransHandler { + ScColumn& mrColumn; + sc::CellStoreType::iterator miPos; ScRange maSource; ScAddress maDest; ScDocument* mpUndoDoc; public: - UpdateTransHandler(const ScRange& rSource, const ScAddress& rDest, ScDocument* pUndoDoc) : + UpdateTransHandler(ScColumn& rColumn, const ScRange& rSource, const ScAddress& rDest, ScDocument* pUndoDoc) : + mrColumn(rColumn), + miPos(rColumn.GetCellStore().begin()), maSource(rSource), maDest(rDest), mpUndoDoc(pUndoDoc) {} - void operator() (size_t, ScFormulaCell* pCell) + void operator() (size_t nRow, ScFormulaCell* pCell) { + sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow); + miPos = aPos.first; + mrColumn.UnshareFormulaCell(aPos, *pCell); pCell->UpdateTranspose(maSource, maDest, mpUndoDoc); + mrColumn.JoinNewFormulaCell(aPos, *pCell); } }; class UpdateGrowHandler { + ScColumn& mrColumn; + sc::CellStoreType::iterator miPos; ScRange maArea; SCCOL mnGrowX; SCROW mnGrowY; public: - UpdateGrowHandler(const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY) : + UpdateGrowHandler(ScColumn& rColumn, const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY) : + mrColumn(rColumn), + miPos(rColumn.GetCellStore().begin()), maArea(rArea), mnGrowX(nGrowX), mnGrowY(nGrowY) {} - void operator() (size_t, ScFormulaCell* pCell) + void operator() (size_t nRow, ScFormulaCell* pCell) { + sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow); + miPos = aPos.first; + mrColumn.UnshareFormulaCell(aPos, *pCell); pCell->UpdateGrow(maArea, mnGrowX, mnGrowY); + mrColumn.JoinNewFormulaCell(aPos, *pCell); } }; @@ -2638,14 +2670,22 @@ public: class CompileErrorCellsHandler { + ScColumn& mrColumn; + sc::CellStoreType::iterator miPos; sal_uInt16 mnErrCode; FormulaGrammar::Grammar meGram; bool mbCompiled; public: - CompileErrorCellsHandler(sal_uInt16 nErrCode, FormulaGrammar::Grammar eGram) : - mnErrCode(nErrCode), meGram(eGram), mbCompiled(false) {} + CompileErrorCellsHandler(ScColumn& rColumn, sal_uInt16 nErrCode, FormulaGrammar::Grammar eGram) : + mrColumn(rColumn), + miPos(mrColumn.GetCellStore().begin()), + mnErrCode(nErrCode), + meGram(eGram), + mbCompiled(false) + { + } - void operator() (size_t /*nRow*/, ScFormulaCell* pCell) + void operator() (size_t nRow, ScFormulaCell* pCell) { sal_uInt16 nCurError = pCell->GetRawError(); if (!nCurError) @@ -2656,10 +2696,14 @@ public: // Error code is specified, and it doesn't match. Skip it. return; + sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow); + miPos = aPos.first; + mrColumn.UnshareFormulaCell(aPos, *pCell); pCell->GetCode()->SetCodeError(0); OUStringBuffer aBuf; pCell->GetFormula(aBuf, meGram); pCell->Compile(aBuf.makeStringAndClear(), false, meGram); + mrColumn.JoinNewFormulaCell(aPos, *pCell); mbCompiled = true; } @@ -2735,17 +2779,15 @@ public: void ScColumn::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest, ScDocument* pUndoDoc ) { - UpdateTransHandler aFunc(rSource, rDest, pUndoDoc); + UpdateTransHandler aFunc(*this, rSource, rDest, pUndoDoc); sc::ProcessFormula(maCells, aFunc); - RegroupFormulaCells(); } void ScColumn::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY ) { - UpdateGrowHandler aFunc(rArea, nGrowX, nGrowY); + UpdateGrowHandler aFunc(*this, rArea, nGrowX, nGrowY); sc::ProcessFormula(maCells, aFunc); - RegroupFormulaCells(); } @@ -2765,10 +2807,7 @@ void ScColumn::UpdateInsertTabOnlyCells(SCTAB nInsPos, SCTAB nNewSheets) InsertTabUpdater aFunc(maCellTextAttrs, nTab, nInsPos, nNewSheets); sc::ProcessFormulaEditText(maCells, aFunc); if (aFunc.isModified()) - { - RegroupFormulaCells(); CellStorageModified(); - } } void ScColumn::UpdateDeleteTab(SCTAB nDelPos, bool bIsMove, ScColumn* /*pRefUndo*/, SCTAB nSheets) @@ -2911,12 +2950,8 @@ void ScColumn::CompileXML( ScProgress& rProgress ) bool ScColumn::CompileErrorCells(sal_uInt16 nErrCode) { - CompileErrorCellsHandler aHdl(nErrCode, pDocument->GetGrammar()); + CompileErrorCellsHandler aHdl(*this, nErrCode, pDocument->GetGrammar()); sc::ProcessFormula(maCells, aHdl); - if (aHdl.isCompiled()) - // TODO: Probably more efficient to do this individually rather than the whole column. - RegroupFormulaCells(); - return aHdl.isCompiled(); } diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index 932e613..46bf525 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -1533,10 +1533,6 @@ void ScColumn::CellStorageModified() #endif } -void ScColumn::RegroupFormulaCells() -{ -} - void ScColumn::RegroupFormulaCells( SCROW /*nRow*/ ) { } diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index bddbd5a..0667d38 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -326,12 +326,14 @@ sc::CellStoreType::iterator ScColumn::GetPositionToInsert( SCROW nRow ) namespace { -void joinFormulaCells(SCROW nRow, ScFormulaCell& rCell1, ScFormulaCell& rCell2) +void joinFormulaCells(const sc::CellStoreType::position_type& rPos, ScFormulaCell& rCell1, ScFormulaCell& rCell2) { ScFormulaCell::CompareState eState = rCell1.CompareByTokenArray(rCell2); if (eState == ScFormulaCell::NotEqual) return; + SCROW nRow = rPos.first->position + rPos.second; + // Formula tokens equal those of the previous formula cell. ScFormulaCellGroupRef xGroup1 = rCell1.GetCellGroup(); ScFormulaCellGroupRef xGroup2 = rCell2.GetCellGroup(); @@ -339,13 +341,23 @@ void joinFormulaCells(SCROW nRow, ScFormulaCell& rCell1, ScFormulaCell& rCell2) { if (xGroup2) { - // Both cell1 and cell2 are shared. Merge them together. + // Both cell 1 and cell 2 are shared. Merge them together. + if (xGroup1.get() == xGroup2.get()) + // They belong to the same group. + return; + + // Set the group object from cell 1 to all cells in group 2. xGroup1->mnLength += xGroup2->mnLength; - rCell2.SetCellGroup(xGroup1); + size_t nOffset = rPos.second + 1; // position of cell 2 + for (size_t i = 0, n = xGroup2->mnLength; i < n; ++i) + { + ScFormulaCell& rCell = *sc::formula_block::at(*rPos.first->data, nOffset+i); + rCell.SetCellGroup(xGroup1); + } } else { - // cell1 is shared but cell2 is not. + // cell 1 is shared but cell 2 is not. rCell2.SetCellGroup(xGroup1); ++xGroup1->mnLength; } @@ -354,7 +366,7 @@ void joinFormulaCells(SCROW nRow, ScFormulaCell& rCell1, ScFormulaCell& rCell2) { if (xGroup2) { - // cell1 is not shared, but cell2 is already shared. + // cell 1 is not shared, but cell 2 is already shared. rCell1.SetCellGroup(xGroup2); xGroup2->mnStart = nRow; ++xGroup2->mnLength; @@ -378,20 +390,20 @@ void joinFormulaCells(SCROW nRow, ScFormulaCell& rCell1, ScFormulaCell& rCell2) void ScColumn::JoinNewFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ) const { - SCROW nRow = aPos.first->position + aPos.second; - // Check the previous row position for possible grouping. if (aPos.first->type == sc::element_type_formula && aPos.second > 0) { ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1); - joinFormulaCells(nRow-1, rPrev, rCell); + sc::CellStoreType::position_type aPosPrev = aPos; + --aPosPrev.second; + joinFormulaCells(aPosPrev, rPrev, rCell); } // Check the next row position for possible grouping. if (aPos.first->type == sc::element_type_formula && aPos.second+1 < aPos.first->size) { ScFormulaCell& rNext = *sc::formula_block::at(*aPos.first->data, aPos.second+1); - joinFormulaCells(nRow, rCell, rNext); + joinFormulaCells(aPos, rCell, rNext); } } @@ -575,6 +587,26 @@ void ScColumn::SplitFormulaCellGroup( const sc::CellStoreType::position_type& aP } } +void ScColumn::JoinFormulaCellAbove( const sc::CellStoreType::position_type& aPos ) const +{ + if (aPos.first->type != sc::element_type_formula) + // This is not a formula cell. + return; + + if (aPos.second == 0) + // This cell is already the top cell in a formula block; the previous + // cell is not a formula cell. + return; + + SCROW nRow = aPos.first->position + aPos.second; + + ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1); + ScFormulaCell& rCell = *sc::formula_block::at(*aPos.first->data, aPos.second); + sc::CellStoreType::position_type aPosPrev = aPos; + --aPosPrev.second; + joinFormulaCells(aPosPrev, rPrev, rCell); +} + sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow ) { // See if we are overwriting an existing formula cell. @@ -742,7 +774,7 @@ class EmptyCells sc::ColumnBlockPosition& mrPos; sc::CellStoreType::iterator miPos; - void splitFormulaGrouping(sc::CellStoreType& rCells, const sc::CellStoreType::position_type& rPos) + void splitFormulaGrouping(const sc::CellStoreType::position_type& rPos) { if (rPos.first->type == sc::element_type_formula) { @@ -762,9 +794,9 @@ public: // First, split formula grouping at the top and bottom boundaries // before emptying the cells. sc::CellStoreType::position_type aPos = rCells.position(mrPos.miCellPos, rSpan.mnRow1); - splitFormulaGrouping(rCells, aPos); + splitFormulaGrouping(aPos); aPos = rCells.position(aPos.first, rSpan.mnRow2); - splitFormulaGrouping(rCells, aPos); + splitFormulaGrouping(aPos); mrPos.miCellPos = rCells.set_empty(mrPos.miCellPos, rSpan.mnRow1, rSpan.mnRow2); mrPos.miCellTextAttrPos = mrColumn.GetCellAttrStore().set_empty(mrPos.miCellTextAttrPos, rSpan.mnRow1, rSpan.mnRow2); @@ -2863,15 +2895,19 @@ void ScColumn::RebuildFormulaGroups() if (!mbDirtyGroups) return; - // clear previous formula groups. + RegroupFormulaCells(); + mbDirtyGroups = false; +} + +void ScColumn::RegroupFormulaCells() +{ + // clear previous formula groups (if any) ScFormulaCellGroupRef xNone; CellGroupSetter aFunc(xNone); sc::ProcessFormula(maCells, aFunc); // re-build formula groups. std::for_each(maCells.begin(), maCells.end(), GroupFormulaCells()); - - mbDirtyGroups = false; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 5cbeb9c56db071b9c658ba4e4997b424fd4fbd4f Author: Kohei Yoshida <[email protected]> Date: Wed Jul 3 22:48:31 2013 -0400 Adjust formula grouping on range deletion. Change-Id: Id3c2cd0a3cffa299c8424f9c9e4989ce8bd60719 diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index 219638d..f04726f 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -6397,7 +6397,49 @@ void Test::testSharedFormulas() CPPUNIT_ASSERT_MESSAGE("B18 should be a formula cell.", pFC); CPPUNIT_ASSERT_MESSAGE("B18 should be non-shared.", !pFC->IsShared()); + // Set up a new group for shared formulas in B2:B10. + clearRange(m_pDoc, ScRange(0,0,0,2,100,0)); + + aPos.SetRow(1); + m_pDoc->SetString(aPos, "=A2*10"); + aPos.IncRow(); + m_pDoc->SetString(aPos, "=A3*10"); + aPos.IncRow(); + m_pDoc->SetString(aPos, "=A4*10"); + aPos.IncRow(); + m_pDoc->SetString(aPos, "=A5*10"); + aPos.IncRow(); + m_pDoc->SetString(aPos, "=A6*10"); + aPos.IncRow(); + m_pDoc->SetString(aPos, "=A7*10"); + aPos.IncRow(); + m_pDoc->SetString(aPos, "=A8*10"); + aPos.IncRow(); + m_pDoc->SetString(aPos, "=A9*10"); + aPos.IncRow(); + m_pDoc->SetString(aPos, "=A10*10"); + + pFC = m_pDoc->GetFormulaCell(aPos); + CPPUNIT_ASSERT_MESSAGE("B10 should be a formula cell.", pFC); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(9), pFC->GetSharedLength()); + + // Delete A4:B8. This should splite the grouping to B2:B3 and B9:B10. + clearRange(m_pDoc, ScRange(0,3,0,1,7,0)); + aPos.SetRow(1); + pFC = m_pDoc->GetFormulaCell(aPos); + CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength()); + + aPos.SetRow(8); + pFC = m_pDoc->GetFormulaCell(aPos); + CPPUNIT_ASSERT_MESSAGE("B9 should be a formula cell.", pFC); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength()); + m_pDoc->DeleteTab(0); + } namespace { diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index af683fe..3a74780 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -2809,7 +2809,6 @@ void ScColumn::UpdateCompile( bool bForceIfNameInUse ) { UpdateCompileHandler aFunc(bForceIfNameInUse); sc::ProcessFormula(maCells, aFunc); - RegroupFormulaCells(); } diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index f02a6a8..bddbd5a 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -741,17 +741,33 @@ class EmptyCells ScColumn& mrColumn; sc::ColumnBlockPosition& mrPos; sc::CellStoreType::iterator miPos; - sc::CellStoreType& mrCells; - sc::CellTextAttrStoreType& mrAttrs; + + void splitFormulaGrouping(sc::CellStoreType& rCells, const sc::CellStoreType::position_type& rPos) + { + if (rPos.first->type == sc::element_type_formula) + { + ScFormulaCell& rCell = *sc::formula_block::at(*rPos.first->data, rPos.second); + mrColumn.UnshareFormulaCell(rPos, rCell); + } + } + public: - EmptyCells(sc::ColumnBlockPosition& rPos, ScColumn& rColumn, sc::CellStoreType& rCells, sc::CellTextAttrStoreType& rAttrs) : - mrColumn(rColumn), mrPos(rPos), mrCells(rCells), mrAttrs(rAttrs) {} + EmptyCells(sc::ColumnBlockPosition& rPos, ScColumn& rColumn) : + mrColumn(rColumn), mrPos(rPos) {} void operator() (const sc::SingleColumnSpanSet::Span& rSpan) { - mrPos.miCellPos = mrCells.set_empty(mrPos.miCellPos, rSpan.mnRow1, rSpan.mnRow2); - mrPos.miCellTextAttrPos = mrAttrs.set_empty(mrPos.miCellTextAttrPos, rSpan.mnRow1, rSpan.mnRow2); - mrColumn.RegroupFormulaCells(rSpan.mnRow1, rSpan.mnRow2); + sc::CellStoreType& rCells = mrColumn.GetCellStore(); + + // First, split formula grouping at the top and bottom boundaries + // before emptying the cells. + sc::CellStoreType::position_type aPos = rCells.position(mrPos.miCellPos, rSpan.mnRow1); + splitFormulaGrouping(rCells, aPos); + aPos = rCells.position(aPos.first, rSpan.mnRow2); + splitFormulaGrouping(rCells, aPos); + + mrPos.miCellPos = rCells.set_empty(mrPos.miCellPos, rSpan.mnRow1, rSpan.mnRow2); + mrPos.miCellTextAttrPos = mrColumn.GetCellAttrStore().set_empty(mrPos.miCellTextAttrPos, rSpan.mnRow1, rSpan.mnRow2); } }; @@ -785,7 +801,7 @@ void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag) aBlockPos.miCellTextAttrPos = maCellTextAttrs.begin(); // Delete the cells for real. - std::for_each(aSpans.begin(), aSpans.end(), EmptyCells(aBlockPos, *this, maCells, maCellTextAttrs)); + std::for_each(aSpans.begin(), aSpans.end(), EmptyCells(aBlockPos, *this)); CellStorageModified(); } commit f08bad7134cf618da82d387195c3c4557e476893 Author: Kohei Yoshida <[email protected]> Date: Wed Jul 3 21:38:53 2013 -0400 ??? Change-Id: Id13bf81cd65fdc0677832993bded37e08f226c0d diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 4fa2a18..af683fe 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -2015,8 +2015,7 @@ void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() ) { rDestCol.DeleteArea( nStart, nEnd, IDF_CONTENTS ); - ((ScColumn*)this)-> - CopyToColumn(aCxt, nStart, nEnd, IDF_CONTENTS, false, rDestCol); + CopyToColumn(aCxt, nStart, nEnd, IDF_CONTENTS, false, rDestCol); // UpdateUsed not needed, is already done in TestCopyScenario (obsolete comment ?) commit 79b074e8bdd13a655f66616df1fbc12012e613e4 Author: Kohei Yoshida <[email protected]> Date: Wed Jul 3 21:34:13 2013 -0400 These methods shouldn't affect formula grouping. They only change sheet index values in all formula cells uniformly; they should not affect how they are grouped. Change-Id: Ie05152de1d6fc5799145e5721c57fd74f8f58239 diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 44e808a..4fa2a18 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -2783,10 +2783,7 @@ void ScColumn::UpdateDeleteTab(SCTAB nDelPos, bool bIsMove, ScColumn* /*pRefUndo DeleteTabUpdater aFunc(maCellTextAttrs, nDelPos, nSheets, nTab, bIsMove); sc::ProcessFormulaEditText(maCells, aFunc); if (aFunc.isModified()) - { - RegroupFormulaCells(); CellStorageModified(); - } } void ScColumn::UpdateInsertTabAbs(SCTAB nNewPos) @@ -2794,10 +2791,7 @@ void ScColumn::UpdateInsertTabAbs(SCTAB nNewPos) InsertAbsTabUpdater aFunc(maCellTextAttrs, nTab, nNewPos); sc::ProcessFormulaEditText(maCells, aFunc); if (aFunc.isModified()) - { - RegroupFormulaCells(); CellStorageModified(); - } } void ScColumn::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo ) @@ -2808,10 +2802,7 @@ void ScColumn::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo ) MoveTabUpdater aFunc(maCellTextAttrs, nTab, nOldPos, nNewPos); sc::ProcessFormulaEditText(maCells, aFunc); if (aFunc.isModified()) - { - RegroupFormulaCells(); CellStorageModified(); - } } commit 18d707b6cfa5675de5fa0d5d64684e54db29ed10 Author: Kohei Yoshida <[email protected]> Date: Wed Jul 3 19:32:31 2013 -0400 More test on shared formula group adjustment on value insertions. Change-Id: Icaa48ef790cd71abdfc1d026ac912a88f727c0d5 diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index c241dfb..219638d 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -54,6 +54,7 @@ #include "tokenarray.hxx" #include "scopetools.hxx" #include "dociter.hxx" +#include "editutil.hxx" #include "formula/IFunctionDescription.hxx" @@ -6364,6 +6365,38 @@ void Test::testSharedFormulas() CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(14), pFC->GetSharedTopRow()); CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength()); + // Set numeric value to B15, to make B16:B18 shared. + aPos.SetRow(14); + m_pDoc->SetValue(aPos, 1.2); + aPos.SetRow(15); + pFC = m_pDoc->GetFormulaCell(aPos); + // B16:B18 should be shared. + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(15), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength()); + + // Set string value to B16 to make B17:B18 shared. + aPos.SetRow(15); + ScCellValue aCell("Test"); + CPPUNIT_ASSERT_MESSAGE("This should be a string value.", aCell.meType == CELLTYPE_STRING); + aCell.commit(*m_pDoc, aPos); + CPPUNIT_ASSERT_EQUAL(*aCell.mpString, m_pDoc->GetString(aPos)); + aPos.SetRow(16); + pFC = m_pDoc->GetFormulaCell(aPos); + // B17:B18 should be shared. + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(16), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength()); + + // Set edit text to B17. Now B18 should be non-shared. + ScFieldEditEngine& rEditEngine = m_pDoc->GetEditEngine(); + rEditEngine.SetText("Edit Text"); + aPos.SetRow(16); + m_pDoc->SetEditText(aPos, rEditEngine.CreateTextObject()); + CPPUNIT_ASSERT_EQUAL(CELLTYPE_EDIT, m_pDoc->GetCellType(aPos)); + aPos.SetRow(17); + pFC = m_pDoc->GetFormulaCell(aPos); + CPPUNIT_ASSERT_MESSAGE("B18 should be a formula cell.", pFC); + CPPUNIT_ASSERT_MESSAGE("B18 should be non-shared.", !pFC->IsShared()); + m_pDoc->DeleteTab(0); } diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index 88f52db..f02a6a8 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -1765,7 +1765,6 @@ void ScColumn::SetEditText( SCROW nRow, EditTextObject* pEditText ) sc::CellStoreType::iterator it = GetPositionToInsert(nRow); maCells.set(it, nRow, pEditText); maCellTextAttrs.set(nRow, sc::CellTextAttr()); - RegroupFormulaCells(nRow); CellStorageModified(); BroadcastNewCell(nRow); @@ -1777,7 +1776,6 @@ void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, Edit rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pEditText); rBlockPos.miCellTextAttrPos = maCellTextAttrs.set( rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr()); - RegroupFormulaCells(nRow); CellStorageModified(); BroadcastNewCell(nRow); @@ -2280,7 +2278,6 @@ void ScColumn::SetError( SCROW nRow, const sal_uInt16 nError) sc::CellStoreType::iterator it = GetPositionToInsert(nRow); it = maCells.set(it, nRow, pCell); maCellTextAttrs.set(nRow, sc::CellTextAttr()); - RegroupFormulaCells(nRow); CellStorageModified(); ActivateNewFormulaCell(it, nRow, *pCell); @@ -2294,7 +2291,6 @@ void ScColumn::SetRawString( SCROW nRow, const OUString& rStr, bool bBroadcast ) sc::CellStoreType::iterator it = GetPositionToInsert(nRow); maCells.set(it, nRow, rStr); maCellTextAttrs.set(nRow, sc::CellTextAttr()); - RegroupFormulaCells(nRow); CellStorageModified(); if (bBroadcast) @@ -2311,7 +2307,6 @@ void ScColumn::SetRawString( rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, rStr); rBlockPos.miCellTextAttrPos = maCellTextAttrs.set( rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr()); - RegroupFormulaCells(nRow); CellStorageModified(); if (bBroadcast) @@ -2326,7 +2321,6 @@ void ScColumn::SetValue( SCROW nRow, double fVal ) sc::CellStoreType::iterator it = GetPositionToInsert(nRow); maCells.set(it, nRow, fVal); maCellTextAttrs.set(nRow, sc::CellTextAttr()); - RegroupFormulaCells(nRow); CellStorageModified(); BroadcastNewCell(nRow); @@ -2342,7 +2336,6 @@ void ScColumn::SetValue( rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, fVal); rBlockPos.miCellTextAttrPos = maCellTextAttrs.set( rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr()); - RegroupFormulaCells(nRow); CellStorageModified(); if (bBroadcast) commit c2325143d38d633b0788ac0104a7d3fc95819ce8 Author: Kohei Yoshida <[email protected]> Date: Wed Jul 3 18:51:59 2013 -0400 Adjust formula cell grouping on cell deletion without shifting. Change-Id: I4dad09faf10406163b5944933422d50b832f45bc diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index d05b7eb..c241dfb 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -6331,25 +6331,38 @@ void Test::testSharedFormulas() m_pDoc->SetString(aPos, "=A20*2"); pFC = m_pDoc->GetFormulaCell(aPos); CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared()); + // B13:B20 shuld be shared. CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(12), pFC->GetSharedTopRow()); CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength()); -#if 0 - // Insert empty rows at B16 to split B13:B20 into B13:B15 and B21:B25. - m_pDoc->InsertRow(1, 0, 1, 0, 15, 5); - + // Empty B19. This should split it into B13:B18, and B20 non-shared. + aPos.SetRow(18); + m_pDoc->SetEmptyCell(aPos); + CPPUNIT_ASSERT_MESSAGE("This cell should have been emptied.", m_pDoc->GetCellType(aPos) == CELLTYPE_NONE); aPos.SetRow(12); // B13 pFC = m_pDoc->GetFormulaCell(aPos); - CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared()); + // B13:B18 should be shared. CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(12), pFC->GetSharedTopRow()); - CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), pFC->GetSharedLength()); + // B20 shold be non-shared. + aPos.SetRow(19); // B20 + pFC = m_pDoc->GetFormulaCell(aPos); + CPPUNIT_ASSERT_MESSAGE("B20 should be a formula cell.", pFC); + CPPUNIT_ASSERT_MESSAGE("This cell should be non-shared.", !pFC->IsShared()); - aPos.SetRow(23); // B24 + // Empty B14, to make B13 non-shared and B15:B18 shared. + aPos.SetRow(13); // B14 + m_pDoc->SetEmptyCell(aPos); + aPos.SetRow(12); // B13 pFC = m_pDoc->GetFormulaCell(aPos); - CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared()); - CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(20), pFC->GetSharedTopRow()); - CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), pFC->GetSharedLength()); -#endif + // B13 should be non-shared. + CPPUNIT_ASSERT_MESSAGE("B13 should be a formula cell.", pFC); + CPPUNIT_ASSERT_MESSAGE("This cell should be non-shared.", !pFC->IsShared()); + // B15:B18 should be shared. + aPos.SetRow(14); // B15 + pFC = m_pDoc->GetFormulaCell(aPos); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(14), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength()); m_pDoc->DeleteTab(0); } diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index b46f1df..88f52db 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -131,16 +131,16 @@ void ScColumn::InterpretDirtyCells( SCROW nRow1, SCROW nRow2 ) void ScColumn::Delete( SCROW nRow ) { - std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow); + sc::CellStoreType::position_type aPos = maCells.position(nRow); sc::CellStoreType::iterator it = aPos.first; if (it == maCells.end()) return; - bool bFormulaCell = it->type == sc::element_type_formula; - if (bFormulaCell) + if (it->type == sc::element_type_formula) { ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second); p->EndListeningTo(pDocument); + UnshareFormulaCell(aPos, *p); } maCells.set_empty(nRow, nRow); maCellTextAttrs.set_empty(nRow, nRow); @@ -148,9 +148,6 @@ void ScColumn::Delete( SCROW nRow ) pDocument->Broadcast( ScHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab))); - if (bFormulaCell) - RegroupFormulaCells(nRow); - CellStorageModified(); } @@ -474,27 +471,54 @@ void ScColumn::UnshareFormulaCell( ScFormulaCellGroupRef xGroup = rCell.GetCellGroup(); SCROW nEndRow = xGroup->mnStart + xGroup->mnLength - 1; xGroup->mnLength = rCell.aPos.Row() - xGroup->mnStart; // Shorten the top group. - - ScFormulaCellGroupRef xGroup2(new ScFormulaCellGroup); - xGroup2->mnStart = rCell.aPos.Row() + 1; - xGroup2->mnLength = nEndRow - rCell.aPos.Row(); - xGroup2->mbInvariant = xGroup->mbInvariant; -#if DEBUG_COLUMN_STORAGE - if (xGroup2->mnStart + xGroup2->mnLength > it->position + it->size) + if (xGroup->mnLength == 1) { - cerr << "ScColumn::UnshareFormulaCell: Shared formula region goes beyond the formula block. Not good." << endl; - cerr.flush(); - abort(); + // Make the top cell non-shared. +#if DEBUG_COLUMN_STORAGE + if (aPos.second == 0) + { + cerr << "ScColumn::UnshareFormulaCell: There is no previous formula cell but there should be!" << endl; + cerr.flush(); + abort(); + } +#endif + ScFormulaCell& rPrev = *sc::formula_block::at(*it->data, aPos.second-1); + rPrev.SetCellGroup(xNone); } + + SCROW nLength2 = nEndRow - rCell.aPos.Row(); + if (nLength2 >= 2) + { + ScFormulaCellGroupRef xGroup2; + xGroup2.reset(new ScFormulaCellGroup); + xGroup2->mnStart = rCell.aPos.Row() + 1; + xGroup2->mnLength = nLength2; + xGroup2->mbInvariant = xGroup->mbInvariant; +#if DEBUG_COLUMN_STORAGE + if (xGroup2->mnStart + xGroup2->mnLength > it->position + it->size) + { + cerr << "ScColumn::UnshareFormulaCell: Shared formula region goes beyond the formula block. Not good." << endl; + cerr.flush(); + abort(); + } #endif - sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data); - std::advance(itCell, aPos.second+1); - sc::formula_block::iterator itCellEnd = itCell; - std::advance(itCellEnd, xGroup2->mnLength); - for (; itCell != itCellEnd; ++itCell) + sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data); + std::advance(itCell, aPos.second+1); + sc::formula_block::iterator itCellEnd = itCell; + std::advance(itCellEnd, xGroup2->mnLength); + for (; itCell != itCellEnd; ++itCell) + { + ScFormulaCell& rCell2 = **itCell; + rCell2.SetCellGroup(xGroup2); + } + } + else { + // Make the next cell non-shared. + sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data); + std::advance(itCell, aPos.second+1); ScFormulaCell& rCell2 = **itCell; - rCell2.SetCellGroup(xGroup2); + rCell2.SetCellGroup(xNone); } } _______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
