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