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 0 : 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 0 : 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 0 : const SwModify* GetRegisteredIn() const { return pRegisteredIn; }
104 0 : bool IsLast() const { return !pLeft && !pRight; }
105 :
106 : // needed for class SwClientIter
107 : TYPEINFO();
108 :
109 : // get information about attribute
110 : virtual bool GetInfo( SfxPoolItem& ) const;
111 : };
112 :
113 0 : inline SwClient::SwClient() :
114 0 : pLeft(0), pRight(0), pRegisteredIn(0), mbIsAllowedToBeRemovedInModifyCall(false)
115 0 : {}
116 :
117 : // SwModify
118 :
119 : // class has a doubly linked list for dependencies
120 : class SW_DLLPUBLIC SwModify: public SwClient
121 : {
122 : SwClient* pRoot; // the start of the linked list of clients
123 : bool bModifyLocked : 1; // don't broadcast changes now
124 : sal_Bool bLockClientList : 1; // may be set when this instance notifies its clients
125 : sal_Bool bInDocDTOR : 1; // workaround for problems when a lot of objects are destroyed
126 : sal_Bool bInCache : 1;
127 : sal_Bool bInSwFntCache : 1;
128 :
129 : // mba: IMHO this method should be pure virtual
130 : virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) SAL_OVERRIDE;
131 :
132 : public:
133 : SwModify();
134 :
135 : // broadcasting: send notifications to all clients
136 : void NotifyClients( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue );
137 :
138 : // the same, but without setting bModifyLocked or checking for any of the flags
139 : // mba: it would be interesting to know why this is necessary
140 : // also allows to limit callback to certain type (HACK)
141 : void ModifyBroadcast( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue, TypeId nType = TYPE(SwClient) );
142 :
143 : // a more universal broadcasting mechanism
144 : void CallSwClientNotify( const SfxHint& rHint ) const;
145 :
146 : // single argument ctors shall be explicit.
147 : explicit SwModify( SwModify *pToRegisterIn );
148 : virtual ~SwModify();
149 :
150 : void Add(SwClient *pDepend);
151 : SwClient* Remove(SwClient *pDepend);
152 0 : const SwClient* GetDepends() const { return pRoot; }
153 :
154 : // get information about attribute
155 : virtual bool GetInfo( SfxPoolItem& ) const SAL_OVERRIDE;
156 :
157 0 : void LockModify() { bModifyLocked = true; }
158 0 : void UnlockModify() { bModifyLocked = false; }
159 0 : void SetInCache( sal_Bool bNew ) { bInCache = bNew; }
160 0 : void SetInSwFntCache( sal_Bool bNew ) { bInSwFntCache = bNew; }
161 0 : void SetInDocDTOR() { bInDocDTOR = sal_True; }
162 0 : bool IsModifyLocked() const { return bModifyLocked; }
163 0 : sal_Bool IsInDocDTOR() const { return bInDocDTOR; }
164 0 : sal_Bool IsInCache() const { return bInCache; }
165 0 : sal_Bool IsInSwFntCache() const { return bInSwFntCache; }
166 :
167 : void CheckCaching( const sal_uInt16 nWhich );
168 0 : bool IsLastDepend() { return pRoot && pRoot->IsLast(); }
169 : };
170 :
171 : // SwDepend
172 :
173 : /*
174 : * Helper class for objects that need to depend on more than one SwClient
175 : */
176 0 : class SW_DLLPUBLIC SwDepend: public SwClient
177 : {
178 : SwClient *pToTell;
179 :
180 : public:
181 : SwDepend() : pToTell(0) {}
182 : SwDepend(SwClient *pTellHim, SwModify *pDepend);
183 :
184 0 : SwClient* GetToTell() { return pToTell; }
185 :
186 : /** get Client information */
187 : virtual bool GetInfo( SfxPoolItem & ) const SAL_OVERRIDE;
188 : protected:
189 : virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNewValue ) SAL_OVERRIDE;
190 : virtual void SwClientNotify( const SwModify& rModify, const SfxHint& rHint ) SAL_OVERRIDE;
191 : };
192 :
193 : class SwClientIter
194 : {
195 : friend SwClient* SwModify::Remove(SwClient *); ///< for pointer adjustments
196 : friend void SwModify::Add(SwClient *pDepend); ///< for pointer adjustments
197 :
198 : const SwModify& rRoot;
199 :
200 : // the current object in an iteration
201 : SwClient* pAct;
202 :
203 : // in case the current object is already removed, the next object in the list
204 : // is marked down to become the current object in the next step
205 : // this is necessary because iteration requires access to members of the current object
206 : SwClient* pDelNext;
207 :
208 : // SwClientIter objects are tracked in linked list so that they can react
209 : // when the current (pAct) or marked down (pDelNext) SwClient is removed
210 : // from its SwModify
211 : SwClientIter *pNxtIter;
212 :
213 : // iterator can be limited to return only SwClient objects of a certain type
214 : TypeId aSrchId;
215 :
216 : public:
217 : SW_DLLPUBLIC SwClientIter( const SwModify& );
218 : SW_DLLPUBLIC ~SwClientIter();
219 :
220 : const SwModify& GetModify() const { return rRoot; }
221 :
222 : SwClient* operator++();
223 : SwClient* GoStart();
224 : SwClient* GoEnd();
225 :
226 : // returns the current SwClient object;
227 : // in case this was already removed, the object marked down to become
228 : // the next current one is returned
229 : SwClient* operator()() const
230 : { return pDelNext == pAct ? pAct : pDelNext; }
231 :
232 : // return "true" if an object was removed from a client chain in iteration
233 : // adding objects to a client chain in iteration is forbidden
234 : // SwModify::Add() asserts this
235 0 : bool IsChanged() const { return pDelNext != pAct; }
236 :
237 : SW_DLLPUBLIC SwClient* First( TypeId nType );
238 : SW_DLLPUBLIC SwClient* Next();
239 : SW_DLLPUBLIC SwClient* Last( TypeId nType );
240 : SW_DLLPUBLIC SwClient* Previous();
241 : };
242 :
243 : #endif
244 :
245 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|