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: */