Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <frame.hxx>
21 : #include <hintids.hxx> // contains RES_.. IDs
22 : #include <hints.hxx>
23 : #include <swcache.hxx> // mba: get rid of that dependency
24 : #include <swfntcch.hxx> // mba: get rid of that dependency
25 :
26 : static SwClientIter* pClientIters = 0;
27 :
28 550894 : TYPEINIT0( SwClient );
29 :
30 : // ----------
31 : // SwClient
32 : // ----------
33 :
34 201745 : SwClient::SwClient( SwModify* pToRegisterIn )
35 201745 : : pLeft( 0 ), pRight( 0 ), pRegisteredIn( 0 ), mbIsAllowedToBeRemovedInModifyCall( false )
36 : {
37 201745 : if(pToRegisterIn)
38 : // connect to SwModify
39 78395 : pToRegisterIn->Add(this);
40 201745 : }
41 :
42 11296 : void SwClient::CheckRegistration( const SfxPoolItem* pOld, const SfxPoolItem* )
43 : {
44 : // this method only handles notification about dying SwModify objects
45 11296 : if( (!pOld || pOld->Which() != RES_OBJECTDYING) )
46 11082 : return;
47 :
48 214 : const SwPtrMsgPoolItem* pDead = static_cast<const SwPtrMsgPoolItem*>(pOld);
49 214 : if(pDead && pDead->pObject == pRegisteredIn)
50 : {
51 : // I've got a notification from the object I know
52 214 : SwModify* pAbove = const_cast<SwModify*>(pRegisteredIn->GetRegisteredIn());
53 214 : if(pAbove)
54 : {
55 : // if the dying object itself was listening at an SwModify, I take over
56 : // adding myself to pAbove will automatically remove me from my current pRegisteredIn
57 0 : pAbove->Add(this);
58 0 : return;
59 : }
60 : // destroy connection
61 214 : pRegisteredIn->Remove(this);
62 : }
63 : }
64 :
65 10390 : void SwClient::Modify( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue )
66 : {
67 10390 : CheckRegistration( pOldValue, pNewValue );
68 10390 : }
69 :
70 153 : void SwClient::SwClientNotify( const SwModify&, const SfxHint& )
71 : {
72 153 : }
73 :
74 356324 : SwClient::~SwClient()
75 : {
76 : OSL_ENSURE( !pRegisteredIn || pRegisteredIn->GetDepends(), "SwModify still known, but Client already disconnected!" );
77 178162 : if( pRegisteredIn && pRegisteredIn->GetDepends() )
78 : // still connected
79 59220 : pRegisteredIn->Remove( this );
80 178162 : }
81 :
82 380 : bool SwClient::GetInfo( SfxPoolItem& ) const
83 : {
84 380 : return true;
85 : }
86 :
87 : // ----------
88 : // SwModify
89 : // ----------
90 :
91 4513 : SwModify::SwModify()
92 4513 : : SwClient(0), pRoot(0)
93 : {
94 4513 : bModifyLocked = false;
95 4513 : bLockClientList = sal_False;
96 4513 : bInDocDTOR = sal_False;
97 4513 : bInCache = sal_False;
98 4513 : bInSwFntCache = sal_False;
99 4513 : }
100 :
101 70900 : SwModify::SwModify( SwModify* pToRegisterIn )
102 70900 : : SwClient( pToRegisterIn ), pRoot( 0 )
103 : {
104 70900 : bModifyLocked = false;
105 70900 : bLockClientList = sal_False;
106 70900 : bInDocDTOR = sal_False;
107 70900 : bInCache = sal_False;
108 70900 : bInSwFntCache = sal_False;
109 70900 : }
110 :
111 92592 : SwModify::~SwModify()
112 : {
113 : OSL_ENSURE( !IsModifyLocked(), "Modify destroyed but locked." );
114 :
115 46221 : if ( IsInCache() )
116 694 : SwFrm::GetCache().Delete( this );
117 :
118 46221 : if ( IsInSwFntCache() )
119 0 : pSwFontCache->Delete( this );
120 :
121 46221 : if( pRoot )
122 : {
123 : // there are depending objects
124 14434 : if( IsInDocDTOR() )
125 : {
126 : // If the document gets destroyed anyway, just tell clients to
127 : // forget me so that they don't try to get removed from my list
128 : // later when they also get destroyed
129 0 : SwClientIter aIter( *this );
130 0 : SwClient* p = aIter.GoStart();
131 0 : while ( p )
132 : {
133 0 : p->pRegisteredIn = 0;
134 0 : p = ++aIter;
135 0 : }
136 : }
137 : else
138 : {
139 : // notify all clients that they shall remove themselves
140 14434 : SwPtrMsgPoolItem aDyObject( RES_OBJECTDYING, this );
141 14434 : NotifyClients( &aDyObject, &aDyObject );
142 :
143 : // remove all clients that have not done themselves
144 : // mba: possibly a hotfix for forgotten base class calls?!
145 29080 : while( pRoot )
146 14646 : pRoot->CheckRegistration( &aDyObject, &aDyObject );
147 : }
148 : }
149 46371 : }
150 :
151 13668 : void SwModify::Modify( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue )
152 : {
153 13668 : NotifyClients( pOldValue, pNewValue );
154 13668 : }
155 :
156 211286 : void SwModify::NotifyClients( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue )
157 : {
158 211286 : if ( IsInCache() || IsInSwFntCache() )
159 : {
160 : const sal_uInt16 nWhich = pOldValue ? pOldValue->Which() :
161 727 : pNewValue ? pNewValue->Which() : 0;
162 727 : CheckCaching( nWhich );
163 : }
164 :
165 211286 : if ( !pRoot || IsModifyLocked() )
166 336910 : return;
167 :
168 85662 : LockModify();
169 :
170 : // mba: WTF?!
171 85662 : if( !pOldValue )
172 : {
173 18501 : bLockClientList = sal_True;
174 : }
175 : else
176 : {
177 67161 : switch( pOldValue->Which() )
178 : {
179 : case RES_OBJECTDYING:
180 : case RES_REMOVE_UNO_OBJECT:
181 14530 : bLockClientList = ((SwPtrMsgPoolItem*)pOldValue)->pObject != this;
182 14530 : break;
183 :
184 : case RES_FOOTNOTE_DELETED:
185 : case RES_REFMARK_DELETED:
186 : case RES_TOXMARK_DELETED:
187 : case RES_FIELD_DELETED:
188 4 : bLockClientList = sal_False;
189 4 : break;
190 :
191 : default:
192 52627 : bLockClientList = sal_True;
193 : }
194 : }
195 :
196 85662 : ModifyBroadcast( pOldValue, pNewValue );
197 85662 : bLockClientList = sal_False;
198 85662 : UnlockModify();
199 : }
200 :
201 16594 : bool SwModify::GetInfo( SfxPoolItem& rInfo ) const
202 : {
203 16594 : bool bRet = true; // means: continue with next
204 :
205 16594 : if( pRoot )
206 : {
207 3472 : SwClientIter aIter( *(SwModify*)this );
208 :
209 3472 : SwClient* pLast = aIter.GoStart();
210 3472 : if( pLast )
211 : {
212 3472 : while( ( bRet = pLast->GetInfo( rInfo ) ) &&
213 : 0 != ( pLast = ++aIter ) )
214 : ;
215 3472 : }
216 : }
217 :
218 16594 : return bRet;
219 : }
220 :
221 126731 : void SwModify::Add( SwClient* pDepend )
222 : {
223 : OSL_ENSURE( !bLockClientList, "Client inserted while in Modify" );
224 :
225 126731 : if(pDepend->pRegisteredIn != this )
226 : {
227 : #if OSL_DEBUG_LEVEL > 0
228 : SwClientIter* pTmp = pClientIters;
229 : while( pTmp )
230 : {
231 : OSL_ENSURE( &pTmp->GetModify() != pRoot, "Client added to active ClientIter" );
232 : pTmp = pTmp->pNxtIter;
233 : }
234 : #endif
235 : // deregister new client in case it is already registered elsewhere
236 119126 : if( pDepend->pRegisteredIn != 0 )
237 7140 : pDepend->pRegisteredIn->Remove( pDepend );
238 :
239 119126 : if( !pRoot )
240 : {
241 : // first client added
242 59442 : pRoot = pDepend;
243 59442 : pRoot->pLeft = 0;
244 59442 : pRoot->pRight = 0;
245 : }
246 : else
247 : {
248 : // append client
249 59684 : pDepend->pRight = pRoot->pRight;
250 59684 : pRoot->pRight = pDepend;
251 59684 : pDepend->pLeft = pRoot;
252 59684 : if( pDepend->pRight )
253 42288 : pDepend->pRight->pLeft = pDepend;
254 : }
255 :
256 : // connect client to me
257 119126 : pDepend->pRegisteredIn = this;
258 : }
259 126731 : }
260 :
261 101604 : SwClient* SwModify::Remove( SwClient* pDepend )
262 : {
263 101604 : if ( bInDocDTOR )
264 0 : return 0;
265 :
266 : OSL_ENSURE( !bLockClientList || pDepend->mbIsAllowedToBeRemovedInModifyCall, "SwClient shall be removed in Modify call!" );
267 :
268 101604 : if( pDepend->pRegisteredIn == this )
269 : {
270 : // SwClient is my listener
271 : // remove it from my list
272 101604 : SwClient* pR = pDepend->pRight;
273 101604 : SwClient* pL = pDepend->pLeft;
274 101604 : if( pRoot == pDepend )
275 65781 : pRoot = pL ? pL : pR;
276 :
277 101604 : if( pL )
278 35823 : pL->pRight = pR;
279 101604 : if( pR )
280 39938 : pR->pLeft = pL;
281 :
282 : // update ClientIters
283 101604 : SwClientIter* pTmp = pClientIters;
284 221891 : while( pTmp )
285 : {
286 18683 : if( pTmp->pAct == pDepend || pTmp->pDelNext == pDepend )
287 : {
288 : // if object being removed is the current or next object in an
289 : // iterator, advance this iterator
290 14397 : pTmp->pDelNext = pR;
291 : }
292 18683 : pTmp = pTmp->pNxtIter;
293 : }
294 :
295 101604 : pDepend->pLeft = 0;
296 101604 : pDepend->pRight = 0;
297 : }
298 : else
299 : {
300 : OSL_FAIL( "SwModify::Remove(): could not find pDepend" );
301 : }
302 :
303 : // disconnect client from me
304 101604 : pDepend->pRegisteredIn = 0;
305 101604 : return pDepend;
306 : }
307 :
308 1153 : void SwModify::CheckCaching( const sal_uInt16 nWhich )
309 : {
310 1153 : if( isCHRATR( nWhich ) )
311 : {
312 0 : SetInSwFntCache( sal_False );
313 : }
314 : else
315 : {
316 1153 : switch( nWhich )
317 : {
318 : case RES_OBJECTDYING:
319 : case RES_FMT_CHG:
320 : case RES_ATTRSET_CHG:
321 688 : SetInSwFntCache( sal_False );
322 :
323 : case RES_UL_SPACE:
324 : case RES_LR_SPACE:
325 : case RES_BOX:
326 : case RES_SHADOW:
327 : case RES_FRM_SIZE:
328 : case RES_KEEP:
329 : case RES_BREAK:
330 690 : if( IsInCache() )
331 : {
332 594 : SwFrm::GetCache().Delete( this );
333 594 : SetInCache( sal_False );
334 : }
335 690 : break;
336 : }
337 : }
338 1153 : }
339 :
340 955 : void SwModify::CallSwClientNotify( const SfxHint& rHint ) const
341 : {
342 955 : SwClientIter aIter(*this);
343 955 : SwClient* pClient = aIter.GoStart();
344 2063 : while( pClient )
345 : {
346 153 : pClient->SwClientNotify( *this, rHint );
347 153 : pClient = ++aIter;
348 955 : }
349 955 : }
350 :
351 85905 : void SwModify::ModifyBroadcast( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue, TypeId nType )
352 : {
353 85905 : SwClientIter aIter( *this );
354 85905 : SwClient* pClient = aIter.First( nType );
355 325679 : while( pClient )
356 : {
357 153869 : pClient->Modify( pOldValue, pNewValue );
358 153869 : pClient = aIter.Next();
359 85905 : }
360 85905 : }
361 :
362 : // ----------
363 : // SwDepend
364 : // ----------
365 :
366 14434 : SwDepend::SwDepend( SwClient* pTellHim, SwModify* pDepend )
367 14434 : : SwClient( pDepend )
368 : {
369 14434 : pToTell = pTellHim;
370 14434 : }
371 :
372 30 : void SwDepend::Modify( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue )
373 : {
374 30 : if( pNewValue && pNewValue->Which() == RES_OBJECTDYING )
375 2 : CheckRegistration(pOldValue,pNewValue);
376 28 : else if( pToTell )
377 28 : pToTell->ModifyNotification(pOldValue, pNewValue);
378 30 : }
379 :
380 0 : void SwDepend::SwClientNotify( const SwModify& rMod, const SfxHint& rHint )
381 : {
382 0 : if ( pToTell )
383 0 : pToTell->SwClientNotifyCall( rMod, rHint );
384 0 : }
385 :
386 0 : bool SwDepend::GetInfo( SfxPoolItem& rInfo ) const
387 : {
388 0 : return pToTell ? pToTell->GetInfo( rInfo ) : true;
389 : }
390 :
391 : // ------------
392 : // SwClientIter
393 : // ------------
394 :
395 174985 : SwClientIter::SwClientIter( const SwModify& rModify )
396 174985 : : rRoot( rModify )
397 : {
398 174985 : pNxtIter = 0;
399 174985 : if( pClientIters )
400 : {
401 : // append to list of ClientIters
402 31330 : SwClientIter* pTmp = pClientIters;
403 84869 : while( pTmp->pNxtIter )
404 22209 : pTmp = pTmp->pNxtIter;
405 31330 : pTmp->pNxtIter = this;
406 : }
407 : else
408 143655 : pClientIters = this;
409 :
410 174985 : pAct = const_cast<SwClient*>(rRoot.GetDepends());
411 174985 : pDelNext = pAct;
412 174985 : }
413 :
414 :
415 :
416 174985 : SwClientIter::~SwClientIter()
417 : {
418 174985 : if( pClientIters )
419 : {
420 : // reorganize list of ClientIters
421 174985 : if( pClientIters == this )
422 143655 : pClientIters = pNxtIter;
423 : else
424 : {
425 31330 : SwClientIter* pTmp = pClientIters;
426 84869 : while( pTmp->pNxtIter != this )
427 22209 : if( 0 == ( pTmp = pTmp->pNxtIter ) )
428 : {
429 : OSL_ENSURE( this, "Lost my pointer" );
430 0 : return ;
431 : }
432 31330 : pTmp->pNxtIter = pNxtIter;
433 : }
434 : }
435 174985 : }
436 :
437 5104 : SwClient* SwClientIter::operator++()
438 : {
439 5104 : if( pDelNext == pAct )
440 : {
441 5104 : pAct = pAct->pRight;
442 5104 : pDelNext = pAct;
443 : }
444 : else
445 0 : pAct = pDelNext;
446 5104 : return pAct;
447 : }
448 :
449 174841 : SwClient* SwClientIter::GoStart()
450 : {
451 174841 : pAct = const_cast<SwClient*>(rRoot.GetDepends());
452 174841 : if( pAct )
453 : {
454 303146 : while( pAct->pLeft )
455 0 : pAct = pAct->pLeft;
456 : }
457 174841 : pDelNext = pAct;
458 174841 : return pAct;
459 : }
460 :
461 72 : SwClient* SwClientIter::GoEnd()
462 : {
463 72 : pAct = pDelNext;
464 72 : if( !pAct )
465 72 : pAct = const_cast<SwClient*>(rRoot.GetDepends());
466 72 : if( pAct )
467 : {
468 0 : while( pAct->pRight )
469 0 : pAct = pAct->pRight;
470 : }
471 72 : pDelNext = pAct;
472 72 : return pAct;
473 : }
474 :
475 169386 : SwClient* SwClientIter::First( TypeId nType )
476 : {
477 169386 : aSrchId = nType;
478 169386 : GoStart();
479 169386 : if( pAct )
480 41237 : do {
481 182269 : if( pAct->IsA( aSrchId ) )
482 141032 : break;
483 :
484 41237 : if( pDelNext == pAct )
485 : {
486 41237 : pAct = pAct->pRight;
487 41237 : pDelNext = pAct;
488 : }
489 : else
490 0 : pAct = pDelNext;
491 : } while( pAct );
492 169386 : return pAct;
493 : }
494 :
495 72 : SwClient* SwClientIter::Last( TypeId nType )
496 : {
497 72 : aSrchId = nType;
498 72 : GoEnd();
499 72 : if( pAct )
500 0 : do {
501 0 : if( pAct->IsA( aSrchId ) )
502 0 : break;
503 :
504 0 : if( pDelNext == pAct )
505 0 : pAct = pAct->pLeft;
506 : else
507 0 : pAct = pDelNext->pLeft;
508 0 : pDelNext = pAct;
509 : } while( pAct );
510 72 : return pAct;
511 : }
512 :
513 172696 : SwClient* SwClientIter::Next()
514 : {
515 104343 : do {
516 172696 : if( pDelNext == pAct )
517 : {
518 158299 : pAct = pAct->pRight;
519 158299 : pDelNext = pAct;
520 : }
521 : else
522 14397 : pAct = pDelNext;
523 :
524 172696 : if( pAct && pAct->IsA( aSrchId ) )
525 68353 : break;
526 : } while( pAct );
527 165636 : return pAct;
528 : }
529 :
530 0 : SwClient* SwClientIter::Previous()
531 : {
532 0 : do {
533 0 : if( pDelNext == pAct )
534 0 : pAct = pAct->pLeft;
535 : else
536 0 : pAct = pDelNext->pLeft;
537 0 : pDelNext = pAct;
538 :
539 0 : if( pAct && pAct->IsA( aSrchId ) )
540 0 : break;
541 : } while( pAct );
542 0 : return pAct;
543 : }
544 :
545 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|