| /************************************************************** |
| * |
| * 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; |
| } |
| |