sc/Library_sc.mk | 1 sc/inc/column.hxx | 2 sc/inc/columnset.hxx | 40 +++++++++++++ sc/inc/refupdatecontext.hxx | 2 sc/inc/table.hxx | 9 +-- sc/qa/unit/ucalc.hxx | 2 sc/qa/unit/ucalc_sharedformula.cxx | 94 ++++++++++++++++++++++++++++++++ sc/source/core/data/column.cxx | 5 + sc/source/core/data/column3.cxx | 108 ++++++++++++++++++++++++++----------- sc/source/core/data/columnset.cxx | 66 ++++++++++++++++++++++ sc/source/core/data/document.cxx | 16 ++--- sc/source/core/data/table2.cxx | 35 +++++++++-- 12 files changed, 328 insertions(+), 52 deletions(-)
New commits: commit 61d01ee9e074cfb8c817c716676d15e92d60f3da Author: Kohei Yoshida <[email protected]> Date: Tue Aug 13 23:47:58 2013 -0400 Do the same when deleting rows. Change-Id: Ib1deab33a8771e196d0520bae872eb0d492c913e diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index fa6247c..5e3f959 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -384,8 +384,8 @@ public: bool TestInsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize ) const; void InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize ); - void DeleteRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize, - bool* pUndoOutline = NULL ); + void DeleteRow( + const sc::ColumnSet& rRegroupCols, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize, bool* pUndoOutline = NULL ); bool TestInsertCol( SCROW nStartRow, SCROW nEndRow, SCSIZE nSize ) const; void InsertCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize ); diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx index 094db8f..4d9ad67 100644 --- a/sc/qa/unit/ucalc_sharedformula.cxx +++ b/sc/qa/unit/ucalc_sharedformula.cxx @@ -309,6 +309,37 @@ void Test::testSharedFormulasRefUpdate() CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow()); CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength()); + // Insert cells over A11:A12 and shift down. + m_pDoc->InsertRow(ScRange(0,10,0,0,11,0)); + if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10")) + CPPUNIT_FAIL("Wrong formula in B1"); + if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "A13")) + CPPUNIT_FAIL("Wrong formula in B2"); + if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A14")) + CPPUNIT_FAIL("Wrong formula in B3"); + + pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0)); + CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC && !pFC->IsShared()); + pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0)); + CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC && pFC->IsShared()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength()); + + // Delete A11:A12 to bring it back to the way it was. + m_pDoc->DeleteRow(ScRange(0,10,0,0,11,0)); + + if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10")) + CPPUNIT_FAIL("Wrong formula in B1"); + if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "A11")) + CPPUNIT_FAIL("Wrong formula in B2"); + if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A12")) + CPPUNIT_FAIL("Wrong formula in B3"); + + pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0)); + CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC && pFC->IsShared()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength()); + m_pDoc->DeleteTab(0); } diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 9fdf84a..2e3a279 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -1301,10 +1301,10 @@ void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab, } while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) ); + sc::RefUpdateContext aCxt(*this); if ( ValidRow(nStartRow+nSize) ) { lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ); - sc::RefUpdateContext aCxt(*this); aCxt.meMode = URM_INSDEL; aCxt.maRange = ScRange(nStartCol, nStartRow+nSize, nTabRangeStart, nEndCol, MAXROW, nTabRangeEnd); aCxt.mnRowDelta = -(static_cast<SCROW>(nSize)); @@ -1320,7 +1320,7 @@ void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab, for ( i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++) if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i))) - maTabs[i]->DeleteRow( nStartCol, nEndCol, nStartRow, nSize, pUndoOutline ); + maTabs[i]->DeleteRow(aCxt.maRegroupCols, nStartCol, nEndCol, nStartRow, nSize, pUndoOutline); if ( ValidRow(nStartRow+nSize) ) { // Listeners have been removed in UpdateReference diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index f900f62..d2174de 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -227,8 +227,9 @@ void ScTable::InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE } -void ScTable::DeleteRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize, - bool* pUndoOutline ) +void ScTable::DeleteRow( + const sc::ColumnSet& rRegroupCols, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize, + bool* pUndoOutline ) { if (nStartCol==0 && nEndCol==MAXCOL) { @@ -266,6 +267,10 @@ void ScTable::DeleteRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE } } + std::vector<SCCOL> aRegroupCols; + rRegroupCols.getColumns(nTab, aRegroupCols); + std::for_each(aRegroupCols.begin(), aRegroupCols.end(), ColumnRegroupFormulaCells(aCol)); + // Transfer those notes that will get shifted into another container. ScNotes aNotes(pDocument); ScNotes::iterator itr = maNotes.begin(); commit 99ae3a94dfc0e955710959b01a0e0a1a77aafd1e Author: Kohei Yoshida <[email protected]> Date: Tue Aug 13 22:53:14 2013 -0400 Regroup formula cells later in columns where references are updated. Change-Id: I4dd6ade18e72d8f57583180463f9dda3603be4c2 diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk index 6f559f5..83e3358 100644 --- a/sc/Library_sc.mk +++ b/sc/Library_sc.mk @@ -108,6 +108,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/core/data/column2 \ sc/source/core/data/column3 \ sc/source/core/data/columniterator \ + sc/source/core/data/columnset \ sc/source/core/data/columnspanset \ sc/source/core/data/compressedarray \ sc/source/core/data/colorscale \ diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 22bb9bd..14d0bfe 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -329,7 +329,7 @@ public: * @return true if reference of at least one formula cell has been * updated, false otherwise. */ - bool UpdateReference( const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = NULL ); + bool UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = NULL ); void UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt ); void UpdateInsertTabOnlyCells( sc::RefUpdateInsertTabContext& rCxt ); diff --git a/sc/inc/columnset.hxx b/sc/inc/columnset.hxx new file mode 100644 index 0000000..fb56303 --- /dev/null +++ b/sc/inc/columnset.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef SC_COLUMNSET_HXX +#define SC_COLUMNSET_HXX + +#include "address.hxx" + +#include <vector> +#include <boost/unordered_set.hpp> +#include <boost/unordered_map.hpp> + +namespace sc { + +/** + * Simple container to keep track of sheet - column pair. + */ +class ColumnSet +{ + typedef boost::unordered_set<SCCOL> ColsType; + typedef boost::unordered_map<SCTAB, ColsType> TabsType; + TabsType maTabs; + +public: + void set(SCTAB nTab, SCCOL nCol); + bool has(SCTAB nTab, SCCOL nCol) const; + void getColumns(SCTAB nTab, std::vector<SCCOL>& rCols) const; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/inc/refupdatecontext.hxx b/sc/inc/refupdatecontext.hxx index f5ca4d0..ba0beed 100644 --- a/sc/inc/refupdatecontext.hxx +++ b/sc/inc/refupdatecontext.hxx @@ -12,6 +12,7 @@ #include "global.hxx" #include "address.hxx" +#include "columnset.hxx" #include <boost/unordered_map.hpp> #include <boost/unordered_set.hpp> @@ -66,6 +67,7 @@ struct RefUpdateContext SCTAB mnTabDelta; UpdatedRangeNames maUpdatedNames; + ColumnSet maRegroupCols; RefUpdateContext(ScDocument& rDoc); diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index a95f2bc..fa6247c 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -58,6 +58,7 @@ namespace sc { class CopyToDocContext; class MixDocContext; class ColumnSpanSet; + class ColumnSet; struct ColumnBlockPosition; struct RefUpdateContext; struct RefUpdateInsertTabContext; @@ -388,8 +389,8 @@ public: bool TestInsertCol( SCROW nStartRow, SCROW nEndRow, SCSIZE nSize ) const; void InsertCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize ); - void DeleteCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize, - bool* pUndoOutline = NULL ); + void DeleteCol( + const sc::ColumnSet& rRegroupCols, SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize, bool* pUndoOutline = NULL ); void DeleteArea(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uInt16 nDelFlag); void CopyToClip( sc::CopyToClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScTable* pTable ); diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index e4ad8c7..d8c3e60 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -2359,7 +2359,7 @@ bool ScColumn::UpdateReferenceOnCopy( const sc::RefUpdateContext& rCxt, ScDocume return aHandler.isUpdated(); } -bool ScColumn::UpdateReference( const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc ) +bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc ) { if (rCxt.meMode == URM_COPY) return UpdateReferenceOnCopy(rCxt, pUndoDoc); @@ -2396,6 +2396,9 @@ bool ScColumn::UpdateReference( const sc::RefUpdateContext& rCxt, ScDocument* pU UpdateRefOnNonCopy aHandler(nCol, nTab, rCxt, pUndoDoc); sc::ProcessFormula(maCells, aHandler); + if (aHandler.isUpdated()) + rCxt.maRegroupCols.set(nTab, nCol); + return aHandler.isUpdated(); } diff --git a/sc/source/core/data/columnset.cxx b/sc/source/core/data/columnset.cxx new file mode 100644 index 0000000..2e1f3aa --- /dev/null +++ b/sc/source/core/data/columnset.cxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "columnset.hxx" + +namespace sc { + +void ColumnSet::set(SCTAB nTab, SCCOL nCol) +{ + TabsType::iterator itTab = maTabs.find(nTab); + if (itTab == maTabs.end()) + { + std::pair<TabsType::iterator,bool> r = + maTabs.insert(TabsType::value_type(nTab, ColsType())); + + if (!r.second) + // insertion failed. + return; + + itTab = r.first; + } + + ColsType& rCols = itTab->second; + rCols.insert(nCol); +} + +bool ColumnSet::has(SCTAB nTab, SCCOL nCol) const +{ + TabsType::const_iterator itTab = maTabs.find(nTab); + if (itTab == maTabs.end()) + return false; + + const ColsType& rCols = itTab->second; + return rCols.count(nCol) > 0; +} + +void ColumnSet::getColumns(SCTAB nTab, std::vector<SCCOL>& rCols) const +{ + std::vector<SCCOL> aCols; + TabsType::const_iterator itTab = maTabs.find(nTab); + if (itTab == maTabs.end()) + { + rCols.swap(aCols); // empty it. + return; + } + + const ColsType& rTabCols = itTab->second; + aCols.assign(rTabCols.begin(), rTabCols.end()); + + // Sort and remove duplicates. + std::sort(aCols.begin(), aCols.end()); + std::vector<SCCOL>::iterator itCol = std::unique(aCols.begin(), aCols.end()); + aCols.erase(itCol, aCols.end()); + + rCols.swap(aCols); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index a6eb5ef..9fdf84a 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -1474,8 +1474,7 @@ void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTA nEndTab = static_cast<SCTAB>(maTabs.size())-1; } - bool bOldAutoCalc = GetAutoCalc(); - SetAutoCalc( false ); // avoid multiple calculations + sc::AutoCalcSwitch aACSwitch(*this, false); // avoid multiple calculations // handle chunks of consecutive selected sheets together SCTAB nTabRangeStart = nStartTab; @@ -1499,10 +1498,10 @@ void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTA } while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) ); + sc::RefUpdateContext aCxt(*this); if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) ) { lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ); - sc::RefUpdateContext aCxt(*this); aCxt.meMode = URM_INSDEL; aCxt.maRange = ScRange(sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart, MAXCOL, nEndRow, nTabRangeEnd); aCxt.mnColDelta = -(static_cast<SCCOL>(nSize)); @@ -1516,9 +1515,11 @@ void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTA if (pUndoOutline) *pUndoOutline = false; - for ( i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++) + for (i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); ++i) + { if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i))) - maTabs[i]->DeleteCol( nStartCol, nStartRow, nEndRow, nSize, pUndoOutline ); + maTabs[i]->DeleteCol(aCxt.maRegroupCols, nStartCol, nStartRow, nEndRow, nSize, pUndoOutline); + } if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) ) {// Listeners have been removed in UpdateReference @@ -1536,7 +1537,6 @@ void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTA std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler()); } - SetAutoCalc( bOldAutoCalc ); pChartListenerCollection->UpdateDirtyCharts(); } diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 537f856..f900f62 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -59,7 +59,21 @@ #include <svl/PasswordHelper.hxx> #include <unotools/transliterationwrapper.hxx> -// STATIC DATA ----------------------------------------------------------- +namespace { + +class ColumnRegroupFormulaCells +{ + ScColumn* mpCols; +public: + ColumnRegroupFormulaCells(ScColumn* pCols) : mpCols(pCols) {} + + void operator() (SCCOL nCol) + { + mpCols[nCol].RegroupFormulaCells(); + } +}; + +} sal_uInt16 ScTable::GetTextWidth(SCCOL nCol, SCROW nRow) const { @@ -425,9 +439,8 @@ void ScTable::InsertCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE SetStreamValid(false); } - -void ScTable::DeleteCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize, - bool* pUndoOutline ) +void ScTable::DeleteCol( + const sc::ColumnSet& rRegroupCols, SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize, bool* pUndoOutline ) { if (nStartRow==0 && nEndRow==MAXROW) { @@ -460,7 +473,6 @@ void ScTable::DeleteCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE } } - { // scope for bulk broadcast ScBulkBroadcast aBulkBroadcast( pDocument->GetBASM()); for (SCSIZE i = 0; i < nSize; i++) @@ -479,6 +491,10 @@ void ScTable::DeleteCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE aCol[nStartCol + nSize + i].MoveTo(nStartRow, nEndRow, aCol[nStartCol + i]); } + std::vector<SCCOL> aRegroupCols; + rRegroupCols.getColumns(nTab, aRegroupCols); + std::for_each(aRegroupCols.begin(), aRegroupCols.end(), ColumnRegroupFormulaCells(aCol)); + // Transfer those notes that will get shifted into another container. ScNotes aNotes(pDocument); ScNotes::iterator itr = maNotes.begin(); commit b93841f70abdd894d1bd17b455577541bc6948a4 Author: Kohei Yoshida <[email protected]> Date: Tue Aug 13 19:47:04 2013 -0400 Try to re-group without ungrouping all cells. Change-Id: I8e5c4e240e64a1d70e599c4a8791133dddc0b75b diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index c4276d9..4f87988 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -2628,18 +2628,6 @@ xub_StrLen ScColumn::GetMaxNumberStringLen( namespace { -class CellGroupSetter -{ - ScFormulaCellGroupRef mxGroup; -public: - CellGroupSetter(const ScFormulaCellGroupRef& xGroup) : mxGroup(xGroup) {} - - void operator() (size_t, ScFormulaCell* pCell) - { - pCell->SetCellGroup(mxGroup); - } -}; - class GroupFormulaCells { ScFormulaCellGroupRef mxNone; @@ -2652,40 +2640,103 @@ public: // We are only interested in formula cells. return; - ScFormulaCell* pPrev = NULL; - ScFormulaCell* pCur = NULL; size_t nRow = node.position; // start row position. sc::formula_block::iterator it = sc::formula_block::begin(*node.data); sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data); - for (; it != itEnd; ++it, ++nRow, pPrev = pCur) + + // This block should never be empty. + + ScFormulaCell* pPrev = *it; + ScFormulaCellGroupRef xPrevGrp = pPrev->GetCellGroup(); + if (xPrevGrp) + { + // Move to the cell after the last cell of the current group. + std::advance(it, xPrevGrp->mnLength); + nRow += xPrevGrp->mnLength; + } + else + { + ++it; + ++nRow; + } + + ScFormulaCell* pCur = NULL; + ScFormulaCellGroupRef xCurGrp; + for (; it != itEnd; pPrev = pCur, xPrevGrp = xCurGrp) { pCur = *it; - if (!pPrev) - continue; + xCurGrp = pCur->GetCellGroup(); ScFormulaCell::CompareState eCompState = pPrev->CompareByTokenArray(*pCur); if (eCompState == ScFormulaCell::NotEqual) { // different formula tokens. pCur->SetCellGroup(mxNone); + if (xCurGrp) + { + // Move to the cell after the last cell of the current group. + std::advance(it, xCurGrp->mnLength); + nRow += xCurGrp->mnLength; + } + else + { + ++it; + ++nRow; + } + continue; } - // Formula tokens equal those of the previous formula cell. - ScFormulaCellGroupRef xGroup = pPrev->GetCellGroup(); - if (!xGroup) + // Formula tokens equal those of the previous formula cell or cell group. + if (xPrevGrp) + { + // Previous cell is a group. + if (xCurGrp) + { + // The current cell is a group. Merge these two groups. + xPrevGrp->mnLength += xCurGrp->mnLength; + pCur->SetCellGroup(xPrevGrp); + sc::formula_block::iterator itGrpEnd = it; + std::advance(itGrpEnd, xCurGrp->mnLength); + for (++it; it != itGrpEnd; ++it) + { + ScFormulaCell* pCell = *it; + pCell->SetCellGroup(xPrevGrp); + } + nRow += xCurGrp->mnLength; + } + else + { + // Add this cell to the previous group. + pCur->SetCellGroup(xPrevGrp); + ++xPrevGrp->mnLength; + ++nRow; + ++it; + } + + } + else if (xCurGrp) { - // create a new group ... - xGroup = pPrev->CreateCellGroup(nRow - 1, 2, eCompState == ScFormulaCell::EqualInvariant); - pCur->SetCellGroup(xGroup); + // Previous cell is a regular cell and current cell is a group. + nRow += xCurGrp->mnLength; + std::advance(it, xCurGrp->mnLength); + pPrev->SetCellGroup(xCurGrp); + --xCurGrp->mnStart; + ++xCurGrp->mnLength; + xPrevGrp = xCurGrp; } else { - // existing group. extend its length. - pCur->SetCellGroup(xGroup); - ++xGroup->mnLength; + // Both previous and current cells are regular cells. + xPrevGrp = pPrev->CreateCellGroup(nRow - 1, 2, eCompState == ScFormulaCell::EqualInvariant); + pCur->SetCellGroup(xPrevGrp); + ++nRow; + ++it; } + + pCur = pPrev; + xCurGrp = xPrevGrp; } } }; @@ -2705,11 +2756,6 @@ void ScColumn::RebuildFormulaGroups() 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()); } commit 0e2fc9fce175199a021d0ac10431efbbb9d8c40a Author: Kohei Yoshida <[email protected]> Date: Tue Aug 13 18:28:11 2013 -0400 Add test for reference update on shared formulas. This currently (rightfully) fails. Change-Id: I254dc7042e93b257765c8ed8cdb9904966afd77e diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx index ebc3221..5e8933c 100644 --- a/sc/qa/unit/ucalc.hxx +++ b/sc/qa/unit/ucalc.hxx @@ -219,6 +219,7 @@ public: void testUpdateReference(); void testSearchCells(); void testSharedFormulas(); + void testSharedFormulasRefUpdate(); void testSharedFormulasCopyPaste(); void testFormulaPosition(); @@ -345,6 +346,7 @@ public: CPPUNIT_TEST(testUpdateReference); CPPUNIT_TEST(testSearchCells); CPPUNIT_TEST(testSharedFormulas); + CPPUNIT_TEST(testSharedFormulasRefUpdate); CPPUNIT_TEST(testSharedFormulasCopyPaste); CPPUNIT_TEST(testFormulaPosition); CPPUNIT_TEST(testJumpToPrecedentsDependents); diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx index 1eba457..094db8f 100644 --- a/sc/qa/unit/ucalc_sharedformula.cxx +++ b/sc/qa/unit/ucalc_sharedformula.cxx @@ -14,6 +14,7 @@ #include "docsh.hxx" #include "clipparam.hxx" #include "undoblk.hxx" +#include "scopetools.hxx" #include "formula/grammar.hxx" @@ -249,6 +250,68 @@ void Test::testSharedFormulas() m_pDoc->DeleteTab(0); } +void Test::testSharedFormulasRefUpdate() +{ + m_pDoc->InsertTab(0, "Test"); + + sc::AutoCalcSwitch aACSwitch(*m_pDoc, false); // turn off auto calculation. + + // Set values to A10:A12. + m_pDoc->SetValue(ScAddress(0,9,0), 1); + m_pDoc->SetValue(ScAddress(0,10,0), 2); + m_pDoc->SetValue(ScAddress(0,11,0), 3); + + // Insert formulas that reference A10:A12 in B1:B3. + m_pDoc->SetString(ScAddress(1,0,0), "=A10"); + m_pDoc->SetString(ScAddress(1,1,0), "=A11"); + m_pDoc->SetString(ScAddress(1,2,0), "=A12"); + + if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10")) + CPPUNIT_FAIL("Wrong formula in B1"); + if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "A11")) + CPPUNIT_FAIL("Wrong formula in B2"); + if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A12")) + CPPUNIT_FAIL("Wrong formula in B3"); + + const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0)); + CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC && pFC->IsShared()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength()); + + // Insert cells over A11:B11 to shift to right. This should split the B1:B3 grouping into 3. + m_pDoc->InsertCol(ScRange(0,10,0,1,10,0)); + if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10")) + CPPUNIT_FAIL("Wrong formula in B1"); + if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "C11")) + CPPUNIT_FAIL("Wrong formula in B2"); + if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A12")) + CPPUNIT_FAIL("Wrong formula in B3"); + + pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0)); + CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC && !pFC->IsShared()); + pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0)); + CPPUNIT_ASSERT_MESSAGE("B2 should be a non-shared formula cell.", pFC && !pFC->IsShared()); + pFC = m_pDoc->GetFormulaCell(ScAddress(1,2,0)); + CPPUNIT_ASSERT_MESSAGE("B3 should be a non-shared formula cell.", pFC && !pFC->IsShared()); + + // Delelte cells over A11:B11 to bring it back to the previous state. + m_pDoc->DeleteCol(ScRange(0,10,0,1,10,0)); + + if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10")) + CPPUNIT_FAIL("Wrong formula in B1"); + if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "A11")) + CPPUNIT_FAIL("Wrong formula in B2"); + if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A12")) + CPPUNIT_FAIL("Wrong formula in B3"); + + pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0)); + CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC && pFC->IsShared()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength()); + + m_pDoc->DeleteTab(0); +} + void Test::testSharedFormulasCopyPaste() { m_pDoc->InsertTab(0, "Test"); _______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
