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

Kohei Yoshida kohei.yoshida at collabora.com
Sat Mar 15 08:50:08 PDT 2014


 sc/inc/listenercontext.hxx              |   12 ++
 sc/qa/unit/ucalc_formula.cxx            |    2 
 sc/source/core/data/column.cxx          |  134 +++++++++++++++++++++++++-------
 sc/source/core/data/listenercontext.cxx |   44 ++++------
 4 files changed, 135 insertions(+), 57 deletions(-)

New commits:
commit 8b368d808e90561a9b34658e6b811a8fad83088f
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Sat Mar 15 11:14:24 2014 -0400

    Unregister all listeners first then re-register them.
    
    It's safe this way in case we are transferring them within the same
    column.  Any empty broadcasters are checked and purged at the end.
    
    Change-Id: Ib2d46e616cde4923720ad21cb101d3a97dc8c5d9

diff --git a/sc/inc/listenercontext.hxx b/sc/inc/listenercontext.hxx
index c0260ef..501f1d2 100644
--- a/sc/inc/listenercontext.hxx
+++ b/sc/inc/listenercontext.hxx
@@ -58,6 +58,18 @@ public:
     void purgeEmptyBroadcasters();
 };
 
+class PurgeListenerAction : public ColumnSpanSet::Action, boost::noncopyable
+{
+    ScDocument& mrDoc;
+    boost::scoped_ptr<ColumnBlockPosition> mpBlockPos;
+
+public:
+    PurgeListenerAction( ScDocument& rDoc );
+
+    virtual void startColumn( SCTAB nTab, SCCOL nCol );
+    virtual void execute( const ScAddress& rPos, SCROW nLength, bool bVal );
+};
+
 }
 
 #endif
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 8b6aa9d..9694790 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -3478,27 +3478,113 @@ namespace {
 
 class TransferListenersHandler
 {
-    sc::BroadcasterStoreType& mrDestBroadcasters;
-    sc::BroadcasterStoreType::iterator miDestPos;
-    SCROW mnRowDelta; /// Add this to the source row to get the destination row.
-
 public:
-    TransferListenersHandler( sc::BroadcasterStoreType& rDestBrd, SCROW nRowDelta ) :
-        mrDestBroadcasters(rDestBrd), miDestPos(rDestBrd.begin()), mnRowDelta(nRowDelta) {}
+    typedef std::vector<SvtListener*> ListenersType;
+    struct Entry
+    {
+        size_t mnRow;
+        ListenersType maListeners;
+    };
+    typedef std::vector<Entry> ListenerListType;
+
+    void swapListeners( std::vector<Entry>& rListenerList )
+    {
+        maListenerList.swap(rListenerList);
+    }
 
     void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster )
     {
         assert(pBroadcaster);
 
-        SvtBroadcaster::ListenersType& rLis = pBroadcaster->GetAllListeners();
-        if (rLis.empty())
+        // It's important to make a copy here.
+        SvtBroadcaster::ListenersType aLis = pBroadcaster->GetAllListeners();
+        if (aLis.empty())
             // No listeners to transfer.
             return;
 
-        SCROW nDestRow = nRow + mnRowDelta;
+        Entry aEntry;
+        aEntry.mnRow = nRow;
+
+        SvtBroadcaster::ListenersType::iterator it = aLis.begin(), itEnd = aLis.end();
+        for (; it != itEnd; ++it)
+        {
+            SvtListener* pLis = *it;
+            pLis->EndListening(*pBroadcaster);
+            aEntry.maListeners.push_back(pLis);
+        }
+
+        maListenerList.push_back(aEntry);
+
+        // At this point, the source broadcaster should have no more listeners.
+        assert(!pBroadcaster->HasListeners());
+    }
+
+private:
+    ListenerListType maListenerList;
+};
+
+class RemoveEmptyBroadcasterHandler
+{
+    sc::ColumnSpanSet maSet;
+    ScDocument& mrDoc;
+    SCCOL mnCol;
+    SCTAB mnTab;
+
+public:
+    RemoveEmptyBroadcasterHandler( ScDocument& rDoc, SCCOL nCol, SCTAB nTab ) :
+        maSet(false), mrDoc(rDoc), mnCol(nCol), mnTab(nTab) {}
+
+    void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster )
+    {
+        if (!pBroadcaster->HasListeners())
+            maSet.set(mnTab, mnCol, nRow, true);
+    }
+
+    void purge()
+    {
+        sc::PurgeListenerAction aAction(mrDoc);
+        maSet.executeAction(aAction);
+    }
+};
+
+}
+
+void ScColumn::TransferListeners(
+    ScColumn& rDestCol, SCROW nRow1, SCROW nRow2, SCROW nRowDelta )
+{
+    if (nRow2 < nRow1)
+        return;
+
+    if (!ValidRow(nRow1) || !ValidRow(nRow2))
+        return;
 
-        sc::BroadcasterStoreType::position_type aPos = mrDestBroadcasters.position(miDestPos, nDestRow);
-        miDestPos = aPos.first;
+    if (nRowDelta <= 0 && !ValidRow(nRow1+nRowDelta))
+        return;
+
+    if (nRowDelta >= 0 && !ValidRow(nRow2+nRowDelta))
+        return;
+
+    // Collect all listeners from the source broadcasters. The listeners will
+    // be removed from their broadcasters as they are collected.
+    TransferListenersHandler aFunc;
+    sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc);
+
+    TransferListenersHandler::ListenerListType aListenerList;
+    aFunc.swapListeners(aListenerList);
+
+    // Re-register listeners with their destination broadcasters.
+    sc::BroadcasterStoreType::iterator itDestPos = rDestCol.maBroadcasters.begin();
+    TransferListenersHandler::ListenerListType::iterator it = aListenerList.begin(), itEnd = aListenerList.end();
+    for (; it != itEnd; ++it)
+    {
+        TransferListenersHandler::Entry& rEntry = *it;
+
+        SCROW nDestRow = rEntry.mnRow + nRowDelta;
+
+        sc::BroadcasterStoreType::position_type aPos =
+            rDestCol.maBroadcasters.position(itDestPos, nDestRow);
+
+        itDestPos = aPos.first;
         SvtBroadcaster* pDestBrd = NULL;
         if (aPos.first->type == sc::element_type_broadcaster)
         {
@@ -3510,32 +3596,22 @@ public:
             // No existing broadcaster. Create a new one.
             assert(aPos.first->type == sc::element_type_empty);
             pDestBrd = new SvtBroadcaster;
-            miDestPos = mrDestBroadcasters.set(miDestPos, nDestRow, pDestBrd);
+            itDestPos = rDestCol.maBroadcasters.set(itDestPos, nDestRow, pDestBrd);
         }
 
         // Transfer all listeners from the source to the destination.
-        SvtBroadcaster::ListenersType::iterator it = rLis.begin(), itEnd = rLis.end();
-        for (; it != itEnd; ++it)
+        SvtBroadcaster::ListenersType::iterator it2 = rEntry.maListeners.begin(), it2End = rEntry.maListeners.end();
+        for (; it2 != it2End; ++it2)
         {
-            SvtListener* pLis = *it;
-            pLis->EndListening(*pBroadcaster);
+            SvtListener* pLis = *it2;
             pLis->StartListening(*pDestBrd);
         }
-
-        // At this point, the source broadcaster should have no more listeners.
-        assert(!pBroadcaster->HasListeners());
     }
-};
-
-}
-
-void ScColumn::TransferListeners(
-    ScColumn& rDestCol, SCROW nRow1, SCROW nRow2, SCROW nRowDelta )
-{
-    TransferListenersHandler aFunc(rDestCol.maBroadcasters, nRowDelta);
-    sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc);
 
-    maBroadcasters.set_empty(nRow1, nRow2); // Remove all source broadcaster.
+    // Remove any broadcasters that have no listeners.
+    RemoveEmptyBroadcasterHandler aFuncRemoveEmpty(*pDocument, nCol, nTab);
+    sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFuncRemoveEmpty);
+    aFuncRemoveEmpty.purge();
 }
 
 void ScColumn::CalcAll()
diff --git a/sc/source/core/data/listenercontext.cxx b/sc/source/core/data/listenercontext.cxx
index 3dfe5ed..add75a2 100644
--- a/sc/source/core/data/listenercontext.cxx
+++ b/sc/source/core/data/listenercontext.cxx
@@ -13,32 +13,6 @@
 
 namespace sc {
 
-namespace {
-
-class PurgeAction : public ColumnSpanSet::Action
-{
-    ScDocument& mrDoc;
-    sc::ColumnBlockPosition maBlockPos;
-
-public:
-    PurgeAction(ScDocument& rDoc) : mrDoc(rDoc) {}
-
-    virtual void startColumn(SCTAB nTab, SCCOL nCol)
-    {
-        mrDoc.InitColumnBlockPosition(maBlockPos, nTab, nCol);
-    }
-
-    virtual void execute(const ScAddress& rPos, SCROW nLength, bool bVal)
-    {
-        if (bVal)
-        {
-            mrDoc.DeleteBroadcasters(maBlockPos, rPos, nLength);
-        }
-    };
-};
-
-}
-
 StartListeningContext::StartListeningContext(ScDocument& rDoc) :
     mrDoc(rDoc), mpSet(new ColumnBlockPositionSet(rDoc)) {}
 
@@ -92,10 +66,26 @@ void EndListeningContext::addEmptyBroadcasterPosition(SCTAB nTab, SCCOL nCol, SC
 
 void EndListeningContext::purgeEmptyBroadcasters()
 {
-    PurgeAction aAction(mrDoc);
+    PurgeListenerAction aAction(mrDoc);
     maSet.executeAction(aAction);
 }
 
+PurgeListenerAction::PurgeListenerAction(ScDocument& rDoc) :
+    mrDoc(rDoc), mpBlockPos(new ColumnBlockPosition) {}
+
+void PurgeListenerAction::startColumn( SCTAB nTab, SCCOL nCol )
+{
+    mrDoc.InitColumnBlockPosition(*mpBlockPos, nTab, nCol);
+}
+
+void PurgeListenerAction::execute( const ScAddress& rPos, SCROW nLength, bool bVal )
+{
+    if (bVal)
+    {
+        mrDoc.DeleteBroadcasters(*mpBlockPos, rPos, nLength);
+    }
+};
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 3ced80133a171bc528ed4600f1d00daadfdbb21b
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Sat Mar 15 11:14:02 2014 -0400

    The test is incorrect.
    
    Change-Id: I4e4b788f34e01f926d60d97515de4191d7346d5e

diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index f939698..a03ba89 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -1677,7 +1677,7 @@ void Test::testFormulaRefUpdateMoveUndo()
     m_pDoc->SetValue(ScAddress(0,0,0), 20);
 
     CPPUNIT_ASSERT_EQUAL(20.0, m_pDoc->GetValue(ScAddress(0,5,0)));
-    CPPUNIT_ASSERT_EQUAL( 6.0, m_pDoc->GetValue(ScAddress(0,6,0)));
+    CPPUNIT_ASSERT_EQUAL(25.0, m_pDoc->GetValue(ScAddress(0,6,0)));
     CPPUNIT_ASSERT_EQUAL(27.0, m_pDoc->GetValue(ScAddress(0,7,0)));
 
     CPPUNIT_ASSERT_EQUAL(22.0, m_pDoc->GetValue(ScAddress(0,9,0)));


More information about the Libreoffice-commits mailing list