xref: /AOO41X/main/sw/source/core/attr/calbck.cxx (revision efeef26f81c84063fb0a91bde3856d4a51172d90)
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