xref: /aoo42x/main/sw/source/core/attr/calbck.cxx (revision 2f121198)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 #include <hintids.hxx>		    // contains RES_.. IDs
32 #include <frame.hxx>
33 #include <hints.hxx>
34 #include <swcache.hxx>          // mba: get rid of that dependency
35 #include <swfntcch.hxx>         // mba: get rid of that dependency
36 
37 static SwClientIter* pClientIters = 0;
38 
39 TYPEINIT0(SwClient);
40 
41 /*************************************************************************/
42 SwClient::SwClient(SwModify *pToRegisterIn)
43 	: pLeft( 0 ), pRight( 0 ), pRegisteredIn( 0 ), mbIsAllowedToBeRemovedInModifyCall(false)
44 {
45 	if(pToRegisterIn)
46         // connect to SwModify
47 		pToRegisterIn->Add(this);
48 }
49 
50 /*************************************************************************/
51 void SwClient::CheckRegistration( const SfxPoolItem* pOld, const SfxPoolItem * )
52 {
53     // this method only handles notification about dying SwModify objects
54 	if( (!pOld || pOld->Which() != RES_OBJECTDYING) )
55 		return;
56 
57 	const SwPtrMsgPoolItem *pDead = static_cast<const SwPtrMsgPoolItem*>(pOld);
58 	if(pDead && pDead->pObject == pRegisteredIn)
59 	{
60         // I've got a notification from the object I know
61 		SwModify *pAbove = const_cast<SwModify*>(pRegisteredIn->GetRegisteredIn());
62 		if(pAbove)
63 		{
64             // if the dying object itself was listening at an SwModify, I take over
65             // adding myself to pAbove will automatically remove me from my current pRegisteredIn
66 			pAbove->Add(this);
67 			return;
68 		}
69 
70         // destroy connection
71 		pRegisteredIn->Remove(this);
72 	}
73 }
74 
75 void SwClient::Modify( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue )
76 {
77     CheckRegistration( pOldValue, pNewValue );
78 }
79 
80 void SwClient::SwClientNotify( const SwModify&, const SfxHint& )
81 {
82 
83 }
84 
85 //*************************************************************************
86 SwClient::~SwClient()
87 {
88     DBG_ASSERT( !pRegisteredIn || pRegisteredIn->GetDepends(),"SwModify still known, but Client already disconnected!" );
89 	if( pRegisteredIn && pRegisteredIn->GetDepends() )
90         // still connected
91 		pRegisteredIn->Remove( this );
92 }
93 
94 
95 sal_Bool SwClient::GetInfo( SfxPoolItem& ) const
96 {
97 	return sal_True;		// und weiter
98 }
99 
100 
101 /*************************************************************************/
102 SwModify::SwModify()
103     : SwClient(0), pRoot(0)
104 {
105     bModifyLocked = sal_False;
106     bLockClientList = sal_False;
107 	bInDocDTOR = sal_False;
108 	bInCache = sal_False;
109 	bInSwFntCache = sal_False;
110 }
111 
112 SwModify::SwModify( SwModify *pToRegisterIn )
113 	: SwClient(pToRegisterIn), pRoot( 0 )
114 {
115     bModifyLocked = sal_False;
116     bLockClientList = sal_False;
117 	bInDocDTOR = sal_False;
118 	bInCache = sal_False;
119 	bInSwFntCache = sal_False;
120 }
121 
122 /*************************************************************************/
123 SwModify::~SwModify()
124 {
125 	ASSERT( !IsModifyLocked(), "Modify destroyed but locked." );
126 
127 	if ( IsInCache() )
128 		SwFrm::GetCache().Delete( this );
129 
130 	if ( IsInSwFntCache() )
131 		pSwFontCache->Delete( this );
132 
133 	if( pRoot )
134 	{
135         // there are depending objects
136 		if( IsInDocDTOR() )
137 		{
138 			// if document gets destroyed anyway, just tell clients to forget me
139             // so that they don't try to get removed from my list later when they also get destroyed
140 			SwClientIter aIter( *this );
141 			SwClient* p = aIter.GoStart();
142 			while ( p )
143             {
144 				p->pRegisteredIn = 0;
145                 p = ++aIter;
146             }
147 		}
148 		else
149 		{
150 			// notify all clients that they shall remove themselves
151 			SwPtrMsgPoolItem aDyObject( RES_OBJECTDYING, this );
152 			NotifyClients( &aDyObject, &aDyObject );
153 
154             // remove all clients that have not done themselves
155             // mba: possibly a hotfix for forgotten base class calls?!
156 			while( pRoot )
157 				pRoot->CheckRegistration(&aDyObject, &aDyObject);
158 		}
159 	}
160 }
161 
162 /*************************************************************************/
163 void SwModify::Modify( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue )
164 {
165     NotifyClients( pOldValue, pNewValue );
166 }
167 
168 void SwModify::NotifyClients( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue )
169 {
170 	if (IsInCache() || IsInSwFntCache())
171 	{
172 		const sal_uInt16 nWhich = pOldValue ? pOldValue->Which() :
173 										pNewValue ? pNewValue->Which() : 0;
174 		CheckCaching( nWhich );
175 	}
176 
177   	if (!pRoot || IsModifyLocked())
178 		return;
179 
180 	LockModify();
181 
182     // mba: WTF?!
183 	if( !pOldValue )
184 		bLockClientList = sal_True;
185 	else
186     {
187 		// following Modifies shouldn't call an ASSERT
188 		switch( pOldValue->Which() )
189 		{
190 		case RES_OBJECTDYING:
191  		case RES_REMOVE_UNO_OBJECT:
192 			bLockClientList = ((SwPtrMsgPoolItem *)pOldValue)->pObject != this;
193 			break;
194 
195 		case RES_FOOTNOTE_DELETED:
196 		case RES_REFMARK_DELETED:
197 		case RES_TOXMARK_DELETED:
198 		case RES_FIELD_DELETED:
199 			bLockClientList = sal_False;
200 			break;
201 		default:
202 			bLockClientList = sal_True;
203 		}
204     }
205 
206     ModifyBroadcast( pOldValue, pNewValue );
207 	bLockClientList = sal_False;
208 	UnlockModify();
209 }
210 
211 sal_Bool SwModify::GetInfo( SfxPoolItem& rInfo ) const
212 {
213 	sal_Bool bRet = sal_True;		// bedeutet weiter zum naechsten
214 
215 	if( pRoot )
216 	{
217 		SwClientIter aIter( *(SwModify*)this );
218 
219 		SwClient* pLast = aIter.GoStart();
220 		if( pLast )
221 			while( 0 != ( bRet = pLast->GetInfo( rInfo )) &&
222 					0 != ( pLast = ++aIter ) )
223 				;
224 	}
225 
226 	return bRet;
227 }
228 
229 /*************************************************************************/
230 void SwModify::Add(SwClient *pDepend)
231 {
232 	ASSERT( !bLockClientList, "Client inserted while in Modify" );
233 
234 	if(pDepend->pRegisteredIn != this )
235 	{
236 #ifdef DBG_UTIL
237 		SwClientIter* pTmp = pClientIters;
238 		while( pTmp )
239 		{
240 			ASSERT( &pTmp->GetModify() != pRoot, "Client added to active ClientIter" );
241 			pTmp = pTmp->pNxtIter;
242 		}
243 #endif
244 		// deregister new client in case it is already registered elsewhere
245 		if( pDepend->pRegisteredIn != 0 )
246 			pDepend->pRegisteredIn->Remove( pDepend );
247 
248 		if( !pRoot )
249 		{
250             // first client added
251 			pRoot = pDepend;
252 			pRoot->pLeft = 0;
253 			pRoot->pRight = 0;
254 		}
255 		else
256 		{
257 			// append client
258 			pDepend->pRight = pRoot->pRight;
259 			pRoot->pRight = pDepend;
260 			pDepend->pLeft = pRoot;
261 			if( pDepend->pRight )
262 				pDepend->pRight->pLeft = pDepend;
263 		}
264 
265         // connect client to me
266 		pDepend->pRegisteredIn = this;
267 	}
268 }
269 
270 /*************************************************************************/
271 
272 SwClient* SwModify::Remove(SwClient * pDepend)
273 {
274 	if ( bInDocDTOR )
275         return 0;
276 
277     ASSERT( !bLockClientList || pDepend->mbIsAllowedToBeRemovedInModifyCall, "SwClient shall be removed in Modify call!" );
278 
279 	if( pDepend->pRegisteredIn == this )
280 	{
281         // SwClient is my listener
282         // remove it from my list
283 		SwClient* pR = pDepend->pRight;
284 		SwClient* pL = pDepend->pLeft;
285 		if( pRoot == pDepend )
286 			pRoot = pL ? pL : pR;
287 
288 		if( pL )
289 			pL->pRight = pR;
290 		if( pR )
291 			pR->pLeft = pL;
292 
293 		// update ClientIters
294 		SwClientIter* pTmp = pClientIters;
295 		while( pTmp )
296 		{
297 			if( pTmp->pAct == pDepend || pTmp->pDelNext == pDepend )
298                 // if object being removed is the current or next object in an iterator, advance this iterator
299 				pTmp->pDelNext = pR;
300 			pTmp = pTmp->pNxtIter;
301 		}
302 
303 		pDepend->pLeft = 0;
304 		pDepend->pRight = 0;
305 	}
306 	else
307     {
308 		ASSERT( false, "SwModify::Remove(): pDepend nicht gefunden" );
309     }
310 
311     // disconnect client from me
312 	pDepend->pRegisteredIn = 0;
313 	return pDepend;
314 }
315 
316 int SwModify::GetClientCount() const
317 {
318     int nRet=0;
319     SwClientIter aIter( *this );
320     SwClient *pLast = aIter.GoStart();
321     if( pLast )
322         do
323         {
324             ++nRet;
325         } while( 0 != ( pLast = ++aIter ));
326     return nRet;
327 }
328 
329 void SwModify::CheckCaching( const sal_uInt16 nWhich )
330 {
331     if (isCHRATR(nWhich))
332     {
333         SetInSwFntCache( sal_False );
334     }
335 	else
336 		switch ( nWhich )
337 		{
338 		case RES_OBJECTDYING:
339 		case RES_FMT_CHG:
340 		case RES_ATTRSET_CHG:
341 			SetInSwFntCache( sal_False );
342 
343 		case RES_UL_SPACE:
344 		case RES_LR_SPACE:
345 		case RES_BOX:
346 		case RES_SHADOW:
347 		case RES_FRM_SIZE:
348 		case RES_KEEP:
349 		case RES_BREAK:
350 			if ( IsInCache() )
351 			{
352 				SwFrm::GetCache().Delete( this );
353 				SetInCache( sal_False );
354 			}
355 			break;
356 		}
357 }
358 
359 void SwModify::CallSwClientNotify( const SfxHint& rHint ) const
360 {
361     SwClientIter aIter(*this);
362     SwClient * pClient = aIter.GoStart();
363     while (pClient)
364     {
365         pClient->SwClientNotify( *this, rHint );
366         pClient = ++aIter;
367     }
368 }
369 
370 void SwModify::ModifyBroadcast( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue, TypeId nType )
371 {
372     SwClientIter aIter(*this);
373     SwClient * pClient = aIter.First( nType );
374     while (pClient)
375     {
376         pClient->Modify( pOldValue, pNewValue );
377         pClient = aIter.Next();
378     }
379 }
380 
381 // ----------
382 // SwDepend
383 // ----------
384 
385 /*************************************************************************/
386 
387 SwDepend::SwDepend(SwClient *pTellHim, SwModify *pDepend)
388 	: SwClient(pDepend)
389 {
390 	pToTell  = pTellHim;
391 }
392 
393 /*************************************************************************/
394 
395 void SwDepend::Modify( const SfxPoolItem* pOldValue, const SfxPoolItem *pNewValue )
396 {
397 	if(pNewValue && pNewValue->Which() == RES_OBJECTDYING)
398 		CheckRegistration(pOldValue,pNewValue);
399 	else if(pToTell)
400 		pToTell->ModifyNotification(pOldValue, pNewValue);
401 }
402 
403 void SwDepend::SwClientNotify( const SwModify& rMod, const SfxHint& rHint )
404 {
405     if ( pToTell )
406         pToTell->SwClientNotifyCall( rMod, rHint );
407 }
408 
409 sal_Bool SwDepend::GetInfo( SfxPoolItem& rInfo ) const
410 {
411 	return pToTell ? pToTell->GetInfo( rInfo ) : sal_True;
412 }
413 
414 /********************************************************************/
415 
416 SwClientIter::SwClientIter( const SwModify& rModify )
417 	: rRoot( rModify )
418 {
419 	pNxtIter = 0;
420 	if( pClientIters )
421 	{
422         // append to list of ClientIters
423 		SwClientIter* pTmp = pClientIters;
424 		while( pTmp->pNxtIter )
425 			pTmp = pTmp->pNxtIter;
426 		pTmp->pNxtIter = this;
427 	}
428 	else
429 		pClientIters = this;
430 
431 	pAct = const_cast<SwClient*>(rRoot.GetDepends());
432 	pDelNext = pAct;
433 }
434 
435 
436 
437 SwClientIter::~SwClientIter()
438 {
439 	if( pClientIters )
440 	{
441         // reorganize list of ClientIters
442 		if( pClientIters == this )
443 			pClientIters = pNxtIter;
444 		else
445 		{
446 			SwClientIter* pTmp = pClientIters;
447 			while( pTmp->pNxtIter != this )
448 				if( 0 == ( pTmp = pTmp->pNxtIter ) )
449 				{
450 					ASSERT( this, "wo ist mein Pointer" );
451 					return ;
452 				}
453 			pTmp->pNxtIter = pNxtIter;
454 		}
455 	}
456 }
457 
458 
459 SwClient* SwClientIter::operator++()
460 {
461 	if( pDelNext == pAct )
462 	{
463 		pAct = pAct->pRight;
464 		pDelNext = pAct;
465 	}
466 	else
467 		pAct = pDelNext;
468 	return pAct;
469 }
470 
471 SwClient* SwClientIter::GoStart()
472 {
473 	pAct = const_cast<SwClient*>(rRoot.GetDepends());
474 	if( pAct )
475 		while( pAct->pLeft )
476 			pAct = pAct->pLeft;
477 	pDelNext = pAct;
478 	return pAct;
479 }
480 
481 SwClient* SwClientIter::GoEnd()
482 {
483 	pAct = pDelNext;
484 	if( !pAct )
485     	pAct = const_cast<SwClient*>(rRoot.GetDepends());
486 	if( pAct )
487 		while( pAct->pRight )
488 			pAct = pAct->pRight;
489 	pDelNext = pAct;
490 	return pAct;
491 }
492 
493 SwClient* SwClientIter::First( TypeId nType )
494 {
495 	aSrchId = nType;
496 	GoStart();
497 	if( pAct )
498 		do {
499 			if( pAct->IsA( aSrchId ) )
500 				break;
501 
502 			if( pDelNext == pAct )
503 			{
504 				pAct = pAct->pRight;
505 				pDelNext = pAct;
506 			}
507 			else
508 				pAct = pDelNext;
509 
510 		} while( pAct );
511 	return pAct;
512 }
513 
514 SwClient* SwClientIter::Next()
515 {
516 	do {
517 		if( pDelNext == pAct )
518 		{
519 			pAct = pAct->pRight;
520 			pDelNext = pAct;
521 		}
522 		else
523 			pAct = pDelNext;
524 
525 		if( pAct && pAct->IsA( aSrchId ) )
526 			break;
527 	} while( pAct );
528 	return pAct;
529 }
530 
531 SwClient* SwClientIter::Last( TypeId nType )
532 {
533 	aSrchId = nType;
534 	GoEnd();
535 	if( pAct )
536 		do {
537 			if( pAct->IsA( aSrchId ) )
538 				break;
539 
540 	        if( pDelNext == pAct )
541 		        pAct = pAct->pLeft;
542 	        else
543 		        pAct = pDelNext->pLeft;
544 	        pDelNext = pAct;
545 
546 		} while( pAct );
547 	return pAct;
548 }
549 
550 SwClient* SwClientIter::Previous()
551 {
552 	do {
553 	    if( pDelNext == pAct )
554 		    pAct = pAct->pLeft;
555 	    else
556 		    pAct = pDelNext->pLeft;
557 	    pDelNext = pAct;
558 
559 		if( pAct && pAct->IsA( aSrchId ) )
560 			break;
561 	} while( pAct );
562 	return pAct;
563 }
564 
565