summaryrefslogtreecommitdiff
path: root/sw/inc/calbck.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/inc/calbck.hxx')
-rw-r--r--sw/inc/calbck.hxx258
1 files changed, 134 insertions, 124 deletions
diff --git a/sw/inc/calbck.hxx b/sw/inc/calbck.hxx
index 407688df2a5f..f34ea4d9995e 100644
--- a/sw/inc/calbck.hxx
+++ b/sw/inc/calbck.hxx
@@ -25,143 +25,161 @@
*
************************************************************************/
-/*************************************************************
-#* Service-Klassen
- *************************************************************/
-
-/*
-#* Aendert sich ein Attribut in einem Format, so muss diese
-#* Aenderung an alle abhaengigen Formate und ueber sie an
-#* alle betroffenen Nodes propagiert werden. Dabei muss
-#* festgestellt werden, ob die Aenderung einen Effekt haben
-#* kann, oder ob das geaenderte Attribut von dem abhaengigen
-#* Format ueberdefiniert wird (so dass ohnehin der
-#* Attributwert des abhaengigen Formates den geaenderten
-#* Wert verdeckt). Weiterhin kann der betroffene Node
-#* feststellen, ob er von dem geaenderten Attribut Gebrauch
-#* macht (Beispiel: Linienabstand fuer Unterstreichung wurde
-#* geaendert, das Attribut Unterstreichung wurde aber nicht
-#* verwendet). So wird bei Aenderungen der minimale Aufwand
-#* zum Reformatieren erkannt.
- */
#ifndef _CALBCK_HXX
#define _CALBCK_HXX
#include <tools/rtti.hxx>
#include "swdllapi.h"
+#include <boost/noncopyable.hpp>
class SwModify;
class SwClientIter;
class SfxPoolItem;
-class SvStream;
+class SfxHint;
+
+/*
+ SwModify and SwClient cooperate in propagating attribute changes.
+ If an attribute changes, the change is notified to all dependent
+ formats and other interested objects, e.g. Nodes. The clients will detect
+ if the change affects them. It could be that the changed attribute is
+ overruled in the receiving object so that its change does not become
+ effective or that the receiver is not interested in the particular attribute
+ in general (though probably in other attributes of the SwModify object they
+ are registered in).
+ As SwModify objects are derived from SwClient, they can create a chain of SwClient
+ objects where changes can get propagated through.
+ Each SwClient can be registered at only one SwModify object, while each SwModify
+ object is connected to a list of SwClient objects. If an object derived from SwClient
+ wants to get notifications from more than one SwModify object, it must create additional
+ SwClient objects. The SwDepend class allows to handle their notifications in the same
+ notification callback as it forwards the Modify() calls it receives to a "master"
+ SwClient implementation.
+ The SwClientIter class allows to iterate over the SwClient objects registered at an
+ SwModify. For historical reasons its ability to use TypeInfo to restrict this iteration
+ to objects of a particular type created a lot of code that misuses SwClient-SwModify
+ relationships that basically should be used only for Modify() callbacks.
+ This is still subject to refactoring.
+ Until this gets resolved, new SwClientIter base code should be reduced to the absolute
+ minimum and it also should be wrapped by SwIterator templates that prevent that the
+ code gets polluted by pointer casts (see switerator.hxx).
+ */
// ----------
// SwClient
// ----------
-class SW_DLLPUBLIC SwClient
+class SW_DLLPUBLIC SwClient : ::boost::noncopyable
{
+ // avoids making the details of the linked list and the callback method public
friend class SwModify;
friend class SwClientIter;
- SwClient *pLeft, *pRight; // fuer die AVL-Sortierung
- sal_Bool bModifyLocked : 1; // wird in SwModify::Modify benutzt,
- // eigentlich ein Member des SwModify
- // aber aus Platzgruenden hier.
- sal_Bool bInModify : 1; // ist in einem Modify. (Debug!!!)
- sal_Bool bInDocDTOR : 1; // Doc wird zerstoert, nicht "abmelden"
- sal_Bool bInCache : 1; // Ist im BorderAttrCache des Layout,
- // Traegt sich dann im Modify aus!
- sal_Bool bInSwFntCache : 1; // Ist im SwFont-Cache der Formatierung
+ SwClient *pLeft, *pRight; // double-linked list of other clients
+ SwModify *pRegisteredIn; // event source
-protected:
- SwModify *pRegisteredIn;
+ // in general clients should not be removed when their SwModify sends out Modify()
+ // notifications; in some rare cases this is necessary, but only the concrete SwClient
+ // sub class will know that; this flag allows to make that known
+ bool mbIsAllowedToBeRemovedInModifyCall;
+
+ // callbacks received from SwModify (friend class - so these methods can be private)
+ // should be called only from SwModify the client is registered in
+ // mba: IMHO these methods should be pure virtual
+ virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew);
+ virtual void SwClientNotify( const SwModify& rModify, const SfxHint& rHint );
+protected:
// single argument ctors shall be explicit.
explicit SwClient(SwModify *pToRegisterIn);
+ // write access to pRegisteredIn shall be granted only to the object itself (protected access)
+ SwModify* GetRegisteredInNonConst() const { return pRegisteredIn; }
+ void SetIsAllowedToBeRemovedInModifyCall( bool bSet ) { mbIsAllowedToBeRemovedInModifyCall = bSet; }
+
public:
+
inline SwClient();
virtual ~SwClient();
- virtual void Modify( SfxPoolItem *pOld, SfxPoolItem *pNew);
+ // 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, const SfxPoolItem *pNewValue );
+
+ // controlled access to Modify method
+ // mba: this is still considered a hack and it should be fixed; the name makes grep-ing easier
+ void ModifyNotification( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ) { Modify ( pOldValue, pNewValue ); }
+ void SwClientNotifyCall( const SwModify& rModify, const SfxHint& rHint ) { SwClientNotify( rModify, rHint ); }
+
const SwModify* GetRegisteredIn() const { return pRegisteredIn; }
+ bool IsLast() const { return !pLeft && !pRight; }
- //rtti, abgeleitete moegens gleichtun oder nicht. Wenn sie es gleichtun
- //kann ueber die Abhaengigkeitsliste eines Modify typsicher gecastet
- //werden.
+ // needed for class SwClientIter
TYPEINFO();
- void LockModify() { bModifyLocked = sal_True; }
- void UnlockModify() { bModifyLocked = sal_False; }
- void SetInCache( sal_Bool bNew ) { bInCache = bNew; }
- void SetInSwFntCache( sal_Bool bNew ) { bInSwFntCache = bNew; }
- sal_Bool IsModifyLocked() const { return bModifyLocked; }
- sal_Bool IsInDocDTOR() const { return bInDocDTOR; }
- sal_Bool IsInCache() const { return bInCache; }
- sal_Bool IsInSwFntCache() const { return bInSwFntCache; }
-
- // erfrage vom Client Informationen
+ // get information about attribute
virtual sal_Bool GetInfo( SfxPoolItem& ) const;
-
-private:
- SwClient( const SwClient& );
- SwClient &operator=( const SwClient& );
};
inline SwClient::SwClient() :
- pLeft(0), pRight(0), pRegisteredIn(0)
-{ bModifyLocked = bInModify = bInDocDTOR = bInCache = bInSwFntCache = sal_False; }
-
+ pLeft(0), pRight(0), pRegisteredIn(0), mbIsAllowedToBeRemovedInModifyCall(false)
+{}
// ----------
// SwModify
// ----------
-// Klasse hat eine doppelt Verkette Liste fuer die Abhaengigen.
-
class SW_DLLPUBLIC SwModify: public SwClient
{
- friend SvStream& operator<<( SvStream& aS, SwModify & );
+// friend class SwClientIter;
- friend class SwClientIter;
- SwClient* pRoot;
+ SwClient* pRoot; // the start of the linked list of clients
+ sal_Bool bModifyLocked : 1; // don't broadcast changes now
+ sal_Bool bLockClientList : 1; // may be set when this instance notifies its clients
+ sal_Bool bInDocDTOR : 1; // workaround for problems when a lot of objects are destroyed
+ sal_Bool bInCache : 1;
+ sal_Bool bInSwFntCache : 1;
- SwClient *_Remove(SwClient *pDepend);
+ // mba: IMHO this method should be pure virtual
+ virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew);
public:
- SwModify() : pRoot(0) {}
+ SwModify();
+
+ // broadcasting: send notifications to all clients
+ void NotifyClients( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue );
+
+ // the same, but without setting bModifyLocked or checking for any of the flags
+ // mba: it would be interesting to know why this is necessary
+ // also allows to limit callback to certain type (HACK)
+ void ModifyBroadcast( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue, TypeId nType = TYPE(SwClient) );
+
+ // a more universal broadcasting mechanism
+ void CallSwClientNotify( const SfxHint& rHint ) const;
// single argument ctors shall be explicit.
- explicit SwModify(SwModify *pToRegisterIn );
+ explicit SwModify( SwModify *pToRegisterIn );
virtual ~SwModify();
- virtual void Modify( SfxPoolItem *pOldValue, SfxPoolItem *pNewValue );
void Add(SwClient *pDepend);
- SwClient *Remove(SwClient *pDepend)
- { return bInDocDTOR ? 0 : _Remove( pDepend ); }
-
+ SwClient* Remove(SwClient *pDepend);
const SwClient* GetDepends() const { return pRoot; }
- // erfrage vom Client Informationen
+ // get information about attribute
virtual sal_Bool GetInfo( SfxPoolItem& ) const;
- void SetInDocDTOR() { bInDocDTOR = sal_True; }
+ void LockModify() { bModifyLocked = sal_True; }
+ void UnlockModify() { bModifyLocked = sal_False; }
+ void SetInCache( sal_Bool bNew ) { bInCache = bNew; }
+ void SetInSwFntCache( sal_Bool bNew ) { bInSwFntCache = bNew; }
+ void SetInDocDTOR() { bInDocDTOR = sal_True; }
+ sal_Bool IsModifyLocked() const { return bModifyLocked; }
+ sal_Bool IsInDocDTOR() const { return bInDocDTOR; }
+ sal_Bool IsInCache() const { return bInCache; }
+ sal_Bool IsInSwFntCache() const { return bInSwFntCache; }
void CheckCaching( const sal_uInt16 nWhich );
-
- sal_Bool IsLastDepend() const
- { return pRoot && !pRoot->pLeft && !pRoot->pRight; }
-
-private:
- // forbidden and not implemented (see @ SwClient).
- SwModify & operator= (const SwModify &);
-
-protected:
- // forbidden and not implemented (see @ SwClient),
- // but GCC >= 3.4 needs an accessible "T (const T&)"
- // to pass a "T" as a "const T&" argument
- SwModify (const SwModify &);
+ bool IsLastDepend() { return pRoot && pRoot->IsLast(); }
+ int GetClientCount() const;
};
// ----------
@@ -169,9 +187,7 @@ protected:
// ----------
/*
- * Sehr sinnvolle Klasse, wenn ein Objekt von mehreren Objekten
- * abhaengig ist. Diese sollte fuer jede Abhaengigkeit ein Objekt
- * der Klasse SwDepend als Member haben.
+ * Helper class for objects that need to depend on more than one SwClient
*/
class SW_DLLPUBLIC SwDepend: public SwClient
{
@@ -182,69 +198,63 @@ public:
SwDepend(SwClient *pTellHim, SwModify *pDepend);
SwClient* GetToTell() { return pToTell; }
- virtual void Modify( SfxPoolItem *pOldValue, SfxPoolItem *pNewValue );
- // erfrage vom Client Informationen
virtual sal_Bool GetInfo( SfxPoolItem & ) const;
-private:
- // forbidden and not implemented (see @ SwClient).
- SwDepend (const SwDepend &);
- SwDepend & operator= (const SwDepend &);
+protected:
+ virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNewValue );
+ virtual void SwClientNotify( const SwModify& rModify, const SfxHint& rHint );
};
class SwClientIter
{
- friend SwClient* SwModify::_Remove(SwClient *); // fuer Ptr-Korrektur
- friend void SwModify::Add(SwClient *); // nur fuer ASSERT !
+ friend SwClient* SwModify::Remove(SwClient *); // for pointer adjustments
+ friend void SwModify::Add(SwClient *pDepend); // for pointer adjustments
- SwModify const& rRoot;
- SwClient *pAkt, *pDelNext;
- // fuers Updaten der aller Iteratoren beim Einfuegen/Loeschen von
- // Clients, wenn der Iterator gerade draufsteht.
- SwClientIter *pNxtIter;
+ const SwModify& rRoot;
- SwClient* mpWatchClient; // if set, SwModify::_Remove checks if this client is removed
+ // the current object in an iteration
+ SwClient* pAct;
- TypeId aSrchId; // fuer First/Next - suche diesen Type
+ // in case the current object is already removed, the next object in the list
+ // is marked down to become the current object in the next step
+ // this is necessary because iteration requires access to members of the current object
+ SwClient* pDelNext;
-public:
- SW_DLLPUBLIC SwClientIter( SwModify const& );
- SW_DLLPUBLIC ~SwClientIter();
+ // SwClientIter objects are tracked in linked list so that they can react
+ // when the current (pAct) or marked down (pDelNext) SwClient is removed
+ // from its SwModify
+ SwClientIter *pNxtIter;
- const SwModify& GetModify() const { return rRoot; }
+ // iterator can be limited to return only SwClient objects of a certain type
+ TypeId aSrchId;
-#ifndef CFRONT
- SwClient* operator++(int); // zum Naechsten
- SwClient* operator--(int); // zum Vorherigen
-#endif
- SwClient* operator++(); // zum Naechsten
- SwClient* operator--(); // zum Vorherigen
+public:
+ SW_DLLPUBLIC SwClientIter( const SwModify& );
+ SW_DLLPUBLIC ~SwClientIter();
- SwClient* GoStart(); // zum Anfang
- SwClient* GoEnd(); // zum Ende
+ const SwModify& GetModify() const { return rRoot; }
- inline SwClient* GoRoot(); // wieder ab Root (==Start) anfangen
+ SwClient* operator++(int);
+ SwClient* GoStart();
+ SwClient* GoEnd();
+ // returns the current SwClient object;
+ // in case this was already removed, the object marked down to become
+ // the next current one is returned
SwClient* operator()() const
- { return pDelNext == pAkt ? pAkt : pDelNext; }
+ { return pDelNext == pAct ? pAct : pDelNext; }
- int IsChanged() const { return pDelNext != pAkt; }
+ // return "true" if an object was removed from a client chain in iteration
+ // adding objects to a client chain in iteration is forbidden
+ // SwModify::Add() asserts this
+ bool IsChanged() const { return pDelNext != pAct; }
SW_DLLPUBLIC SwClient* First( TypeId nType );
SW_DLLPUBLIC SwClient* Next();
-
- const SwClient* GetWatchClient() const { return mpWatchClient; }
- void SetWatchClient( SwClient* pWatch ) { mpWatchClient = pWatch; }
+ SW_DLLPUBLIC SwClient* Last( TypeId nType );
+ SW_DLLPUBLIC SwClient* Previous();
};
-inline SwClient* SwClientIter::GoRoot() // wieder ab Root anfangen
-{
- pAkt = rRoot.pRoot;
- return (pDelNext = pAkt);
-}
-
-
-
#endif