|  | /************************************************************** | 
|  | * | 
|  | * 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. | 
|  | * | 
|  | *************************************************************/ | 
|  |  | 
|  |  | 
|  |  | 
|  | // MARKER(update_precomp.py): autogen include statement, do not remove | 
|  | #include "precompiled_sw.hxx" | 
|  |  | 
|  | #include <hintids.hxx>		    // contains RES_.. IDs | 
|  | #include <frame.hxx> | 
|  | #include <hints.hxx> | 
|  | #include <swcache.hxx>          // mba: get rid of that dependency | 
|  | #include <swfntcch.hxx>         // mba: get rid of that dependency | 
|  |  | 
|  | static SwClientIter* pClientIters = 0; | 
|  |  | 
|  | TYPEINIT0(SwClient); | 
|  |  | 
|  | /*************************************************************************/ | 
|  | SwClient::SwClient(SwModify *pToRegisterIn) | 
|  | : pLeft( 0 ), pRight( 0 ), pRegisteredIn( 0 ), mbIsAllowedToBeRemovedInModifyCall(false) | 
|  | { | 
|  | if(pToRegisterIn) | 
|  | // connect to SwModify | 
|  | pToRegisterIn->Add(this); | 
|  | } | 
|  |  | 
|  | /*************************************************************************/ | 
|  | void SwClient::CheckRegistration( const SfxPoolItem* pOld, const SfxPoolItem * ) | 
|  | { | 
|  | // this method only handles notification about dying SwModify objects | 
|  | if( (!pOld || pOld->Which() != RES_OBJECTDYING) ) | 
|  | return; | 
|  |  | 
|  | const SwPtrMsgPoolItem *pDead = static_cast<const SwPtrMsgPoolItem*>(pOld); | 
|  | if(pDead && pDead->pObject == pRegisteredIn) | 
|  | { | 
|  | // I've got a notification from the object I know | 
|  | SwModify *pAbove = const_cast<SwModify*>(pRegisteredIn->GetRegisteredIn()); | 
|  | if(pAbove) | 
|  | { | 
|  | // if the dying object itself was listening at an SwModify, I take over | 
|  | // adding myself to pAbove will automatically remove me from my current pRegisteredIn | 
|  | pAbove->Add(this); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // destroy connection | 
|  | pRegisteredIn->Remove(this); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SwClient::Modify( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ) | 
|  | { | 
|  | CheckRegistration( pOldValue, pNewValue ); | 
|  | } | 
|  |  | 
|  | void SwClient::SwClientNotify( const SwModify&, const SfxHint& ) | 
|  | { | 
|  |  | 
|  | } | 
|  |  | 
|  | //************************************************************************* | 
|  | SwClient::~SwClient() | 
|  | { | 
|  | DBG_ASSERT( !pRegisteredIn || pRegisteredIn->GetDepends(),"SwModify still known, but Client already disconnected!" ); | 
|  | if( pRegisteredIn && pRegisteredIn->GetDepends() ) | 
|  | // still connected | 
|  | pRegisteredIn->Remove( this ); | 
|  | } | 
|  |  | 
|  |  | 
|  | sal_Bool SwClient::GetInfo( SfxPoolItem& ) const | 
|  | { | 
|  | return sal_True;		// und weiter | 
|  | } | 
|  |  | 
|  |  | 
|  | /*************************************************************************/ | 
|  | SwModify::SwModify() | 
|  | : SwClient(0), pRoot(0) | 
|  | { | 
|  | bModifyLocked = sal_False; | 
|  | bLockClientList = sal_False; | 
|  | bInDocDTOR = sal_False; | 
|  | bInCache = sal_False; | 
|  | bInSwFntCache = sal_False; | 
|  | } | 
|  |  | 
|  | SwModify::SwModify( SwModify *pToRegisterIn ) | 
|  | : SwClient(pToRegisterIn), pRoot( 0 ) | 
|  | { | 
|  | bModifyLocked = sal_False; | 
|  | bLockClientList = sal_False; | 
|  | bInDocDTOR = sal_False; | 
|  | bInCache = sal_False; | 
|  | bInSwFntCache = sal_False; | 
|  | } | 
|  |  | 
|  | /*************************************************************************/ | 
|  | SwModify::~SwModify() | 
|  | { | 
|  | ASSERT( !IsModifyLocked(), "Modify destroyed but locked." ); | 
|  |  | 
|  | if ( IsInCache() ) | 
|  | SwFrm::GetCache().Delete( this ); | 
|  |  | 
|  | if ( IsInSwFntCache() ) | 
|  | pSwFontCache->Delete( this ); | 
|  |  | 
|  | if( pRoot ) | 
|  | { | 
|  | // there are depending objects | 
|  | if( IsInDocDTOR() ) | 
|  | { | 
|  | // if document gets destroyed anyway, just tell clients to forget me | 
|  | // so that they don't try to get removed from my list later when they also get destroyed | 
|  | SwClientIter aIter( *this ); | 
|  | SwClient* p = aIter.GoStart(); | 
|  | while ( p ) | 
|  | { | 
|  | p->pRegisteredIn = 0; | 
|  | p = ++aIter; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // notify all clients that they shall remove themselves | 
|  | SwPtrMsgPoolItem aDyObject( RES_OBJECTDYING, this ); | 
|  | NotifyClients( &aDyObject, &aDyObject ); | 
|  |  | 
|  | // remove all clients that have not done themselves | 
|  | // mba: possibly a hotfix for forgotten base class calls?! | 
|  | while( pRoot ) | 
|  | pRoot->CheckRegistration(&aDyObject, &aDyObject); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /*************************************************************************/ | 
|  | void SwModify::Modify( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ) | 
|  | { | 
|  | NotifyClients( pOldValue, pNewValue ); | 
|  | } | 
|  |  | 
|  | void SwModify::NotifyClients( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ) | 
|  | { | 
|  | if (IsInCache() || IsInSwFntCache()) | 
|  | { | 
|  | const sal_uInt16 nWhich = pOldValue ? pOldValue->Which() : | 
|  | pNewValue ? pNewValue->Which() : 0; | 
|  | CheckCaching( nWhich ); | 
|  | } | 
|  |  | 
|  | if (!pRoot || IsModifyLocked()) | 
|  | return; | 
|  |  | 
|  | LockModify(); | 
|  |  | 
|  | // mba: WTF?! | 
|  | if( !pOldValue ) | 
|  | bLockClientList = sal_True; | 
|  | else | 
|  | { | 
|  | // following Modifies shouldn't call an ASSERT | 
|  | switch( pOldValue->Which() ) | 
|  | { | 
|  | case RES_OBJECTDYING: | 
|  | case RES_REMOVE_UNO_OBJECT: | 
|  | bLockClientList = ((SwPtrMsgPoolItem *)pOldValue)->pObject != this; | 
|  | break; | 
|  |  | 
|  | case RES_FOOTNOTE_DELETED: | 
|  | case RES_REFMARK_DELETED: | 
|  | case RES_TOXMARK_DELETED: | 
|  | case RES_FIELD_DELETED: | 
|  | bLockClientList = sal_False; | 
|  | break; | 
|  | default: | 
|  | bLockClientList = sal_True; | 
|  | } | 
|  | } | 
|  |  | 
|  | ModifyBroadcast( pOldValue, pNewValue ); | 
|  | bLockClientList = sal_False; | 
|  | UnlockModify(); | 
|  | } | 
|  |  | 
|  | sal_Bool SwModify::GetInfo( SfxPoolItem& rInfo ) const | 
|  | { | 
|  | sal_Bool bRet = sal_True;		// bedeutet weiter zum naechsten | 
|  |  | 
|  | if( pRoot ) | 
|  | { | 
|  | SwClientIter aIter( *(SwModify*)this ); | 
|  |  | 
|  | SwClient* pLast = aIter.GoStart(); | 
|  | if( pLast ) | 
|  | while( 0 != ( bRet = pLast->GetInfo( rInfo )) && | 
|  | 0 != ( pLast = ++aIter ) ) | 
|  | ; | 
|  | } | 
|  |  | 
|  | return bRet; | 
|  | } | 
|  |  | 
|  | /*************************************************************************/ | 
|  | void SwModify::Add(SwClient *pDepend) | 
|  | { | 
|  | ASSERT( !bLockClientList, "Client inserted while in Modify" ); | 
|  |  | 
|  | if(pDepend->pRegisteredIn != this ) | 
|  | { | 
|  | #ifdef DBG_UTIL | 
|  | SwClientIter* pTmp = pClientIters; | 
|  | while( pTmp ) | 
|  | { | 
|  | ASSERT( &pTmp->GetModify() != pRoot, "Client added to active ClientIter" ); | 
|  | pTmp = pTmp->pNxtIter; | 
|  | } | 
|  | #endif | 
|  | // deregister new client in case it is already registered elsewhere | 
|  | if( pDepend->pRegisteredIn != 0 ) | 
|  | pDepend->pRegisteredIn->Remove( pDepend ); | 
|  |  | 
|  | if( !pRoot ) | 
|  | { | 
|  | // first client added | 
|  | pRoot = pDepend; | 
|  | pRoot->pLeft = 0; | 
|  | pRoot->pRight = 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | // append client | 
|  | pDepend->pRight = pRoot->pRight; | 
|  | pRoot->pRight = pDepend; | 
|  | pDepend->pLeft = pRoot; | 
|  | if( pDepend->pRight ) | 
|  | pDepend->pRight->pLeft = pDepend; | 
|  | } | 
|  |  | 
|  | // connect client to me | 
|  | pDepend->pRegisteredIn = this; | 
|  | } | 
|  | } | 
|  |  | 
|  | /*************************************************************************/ | 
|  |  | 
|  | SwClient* SwModify::Remove(SwClient * pDepend) | 
|  | { | 
|  | if ( bInDocDTOR ) | 
|  | return 0; | 
|  |  | 
|  | ASSERT( !bLockClientList || pDepend->mbIsAllowedToBeRemovedInModifyCall, "SwClient shall be removed in Modify call!" ); | 
|  |  | 
|  | if( pDepend->pRegisteredIn == this ) | 
|  | { | 
|  | // SwClient is my listener | 
|  | // remove it from my list | 
|  | SwClient* pR = pDepend->pRight; | 
|  | SwClient* pL = pDepend->pLeft; | 
|  | if( pRoot == pDepend ) | 
|  | pRoot = pL ? pL : pR; | 
|  |  | 
|  | if( pL ) | 
|  | pL->pRight = pR; | 
|  | if( pR ) | 
|  | pR->pLeft = pL; | 
|  |  | 
|  | // update ClientIters | 
|  | SwClientIter* pTmp = pClientIters; | 
|  | while( pTmp ) | 
|  | { | 
|  | if( pTmp->pAct == pDepend || pTmp->pDelNext == pDepend ) | 
|  | // if object being removed is the current or next object in an iterator, advance this iterator | 
|  | pTmp->pDelNext = pR; | 
|  | pTmp = pTmp->pNxtIter; | 
|  | } | 
|  |  | 
|  | pDepend->pLeft = 0; | 
|  | pDepend->pRight = 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | ASSERT( false, "SwModify::Remove(): pDepend nicht gefunden" ); | 
|  | } | 
|  |  | 
|  | // disconnect client from me | 
|  | pDepend->pRegisteredIn = 0; | 
|  | return pDepend; | 
|  | } | 
|  |  | 
|  | int SwModify::GetClientCount() const | 
|  | { | 
|  | int nRet=0; | 
|  | SwClientIter aIter( *this ); | 
|  | SwClient *pLast = aIter.GoStart(); | 
|  | if( pLast ) | 
|  | do | 
|  | { | 
|  | ++nRet; | 
|  | } while( 0 != ( pLast = ++aIter )); | 
|  | return nRet; | 
|  | } | 
|  |  | 
|  | void SwModify::CheckCaching( const sal_uInt16 nWhich ) | 
|  | { | 
|  | if (isCHRATR(nWhich)) | 
|  | { | 
|  | SetInSwFntCache( sal_False ); | 
|  | } | 
|  | else | 
|  | switch ( nWhich ) | 
|  | { | 
|  | case RES_OBJECTDYING: | 
|  | case RES_FMT_CHG: | 
|  | case RES_ATTRSET_CHG: | 
|  | SetInSwFntCache( sal_False ); | 
|  |  | 
|  | case RES_UL_SPACE: | 
|  | case RES_LR_SPACE: | 
|  | case RES_BOX: | 
|  | case RES_SHADOW: | 
|  | case RES_FRM_SIZE: | 
|  | case RES_KEEP: | 
|  | case RES_BREAK: | 
|  | if ( IsInCache() ) | 
|  | { | 
|  | SwFrm::GetCache().Delete( this ); | 
|  | SetInCache( sal_False ); | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void SwModify::CallSwClientNotify( const SfxHint& rHint ) const | 
|  | { | 
|  | SwClientIter aIter(*this); | 
|  | SwClient * pClient = aIter.GoStart(); | 
|  | while (pClient) | 
|  | { | 
|  | pClient->SwClientNotify( *this, rHint ); | 
|  | pClient = ++aIter; | 
|  | } | 
|  | } | 
|  |  | 
|  | void SwModify::ModifyBroadcast( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue, TypeId nType ) | 
|  | { | 
|  | SwClientIter aIter(*this); | 
|  | SwClient * pClient = aIter.First( nType ); | 
|  | while (pClient) | 
|  | { | 
|  | pClient->Modify( pOldValue, pNewValue ); | 
|  | pClient = aIter.Next(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // ---------- | 
|  | // SwDepend | 
|  | // ---------- | 
|  |  | 
|  | /*************************************************************************/ | 
|  |  | 
|  | SwDepend::SwDepend(SwClient *pTellHim, SwModify *pDepend) | 
|  | : SwClient(pDepend) | 
|  | { | 
|  | pToTell  = pTellHim; | 
|  | } | 
|  |  | 
|  | /*************************************************************************/ | 
|  |  | 
|  | void SwDepend::Modify( const SfxPoolItem* pOldValue, const SfxPoolItem *pNewValue ) | 
|  | { | 
|  | if(pNewValue && pNewValue->Which() == RES_OBJECTDYING) | 
|  | CheckRegistration(pOldValue,pNewValue); | 
|  | else if(pToTell) | 
|  | pToTell->ModifyNotification(pOldValue, pNewValue); | 
|  | } | 
|  |  | 
|  | void SwDepend::SwClientNotify( const SwModify& rMod, const SfxHint& rHint ) | 
|  | { | 
|  | if ( pToTell ) | 
|  | pToTell->SwClientNotifyCall( rMod, rHint ); | 
|  | } | 
|  |  | 
|  | sal_Bool SwDepend::GetInfo( SfxPoolItem& rInfo ) const | 
|  | { | 
|  | return pToTell ? pToTell->GetInfo( rInfo ) : sal_True; | 
|  | } | 
|  |  | 
|  | /********************************************************************/ | 
|  |  | 
|  | SwClientIter::SwClientIter( const SwModify& rModify ) | 
|  | : rRoot( rModify ) | 
|  | { | 
|  | pNxtIter = 0; | 
|  | if( pClientIters ) | 
|  | { | 
|  | // append to list of ClientIters | 
|  | SwClientIter* pTmp = pClientIters; | 
|  | while( pTmp->pNxtIter ) | 
|  | pTmp = pTmp->pNxtIter; | 
|  | pTmp->pNxtIter = this; | 
|  | } | 
|  | else | 
|  | pClientIters = this; | 
|  |  | 
|  | pAct = const_cast<SwClient*>(rRoot.GetDepends()); | 
|  | pDelNext = pAct; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | SwClientIter::~SwClientIter() | 
|  | { | 
|  | if( pClientIters ) | 
|  | { | 
|  | // reorganize list of ClientIters | 
|  | if( pClientIters == this ) | 
|  | pClientIters = pNxtIter; | 
|  | else | 
|  | { | 
|  | SwClientIter* pTmp = pClientIters; | 
|  | while( pTmp->pNxtIter != this ) | 
|  | if( 0 == ( pTmp = pTmp->pNxtIter ) ) | 
|  | { | 
|  | ASSERT( this, "wo ist mein Pointer" ); | 
|  | return ; | 
|  | } | 
|  | pTmp->pNxtIter = pNxtIter; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | SwClient* SwClientIter::operator++() | 
|  | { | 
|  | if( pDelNext == pAct ) | 
|  | { | 
|  | pAct = pAct->pRight; | 
|  | pDelNext = pAct; | 
|  | } | 
|  | else | 
|  | pAct = pDelNext; | 
|  | return pAct; | 
|  | } | 
|  |  | 
|  | SwClient* SwClientIter::GoStart() | 
|  | { | 
|  | pAct = const_cast<SwClient*>(rRoot.GetDepends()); | 
|  | if( pAct ) | 
|  | while( pAct->pLeft ) | 
|  | pAct = pAct->pLeft; | 
|  | pDelNext = pAct; | 
|  | return pAct; | 
|  | } | 
|  |  | 
|  | SwClient* SwClientIter::GoEnd() | 
|  | { | 
|  | pAct = pDelNext; | 
|  | if( !pAct ) | 
|  | pAct = const_cast<SwClient*>(rRoot.GetDepends()); | 
|  | if( pAct ) | 
|  | while( pAct->pRight ) | 
|  | pAct = pAct->pRight; | 
|  | pDelNext = pAct; | 
|  | return pAct; | 
|  | } | 
|  |  | 
|  | SwClient* SwClientIter::First( TypeId nType ) | 
|  | { | 
|  | aSrchId = nType; | 
|  | GoStart(); | 
|  | if( pAct ) | 
|  | do { | 
|  | if( pAct->IsA( aSrchId ) ) | 
|  | break; | 
|  |  | 
|  | if( pDelNext == pAct ) | 
|  | { | 
|  | pAct = pAct->pRight; | 
|  | pDelNext = pAct; | 
|  | } | 
|  | else | 
|  | pAct = pDelNext; | 
|  |  | 
|  | } while( pAct ); | 
|  | return pAct; | 
|  | } | 
|  |  | 
|  | SwClient* SwClientIter::Next() | 
|  | { | 
|  | do { | 
|  | if( pDelNext == pAct ) | 
|  | { | 
|  | pAct = pAct->pRight; | 
|  | pDelNext = pAct; | 
|  | } | 
|  | else | 
|  | pAct = pDelNext; | 
|  |  | 
|  | if( pAct && pAct->IsA( aSrchId ) ) | 
|  | break; | 
|  | } while( pAct ); | 
|  | return pAct; | 
|  | } | 
|  |  | 
|  | SwClient* SwClientIter::Last( TypeId nType ) | 
|  | { | 
|  | aSrchId = nType; | 
|  | GoEnd(); | 
|  | if( pAct ) | 
|  | do { | 
|  | if( pAct->IsA( aSrchId ) ) | 
|  | break; | 
|  |  | 
|  | if( pDelNext == pAct ) | 
|  | pAct = pAct->pLeft; | 
|  | else | 
|  | pAct = pDelNext->pLeft; | 
|  | pDelNext = pAct; | 
|  |  | 
|  | } while( pAct ); | 
|  | return pAct; | 
|  | } | 
|  |  | 
|  | SwClient* SwClientIter::Previous() | 
|  | { | 
|  | do { | 
|  | if( pDelNext == pAct ) | 
|  | pAct = pAct->pLeft; | 
|  | else | 
|  | pAct = pDelNext->pLeft; | 
|  | pDelNext = pAct; | 
|  |  | 
|  | if( pAct && pAct->IsA( aSrchId ) ) | 
|  | break; | 
|  | } while( pAct ); | 
|  | return pAct; | 
|  | } | 
|  |  |