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 INCLUDED_SW_INC_CALBCK_HXX
21 : #define INCLUDED_SW_INC_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 : // SwClient
60 :
61 : class SW_DLLPUBLIC SwClient : ::boost::noncopyable
62 : {
63 : // avoids making the details of the linked list and the callback method public
64 : friend class SwModify;
65 : friend class SwClientIter;
66 :
67 : SwClient *pLeft, *pRight; ///< double-linked list of other clients
68 : SwModify *pRegisteredIn; ///< event source
69 :
70 : // in general clients should not be removed when their SwModify sends out Modify()
71 : // notifications; in some rare cases this is necessary, but only the concrete SwClient
72 : // sub class will know that; this flag allows to make that known
73 : bool mbIsAllowedToBeRemovedInModifyCall;
74 :
75 : // callbacks received from SwModify (friend class - so these methods can be private)
76 : // should be called only from SwModify the client is registered in
77 : // mba: IMHO these methods should be pure virtual
78 : virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew);
79 : virtual void SwClientNotify( const SwModify& rModify, const SfxHint& rHint );
80 :
81 : protected:
82 : // single argument ctors shall be explicit.
83 : explicit SwClient(SwModify *pToRegisterIn);
84 :
85 : // write access to pRegisteredIn shall be granted only to the object itself (protected access)
86 21866862 : SwModify* GetRegisteredInNonConst() const { return pRegisteredIn; }
87 0 : void SetIsAllowedToBeRemovedInModifyCall( bool bSet ) { mbIsAllowedToBeRemovedInModifyCall = bSet; }
88 :
89 : public:
90 :
91 : inline SwClient();
92 : virtual ~SwClient();
93 :
94 : // in case an SwModify object is destroyed that itself is registered in another SwModify,
95 : // its SwClient objects can decide to get registered to the latter instead by calling this method
96 : void CheckRegistration( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue );
97 :
98 : // controlled access to Modify method
99 : // mba: this is still considered a hack and it should be fixed; the name makes grep-ing easier
100 1342091 : void ModifyNotification( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ) { Modify ( pOldValue, pNewValue ); }
101 0 : void SwClientNotifyCall( const SwModify& rModify, const SfxHint& rHint ) { SwClientNotify( rModify, rHint ); }
102 :
103 41656467 : const SwModify* GetRegisteredIn() const { return pRegisteredIn; }
104 10949971 : SwModify* GetRegisteredIn() { return pRegisteredIn; }
105 11126 : bool IsLast() const { return !pLeft && !pRight; }
106 :
107 : // needed for class SwClientIter
108 : TYPEINFO();
109 :
110 : // get information about attribute
111 : virtual bool GetInfo( SfxPoolItem& ) const;
112 : };
113 :
114 3492533 : inline SwClient::SwClient() :
115 3492533 : pLeft(0), pRight(0), pRegisteredIn(0), mbIsAllowedToBeRemovedInModifyCall(false)
116 3492533 : {}
117 :
118 : // SwModify
119 :
120 : // class has a doubly linked list for dependencies
121 : class SW_DLLPUBLIC SwModify: public SwClient
122 : {
123 : SwClient* pRoot; // the start of the linked list of clients
124 : bool bModifyLocked : 1; // don't broadcast changes now
125 : bool bLockClientList : 1; // may be set when this instance notifies its clients
126 : bool bInDocDTOR : 1; // workaround for problems when a lot of objects are destroyed
127 : bool bInCache : 1;
128 : bool bInSwFntCache : 1;
129 :
130 : // mba: IMHO this method should be pure virtual
131 : virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) SAL_OVERRIDE;
132 :
133 : public:
134 : SwModify();
135 :
136 : // broadcasting: send notifications to all clients
137 : void NotifyClients( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue );
138 :
139 : // the same, but without setting bModifyLocked or checking for any of the flags
140 : // mba: it would be interesting to know why this is necessary
141 : // also allows to limit callback to certain type (HACK)
142 : void ModifyBroadcast( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue, TypeId nType = TYPE(SwClient) );
143 :
144 : // a more universal broadcasting mechanism
145 : void CallSwClientNotify( const SfxHint& rHint ) const;
146 :
147 : // single argument ctors shall be explicit.
148 : explicit SwModify( SwModify *pToRegisterIn );
149 : virtual ~SwModify();
150 :
151 : void Add(SwClient *pDepend);
152 : SwClient* Remove(SwClient *pDepend);
153 12079419 : const SwClient* GetDepends() const { return pRoot; }
154 :
155 : // get information about attribute
156 : virtual bool GetInfo( SfxPoolItem& ) const SAL_OVERRIDE;
157 :
158 1527064 : void LockModify() { bModifyLocked = true; }
159 1527064 : void UnlockModify() { bModifyLocked = false; }
160 356397 : void SetInCache( bool bNew ) { bInCache = bNew; }
161 820478 : void SetInSwFntCache( bool bNew ) { bInSwFntCache = bNew; }
162 40664 : void SetInDocDTOR() { bInDocDTOR = true; }
163 5552546 : bool IsModifyLocked() const { return bModifyLocked; }
164 685159 : bool IsInDocDTOR() const { return bInDocDTOR; }
165 9155252 : bool IsInCache() const { return bInCache; }
166 7761724 : bool IsInSwFntCache() const { return bInSwFntCache; }
167 :
168 : void CheckCaching( const sal_uInt16 nWhich );
169 11126 : bool IsLastDepend() { return pRoot && pRoot->IsLast(); }
170 : };
171 :
172 : // SwDepend
173 :
174 : /*
175 : * Helper class for objects that need to depend on more than one SwClient
176 : */
177 273734 : class SW_DLLPUBLIC SwDepend: public SwClient
178 : {
179 : SwClient *pToTell;
180 :
181 : public:
182 : SwDepend() : pToTell(0) {}
183 : SwDepend(SwClient *pTellHim, SwModify *pDepend);
184 :
185 0 : SwClient* GetToTell() { return pToTell; }
186 :
187 : /** get Client information */
188 : virtual bool GetInfo( SfxPoolItem & ) const SAL_OVERRIDE;
189 : protected:
190 : virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNewValue ) SAL_OVERRIDE;
191 : virtual void SwClientNotify( const SwModify& rModify, const SfxHint& rHint ) SAL_OVERRIDE;
192 : };
193 :
194 : class SwClientIter
195 : {
196 : friend SwClient* SwModify::Remove(SwClient *); ///< for pointer adjustments
197 : friend void SwModify::Add(SwClient *pDepend); ///< for pointer adjustments
198 :
199 : const SwModify& rRoot;
200 :
201 : // the current object in an iteration
202 : SwClient* pAct;
203 :
204 : // in case the current object is already removed, the next object in the list
205 : // is marked down to become the current object in the next step
206 : // this is necessary because iteration requires access to members of the current object
207 : SwClient* pDelNext;
208 :
209 : // SwClientIter objects are tracked in linked list so that they can react
210 : // when the current (pAct) or marked down (pDelNext) SwClient is removed
211 : // from its SwModify
212 : SwClientIter *pNxtIter;
213 :
214 : // iterator can be limited to return only SwClient objects of a certain type
215 : TypeId aSrchId;
216 :
217 : public:
218 : SW_DLLPUBLIC SwClientIter( const SwModify& );
219 : SW_DLLPUBLIC ~SwClientIter();
220 :
221 : const SwModify& GetModify() const { return rRoot; }
222 :
223 : SwClient* operator++();
224 : SwClient* GoStart();
225 : SwClient* GoEnd();
226 :
227 : // returns the current SwClient object;
228 : // in case this was already removed, the object marked down to become
229 : // the next current one is returned
230 : SwClient* operator()() const
231 : { return pDelNext == pAct ? pAct : pDelNext; }
232 :
233 : // return "true" if an object was removed from a client chain in iteration
234 : // adding objects to a client chain in iteration is forbidden
235 : // SwModify::Add() asserts this
236 372997 : bool IsChanged() const { return pDelNext != pAct; }
237 :
238 : SW_DLLPUBLIC SwClient* First( TypeId nType );
239 : SW_DLLPUBLIC SwClient* Next();
240 : SW_DLLPUBLIC SwClient* Last( TypeId nType );
241 : SW_DLLPUBLIC SwClient* Previous();
242 : };
243 :
244 : #endif
245 :
246 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|