xref: /trunk/main/sw/inc/calbck.hxx (revision 2f121198)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #ifndef _CALBCK_HXX
29 #define _CALBCK_HXX
30 
31 #include <tools/rtti.hxx>
32 #include "swdllapi.h"
33 #include <boost/noncopyable.hpp>
34 
35 class SwModify;
36 class SwClientIter;
37 class SfxPoolItem;
38 class SfxHint;
39 
40 /*
41     SwModify and SwClient cooperate in propagating attribute changes.
42     If an attribute changes, the change is notified to all dependent
43     formats and other interested objects, e.g. Nodes. The clients will detect
44     if the change affects them. It could be that the changed attribute is
45     overruled in the receiving object so that its change does not become
46     effective or that the receiver is not interested in the particular attribute
47     in general (though probably in other attributes of the SwModify object they
48     are registered in).
49     As SwModify objects are derived from SwClient, they can create a chain of SwClient
50     objects where changes can get propagated through.
51     Each SwClient can be registered at only one SwModify object, while each SwModify
52     object is connected to a list of SwClient objects. If an object derived from SwClient
53     wants to get notifications from more than one SwModify object, it must create additional
54     SwClient objects. The SwDepend class allows to handle their notifications in the same
55     notification callback as it forwards the Modify() calls it receives to a "master"
56     SwClient implementation.
57     The SwClientIter class allows to iterate over the SwClient objects registered at an
58     SwModify. For historical reasons its ability to use TypeInfo to restrict this iteration
59     to objects of a particular type created a lot of code that misuses SwClient-SwModify
60     relationships that basically should be used only for Modify() callbacks.
61     This is still subject to refactoring.
62     Until this gets resolved, new SwClientIter base code should be reduced to the absolute
63     minimum and it also should be wrapped by SwIterator templates that prevent that the
64     code gets polluted by pointer casts (see switerator.hxx).
65  */
66 
67 // ----------
68 // SwClient
69 // ----------
70 
71 class SW_DLLPUBLIC SwClient : ::boost::noncopyable
72 {
73     // avoids making the details of the linked list and the callback method public
74 	friend class SwModify;
75 	friend class SwClientIter;
76 
77 	SwClient *pLeft, *pRight;       // double-linked list of other clients
78 	SwModify *pRegisteredIn;        // event source
79 
80     // in general clients should not be removed when their SwModify sends out Modify()
81     // notifications; in some rare cases this is necessary, but only the concrete SwClient
82     // sub class will know that; this flag allows to make that known
83     bool mbIsAllowedToBeRemovedInModifyCall;
84 
85     // callbacks received from SwModify (friend class - so these methods can be private)
86     // should be called only from SwModify the client is registered in
87     // mba: IMHO these methods should be pure virtual
88     virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew);
89     virtual void SwClientNotify( const SwModify& rModify, const SfxHint& rHint );
90 
91 protected:
92 	// single argument ctors shall be explicit.
93 	explicit SwClient(SwModify *pToRegisterIn);
94 
95     // write access to pRegisteredIn shall be granted only to the object itself (protected access)
96     SwModify* GetRegisteredInNonConst() const { return pRegisteredIn; }
97     void SetIsAllowedToBeRemovedInModifyCall( bool bSet ) { mbIsAllowedToBeRemovedInModifyCall = bSet; }
98 
99 public:
100 
101 	inline SwClient();
102 	virtual ~SwClient();
103 
104     // in case an SwModify object is destroyed that itself is registered in another SwModify,
105     // its SwClient objects can decide to get registered to the latter instead by calling this method
106 	void CheckRegistration( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue );
107 
108     // controlled access to Modify method
109     // mba: this is still considered a hack and it should be fixed; the name makes grep-ing easier
110 	void ModifyNotification( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ) { Modify ( pOldValue, pNewValue ); }
111    void SwClientNotifyCall( const SwModify& rModify, const SfxHint& rHint ) { SwClientNotify( rModify, rHint ); }
112 
113 	const SwModify* GetRegisteredIn() const { return pRegisteredIn; }
114     bool IsLast() const { return !pLeft && !pRight; }
115 
116     // needed for class SwClientIter
117 	TYPEINFO();
118 
119 	// get information about attribute
120 	virtual sal_Bool GetInfo( SfxPoolItem& ) const;
121 };
122 
123 inline SwClient::SwClient() :
124 	pLeft(0), pRight(0), pRegisteredIn(0), mbIsAllowedToBeRemovedInModifyCall(false)
125 {}
126 
127 // ----------
128 // SwModify
129 // ----------
130 
131 class SW_DLLPUBLIC SwModify: public SwClient
132 {
133 //	friend class SwClientIter;
134 
135 	SwClient* pRoot;                // the start of the linked list of clients
136 	sal_Bool bModifyLocked : 1;         // don't broadcast changes now
137 	sal_Bool bLockClientList : 1;       // may be set when this instance notifies its clients
138 	sal_Bool bInDocDTOR	: 1;            // workaround for problems when a lot of objects are destroyed
139 	sal_Bool bInCache	: 1;
140 	sal_Bool bInSwFntCache : 1;
141 
142     // mba: IMHO this method should be pure virtual
143     virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew);
144 
145 public:
146 	SwModify();
147 
148     // broadcasting: send notifications to all clients
149 	void NotifyClients( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue );
150 
151     // the same, but without setting bModifyLocked or checking for any of the flags
152     // mba: it would be interesting to know why this is necessary
153     // also allows to limit callback to certain type (HACK)
154 	void ModifyBroadcast( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue, TypeId nType = TYPE(SwClient) );
155 
156     // a more universal broadcasting mechanism
157 	void CallSwClientNotify( const SfxHint& rHint ) const;
158 
159 	// single argument ctors shall be explicit.
160 	explicit SwModify( SwModify *pToRegisterIn );
161 	virtual ~SwModify();
162 
163 	void Add(SwClient *pDepend);
164 	SwClient* Remove(SwClient *pDepend);
165 	const SwClient* GetDepends() const	{ return pRoot; }
166 
167 	// get information about attribute
168 	virtual sal_Bool GetInfo( SfxPoolItem& ) const;
169 
170 	void LockModify()                   { bModifyLocked = sal_True;  }
171 	void UnlockModify()  				{ bModifyLocked = sal_False; }
172 	void SetInCache( sal_Bool bNew )		{ bInCache = bNew;		 }
173 	void SetInSwFntCache( sal_Bool bNew ) 	{ bInSwFntCache = bNew;	 }
174 	void SetInDocDTOR()                 { bInDocDTOR = sal_True; }
175 	sal_Bool IsModifyLocked() const		{ return bModifyLocked;  }
176 	sal_Bool IsInDocDTOR()	  const 	{ return bInDocDTOR;	 }
177 	sal_Bool IsInCache()	  const 	{ return bInCache;		 }
178 	sal_Bool IsInSwFntCache() const     { return bInSwFntCache;	 }
179 
180 	void CheckCaching( const sal_uInt16 nWhich );
181     bool IsLastDepend() { return pRoot && pRoot->IsLast(); }
182     int GetClientCount() const;
183 };
184 
185 // ----------
186 // SwDepend
187 // ----------
188 
189 /*
190  * Helper class for objects that need to depend on more than one SwClient
191  */
192 class SW_DLLPUBLIC SwDepend: public SwClient
193 {
194 	SwClient *pToTell;
195 
196 public:
197 	SwDepend() : pToTell(0) {}
198 	SwDepend(SwClient *pTellHim, SwModify *pDepend);
199 
200 	SwClient* GetToTell() { return pToTell; }
201 
202 	virtual sal_Bool GetInfo( SfxPoolItem & ) const;
203 
204 protected:
205     virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNewValue );
206     virtual void SwClientNotify( const SwModify& rModify, const SfxHint& rHint );
207 };
208 
209 
210 class SwClientIter
211 {
212 	friend SwClient* SwModify::Remove(SwClient *); // for pointer adjustments
213 	friend void SwModify::Add(SwClient *pDepend);   // for pointer adjustments
214 
215     const SwModify& rRoot;
216 
217     // the current object in an iteration
218 	SwClient* pAct;
219 
220     // in case the current object is already removed, the next object in the list
221     // is marked down to become the current object in the next step
222     // this is necessary because iteration requires access to members of the current object
223     SwClient* pDelNext;
224 
225     // SwClientIter objects are tracked in linked list so that they can react
226     // when the current (pAct) or marked down (pDelNext) SwClient is removed
227     // from its SwModify
228 	SwClientIter *pNxtIter;
229 
230     // iterator can be limited to return only SwClient objects of a certain type
231 	TypeId aSrchId;
232 
233 public:
234     SW_DLLPUBLIC SwClientIter( const SwModify& );
235 	SW_DLLPUBLIC ~SwClientIter();
236 
237 	const SwModify& GetModify() const { return rRoot; }
238 
239 	SwClient* operator++();
240 	SwClient* GoStart();
241 	SwClient* GoEnd();
242 
243     // returns the current SwClient object;
244     // in case this was already removed, the object marked down to become
245     // the next current one is returned
246 	SwClient* operator()() const
247 		{ return pDelNext == pAct ? pAct : pDelNext; }
248 
249     // return "true" if an object was removed from a client chain in iteration
250     // adding objects to a client chain in iteration is forbidden
251     // SwModify::Add() asserts this
252 	bool IsChanged() const { return pDelNext != pAct; }
253 
254 	SW_DLLPUBLIC SwClient* First( TypeId nType );
255 	SW_DLLPUBLIC SwClient* Next();
256 	SW_DLLPUBLIC SwClient* Last( TypeId nType );
257 	SW_DLLPUBLIC SwClient* Previous();
258 };
259 
260 #endif
261