[Libreoffice-commits] core.git: sc/inc sc/qa sc/source

Kohei Yoshida kohei.yoshida at collabora.com
Fri Dec 5 19:46:48 PST 2014


 sc/inc/column.hxx                         |    1 
 sc/inc/columnspanset.hxx                  |    2 
 sc/inc/grouparealistener.hxx              |    2 
 sc/inc/listenerquery.hxx                  |   19 +++
 sc/inc/listenerqueryids.hxx               |    3 
 sc/inc/rangelst.hxx                       |    2 
 sc/inc/types.hxx                          |    8 +
 sc/qa/unit/ucalc.hxx                      |   22 +---
 sc/qa/unit/ucalc_formula.cxx              |    2 
 sc/qa/unit/ucalc_sharedformula.cxx        |    2 
 sc/source/core/data/bcaslot.cxx           |   26 ++++-
 sc/source/core/data/column4.cxx           |   21 ++++
 sc/source/core/data/columnspanset.cxx     |    6 +
 sc/source/core/data/table3.cxx            |  153 +++++++++++++++++++++++++++++-
 sc/source/core/inc/bcaslot.hxx            |    6 -
 sc/source/core/tool/grouparealistener.cxx |   26 +++++
 sc/source/core/tool/listenerquery.cxx     |   25 ++++
 sc/source/core/tool/rangelst.cxx          |    6 +
 18 files changed, 307 insertions(+), 25 deletions(-)

New commits:
commit 68fd7b7adc3021d30460a2c80d6876df239fd490
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Dec 5 22:01:29 2014 -0500

    Fix incorrect adjustment of range references during sort.
    
    ... as a result of the introduction of range-based area listeners.
    
    With this change, the insertRangeData() function for ucalc no longer needs
    the additional bGroupListening flag. All tests pass with group listening
    enabled at all times.
    
    Change-Id: I9b9fb9443c727ff62badbd60ec9cd94094eb5a45

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 7d7e39b..8709935 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -510,6 +510,7 @@ public:
     void BroadcastRecalcOnRefMove();
     void TransferListeners( ScColumn& rDestCol, SCROW nRow1, SCROW nRow2, SCROW nRowDelta );
     void CollectListeners( std::vector<SvtListener*>& rListeners, SCROW nRow1, SCROW nRow2 );
+    void CollectFormulaCells( std::vector<ScFormulaCell*>& rCells, SCROW nRow1, SCROW nRow2 );
 
     void CompileDBFormula( sc::CompileFormulaContext& rCxt );
     void CompileColRowNameFormula( sc::CompileFormulaContext& rCxt );
diff --git a/sc/inc/columnspanset.hxx b/sc/inc/columnspanset.hxx
index 63e8c90..797b425 100644
--- a/sc/inc/columnspanset.hxx
+++ b/sc/inc/columnspanset.hxx
@@ -103,6 +103,8 @@ public:
 
     void executeAction(Action& ac) const;
     void executeColumnAction(ScDocument& rDoc, ColumnAction& ac) const;
+
+    void swap( ColumnSpanSet& r );
 };
 
 /**
diff --git a/sc/inc/grouparealistener.hxx b/sc/inc/grouparealistener.hxx
index 2c6ea50..feb10df 100644
--- a/sc/inc/grouparealistener.hxx
+++ b/sc/inc/grouparealistener.hxx
@@ -39,6 +39,7 @@ public:
     ScRange getListeningRange() const;
 
     virtual void Notify( const SfxHint& rHint ) SAL_OVERRIDE;
+    virtual void Query( QueryBase& rQuery ) const SAL_OVERRIDE;
 
     /**
      * Given the row span of changed cells within a single column, collect all
@@ -52,6 +53,7 @@ public:
      *               this container.
      */
     void collectFormulaCells( SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2, std::vector<ScFormulaCell*>& rCells ) const;
+    void collectFormulaCells( SCROW nRow1, SCROW nRow2, std::vector<ScFormulaCell*>& rCells ) const;
 
     ScAddress getTopCellPos() const;
     const ScRange& getRange() const;
diff --git a/sc/inc/listenerquery.hxx b/sc/inc/listenerquery.hxx
index c0620bb..65fbc0e 100644
--- a/sc/inc/listenerquery.hxx
+++ b/sc/inc/listenerquery.hxx
@@ -15,6 +15,8 @@
 
 #include <boost/unordered_map.hpp>
 
+class ScRangeList;
+
 namespace sc {
 
 /**
@@ -45,6 +47,23 @@ private:
     TabsType maTabs;
 };
 
+class QueryRange : public SvtListener::QueryBase
+{
+    struct Impl;
+    Impl* mpImpl;
+
+    QueryRange( const QueryRange& ); // disabled
+    QueryRange& operator= ( const QueryRange& ); // disabled
+
+public:
+    QueryRange();
+    virtual ~QueryRange();
+
+    void add( const ScRange& rRange );
+
+    void swapRanges( ScRangeList& rRanges );
+};
+
 }
 
 #endif
diff --git a/sc/inc/listenerqueryids.hxx b/sc/inc/listenerqueryids.hxx
index 48f240b..ce8a0e2 100644
--- a/sc/inc/listenerqueryids.hxx
+++ b/sc/inc/listenerqueryids.hxx
@@ -10,7 +10,8 @@
 #ifndef SC_LISTENERQUERYIDS_HXX
 #define SC_LISTENERQUERYIDS_HXX
 
-#define SC_LISTENER_QUERY_FORMULA_GROUP_POS 0
+#define SC_LISTENER_QUERY_FORMULA_GROUP_POS        0
+#define SC_LISTENER_QUERY_FORMULA_GROUP_RANGE      1
 
 #endif
 
diff --git a/sc/inc/rangelst.hxx b/sc/inc/rangelst.hxx
index 4a10eed..062e618 100644
--- a/sc/inc/rangelst.hxx
+++ b/sc/inc/rangelst.hxx
@@ -91,6 +91,8 @@ public:
     const ScRange*  back() const;
     void            push_back(ScRange* p);
 
+    void swap( ScRangeList& r );
+
 private:
     ::std::vector<ScRange*> maRanges;
     SCROW           mnMaxRowUsed;
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index 039010a..77934f0 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -101,10 +101,18 @@ enum AreaOverlapType
 {
     AreaInside,
     AreaPartialOverlap,
+    AreaInsideOrOverlap,
     OneRowInsideArea,
     OneColumnInsideArea
 };
 
+enum ListenerGroupType
+{
+    ListenerSingle,
+    ListenerGroup,
+    ListenerBoth
+};
+
 enum StartListeningType
 {
     ConvertToGroupListening,
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index cb2f839..d5fd983 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -59,13 +59,8 @@ public:
 
     template<size_t _Size>
     static ScRange insertRangeData(
-        ScDocument* pDoc, const ScAddress& rPos, const char* aData[][_Size], size_t nRowCount,
-        bool bGroupListening = false )
+        ScDocument* pDoc, const ScAddress& rPos, const char* aData[][_Size], size_t nRowCount )
     {
-        // TODO : Ideally bGroupListening should be always true for all tests.
-        // Eventually we want to drop this parameter once all tests pass with
-        // group listening turned on.
-
         ScRange aRange(rPos);
         aRange.aEnd.SetCol(rPos.Col()+_Size-1);
         aRange.aEnd.SetRow(rPos.Row()+nRowCount-1);
@@ -82,19 +77,14 @@ public:
                 SCCOL nCol = i + rPos.Col();
                 SCROW nRow = j + rPos.Row();
                 OUString aStr(aData[j][i], strlen(aData[j][i]), RTL_TEXTENCODING_UTF8);
-                if (bGroupListening)
-                {
-                    ScSetStringParam aParam; // Leave default.
-                    aParam.meStartListening = sc::NoListening;
-                    pDoc->SetString(nCol, nRow, rPos.Tab(), aStr, &aParam);
-                }
-                else
-                    pDoc->SetString(nCol, nRow, rPos.Tab(), aStr, NULL);
+
+                ScSetStringParam aParam; // Leave default.
+                aParam.meStartListening = sc::NoListening;
+                pDoc->SetString(nCol, nRow, rPos.Tab(), aStr, &aParam);
             }
         }
 
-        if (bGroupListening)
-            pDoc->StartAllListeners(aRange);
+        pDoc->StartAllListeners(aRange);
 
         printRange(pDoc, aRange, "Range data content");
         return aRange;
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index 56f5f8c..c66194c 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -4274,7 +4274,7 @@ void Test::testFormulaDepTracking3()
         { "5", "6", "=SUM(A3:B3)", 0 },
     };
 
-    insertRangeData(m_pDoc, ScAddress(0,0,0), pData, SAL_N_ELEMENTS(pData), true);
+    insertRangeData(m_pDoc, ScAddress(0,0,0), pData, SAL_N_ELEMENTS(pData));
 
     // Check the initial formula results.
     CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(2,0,0)));
diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx
index 8116123..2ef7d88 100644
--- a/sc/qa/unit/ucalc_sharedformula.cxx
+++ b/sc/qa/unit/ucalc_sharedformula.cxx
@@ -596,7 +596,7 @@ void Test::testSharedFormulasRefUpdateRangeDeleteRow()
         { "7", "8", "=SUM(A5:B5)" }
     };
 
-    insertRangeData(m_pDoc, ScAddress(0,0,0), aData, SAL_N_ELEMENTS(aData), true);
+    insertRangeData(m_pDoc, ScAddress(0,0,0), aData, SAL_N_ELEMENTS(aData));
 
     // Check initial formula values.
     CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(2,0,0)));
diff --git a/sc/source/core/data/bcaslot.cxx b/sc/source/core/data/bcaslot.cxx
index 31b665c..12aeee7 100644
--- a/sc/source/core/data/bcaslot.cxx
+++ b/sc/source/core/data/bcaslot.cxx
@@ -587,7 +587,8 @@ void ScBroadcastAreaSlot::EraseArea( ScBroadcastAreas::iterator& rIter )
 }
 
 void ScBroadcastAreaSlot::GetAllListeners(
-    const ScRange& rRange, std::vector<sc::AreaListener>& rListeners, sc::AreaOverlapType eType )
+    const ScRange& rRange, std::vector<sc::AreaListener>& rListeners,
+    sc::AreaOverlapType eType, sc::ListenerGroupType eGroup )
 {
     for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
             aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
@@ -597,6 +598,20 @@ void ScBroadcastAreaSlot::GetAllListeners(
 
         ScBroadcastArea* pArea = (*aIter).mpArea;
         const ScRange& rAreaRange = pArea->GetRange();
+        switch (eGroup)
+        {
+            case sc::ListenerSingle:
+                if (pArea->IsGroupListening())
+                    continue;
+            break;
+            case sc::ListenerGroup:
+                if (!pArea->IsGroupListening())
+                    continue;
+            break;
+            case sc::ListenerBoth:
+            default:
+                ;
+        }
 
         switch (eType)
         {
@@ -610,6 +625,11 @@ void ScBroadcastAreaSlot::GetAllListeners(
                     // The range needs to be only partially overlapping.
                     continue;
                 break;
+            case sc::AreaInsideOrOverlap:
+                if (!rRange.Intersects(rAreaRange))
+                    // The range needs to be partially overlapping or fully inside.
+                    continue;
+                break;
             case sc::OneRowInsideArea:
                 if (rAreaRange.aStart.Row() != rAreaRange.aEnd.Row() || !rRange.In(rAreaRange))
                     // The range needs to be one single row and fully inside
@@ -1256,7 +1276,7 @@ void ScBroadcastAreaSlotMachine::FinallyEraseAreas( ScBroadcastAreaSlot* pSlot )
 }
 
 std::vector<sc::AreaListener> ScBroadcastAreaSlotMachine::GetAllListeners(
-    const ScRange& rRange, sc::AreaOverlapType eType )
+    const ScRange& rRange, sc::AreaOverlapType eType, sc::ListenerGroupType eGroup )
 {
     std::vector<sc::AreaListener> aRet;
 
@@ -1274,7 +1294,7 @@ std::vector<sc::AreaListener> ScBroadcastAreaSlotMachine::GetAllListeners(
         {
             ScBroadcastAreaSlot* p = *pp;
             if (p)
-                p->GetAllListeners(rRange, aRet, eType);
+                p->GetAllListeners(rRange, aRet, eType, eGroup);
             ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
         }
     }
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index ab804dd..2291d38 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -1107,6 +1107,18 @@ public:
     }
 };
 
+class FormulaCellCollector
+{
+    std::vector<ScFormulaCell*>& mrCells;
+public:
+    FormulaCellCollector( std::vector<ScFormulaCell*>& rCells ) : mrCells(rCells) {}
+
+    void operator() ( size_t /*nRow*/, ScFormulaCell* p )
+    {
+        mrCells.push_back(p);
+    }
+};
+
 }
 
 void ScColumn::CollectListeners( std::vector<SvtListener*>& rListeners, SCROW nRow1, SCROW nRow2 )
@@ -1118,6 +1130,15 @@ void ScColumn::CollectListeners( std::vector<SvtListener*>& rListeners, SCROW nR
     sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc);
 }
 
+void ScColumn::CollectFormulaCells( std::vector<ScFormulaCell*>& rCells, SCROW nRow1, SCROW nRow2 )
+{
+    if (nRow2 < nRow1 || !ValidRow(nRow1) || !ValidRow(nRow2))
+        return;
+
+    FormulaCellCollector aFunc(rCells);
+    sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
+}
+
 namespace {
 
 struct FindAnyFormula
diff --git a/sc/source/core/data/columnspanset.cxx b/sc/source/core/data/columnspanset.cxx
index 6132906..25f6b5b 100644
--- a/sc/source/core/data/columnspanset.cxx
+++ b/sc/source/core/data/columnspanset.cxx
@@ -227,6 +227,12 @@ void ColumnSpanSet::executeColumnAction(ScDocument& rDoc, ColumnAction& ac) cons
     }
 }
 
+void ColumnSpanSet::swap( ColumnSpanSet& r )
+{
+    maDoc.swap(r.maDoc);
+    std::swap(mbInit, r.mbInit);
+}
+
 namespace {
 
 class Scanner
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index a715194..9981356 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -824,6 +824,70 @@ void fillSortedColumnArray(
     rRowFlags.swap(aRowFlags);
 }
 
+void expandRowRange( ScRange& rRange, SCROW nTop, SCROW nBottom )
+{
+    if (nTop < rRange.aStart.Row())
+        rRange.aStart.SetRow(nTop);
+
+    if (rRange.aEnd.Row() < nBottom)
+        rRange.aEnd.SetRow(nBottom);
+}
+
+class FormulaCellCollectAction : public sc::ColumnSpanSet::ColumnAction
+{
+    std::vector<ScFormulaCell*>& mrCells;
+    ScColumn* mpCol;
+
+public:
+    FormulaCellCollectAction( std::vector<ScFormulaCell*>& rCells ) :
+        mrCells(rCells), mpCol(NULL) {}
+
+    virtual void startColumn( ScColumn* pCol ) SAL_OVERRIDE
+    {
+        mpCol = pCol;
+    }
+
+    virtual void execute( SCROW nRow1, SCROW nRow2, bool bVal ) SAL_OVERRIDE
+    {
+        assert(mpCol);
+
+        if (!bVal)
+            return;
+
+        mpCol->CollectFormulaCells(mrCells, nRow1, nRow2);
+    }
+};
+
+class ListenerStartAction : public sc::ColumnSpanSet::ColumnAction
+{
+    ScColumn* mpCol;
+
+    boost::shared_ptr<sc::ColumnBlockPositionSet> mpPosSet;
+    sc::StartListeningContext maStartCxt;
+    sc::EndListeningContext maEndCxt;
+
+public:
+    ListenerStartAction( ScDocument& rDoc ) :
+        mpPosSet(new sc::ColumnBlockPositionSet(rDoc)),
+        maStartCxt(rDoc, mpPosSet),
+        maEndCxt(rDoc, mpPosSet) {}
+
+    virtual void startColumn( ScColumn* pCol ) SAL_OVERRIDE
+    {
+        mpCol = pCol;
+    }
+
+    virtual void execute( SCROW nRow1, SCROW nRow2, bool bVal ) SAL_OVERRIDE
+    {
+        assert(mpCol);
+
+        if (!bVal)
+            return;
+
+        mpCol->StartListeningFormulaCells(maStartCxt, maEndCxt, nRow1, nRow2);
+    }
+};
+
 }
 
 void ScTable::SortReorderByColumn(
@@ -1121,6 +1185,78 @@ void ScTable::SortReorderByRowRefUpdate(
     SCROW nRow1 = pArray->GetStart();
     SCROW nRow2 = pArray->GetLast();
 
+    ScRange aMoveRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab);
+    sc::ColumnSpanSet aGrpListenerRanges(false);
+
+    {
+        // Get the range of formula group listeners within sorted range (if any).
+        sc::QueryRange aQuery;
+
+        ScBroadcastAreaSlotMachine* pBASM = pDocument->GetBASM();
+        std::vector<sc::AreaListener> aGrpListeners =
+            pBASM->GetAllListeners(
+                aMoveRange, sc::AreaInsideOrOverlap, sc::ListenerGroup);
+
+        {
+            std::vector<sc::AreaListener>::iterator it = aGrpListeners.begin(), itEnd = aGrpListeners.end();
+            for (; it != itEnd; ++it)
+            {
+                assert(it->mbGroupListening);
+                SvtListener* pGrpLis = it->mpListener;
+                pGrpLis->Query(aQuery);
+                pDocument->EndListeningArea(it->maArea, it->mbGroupListening, pGrpLis);
+            }
+        }
+
+        ScRangeList aTmp;
+        aQuery.swapRanges(aTmp);
+
+        // If the range is within the sorted range, we need to expand its rows
+        // to the top and bottom of the sorted range, since the formula cells
+        // could be anywhere in the sorted range after reordering.
+        for (size_t i = 0, n = aTmp.size(); i < n; ++i)
+        {
+            ScRange aRange = *aTmp[i];
+            if (!aMoveRange.Intersects(aRange))
+            {
+                // Doesn't overlap with the sorted range at all.
+                aGrpListenerRanges.set(aRange, true);
+                continue;
+            }
+
+            if (aMoveRange.aStart.Col() <= aRange.aStart.Col() && aRange.aEnd.Col() <= aMoveRange.aEnd.Col())
+            {
+                // Its column range is within the column range of the sorted range.
+                expandRowRange(aRange, aMoveRange.aStart.Row(), aMoveRange.aEnd.Row());
+                aGrpListenerRanges.set(aRange, true);
+                continue;
+            }
+
+            // It intersects with the sorted range, but its column range is
+            // not within the column range of the sorted range.  Split it into
+            // 2 ranges.
+            ScRange aR1 = aRange;
+            ScRange aR2 = aRange;
+            if (aRange.aStart.Col() < aMoveRange.aStart.Col())
+            {
+                // Left half is outside the sorted range while the right half is inside.
+                aR1.aEnd.SetCol(aMoveRange.aStart.Col()-1);
+                aR2.aStart.SetCol(aMoveRange.aStart.Col());
+                expandRowRange(aR2, aMoveRange.aStart.Row(), aMoveRange.aEnd.Row());
+            }
+            else
+            {
+                // Left half is inside the sorted range while the right half is outside.
+                aR1.aEnd.SetCol(aMoveRange.aEnd.Col()-1);
+                aR2.aStart.SetCol(aMoveRange.aEnd.Col());
+                expandRowRange(aR1, aMoveRange.aStart.Row(), aMoveRange.aEnd.Row());
+            }
+
+            aGrpListenerRanges.set(aR1, true);
+            aGrpListenerRanges.set(aR2, true);
+        }
+    }
+
     // Split formula groups at the sort range boundaries (if applicable).
     std::vector<SCROW> aRowBounds;
     aRowBounds.reserve(2);
@@ -1237,7 +1373,6 @@ void ScTable::SortReorderByRowRefUpdate(
 
     // Get all area listeners that listen on one row within the range and end
     // their listening.
-    ScRange aMoveRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab);
     std::vector<sc::AreaListener> aAreaListeners = pDocument->GetBASM()->GetAllListeners(
             aMoveRange, sc::OneRowInsideArea);
     {
@@ -1249,6 +1384,16 @@ void ScTable::SortReorderByRowRefUpdate(
         }
     }
 
+    {
+        // Get all formula cells from the former group area listener ranges.
+
+        std::vector<ScFormulaCell*> aFCells;
+        FormulaCellCollectAction aAction(aFCells);
+        aGrpListenerRanges.executeColumnAction(*pDocument, aAction);
+
+        std::copy(aFCells.begin(), aFCells.end(), std::back_inserter(aListeners));
+    }
+
     // Remove any duplicate listener entries.  We must ensure that we notify
     // each unique listener only once.
     std::sort(aListeners.begin(), aListeners.end());
@@ -1306,6 +1451,12 @@ void ScTable::SortReorderByRowRefUpdate(
     // Re-group columns in the sorted range too.
     for (SCCOL i = nCol1; i <= nCol2; ++i)
         aCol[i].RegroupFormulaCells();
+
+    {
+        // Re-start area listeners on the old group listener ranges.
+        ListenerStartAction aAction(*pDocument);
+        aGrpListenerRanges.executeColumnAction(*pDocument, aAction);
+    }
 }
 
 short ScTable::CompareCell(
diff --git a/sc/source/core/inc/bcaslot.hxx b/sc/source/core/inc/bcaslot.hxx
index 7eea136..a566440 100644
--- a/sc/source/core/inc/bcaslot.hxx
+++ b/sc/source/core/inc/bcaslot.hxx
@@ -239,7 +239,8 @@ public:
     void                EraseArea( ScBroadcastAreas::iterator& rIter );
 
     void GetAllListeners(
-        const ScRange& rRange, std::vector<sc::AreaListener>& rListeners, sc::AreaOverlapType eType );
+        const ScRange& rRange, std::vector<sc::AreaListener>& rListeners,
+        sc::AreaOverlapType eType, sc::ListenerGroupType eGroup );
 
 #if DEBUG_AREA_BROADCASTER
     void Dump() const;
@@ -348,7 +349,8 @@ public:
     void                FinallyEraseAreas( ScBroadcastAreaSlot* pSlot );
 
     std::vector<sc::AreaListener> GetAllListeners(
-        const ScRange& rRange, sc::AreaOverlapType eType );
+        const ScRange& rRange, sc::AreaOverlapType eType,
+        sc::ListenerGroupType eGroup = sc::ListenerBoth );
 
 #if DEBUG_AREA_BROADCASTER
     void Dump() const;
diff --git a/sc/source/core/tool/grouparealistener.cxx b/sc/source/core/tool/grouparealistener.cxx
index 4a13398..2249732 100644
--- a/sc/source/core/tool/grouparealistener.cxx
+++ b/sc/source/core/tool/grouparealistener.cxx
@@ -13,6 +13,8 @@
 #include <bulkdatahint.hxx>
 #include <columnspanset.hxx>
 #include <column.hxx>
+#include <listenerquery.hxx>
+#include <listenerqueryids.hxx>
 
 namespace sc {
 
@@ -108,6 +110,24 @@ void FormulaGroupAreaListener::Notify( const SfxHint& rHint )
     }
 }
 
+void FormulaGroupAreaListener::Query( QueryBase& rQuery ) const
+{
+    switch (rQuery.getId())
+    {
+        case SC_LISTENER_QUERY_FORMULA_GROUP_RANGE:
+        {
+            ScFormulaCell* pTop = *mppTopCell;
+            ScRange aRange(pTop->aPos);
+            aRange.aEnd.IncRow(mnGroupLen-1);
+            QueryRange& rQR = static_cast<QueryRange&>(rQuery);
+            rQR.add(aRange);
+        }
+        break;
+        default:
+            ;
+    }
+}
+
 void FormulaGroupAreaListener::notifyBulkChange( const BulkDataHint& rHint )
 {
     const ColumnSpanSet* pSpans = rHint.getSpans();
@@ -138,6 +158,12 @@ void FormulaGroupAreaListener::collectFormulaCells(
         // Outside the column range.
         return;
 
+    collectFormulaCells(nRow1, nRow2, rCells);
+}
+
+void FormulaGroupAreaListener::collectFormulaCells(
+    SCROW nRow1, SCROW nRow2, std::vector<ScFormulaCell*>& rCells ) const
+{
     ScFormulaCell** pp = mppTopCell;
     ScFormulaCell** ppEnd = pp + mnGroupLen;
 
diff --git a/sc/source/core/tool/listenerquery.cxx b/sc/source/core/tool/listenerquery.cxx
index bf9d38f..faa3bbb 100644
--- a/sc/source/core/tool/listenerquery.cxx
+++ b/sc/source/core/tool/listenerquery.cxx
@@ -10,6 +10,7 @@
 #include <listenerquery.hxx>
 #include <listenerqueryids.hxx>
 #include <address.hxx>
+#include <rangelst.hxx>
 
 namespace sc {
 
@@ -67,6 +68,30 @@ const RefQueryFormulaGroup::TabsType& RefQueryFormulaGroup::getAllPositions() co
     return maTabs;
 }
 
+struct QueryRange::Impl
+{
+    ScRangeList maRanges;
+};
+
+QueryRange::QueryRange() :
+    SvtListener::QueryBase(SC_LISTENER_QUERY_FORMULA_GROUP_RANGE),
+    mpImpl(new Impl) {}
+
+QueryRange::~QueryRange()
+{
+    delete mpImpl;
+}
+
+void QueryRange::add( const ScRange& rRange )
+{
+    mpImpl->maRanges.Join(rRange);
+}
+
+void QueryRange::swapRanges( ScRangeList& rRanges )
+{
+    mpImpl->maRanges.swap(rRanges);
+}
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/tool/rangelst.cxx b/sc/source/core/tool/rangelst.cxx
index 7cf7bcd..788ef96 100644
--- a/sc/source/core/tool/rangelst.cxx
+++ b/sc/source/core/tool/rangelst.cxx
@@ -1170,6 +1170,12 @@ void ScRangeList::push_back(ScRange* p)
         mnMaxRowUsed = p->aEnd.Row();
 }
 
+void ScRangeList::swap( ScRangeList& r )
+{
+    maRanges.swap(r.maRanges);
+    std::swap(mnMaxRowUsed, r.mnMaxRowUsed);
+}
+
 ScAddress ScRangeList::GetTopLeftCorner() const
 {
     if(empty())


More information about the Libreoffice-commits mailing list