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 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sw.hxx" 26 27 #include <hintids.hxx> // contains RES_.. IDs 28 #include <frame.hxx> 29 #include <hints.hxx> 30 #include <swcache.hxx> // mba: get rid of that dependency 31 #include <swfntcch.hxx> // mba: get rid of that dependency 32 33 static SwClientIter* pClientIters = 0; 34 35 TYPEINIT0(SwClient); 36 37 /*************************************************************************/ 38 SwClient::SwClient(SwModify *pToRegisterIn) 39 : pLeft( 0 ), pRight( 0 ), pRegisteredIn( 0 ), mbIsAllowedToBeRemovedInModifyCall(false) 40 { 41 if(pToRegisterIn) 42 // connect to SwModify 43 pToRegisterIn->Add(this); 44 } 45 46 /*************************************************************************/ 47 void SwClient::CheckRegistration( const SfxPoolItem* pOld, const SfxPoolItem * ) 48 { 49 // this method only handles notification about dying SwModify objects 50 if( (!pOld || pOld->Which() != RES_OBJECTDYING) ) 51 return; 52 53 const SwPtrMsgPoolItem *pDead = static_cast<const SwPtrMsgPoolItem*>(pOld); 54 if(pDead && pDead->pObject == pRegisteredIn) 55 { 56 // I've got a notification from the object I know 57 SwModify *pAbove = const_cast<SwModify*>(pRegisteredIn->GetRegisteredIn()); 58 if(pAbove) 59 { 60 // if the dying object itself was listening at an SwModify, I take over 61 // adding myself to pAbove will automatically remove me from my current pRegisteredIn 62 pAbove->Add(this); 63 return; 64 } 65 66 // destroy connection 67 pRegisteredIn->Remove(this); 68 } 69 } 70 71 void SwClient::Modify( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ) 72 { 73 CheckRegistration( pOldValue, pNewValue ); 74 } 75 76 void SwClient::SwClientNotify( const SwModify&, const SfxHint& ) 77 { 78 79 } 80 81 //************************************************************************* 82 SwClient::~SwClient() 83 { 84 DBG_ASSERT( !pRegisteredIn || pRegisteredIn->GetDepends(),"SwModify still known, but Client already disconnected!" ); 85 if( pRegisteredIn && pRegisteredIn->GetDepends() ) 86 // still connected 87 pRegisteredIn->Remove( this ); 88 } 89 90 91 sal_Bool SwClient::GetInfo( SfxPoolItem& ) const 92 { 93 return sal_True; // und weiter 94 } 95 96 97 /*************************************************************************/ 98 SwModify::SwModify() 99 : SwClient(0), pRoot(0) 100 { 101 bModifyLocked = sal_False; 102 bLockClientList = sal_False; 103 bInDocDTOR = sal_False; 104 bInCache = sal_False; 105 bInSwFntCache = sal_False; 106 } 107 108 SwModify::SwModify( SwModify *pToRegisterIn ) 109 : SwClient(pToRegisterIn), pRoot( 0 ) 110 { 111 bModifyLocked = sal_False; 112 bLockClientList = sal_False; 113 bInDocDTOR = sal_False; 114 bInCache = sal_False; 115 bInSwFntCache = sal_False; 116 } 117 118 /*************************************************************************/ 119 SwModify::~SwModify() 120 { 121 ASSERT( !IsModifyLocked(), "Modify destroyed but locked." ); 122 123 if ( IsInCache() ) 124 SwFrm::GetCache().Delete( this ); 125 126 if ( IsInSwFntCache() ) 127 pSwFontCache->Delete( this ); 128 129 if( pRoot ) 130 { 131 // there are depending objects 132 if( IsInDocDTOR() ) 133 { 134 // if document gets destroyed anyway, just tell clients to forget me 135 // so that they don't try to get removed from my list later when they also get destroyed 136 SwClientIter aIter( *this ); 137 SwClient* p = aIter.GoStart(); 138 while ( p ) 139 { 140 p->pRegisteredIn = 0; 141 p = ++aIter; 142 } 143 } 144 else 145 { 146 // notify all clients that they shall remove themselves 147 SwPtrMsgPoolItem aDyObject( RES_OBJECTDYING, this ); 148 NotifyClients( &aDyObject, &aDyObject ); 149 150 // remove all clients that have not done themselves 151 // mba: possibly a hotfix for forgotten base class calls?! 152 while( pRoot ) 153 pRoot->CheckRegistration(&aDyObject, &aDyObject); 154 } 155 } 156 } 157 158 /*************************************************************************/ 159 void SwModify::Modify( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ) 160 { 161 NotifyClients( pOldValue, pNewValue ); 162 } 163 164 void SwModify::NotifyClients( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ) 165 { 166 if (IsInCache() || IsInSwFntCache()) 167 { 168 const sal_uInt16 nWhich = pOldValue ? pOldValue->Which() : 169 pNewValue ? pNewValue->Which() : 0; 170 CheckCaching( nWhich ); 171 } 172 173 if (!pRoot || IsModifyLocked()) 174 return; 175 176 LockModify(); 177 178 // mba: WTF?! 179 if( !pOldValue ) 180 bLockClientList = sal_True; 181 else 182 { 183 // following Modifies shouldn't call an ASSERT 184 switch( pOldValue->Which() ) 185 { 186 case RES_OBJECTDYING: 187 case RES_REMOVE_UNO_OBJECT: 188 bLockClientList = ((SwPtrMsgPoolItem *)pOldValue)->pObject != this; 189 break; 190 191 case RES_FOOTNOTE_DELETED: 192 case RES_REFMARK_DELETED: 193 case RES_TOXMARK_DELETED: 194 case RES_FIELD_DELETED: 195 bLockClientList = sal_False; 196 break; 197 default: 198 bLockClientList = sal_True; 199 } 200 } 201 202 ModifyBroadcast( pOldValue, pNewValue ); 203 bLockClientList = sal_False; 204 UnlockModify(); 205 } 206 207 sal_Bool SwModify::GetInfo( SfxPoolItem& rInfo ) const 208 { 209 sal_Bool bRet = sal_True; // bedeutet weiter zum naechsten 210 211 if( pRoot ) 212 { 213 SwClientIter aIter( *(SwModify*)this ); 214 215 SwClient* pLast = aIter.GoStart(); 216 if( pLast ) 217 while( 0 != ( bRet = pLast->GetInfo( rInfo )) && 218 0 != ( pLast = ++aIter ) ) 219 ; 220 } 221 222 return bRet; 223 } 224 225 /*************************************************************************/ 226 void SwModify::Add(SwClient *pDepend) 227 { 228 ASSERT( !bLockClientList, "Client inserted while in Modify" ); 229 230 if(pDepend->pRegisteredIn != this ) 231 { 232 #ifdef DBG_UTIL 233 SwClientIter* pTmp = pClientIters; 234 while( pTmp ) 235 { 236 ASSERT( &pTmp->GetModify() != pRoot, "Client added to active ClientIter" ); 237 pTmp = pTmp->pNxtIter; 238 } 239 #endif 240 // deregister new client in case it is already registered elsewhere 241 if( pDepend->pRegisteredIn != 0 ) 242 pDepend->pRegisteredIn->Remove( pDepend ); 243 244 if( !pRoot ) 245 { 246 // first client added 247 pRoot = pDepend; 248 pRoot->pLeft = 0; 249 pRoot->pRight = 0; 250 } 251 else 252 { 253 // append client 254 pDepend->pRight = pRoot->pRight; 255 pRoot->pRight = pDepend; 256 pDepend->pLeft = pRoot; 257 if( pDepend->pRight ) 258 pDepend->pRight->pLeft = pDepend; 259 } 260 261 // connect client to me 262 pDepend->pRegisteredIn = this; 263 } 264 } 265 266 /*************************************************************************/ 267 268 SwClient* SwModify::Remove(SwClient * pDepend) 269 { 270 if ( bInDocDTOR ) 271 return 0; 272 273 ASSERT( !bLockClientList || pDepend->mbIsAllowedToBeRemovedInModifyCall, "SwClient shall be removed in Modify call!" ); 274 275 if( pDepend->pRegisteredIn == this ) 276 { 277 // SwClient is my listener 278 // remove it from my list 279 SwClient* pR = pDepend->pRight; 280 SwClient* pL = pDepend->pLeft; 281 if( pRoot == pDepend ) 282 pRoot = pL ? pL : pR; 283 284 if( pL ) 285 pL->pRight = pR; 286 if( pR ) 287 pR->pLeft = pL; 288 289 // update ClientIters 290 SwClientIter* pTmp = pClientIters; 291 while( pTmp ) 292 { 293 if( pTmp->pAct == pDepend || pTmp->pDelNext == pDepend ) 294 // if object being removed is the current or next object in an iterator, advance this iterator 295 pTmp->pDelNext = pR; 296 pTmp = pTmp->pNxtIter; 297 } 298 299 pDepend->pLeft = 0; 300 pDepend->pRight = 0; 301 } 302 else 303 { 304 ASSERT( false, "SwModify::Remove(): pDepend nicht gefunden" ); 305 } 306 307 // disconnect client from me 308 pDepend->pRegisteredIn = 0; 309 return pDepend; 310 } 311 312 int SwModify::GetClientCount() const 313 { 314 int nRet=0; 315 SwClientIter aIter( *this ); 316 SwClient *pLast = aIter.GoStart(); 317 if( pLast ) 318 do 319 { 320 ++nRet; 321 } while( 0 != ( pLast = ++aIter )); 322 return nRet; 323 } 324 325 void SwModify::CheckCaching( const sal_uInt16 nWhich ) 326 { 327 if (isCHRATR(nWhich)) 328 { 329 SetInSwFntCache( sal_False ); 330 } 331 else 332 switch ( nWhich ) 333 { 334 case RES_OBJECTDYING: 335 case RES_FMT_CHG: 336 case RES_ATTRSET_CHG: 337 SetInSwFntCache( sal_False ); 338 339 case RES_UL_SPACE: 340 case RES_LR_SPACE: 341 case RES_BOX: 342 case RES_SHADOW: 343 case RES_FRM_SIZE: 344 case RES_KEEP: 345 case RES_BREAK: 346 if ( IsInCache() ) 347 { 348 SwFrm::GetCache().Delete( this ); 349 SetInCache( sal_False ); 350 } 351 break; 352 } 353 } 354 355 void SwModify::CallSwClientNotify( const SfxHint& rHint ) const 356 { 357 SwClientIter aIter(*this); 358 SwClient * pClient = aIter.GoStart(); 359 while (pClient) 360 { 361 pClient->SwClientNotify( *this, rHint ); 362 pClient = ++aIter; 363 } 364 } 365 366 void SwModify::ModifyBroadcast( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue, TypeId nType ) 367 { 368 SwClientIter aIter(*this); 369 SwClient * pClient = aIter.First( nType ); 370 while (pClient) 371 { 372 pClient->Modify( pOldValue, pNewValue ); 373 pClient = aIter.Next(); 374 } 375 } 376 377 // ---------- 378 // SwDepend 379 // ---------- 380 381 /*************************************************************************/ 382 383 SwDepend::SwDepend(SwClient *pTellHim, SwModify *pDepend) 384 : SwClient(pDepend) 385 { 386 pToTell = pTellHim; 387 } 388 389 /*************************************************************************/ 390 391 void SwDepend::Modify( const SfxPoolItem* pOldValue, const SfxPoolItem *pNewValue ) 392 { 393 if(pNewValue && pNewValue->Which() == RES_OBJECTDYING) 394 CheckRegistration(pOldValue,pNewValue); 395 else if(pToTell) 396 pToTell->ModifyNotification(pOldValue, pNewValue); 397 } 398 399 void SwDepend::SwClientNotify( const SwModify& rMod, const SfxHint& rHint ) 400 { 401 if ( pToTell ) 402 pToTell->SwClientNotifyCall( rMod, rHint ); 403 } 404 405 sal_Bool SwDepend::GetInfo( SfxPoolItem& rInfo ) const 406 { 407 return pToTell ? pToTell->GetInfo( rInfo ) : sal_True; 408 } 409 410 /********************************************************************/ 411 412 SwClientIter::SwClientIter( const SwModify& rModify ) 413 : rRoot( rModify ) 414 { 415 pNxtIter = 0; 416 if( pClientIters ) 417 { 418 // append to list of ClientIters 419 SwClientIter* pTmp = pClientIters; 420 while( pTmp->pNxtIter ) 421 pTmp = pTmp->pNxtIter; 422 pTmp->pNxtIter = this; 423 } 424 else 425 pClientIters = this; 426 427 pAct = const_cast<SwClient*>(rRoot.GetDepends()); 428 pDelNext = pAct; 429 } 430 431 432 433 SwClientIter::~SwClientIter() 434 { 435 if( pClientIters ) 436 { 437 // reorganize list of ClientIters 438 if( pClientIters == this ) 439 pClientIters = pNxtIter; 440 else 441 { 442 SwClientIter* pTmp = pClientIters; 443 while( pTmp->pNxtIter != this ) 444 if( 0 == ( pTmp = pTmp->pNxtIter ) ) 445 { 446 ASSERT( this, "wo ist mein Pointer" ); 447 return ; 448 } 449 pTmp->pNxtIter = pNxtIter; 450 } 451 } 452 } 453 454 455 SwClient* SwClientIter::operator++() 456 { 457 if( pDelNext == pAct ) 458 { 459 pAct = pAct->pRight; 460 pDelNext = pAct; 461 } 462 else 463 pAct = pDelNext; 464 return pAct; 465 } 466 467 SwClient* SwClientIter::GoStart() 468 { 469 pAct = const_cast<SwClient*>(rRoot.GetDepends()); 470 if( pAct ) 471 while( pAct->pLeft ) 472 pAct = pAct->pLeft; 473 pDelNext = pAct; 474 return pAct; 475 } 476 477 SwClient* SwClientIter::GoEnd() 478 { 479 pAct = pDelNext; 480 if( !pAct ) 481 pAct = const_cast<SwClient*>(rRoot.GetDepends()); 482 if( pAct ) 483 while( pAct->pRight ) 484 pAct = pAct->pRight; 485 pDelNext = pAct; 486 return pAct; 487 } 488 489 SwClient* SwClientIter::First( TypeId nType ) 490 { 491 aSrchId = nType; 492 GoStart(); 493 if( pAct ) 494 do { 495 if( pAct->IsA( aSrchId ) ) 496 break; 497 498 if( pDelNext == pAct ) 499 { 500 pAct = pAct->pRight; 501 pDelNext = pAct; 502 } 503 else 504 pAct = pDelNext; 505 506 } while( pAct ); 507 return pAct; 508 } 509 510 SwClient* SwClientIter::Next() 511 { 512 do { 513 if( pDelNext == pAct ) 514 { 515 pAct = pAct->pRight; 516 pDelNext = pAct; 517 } 518 else 519 pAct = pDelNext; 520 521 if( pAct && pAct->IsA( aSrchId ) ) 522 break; 523 } while( pAct ); 524 return pAct; 525 } 526 527 SwClient* SwClientIter::Last( TypeId nType ) 528 { 529 aSrchId = nType; 530 GoEnd(); 531 if( pAct ) 532 do { 533 if( pAct->IsA( aSrchId ) ) 534 break; 535 536 if( pDelNext == pAct ) 537 pAct = pAct->pLeft; 538 else 539 pAct = pDelNext->pLeft; 540 pDelNext = pAct; 541 542 } while( pAct ); 543 return pAct; 544 } 545 546 SwClient* SwClientIter::Previous() 547 { 548 do { 549 if( pDelNext == pAct ) 550 pAct = pAct->pLeft; 551 else 552 pAct = pDelNext->pLeft; 553 pDelNext = pAct; 554 555 if( pAct && pAct->IsA( aSrchId ) ) 556 break; 557 } while( pAct ); 558 return pAct; 559 } 560 561