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