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 /*************************************************************************/
SwClient(SwModify * pToRegisterIn)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 /*************************************************************************/
CheckRegistration(const SfxPoolItem * pOld,const SfxPoolItem *)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
Modify(const SfxPoolItem * pOldValue,const SfxPoolItem * pNewValue)71 void SwClient::Modify( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue )
72 {
73 CheckRegistration( pOldValue, pNewValue );
74 }
75
SwClientNotify(const SwModify &,const SfxHint &)76 void SwClient::SwClientNotify( const SwModify&, const SfxHint& )
77 {
78
79 }
80
81 //*************************************************************************
~SwClient()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
GetInfo(SfxPoolItem &) const91 sal_Bool SwClient::GetInfo( SfxPoolItem& ) const
92 {
93 return sal_True; // und weiter
94 }
95
96
97 /*************************************************************************/
SwModify()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
SwModify(SwModify * pToRegisterIn)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 /*************************************************************************/
~SwModify()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 /*************************************************************************/
Modify(const SfxPoolItem * pOldValue,const SfxPoolItem * pNewValue)159 void SwModify::Modify( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue )
160 {
161 NotifyClients( pOldValue, pNewValue );
162 }
163
NotifyClients(const SfxPoolItem * pOldValue,const SfxPoolItem * pNewValue)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
GetInfo(SfxPoolItem & rInfo) const207 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 /*************************************************************************/
Add(SwClient * pDepend)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
Remove(SwClient * pDepend)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
GetClientCount() const312 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
CheckCaching(const sal_uInt16 nWhich)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
CallSwClientNotify(const SfxHint & rHint) const355 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
ModifyBroadcast(const SfxPoolItem * pOldValue,const SfxPoolItem * pNewValue,TypeId nType)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
SwDepend(SwClient * pTellHim,SwModify * pDepend)383 SwDepend::SwDepend(SwClient *pTellHim, SwModify *pDepend)
384 : SwClient(pDepend)
385 {
386 pToTell = pTellHim;
387 }
388
389 /*************************************************************************/
390
Modify(const SfxPoolItem * pOldValue,const SfxPoolItem * pNewValue)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
SwClientNotify(const SwModify & rMod,const SfxHint & rHint)399 void SwDepend::SwClientNotify( const SwModify& rMod, const SfxHint& rHint )
400 {
401 if ( pToTell )
402 pToTell->SwClientNotifyCall( rMod, rHint );
403 }
404
GetInfo(SfxPoolItem & rInfo) const405 sal_Bool SwDepend::GetInfo( SfxPoolItem& rInfo ) const
406 {
407 return pToTell ? pToTell->GetInfo( rInfo ) : sal_True;
408 }
409
410 /********************************************************************/
411
SwClientIter(const SwModify & rModify)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
~SwClientIter()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
operator ++()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
GoStart()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
GoEnd()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
First(TypeId nType)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
Next()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
Last(TypeId nType)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
Previous()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