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