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