| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #ifndef _CALBCK_HXX |
| #define _CALBCK_HXX |
| |
| #include <tools/rtti.hxx> |
| #include "swdllapi.h" |
| #include <boost/noncopyable.hpp> |
| |
| class SwModify; |
| class SwClientIter; |
| class SfxPoolItem; |
| class SfxHint; |
| |
| /* |
| SwModify and SwClient cooperate in propagating attribute changes. |
| If an attribute changes, the change is notified to all dependent |
| formats and other interested objects, e.g. Nodes. The clients will detect |
| if the change affects them. It could be that the changed attribute is |
| overruled in the receiving object so that its change does not become |
| effective or that the receiver is not interested in the particular attribute |
| in general (though probably in other attributes of the SwModify object they |
| are registered in). |
| As SwModify objects are derived from SwClient, they can create a chain of SwClient |
| objects where changes can get propagated through. |
| Each SwClient can be registered at only one SwModify object, while each SwModify |
| object is connected to a list of SwClient objects. If an object derived from SwClient |
| wants to get notifications from more than one SwModify object, it must create additional |
| SwClient objects. The SwDepend class allows to handle their notifications in the same |
| notification callback as it forwards the Modify() calls it receives to a "master" |
| SwClient implementation. |
| The SwClientIter class allows to iterate over the SwClient objects registered at an |
| SwModify. For historical reasons its ability to use TypeInfo to restrict this iteration |
| to objects of a particular type created a lot of code that misuses SwClient-SwModify |
| relationships that basically should be used only for Modify() callbacks. |
| This is still subject to refactoring. |
| Until this gets resolved, new SwClientIter base code should be reduced to the absolute |
| minimum and it also should be wrapped by SwIterator templates that prevent that the |
| code gets polluted by pointer casts (see switerator.hxx). |
| */ |
| |
| // ---------- |
| // SwClient |
| // ---------- |
| |
| class SW_DLLPUBLIC SwClient : ::boost::noncopyable |
| { |
| // avoids making the details of the linked list and the callback method public |
| friend class SwModify; |
| friend class SwClientIter; |
| |
| SwClient *pLeft, *pRight; // double-linked list of other clients |
| SwModify *pRegisteredIn; // event source |
| |
| // in general clients should not be removed when their SwModify sends out Modify() |
| // notifications; in some rare cases this is necessary, but only the concrete SwClient |
| // sub class will know that; this flag allows to make that known |
| bool mbIsAllowedToBeRemovedInModifyCall; |
| |
| // callbacks received from SwModify (friend class - so these methods can be private) |
| // should be called only from SwModify the client is registered in |
| // mba: IMHO these methods should be pure virtual |
| virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew); |
| virtual void SwClientNotify( const SwModify& rModify, const SfxHint& rHint ); |
| |
| protected: |
| // single argument ctors shall be explicit. |
| explicit SwClient(SwModify *pToRegisterIn); |
| |
| // write access to pRegisteredIn shall be granted only to the object itself (protected access) |
| SwModify* GetRegisteredInNonConst() const { return pRegisteredIn; } |
| void SetIsAllowedToBeRemovedInModifyCall( bool bSet ) { mbIsAllowedToBeRemovedInModifyCall = bSet; } |
| |
| public: |
| |
| inline SwClient(); |
| virtual ~SwClient(); |
| |
| // in case an SwModify object is destroyed that itself is registered in another SwModify, |
| // its SwClient objects can decide to get registered to the latter instead by calling this method |
| void CheckRegistration( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ); |
| |
| // controlled access to Modify method |
| // mba: this is still considered a hack and it should be fixed; the name makes grep-ing easier |
| void ModifyNotification( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ) { Modify ( pOldValue, pNewValue ); } |
| void SwClientNotifyCall( const SwModify& rModify, const SfxHint& rHint ) { SwClientNotify( rModify, rHint ); } |
| |
| const SwModify* GetRegisteredIn() const { return pRegisteredIn; } |
| bool IsLast() const { return !pLeft && !pRight; } |
| |
| // needed for class SwClientIter |
| TYPEINFO(); |
| |
| // get information about attribute |
| virtual sal_Bool GetInfo( SfxPoolItem& ) const; |
| }; |
| |
| inline SwClient::SwClient() : |
| pLeft(0), pRight(0), pRegisteredIn(0), mbIsAllowedToBeRemovedInModifyCall(false) |
| {} |
| |
| // ---------- |
| // SwModify |
| // ---------- |
| |
| class SW_DLLPUBLIC SwModify: public SwClient |
| { |
| // friend class SwClientIter; |
| |
| SwClient* pRoot; // the start of the linked list of clients |
| sal_Bool bModifyLocked : 1; // don't broadcast changes now |
| sal_Bool bLockClientList : 1; // may be set when this instance notifies its clients |
| sal_Bool bInDocDTOR : 1; // workaround for problems when a lot of objects are destroyed |
| sal_Bool bInCache : 1; |
| sal_Bool bInSwFntCache : 1; |
| |
| // mba: IMHO this method should be pure virtual |
| virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew); |
| |
| public: |
| SwModify(); |
| |
| // broadcasting: send notifications to all clients |
| void NotifyClients( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ); |
| |
| // the same, but without setting bModifyLocked or checking for any of the flags |
| // mba: it would be interesting to know why this is necessary |
| // also allows to limit callback to certain type (HACK) |
| void ModifyBroadcast( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue, TypeId nType = TYPE(SwClient) ); |
| |
| // a more universal broadcasting mechanism |
| void CallSwClientNotify( const SfxHint& rHint ) const; |
| |
| // single argument ctors shall be explicit. |
| explicit SwModify( SwModify *pToRegisterIn ); |
| virtual ~SwModify(); |
| |
| void Add(SwClient *pDepend); |
| SwClient* Remove(SwClient *pDepend); |
| const SwClient* GetDepends() const { return pRoot; } |
| |
| // get information about attribute |
| virtual sal_Bool GetInfo( SfxPoolItem& ) const; |
| |
| void LockModify() { bModifyLocked = sal_True; } |
| void UnlockModify() { bModifyLocked = sal_False; } |
| void SetInCache( sal_Bool bNew ) { bInCache = bNew; } |
| void SetInSwFntCache( sal_Bool bNew ) { bInSwFntCache = bNew; } |
| void SetInDocDTOR() { bInDocDTOR = sal_True; } |
| sal_Bool IsModifyLocked() const { return bModifyLocked; } |
| sal_Bool IsInDocDTOR() const { return bInDocDTOR; } |
| sal_Bool IsInCache() const { return bInCache; } |
| sal_Bool IsInSwFntCache() const { return bInSwFntCache; } |
| |
| void CheckCaching( const sal_uInt16 nWhich ); |
| bool IsLastDepend() { return pRoot && pRoot->IsLast(); } |
| int GetClientCount() const; |
| }; |
| |
| // ---------- |
| // SwDepend |
| // ---------- |
| |
| /* |
| * Helper class for objects that need to depend on more than one SwClient |
| */ |
| class SW_DLLPUBLIC SwDepend: public SwClient |
| { |
| SwClient *pToTell; |
| |
| public: |
| SwDepend() : pToTell(0) {} |
| SwDepend(SwClient *pTellHim, SwModify *pDepend); |
| |
| SwClient* GetToTell() { return pToTell; } |
| |
| virtual sal_Bool GetInfo( SfxPoolItem & ) const; |
| |
| protected: |
| virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNewValue ); |
| virtual void SwClientNotify( const SwModify& rModify, const SfxHint& rHint ); |
| }; |
| |
| |
| class SwClientIter |
| { |
| friend SwClient* SwModify::Remove(SwClient *); // for pointer adjustments |
| friend void SwModify::Add(SwClient *pDepend); // for pointer adjustments |
| |
| const SwModify& rRoot; |
| |
| // the current object in an iteration |
| SwClient* pAct; |
| |
| // in case the current object is already removed, the next object in the list |
| // is marked down to become the current object in the next step |
| // this is necessary because iteration requires access to members of the current object |
| SwClient* pDelNext; |
| |
| // SwClientIter objects are tracked in linked list so that they can react |
| // when the current (pAct) or marked down (pDelNext) SwClient is removed |
| // from its SwModify |
| SwClientIter *pNxtIter; |
| |
| // iterator can be limited to return only SwClient objects of a certain type |
| TypeId aSrchId; |
| |
| public: |
| SW_DLLPUBLIC SwClientIter( const SwModify& ); |
| SW_DLLPUBLIC ~SwClientIter(); |
| |
| const SwModify& GetModify() const { return rRoot; } |
| |
| SwClient* operator++(); |
| SwClient* GoStart(); |
| SwClient* GoEnd(); |
| |
| // returns the current SwClient object; |
| // in case this was already removed, the object marked down to become |
| // the next current one is returned |
| SwClient* operator()() const |
| { return pDelNext == pAct ? pAct : pDelNext; } |
| |
| // return "true" if an object was removed from a client chain in iteration |
| // adding objects to a client chain in iteration is forbidden |
| // SwModify::Add() asserts this |
| bool IsChanged() const { return pDelNext != pAct; } |
| |
| SW_DLLPUBLIC SwClient* First( TypeId nType ); |
| SW_DLLPUBLIC SwClient* Next(); |
| SW_DLLPUBLIC SwClient* Last( TypeId nType ); |
| SW_DLLPUBLIC SwClient* Previous(); |
| }; |
| |
| #endif |