fdo#88398: Handle group listeners correctly when splitting formula group.

It's basically the same thing we do in ScDocument::DeleteArea(), implemented
in ScDocument::SetValue() and SetString().

Change-Id: Ifcae31aaef0e00ed8659aa5e2b9b8e206dc1a099
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index f36f7fc..1911a95 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -704,6 +704,9 @@ private:
     */
    std::vector<sc::FormulaGroupEntry> GetFormulaGroupEntries();

    void EndListeningIntersectedGroup(
        sc::EndListeningContext& rCxt, SCROW nRow, std::vector<ScAddress>* pGroupPos = NULL );

    void EndListeningIntersectedGroups(
        sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2, std::vector<ScAddress>* pGroupPos = NULL );

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index ddf427d..baf8c9c 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -2210,6 +2210,9 @@ private:

    void SharePooledResources( ScDocument* pSrcDoc );

    void EndListeningIntersectedGroup(
        sc::EndListeningContext& rCxt, const ScAddress& rPos, std::vector<ScAddress>* pGroupPos = NULL );

    void EndListeningIntersectedGroups(
        sc::EndListeningContext& rCxt, const ScRange& rRange, std::vector<ScAddress>* pGroupPos = NULL );

diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 88a0461..3ad7162 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -1128,6 +1128,9 @@ private:
    ScColumn* FetchColumn( SCCOL nCol );
    const ScColumn* FetchColumn( SCCOL nCol ) const;

    void EndListeningIntersectedGroup(
        sc::EndListeningContext& rCxt, SCCOL nCol, SCROW nRow, std::vector<ScAddress>* pGroupPos = NULL );

    void EndListeningIntersectedGroups(
        sc::EndListeningContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
        std::vector<ScAddress>* pGroupPos = NULL );
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index c46634c..b997948 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -1382,6 +1382,40 @@ void ScColumn::EndListeningFormulaCells(
        *pEndRow = aFunc.getEndRow();
}

void ScColumn::EndListeningIntersectedGroup(
    sc::EndListeningContext& rCxt, SCROW nRow, std::vector<ScAddress>* pGroupPos )
{
    if (!ValidRow(nRow))
        return;

    sc::CellStoreType::position_type aPos = maCells.position(nRow);
    sc::CellStoreType::iterator it = aPos.first;
    if (it->type != sc::element_type_formula)
        // Only interested in a formula block.
        return;

    ScFormulaCell* pFC = sc::formula_block::at(*it->data, aPos.second);
    ScFormulaCellGroupRef xGroup = pFC->GetCellGroup();
    if (!xGroup)
        // Not a formula group.
        return;

    // End listening.
    pFC->EndListeningTo(rCxt);

    if (pGroupPos)
    {
        if (!pFC->IsSharedTop())
            // Record the position of the top cell of the group.
            pGroupPos->push_back(xGroup->mpTopCell->aPos);

        SCROW nGrpLastRow = pFC->GetSharedTopRow() + pFC->GetSharedLength() - 1;
        if (nRow < nGrpLastRow)
            // Record the last position of the group.
            pGroupPos->push_back(ScAddress(nCol, nGrpLastRow, nTab));
    }
}

void ScColumn::EndListeningIntersectedGroups(
    sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2, std::vector<ScAddress>* pGroupPos )
{
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 43117b0..ccbaf00e 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -3212,10 +3212,25 @@ void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
bool ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString& rString,
                            ScSetStringParam* pParam )
{
    if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
        return maTabs[nTab]->SetString( nCol, nRow, nTab, rString, pParam );
    else
    ScTable* pTab = FetchTable(nTab);
    if (!pTab)
        return false;

    // In case setting this string affects an existing formula group, record
    // its above and below position for later listening.

    std::vector<ScAddress> aGroupPos;
    sc::EndListeningContext aCxt(*this);
    ScAddress aPos(nCol, nRow, nTab);
    EndListeningIntersectedGroup(aCxt, aPos, &aGroupPos);
    aCxt.purgeEmptyBroadcasters();

    bool bNumFmtSet = pTab->SetString(nCol, nRow, nTab, rString, pParam);

    SetNeedsListeningGroups(aGroupPos);
    StartNeededListeners();

    return bNumFmtSet;
}

bool ScDocument::SetString(
@@ -3291,17 +3306,27 @@ void ScDocument::SetEmptyCell( const ScAddress& rPos )

void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
{
    if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
        if (maTabs[nTab])
            maTabs[nTab]->SetValue( nCol, nRow, rVal );
    SetValue(ScAddress(nCol, nRow, nTab), rVal);
}

void ScDocument::SetValue( const ScAddress& rPos, double fVal )
{
    if (!TableExists(rPos.Tab()))
    ScTable* pTab = FetchTable(rPos.Tab());
    if (!pTab)
        return;

    maTabs[rPos.Tab()]->SetValue(rPos.Col(), rPos.Row(), fVal);
    // In case setting this string affects an existing formula group, record
    // its above and below position for later listening.

    std::vector<ScAddress> aGroupPos;
    sc::EndListeningContext aCxt(*this);
    EndListeningIntersectedGroup(aCxt, rPos, &aGroupPos);
    aCxt.purgeEmptyBroadcasters();

    pTab->SetValue(rPos.Col(), rPos.Row(), fVal);

    SetNeedsListeningGroups(aGroupPos);
    StartNeededListeners();
}

OUString ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx
index 06ab0b9..0a2e3cb 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -361,6 +361,16 @@ bool ScDocument::HasFormulaCell( const ScRange& rRange ) const
    return false;
}

void ScDocument::EndListeningIntersectedGroup(
    sc::EndListeningContext& rCxt, const ScAddress& rPos, std::vector<ScAddress>* pGroupPos )
{
    ScTable* pTab = FetchTable(rPos.Tab());
    if (!pTab)
        return;

    pTab->EndListeningIntersectedGroup(rCxt, rPos.Col(), rPos.Row(), pGroupPos);
}

void ScDocument::EndListeningIntersectedGroups(
    sc::EndListeningContext& rCxt, const ScRange& rRange, std::vector<ScAddress>* pGroupPos )
{
diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx
index 2740735..f940ee5 100644
--- a/sc/source/core/data/table7.cxx
+++ b/sc/source/core/data/table7.cxx
@@ -199,6 +199,15 @@ bool ScTable::HasFormulaCell( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2
    return false;
}

void ScTable::EndListeningIntersectedGroup(
    sc::EndListeningContext& rCxt, SCCOL nCol, SCROW nRow, std::vector<ScAddress>* pGroupPos )
{
    if (!ValidCol(nCol))
        return;

    aCol[nCol].EndListeningIntersectedGroup(rCxt, nRow, pGroupPos);
}

void ScTable::EndListeningIntersectedGroups(
    sc::EndListeningContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
    std::vector<ScAddress>* pGroupPos )