[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