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

Bjoern Michaelsen bjoern.michaelsen at libreoffice.org
Sun Mar 11 22:32:35 UTC 2018


 sw/inc/calbck.hxx              |   56 ++++++++++++++++++--
 sw/qa/core/uwriter.cxx         |  112 ++++++++++++++++++++++++++---------------
 sw/source/core/attr/calbck.cxx |   70 +++++++++++++++++++++----
 3 files changed, 180 insertions(+), 58 deletions(-)

New commits:
commit 5c04518c2d4b289289d551e22709e22702563d50
Author: Bjoern Michaelsen <bjoern.michaelsen at libreoffice.org>
Date:   Wed Jan 31 01:13:53 2018 +0100

    introduce sw::WriterMultiListener
    
    - it can handle multple sources to listen to: this should make SwDepend
      (always been a hack) soon obsolete
    - also add a unittest for it
    - WriterMultiListener notifies via hints about reregistering, so help
      migrating away from these crazy static_cast<>(GetRegisteredIn())
    - fix expected<->actual asserts in uwriter.cxx
    
    Change-Id: I8c70826d1a8be5c8097d81304f0df42bb7319cd4
    Reviewed-on: https://gerrit.libreoffice.org/49565
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Björn Michaelsen <bjoern.michaelsen at libreoffice.org>

diff --git a/sw/inc/calbck.hxx b/sw/inc/calbck.hxx
index d42f1e95dbd0..7b903c2c9638 100644
--- a/sw/inc/calbck.hxx
+++ b/sw/inc/calbck.hxx
@@ -26,6 +26,8 @@
 #include "ring.hxx"
 #include "hintids.hxx"
 #include <type_traits>
+#include <list>
+#include <memory>
 
 
 class SwModify;
@@ -69,6 +71,12 @@ namespace sw
         const SfxPoolItem* m_pOld;
         const SfxPoolItem* m_pNew;
     };
+    struct SW_DLLPUBLIC ModifyChangedHint final: SfxHint
+    {
+        ModifyChangedHint(const SwModify* pNew) : m_pNew(pNew) {};
+        virtual ~ModifyChangedHint() override;
+        const SwModify* m_pNew;
+    };
     /// refactoring out the some of the more sane SwClient functionality
     class SW_DLLPUBLIC WriterListener
     {
@@ -104,6 +112,7 @@ class SW_DLLPUBLIC SwClient : public ::sw::WriterListener
 protected:
     // single argument ctors shall be explicit.
     inline explicit SwClient( SwModify* pToRegisterIn );
+    SwClient(SwClient&&);
 
     // write access to pRegisteredIn shall be granted only to the object itself (protected access)
     SwModify* GetRegisteredInNonConst() const { return m_pRegisteredIn; }
@@ -122,7 +131,7 @@ public:
 
     // in case an SwModify object is destroyed that itself is registered in another SwModify,
     // its SwClient objects can decide to get registered to the latter instead by calling this method
-    void CheckRegistration( const SfxPoolItem *pOldValue );
+    std::unique_ptr<sw::ModifyChangedHint> CheckRegistration( const SfxPoolItem* pOldValue );
 
     // controlled access to Modify method
     // mba: this is still considered a hack and it should be fixed; the name makes grep-ing easier
@@ -212,6 +221,12 @@ class SW_DLLPUBLIC SwDepend final : public SwClient
 
 public:
     SwDepend(SwClient *pTellHim, SwModify *pDepend) : SwClient(pDepend), m_pToTell(pTellHim) {}
+    SwDepend(SwDepend&) = delete;
+    SwDepend(SwDepend&& o)
+        : SwClient(std::move(o)), m_pToTell(o.m_pToTell)
+    {
+        o.m_pToTell = nullptr;
+    }
 
     SwClient* GetToTell() { return m_pToTell; }
 
@@ -221,17 +236,46 @@ public:
 private:
     virtual void Modify( const SfxPoolItem* pOldValue, const SfxPoolItem *pNewValue ) override
     {
-        if( pNewValue && pNewValue->Which() == RES_OBJECTDYING )
-            CheckRegistration(pOldValue);
-        else if( m_pToTell )
-            m_pToTell->ModifyNotification(pOldValue, pNewValue);
+        SwClientNotify(*GetRegisteredIn(), sw::LegacyModifyHint(pOldValue, pNewValue));
     }
     virtual void SwClientNotify( const SwModify& rModify, const SfxHint& rHint ) override
-        { if(m_pToTell) m_pToTell->SwClientNotifyCall(rModify, rHint); }
+    {
+        if (auto pLegacyHint = dynamic_cast<const sw::LegacyModifyHint*>(&rHint))
+        {
+            if( pLegacyHint->m_pNew && pLegacyHint->m_pNew->Which() == RES_OBJECTDYING )
+            {
+                auto pModifyChanged = CheckRegistration(pLegacyHint->m_pOld);
+                if(pModifyChanged)
+                    m_pToTell->SwClientNotify(rModify, *pModifyChanged);
+            }
+            else if( m_pToTell )
+                m_pToTell->ModifyNotification(pLegacyHint->m_pOld, pLegacyHint->m_pNew);
+        }
+        else if(m_pToTell)
+            m_pToTell->SwClientNotifyCall(rModify, rHint);
+    }
 };
 
+
 namespace sw
 {
+    class SW_DLLPUBLIC WriterMultiListener final
+    {
+        #ifdef WNT
+            typedef std::shared_ptr<SwDepend> pointer_t;
+        #else
+            typedef std::unique_ptr<SwDepend> pointer_t;
+        #endif
+        SwClient& m_rToTell;
+        std::list<pointer_t> m_vDepends;
+        public:
+            WriterMultiListener(SwClient& rToTell)
+                : m_rToTell(rToTell) {}
+            void StartListening(SwModify* pDepend);
+            void EndListening(SwModify* pDepend);
+            bool IsListeningTo(const SwModify* const pDepend);
+            void EndListeningAll();
+    };
     class ClientIteratorBase : public sw::Ring< ::sw::ClientIteratorBase >
     {
             friend SwClient* SwModify::Remove(SwClient*);
diff --git a/sw/qa/core/uwriter.cxx b/sw/qa/core/uwriter.cxx
index 6bc47bdc3df1..f642735c33c1 100644
--- a/sw/qa/core/uwriter.cxx
+++ b/sw/qa/core/uwriter.cxx
@@ -116,6 +116,7 @@ public:
     void testFormulas();
     void testIntrusiveRing();
     void testClientModify();
+    void testWriterMultiListener();
     void test64kPageDescs();
     void testTdf92308();
     void testTableCellComparison();
@@ -152,6 +153,7 @@ public:
     CPPUNIT_TEST(testFormulas);
     CPPUNIT_TEST(testIntrusiveRing);
     CPPUNIT_TEST(testClientModify);
+    CPPUNIT_TEST(testWriterMultiListener);
     CPPUNIT_TEST(test64kPageDescs);
     CPPUNIT_TEST(testTdf92308);
     CPPUNIT_TEST(testTableCellComparison);
@@ -1775,24 +1777,30 @@ namespace
     {
         int m_nModifyCount;
         int m_nNotifyCount;
-        TestClient() : m_nModifyCount(0), m_nNotifyCount(0) {};
+        int m_nModifyChangedCount;
+        const SwModify* m_pLastChangedModify;
+        TestClient() : m_nModifyCount(0), m_nNotifyCount(0), m_nModifyChangedCount(0), m_pLastChangedModify(nullptr) {};
         virtual void Modify( const SfxPoolItem*, const SfxPoolItem*) override
-        { ++m_nModifyCount; }
-        virtual void SwClientNotify(const SwModify& rModify, const SfxHint& rHint) override
+        { assert(false); }
+        virtual void SwClientNotify(const SwModify&, const SfxHint& rHint) override
         {
             if(typeid(TestHint) == typeid(rHint))
                 ++m_nNotifyCount;
-            else
-                SwClient::SwClientNotify(rModify, rHint);
+            else if(dynamic_cast<const sw::LegacyModifyHint*>(&rHint))
+                ++m_nModifyCount;
+            else if(auto pModifyChangedHint = dynamic_cast<const sw::ModifyChangedHint*>(&rHint))
+            {
+                ++m_nModifyChangedCount;
+                m_pLastChangedModify = pModifyChangedHint->m_pNew;
+            }
         }
     };
-    // sad copypasta as tools/rtti.hxx little brain can't cope with templates
     struct OtherTestClient : SwClient
     {
         int m_nModifyCount;
         OtherTestClient() : m_nModifyCount(0) {};
         virtual void Modify( const SfxPoolItem*, const SfxPoolItem*) override
-        { ++m_nModifyCount; }
+            { ++m_nModifyCount; }
     };
 }
 void SwDocTest::testClientModify()
@@ -1804,36 +1812,36 @@ void SwDocTest::testClientModify()
     // test client registration
     CPPUNIT_ASSERT(!aMod.HasWriterListeners());
     CPPUNIT_ASSERT(!aMod.HasOnlyOneListener());
-    CPPUNIT_ASSERT_EQUAL(aClient1.GetRegisteredIn(),static_cast<SwModify*>(nullptr));
-    CPPUNIT_ASSERT_EQUAL(aClient2.GetRegisteredIn(),static_cast<SwModify*>(nullptr));
-    CPPUNIT_ASSERT_EQUAL(aClient2.GetRegisteredIn(),static_cast<SwModify*>(nullptr));
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient1.GetRegisteredIn());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient2.GetRegisteredIn());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient2.GetRegisteredIn());
     aMod.Add(&aClient1);
     CPPUNIT_ASSERT(aMod.HasWriterListeners());
     CPPUNIT_ASSERT(aMod.HasOnlyOneListener());
     aMod.Add(&aClient2);
-    CPPUNIT_ASSERT_EQUAL(aClient1.GetRegisteredIn(),static_cast<SwModify*>(&aMod));
-    CPPUNIT_ASSERT_EQUAL(aClient2.GetRegisteredIn(),static_cast<SwModify*>(&aMod));
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(&aMod),aClient1.GetRegisteredIn());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(&aMod), aClient2.GetRegisteredIn());
     CPPUNIT_ASSERT(aMod.HasWriterListeners());
     CPPUNIT_ASSERT(!aMod.HasOnlyOneListener());
     // test broadcast
     aMod.ModifyBroadcast(nullptr, nullptr);
-    CPPUNIT_ASSERT_EQUAL(aClient1.m_nModifyCount,1);
-    CPPUNIT_ASSERT_EQUAL(aClient2.m_nModifyCount,1);
-    CPPUNIT_ASSERT_EQUAL(aClient1.m_nNotifyCount,0);
-    CPPUNIT_ASSERT_EQUAL(aClient2.m_nNotifyCount,0);
+    CPPUNIT_ASSERT_EQUAL(1,aClient1.m_nModifyCount);
+    CPPUNIT_ASSERT_EQUAL(1,aClient2.m_nModifyCount);
+    CPPUNIT_ASSERT_EQUAL(0,aClient1.m_nNotifyCount);
+    CPPUNIT_ASSERT_EQUAL(0,aClient2.m_nNotifyCount);
     aMod.ModifyBroadcast(nullptr, nullptr);
-    CPPUNIT_ASSERT_EQUAL(aClient1.m_nModifyCount,2);
-    CPPUNIT_ASSERT_EQUAL(aClient2.m_nModifyCount,2);
-    CPPUNIT_ASSERT_EQUAL(aClient1.m_nNotifyCount,0);
-    CPPUNIT_ASSERT_EQUAL(aClient2.m_nNotifyCount,0);
+    CPPUNIT_ASSERT_EQUAL(2,aClient1.m_nModifyCount);
+    CPPUNIT_ASSERT_EQUAL(2,aClient2.m_nModifyCount);
+    CPPUNIT_ASSERT_EQUAL(0,aClient1.m_nNotifyCount);
+    CPPUNIT_ASSERT_EQUAL(0,aClient2.m_nNotifyCount);
     // test notify
     {
         TestHint aHint;
         aMod.CallSwClientNotify(aHint);
-        CPPUNIT_ASSERT_EQUAL(aClient1.m_nModifyCount,2);
-        CPPUNIT_ASSERT_EQUAL(aClient2.m_nModifyCount,2);
-        CPPUNIT_ASSERT_EQUAL(aClient1.m_nNotifyCount,1);
-        CPPUNIT_ASSERT_EQUAL(aClient2.m_nNotifyCount,1);
+        CPPUNIT_ASSERT_EQUAL(2,aClient1.m_nModifyCount);
+        CPPUNIT_ASSERT_EQUAL(2,aClient2.m_nModifyCount);
+        CPPUNIT_ASSERT_EQUAL(1,aClient1.m_nNotifyCount);
+        CPPUNIT_ASSERT_EQUAL(1,aClient2.m_nNotifyCount);
     }
     // test typed iteration
     CPPUNIT_ASSERT(typeid(aClient1) != typeid(OtherTestClient));
@@ -1847,28 +1855,28 @@ void SwDocTest::testClientModify()
         SwIterator<TestClient,SwModify> aIter(aMod);
         for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
         {
-            CPPUNIT_ASSERT_EQUAL(pClient->m_nModifyCount,2);
+            CPPUNIT_ASSERT_EQUAL(2,pClient->m_nModifyCount);
             ++nCount;
         }
-        CPPUNIT_ASSERT_EQUAL(nCount,2);
+        CPPUNIT_ASSERT_EQUAL(2,nCount);
     }
     aMod.Add(&aOtherClient1);
-    CPPUNIT_ASSERT_EQUAL(aOtherClient1.m_nModifyCount,0);
+    CPPUNIT_ASSERT_EQUAL(0,aOtherClient1.m_nModifyCount);
     {
         int nCount = 0;
         SwIterator<TestClient,SwModify> aIter(aMod);
         for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
         {
-            CPPUNIT_ASSERT_EQUAL(pClient->m_nModifyCount,2);
+            CPPUNIT_ASSERT_EQUAL(2,pClient->m_nModifyCount);
             ++nCount;
         }
-        CPPUNIT_ASSERT_EQUAL(nCount,2);
+        CPPUNIT_ASSERT_EQUAL(2,nCount);
     }
-    CPPUNIT_ASSERT_EQUAL(aOtherClient1.m_nModifyCount,0);
+    CPPUNIT_ASSERT_EQUAL(0,aOtherClient1.m_nModifyCount);
     aMod.Remove(&aOtherClient1);
-    CPPUNIT_ASSERT_EQUAL(aClient1.GetRegisteredIn(),static_cast<SwModify*>(&aMod));
-    CPPUNIT_ASSERT_EQUAL(aClient2.GetRegisteredIn(),static_cast<SwModify*>(&aMod));
-    CPPUNIT_ASSERT_EQUAL(aOtherClient1.GetRegisteredIn(),static_cast<SwModify*>(nullptr));
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(&aMod),aClient1.GetRegisteredIn());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(&aMod),aClient2.GetRegisteredIn());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aOtherClient1.GetRegisteredIn());
     // test client self-deregistration during iteration
     {
         int nCount = 0;
@@ -1878,10 +1886,10 @@ void SwDocTest::testClientModify()
             aMod.Remove(pClient);
             ++nCount;
         }
-        CPPUNIT_ASSERT_EQUAL(nCount,2);
+        CPPUNIT_ASSERT_EQUAL(2,nCount);
     }
-    CPPUNIT_ASSERT_EQUAL(aClient1.GetRegisteredIn(), static_cast<SwModify*>(nullptr));
-    CPPUNIT_ASSERT_EQUAL(aClient2.GetRegisteredIn(), static_cast<SwModify*>(nullptr));
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient1.GetRegisteredIn());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient2.GetRegisteredIn());
     {
         SwIterator<TestClient,SwModify> aIter(aMod);
         for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
@@ -1890,10 +1898,34 @@ void SwDocTest::testClientModify()
         }
     }
     aMod.ModifyBroadcast(nullptr, nullptr);
-    CPPUNIT_ASSERT_EQUAL(aClient1.m_nModifyCount,2);
-    CPPUNIT_ASSERT_EQUAL(aClient2.m_nModifyCount,2);
-    CPPUNIT_ASSERT_EQUAL(aClient1.m_nNotifyCount,1);
-    CPPUNIT_ASSERT_EQUAL(aClient2.m_nNotifyCount,1);
+    CPPUNIT_ASSERT_EQUAL(2,aClient1.m_nModifyCount);
+    CPPUNIT_ASSERT_EQUAL(2,aClient2.m_nModifyCount);
+    CPPUNIT_ASSERT_EQUAL(1,aClient1.m_nNotifyCount);
+    CPPUNIT_ASSERT_EQUAL(1,aClient2.m_nNotifyCount);
+}
+void SwDocTest::testWriterMultiListener()
+{
+    TestModify aMod;
+    TestClient aClient;
+    sw::WriterMultiListener aMulti(aClient);
+    CPPUNIT_ASSERT(!aMulti.IsListeningTo(&aMod));
+    aMulti.StartListening(&aMod);
+    CPPUNIT_ASSERT(aMulti.IsListeningTo(&aMod));
+    aMulti.EndListeningAll();
+    CPPUNIT_ASSERT(!aMulti.IsListeningTo(&aMod));
+    aMulti.StartListening(&aMod);
+    aMulti.EndListening(&aMod);
+    CPPUNIT_ASSERT(!aMulti.IsListeningTo(&aMod));
+    int nPreDeathChangedCount;
+    {
+        TestModify aTempMod;
+        aMod.Add(&aTempMod);
+        aMulti.StartListening(&aTempMod);
+        nPreDeathChangedCount = aClient.m_nModifyChangedCount;
+    }
+    CPPUNIT_ASSERT(aMulti.IsListeningTo(&aMod));
+    CPPUNIT_ASSERT_EQUAL(nPreDeathChangedCount+1, aClient.m_nModifyChangedCount);
+    CPPUNIT_ASSERT_EQUAL(static_cast<const SwModify*>(&aMod),aClient.m_pLastChangedModify);
 }
 
 void SwDocTest::test64kPageDescs()
diff --git a/sw/source/core/attr/calbck.cxx b/sw/source/core/attr/calbck.cxx
index 98376e649a93..a0f82b381841 100644
--- a/sw/source/core/attr/calbck.cxx
+++ b/sw/source/core/attr/calbck.cxx
@@ -23,8 +23,20 @@
 #include <swcache.hxx>
 #include <swfntcch.hxx>
 #include <tools/debug.hxx>
+#include <algorithm>
 
 sw::LegacyModifyHint::~LegacyModifyHint() {}
+sw::ModifyChangedHint::~ModifyChangedHint() {}
+
+
+SwClient::SwClient(SwClient&& o)
+{
+    if(o.m_pRegisteredIn)
+    {
+        o.m_pRegisteredIn->Add(this);
+        o.EndListeningAll();
+    }
+}
 
 
 SwClient::~SwClient()
@@ -36,28 +48,33 @@ SwClient::~SwClient()
         m_pRegisteredIn->Remove( this );
 }
 
-void SwClient::CheckRegistration( const SfxPoolItem* pOld )
+std::unique_ptr<sw::ModifyChangedHint> SwClient::CheckRegistration( const SfxPoolItem* pOld )
 {
     DBG_TESTSOLARMUTEX();
     // this method only handles notification about dying SwModify objects
     if( !pOld || pOld->Which() != RES_OBJECTDYING )
-        return;
+        return nullptr;
 
     const SwPtrMsgPoolItem* pDead = static_cast<const SwPtrMsgPoolItem*>(pOld);
-    if(pDead && pDead->pObject == m_pRegisteredIn)
+    if(!pDead || pDead->pObject != m_pRegisteredIn)
+    {
+        // we should only care received death notes from objects we are following
+        return nullptr;
+    }
+    // I've got a notification from the object I know
+    SwModify* pAbove = m_pRegisteredIn->GetRegisteredIn();
+    if(pAbove)
+    {
+        // if the dying object itself was listening at an SwModify, I take over
+        // adding myself to pAbove will automatically remove me from my current pRegisteredIn
+        pAbove->Add(this);
+    }
+    else
     {
-        // I've got a notification from the object I know
-        SwModify* pAbove = m_pRegisteredIn->GetRegisteredIn();
-        if(pAbove)
-        {
-            // if the dying object itself was listening at an SwModify, I take over
-            // adding myself to pAbove will automatically remove me from my current pRegisteredIn
-            pAbove->Add(this);
-            return;
-        }
         // destroy connection
         EndListeningAll();
     }
+    return std::unique_ptr<sw::ModifyChangedHint>(new sw::ModifyChangedHint(pAbove));
 }
 
 void SwClient::SwClientNotify(const SwModify&, const SfxHint& rHint)
@@ -280,5 +297,34 @@ void SwModify::CheckCaching( const sal_uInt16 nWhich )
     }
 }
 
+void sw::WriterMultiListener::StartListening(SwModify* pDepend)
+{
+    EndListening(nullptr);
+    m_vDepends.emplace_back(pointer_t( new SwDepend(&m_rToTell, pDepend)));
+}
+
+
+bool sw::WriterMultiListener::IsListeningTo(const SwModify* const pBroadcaster)
+{
+    return std::any_of(m_vDepends.begin(), m_vDepends.end(),
+        [&pBroadcaster](const pointer_t& pListener)
+        {
+            return pListener->GetRegisteredIn() == pBroadcaster;
+        });
+}
+
+void sw::WriterMultiListener::EndListening(SwModify* pBroadcaster)
+{
+    m_vDepends.remove_if( [&pBroadcaster](const pointer_t& pListener)
+        {
+            return pListener->GetRegisteredIn() == nullptr || pListener->GetRegisteredIn() == pBroadcaster;
+        });
+}
+
+void sw::WriterMultiListener::EndListeningAll()
+{
+    m_vDepends.clear();
+}
+
 sw::ClientIteratorBase* sw::ClientIteratorBase::our_pClientIters = nullptr;
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list