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