More on regrouping of formula cells.
Change-Id: Icd3403e759841dce351c932ea8915ba9819e5a29
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 62e1ddf..6bbfb6a 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -505,6 +505,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 095acce4..91b3b75 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);
}
};
@@ -2647,14 +2679,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)
@@ -2665,10 +2705,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;
}
@@ -2743,17 +2787,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();
}
@@ -2773,10 +2815,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)
@@ -2919,12 +2958,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 98081356..a651fa6 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1530,10 +1530,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 3b71a19..8a54f50 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.
@@ -740,7 +772,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)
{
@@ -760,9 +792,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);
@@ -2880,15 +2912,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: */