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 1017151 : TYPEINIT0( SwClient );
29 :
30 : // ----------
31 : // SwClient
32 : // ----------
33 :
34 335084 : SwClient::SwClient( SwModify* pToRegisterIn )
35 335084 : : pLeft( 0 ), pRight( 0 ), pRegisteredIn( 0 ), mbIsAllowedToBeRemovedInModifyCall( false )
36 : {
37 335084 : if(pToRegisterIn)
38 : // connect to SwModify
39 89044 : pToRegisterIn->Add(this);
40 335084 : }
41 :
42 15486 : void SwClient::CheckRegistration( const SfxPoolItem* pOld, const SfxPoolItem* )
43 : {
44 : // this method only handles notification about dying SwModify objects
45 15486 : if( (!pOld || pOld->Which() != RES_OBJECTDYING) )
46 14523 : return;
47 :
48 963 : const SwPtrMsgPoolItem* pDead = static_cast<const SwPtrMsgPoolItem*>(pOld);
49 963 : if(pDead && pDead->pObject == pRegisteredIn)
50 : {
51 : // I've got a notification from the object I know
52 963 : SwModify* pAbove = const_cast<SwModify*>(pRegisteredIn->GetRegisteredIn());
53 963 : 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 20 : pAbove->Add(this);
58 20 : return;
59 : }
60 : // destroy connection
61 943 : pRegisteredIn->Remove(this);
62 : }
63 : }
64 :
65 11720 : void SwClient::Modify( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue )
66 : {
67 11720 : CheckRegistration( pOldValue, pNewValue );
68 11720 : }
69 :
70 321 : void SwClient::SwClientNotify( const SwModify&, const SfxHint& )
71 : {
72 321 : }
73 :
74 757106 : SwClient::~SwClient()
75 : {
76 : OSL_ENSURE( !pRegisteredIn || pRegisteredIn->GetDepends(), "SwModify still known, but Client already disconnected!" );
77 378553 : if( pRegisteredIn && pRegisteredIn->GetDepends() )
78 : // still connected
79 87206 : pRegisteredIn->Remove( this );
80 378553 : }
81 :
82 2526 : bool SwClient::GetInfo( SfxPoolItem& ) const
83 : {
84 2526 : return true;
85 : }
86 :
87 : // ----------
88 : // SwModify
89 : // ----------
90 :
91 14079 : SwModify::SwModify()
92 14079 : : SwClient(0), pRoot(0)
93 : {
94 14079 : bModifyLocked = false;
95 14079 : bLockClientList = sal_False;
96 14079 : bInDocDTOR = sal_False;
97 14079 : bInCache = sal_False;
98 14079 : bInSwFntCache = sal_False;
99 14079 : }
100 :
101 109674 : SwModify::SwModify( SwModify* pToRegisterIn )
102 109674 : : SwClient( pToRegisterIn ), pRoot( 0 )
103 : {
104 109674 : bModifyLocked = false;
105 109674 : bLockClientList = sal_False;
106 109674 : bInDocDTOR = sal_False;
107 109674 : bInCache = sal_False;
108 109674 : bInSwFntCache = sal_False;
109 109674 : }
110 :
111 247977 : SwModify::~SwModify()
112 : {
113 : OSL_ENSURE( !IsModifyLocked(), "Modify destroyed but locked." );
114 :
115 123541 : if ( IsInCache() )
116 3404 : SwFrm::GetCache().Delete( this );
117 :
118 123541 : if ( IsInSwFntCache() )
119 0 : pSwFontCache->Delete( this );
120 :
121 123541 : if( pRoot )
122 : {
123 : // there are depending objects
124 31694 : 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 31 : SwClientIter aIter( *this );
130 31 : SwClient* p = aIter.GoStart();
131 173 : while ( p )
132 : {
133 111 : p->pRegisteredIn = 0;
134 111 : p = ++aIter;
135 31 : }
136 : }
137 : else
138 : {
139 : // notify all clients that they shall remove themselves
140 31663 : SwPtrMsgPoolItem aDyObject( RES_OBJECTDYING, this );
141 31663 : NotifyClients( &aDyObject, &aDyObject );
142 :
143 : // remove all clients that have not done themselves
144 : // mba: possibly a hotfix for forgotten base class calls?!
145 64211 : while( pRoot )
146 32548 : pRoot->CheckRegistration( &aDyObject, &aDyObject );
147 : }
148 : }
149 124436 : }
150 :
151 25529 : void SwModify::Modify( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue )
152 : {
153 25529 : NotifyClients( pOldValue, pNewValue );
154 25529 : }
155 :
156 279225 : void SwModify::NotifyClients( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue )
157 : {
158 279225 : if ( IsInCache() || IsInSwFntCache() )
159 : {
160 : const sal_uInt16 nWhich = pOldValue ? pOldValue->Which() :
161 9662 : pNewValue ? pNewValue->Which() : 0;
162 9662 : CheckCaching( nWhich );
163 : }
164 :
165 279225 : if ( !pRoot || IsModifyLocked() )
166 435530 : return;
167 :
168 122920 : LockModify();
169 :
170 : // mba: WTF?!
171 122920 : if( !pOldValue )
172 : {
173 16395 : bLockClientList = sal_True;
174 : }
175 : else
176 : {
177 106525 : switch( pOldValue->Which() )
178 : {
179 : case RES_OBJECTDYING:
180 : case RES_REMOVE_UNO_OBJECT:
181 32007 : bLockClientList = ((SwPtrMsgPoolItem*)pOldValue)->pObject != this;
182 32007 : break;
183 :
184 : case RES_FOOTNOTE_DELETED:
185 : case RES_REFMARK_DELETED:
186 : case RES_TOXMARK_DELETED:
187 : case RES_FIELD_DELETED:
188 44 : bLockClientList = sal_False;
189 44 : break;
190 :
191 : default:
192 74474 : bLockClientList = sal_True;
193 : }
194 : }
195 :
196 122920 : ModifyBroadcast( pOldValue, pNewValue );
197 122920 : bLockClientList = sal_False;
198 122920 : UnlockModify();
199 : }
200 :
201 131367 : bool SwModify::GetInfo( SfxPoolItem& rInfo ) const
202 : {
203 131367 : bool bRet = true; // means: continue with next
204 :
205 131367 : if( pRoot )
206 : {
207 51444 : SwClientIter aIter( *(SwModify*)this );
208 :
209 51444 : SwClient* pLast = aIter.GoStart();
210 51444 : if( pLast )
211 : {
212 51444 : while( ( bRet = pLast->GetInfo( rInfo ) ) &&
213 : 0 != ( pLast = ++aIter ) )
214 : ;
215 51444 : }
216 : }
217 :
218 131367 : return bRet;
219 : }
220 :
221 191973 : void SwModify::Add( SwClient* pDepend )
222 : {
223 : OSL_ENSURE( !bLockClientList, "Client inserted while in Modify" );
224 :
225 191973 : 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 163635 : if( pDepend->pRegisteredIn != 0 )
237 10973 : pDepend->pRegisteredIn->Remove( pDepend );
238 :
239 163635 : if( !pRoot )
240 : {
241 : // first client added
242 85679 : pRoot = pDepend;
243 85679 : pRoot->pLeft = 0;
244 85679 : pRoot->pRight = 0;
245 : }
246 : else
247 : {
248 : // append client
249 77956 : pDepend->pRight = pRoot->pRight;
250 77956 : pRoot->pRight = pDepend;
251 77956 : pDepend->pLeft = pRoot;
252 77956 : if( pDepend->pRight )
253 51543 : pDepend->pRight->pLeft = pDepend;
254 : }
255 :
256 : // connect client to me
257 163635 : pDepend->pRegisteredIn = this;
258 : }
259 191973 : }
260 :
261 163387 : SwClient* SwModify::Remove( SwClient* pDepend )
262 : {
263 163387 : if ( bInDocDTOR )
264 0 : return 0;
265 :
266 : OSL_ENSURE( !bLockClientList || pDepend->mbIsAllowedToBeRemovedInModifyCall, "SwClient shall be removed in Modify call!" );
267 :
268 163387 : if( pDepend->pRegisteredIn == this )
269 : {
270 : // SwClient is my listener
271 : // remove it from my list
272 163387 : SwClient* pR = pDepend->pRight;
273 163387 : SwClient* pL = pDepend->pLeft;
274 163387 : if( pRoot == pDepend )
275 109379 : pRoot = pL ? pL : pR;
276 :
277 163387 : if( pL )
278 54008 : pL->pRight = pR;
279 163387 : if( pR )
280 58751 : pR->pLeft = pL;
281 :
282 : // update ClientIters
283 163387 : SwClientIter* pTmp = pClientIters;
284 363518 : while( pTmp )
285 : {
286 36744 : 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 31970 : pTmp->pDelNext = pR;
291 : }
292 36744 : pTmp = pTmp->pNxtIter;
293 : }
294 :
295 163387 : pDepend->pLeft = 0;
296 163387 : pDepend->pRight = 0;
297 : }
298 : else
299 : {
300 : OSL_FAIL( "SwModify::Remove(): could not find pDepend" );
301 : }
302 :
303 : // disconnect client from me
304 163387 : pDepend->pRegisteredIn = 0;
305 163387 : return pDepend;
306 : }
307 :
308 10177 : void SwModify::CheckCaching( const sal_uInt16 nWhich )
309 : {
310 10177 : if( isCHRATR( nWhich ) )
311 : {
312 0 : SetInSwFntCache( sal_False );
313 : }
314 : else
315 : {
316 10177 : switch( nWhich )
317 : {
318 : case RES_OBJECTDYING:
319 : case RES_FMT_CHG:
320 : case RES_ATTRSET_CHG:
321 4391 : 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 4423 : if( IsInCache() )
331 : {
332 3394 : SwFrm::GetCache().Delete( this );
333 3394 : SetInCache( sal_False );
334 : }
335 4423 : break;
336 : }
337 : }
338 10177 : }
339 :
340 960 : void SwModify::CallSwClientNotify( const SfxHint& rHint ) const
341 : {
342 960 : SwClientIter aIter(*this);
343 960 : SwClient* pClient = aIter.GoStart();
344 2264 : while( pClient )
345 : {
346 344 : pClient->SwClientNotify( *this, rHint );
347 344 : pClient = ++aIter;
348 960 : }
349 960 : }
350 :
351 123278 : void SwModify::ModifyBroadcast( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue, TypeId nType )
352 : {
353 123278 : SwClientIter aIter( *this );
354 123278 : SwClient* pClient = aIter.First( nType );
355 468310 : while( pClient )
356 : {
357 221754 : pClient->Modify( pOldValue, pNewValue );
358 221754 : pClient = aIter.Next();
359 123278 : }
360 123278 : }
361 :
362 : // ----------
363 : // SwDepend
364 : // ----------
365 :
366 29286 : SwDepend::SwDepend( SwClient* pTellHim, SwModify* pDepend )
367 29286 : : SwClient( pDepend )
368 : {
369 29286 : pToTell = pTellHim;
370 29286 : }
371 :
372 343 : void SwDepend::Modify( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue )
373 : {
374 343 : if( pNewValue && pNewValue->Which() == RES_OBJECTDYING )
375 46 : CheckRegistration(pOldValue,pNewValue);
376 297 : else if( pToTell )
377 297 : pToTell->ModifyNotification(pOldValue, pNewValue);
378 343 : }
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 468917 : SwClientIter::SwClientIter( const SwModify& rModify )
396 468917 : : rRoot( rModify )
397 : {
398 468917 : pNxtIter = 0;
399 468917 : if( pClientIters )
400 : {
401 : // append to list of ClientIters
402 62486 : SwClientIter* pTmp = pClientIters;
403 159918 : while( pTmp->pNxtIter )
404 34946 : pTmp = pTmp->pNxtIter;
405 62486 : pTmp->pNxtIter = this;
406 : }
407 : else
408 406431 : pClientIters = this;
409 :
410 468917 : pAct = const_cast<SwClient*>(rRoot.GetDepends());
411 468917 : pDelNext = pAct;
412 468917 : }
413 :
414 :
415 :
416 468917 : SwClientIter::~SwClientIter()
417 : {
418 468917 : if( pClientIters )
419 : {
420 : // reorganize list of ClientIters
421 468917 : if( pClientIters == this )
422 406431 : pClientIters = pNxtIter;
423 : else
424 : {
425 62486 : SwClientIter* pTmp = pClientIters;
426 159918 : while( pTmp->pNxtIter != this )
427 34946 : if( 0 == ( pTmp = pTmp->pNxtIter ) )
428 : {
429 : OSL_ENSURE( this, "Lost my pointer" );
430 0 : return ;
431 : }
432 62486 : pTmp->pNxtIter = pNxtIter;
433 : }
434 : }
435 468917 : }
436 :
437 32617 : SwClient* SwClientIter::operator++()
438 : {
439 32617 : if( pDelNext == pAct )
440 : {
441 32595 : pAct = pAct->pRight;
442 32595 : pDelNext = pAct;
443 : }
444 : else
445 22 : pAct = pDelNext;
446 32617 : return pAct;
447 : }
448 :
449 468727 : SwClient* SwClientIter::GoStart()
450 : {
451 468727 : pAct = const_cast<SwClient*>(rRoot.GetDepends());
452 468727 : if( pAct )
453 : {
454 894560 : while( pAct->pLeft )
455 0 : pAct = pAct->pLeft;
456 : }
457 468727 : pDelNext = pAct;
458 468727 : return pAct;
459 : }
460 :
461 148 : SwClient* SwClientIter::GoEnd()
462 : {
463 148 : pAct = pDelNext;
464 148 : if( !pAct )
465 148 : pAct = const_cast<SwClient*>(rRoot.GetDepends());
466 148 : if( pAct )
467 : {
468 0 : while( pAct->pRight )
469 0 : pAct = pAct->pRight;
470 : }
471 148 : pDelNext = pAct;
472 148 : return pAct;
473 : }
474 :
475 415517 : SwClient* SwClientIter::First( TypeId nType )
476 : {
477 415517 : aSrchId = nType;
478 415517 : GoStart();
479 415517 : if( pAct )
480 78477 : do {
481 466642 : if( pAct->IsA( aSrchId ) )
482 388165 : break;
483 :
484 78477 : if( pDelNext == pAct )
485 : {
486 78477 : pAct = pAct->pRight;
487 78477 : pDelNext = pAct;
488 : }
489 : else
490 0 : pAct = pDelNext;
491 : } while( pAct );
492 415517 : return pAct;
493 : }
494 :
495 148 : SwClient* SwClientIter::Last( TypeId nType )
496 : {
497 148 : aSrchId = nType;
498 148 : GoEnd();
499 148 : 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 148 : return pAct;
511 : }
512 :
513 384092 : SwClient* SwClientIter::Next()
514 : {
515 251823 : do {
516 384092 : if( pDelNext == pAct )
517 : {
518 352153 : pAct = pAct->pRight;
519 352153 : pDelNext = pAct;
520 : }
521 : else
522 31939 : pAct = pDelNext;
523 :
524 384092 : if( pAct && pAct->IsA( aSrchId ) )
525 132269 : break;
526 : } while( pAct );
527 309214 : 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 99 : }
544 :
545 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|