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