xref: /trunk/main/svl/source/items/itempool.cxx (revision 40df464e)
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_svl.hxx"
26 
27 #include <string.h>
28 #include <stdio.h>
29 #ifndef GCC
30 #endif
31 
32 #include <svl/itempool.hxx>
33 #include "whassert.hxx"
34 #include <svl/brdcst.hxx>
35 #include <svl/smplhint.hxx>
36 #include "poolio.hxx"
37 
38 //========================================================================
39 
40 
41 void SfxItemPool::AddSfxItemPoolUser(SfxItemPoolUser& rNewUser)
42 {
43 	maSfxItemPoolUsers.push_back(&rNewUser);
44 }
45 
46 void SfxItemPool::RemoveSfxItemPoolUser(SfxItemPoolUser& rOldUser)
47 {
48 	const SfxItemPoolUserVector::iterator aFindResult = ::std::find(maSfxItemPoolUsers.begin(), maSfxItemPoolUsers.end(), &rOldUser);
49 	if(aFindResult != maSfxItemPoolUsers.end())
50 	{
51 		maSfxItemPoolUsers.erase(aFindResult);
52 	}
53 }
54 
55 const SfxPoolItem* SfxItemPool::GetPoolDefaultItem( sal_uInt16 nWhich ) const
56 {
57 	DBG_CHKTHIS(SfxItemPool, 0);
58 	const SfxPoolItem* pRet;
59 	if( IsInRange( nWhich ) )
60 		pRet = *(ppPoolDefaults + GetIndex_Impl( nWhich ));
61 	else if( pSecondary )
62 		pRet = pSecondary->GetPoolDefaultItem( nWhich );
63 	else
64 	{
65 		SFX_ASSERT( 0, nWhich, "unknown Which-Id - cannot get pool default" );
66 		pRet = 0;
67 	}
68 	return pRet;
69 }
70 
71 // -----------------------------------------------------------------------
72 
73 inline FASTBOOL SfxItemPool::IsItemFlag_Impl( sal_uInt16 nPos, sal_uInt16 nFlag ) const
74 {
75 	sal_uInt16 nItemFlag = pItemInfos[nPos]._nFlags;
76 	return nFlag == (nItemFlag & nFlag);
77 }
78 
79 // -----------------------------------------------------------------------
80 
81 FASTBOOL SfxItemPool::IsItemFlag( sal_uInt16 nWhich, sal_uInt16 nFlag ) const
82 {
83 	for ( const SfxItemPool *pPool = this; pPool; pPool = pPool->pSecondary )
84 	{
85 		if ( pPool->IsInRange(nWhich) )
86 			return pPool->IsItemFlag_Impl( pPool->GetIndex_Impl(nWhich), nFlag);
87 	}
88 	DBG_ASSERT( !IsWhich(nWhich), "unknown which-id" );
89 	return sal_False;
90 }
91 
92 // -----------------------------------------------------------------------
93 
94 SfxBroadcaster& SfxItemPool::BC()
95 {
96 	return pImp->aBC;
97 }
98 
99 // -----------------------------------------------------------------------
100 
101 
102 SfxItemPool::SfxItemPool
103 (
104 	UniString const &	rName,          /* Name des Pools zur Idetifikation
105 										   im File-Format */
106 	sal_uInt16              nStartWhich,    /* erste Which-Id des Pools */
107 	sal_uInt16              nEndWhich,      /* letzte Which-Id des Pools */
108 #ifdef TF_POOLABLE
109 	const SfxItemInfo*  pInfos,         /* SID-Map und Item-Flags */
110 #endif
111 	SfxPoolItem**       pDefaults,      /* Pointer auf statische Defaults,
112 										   wird direkt vom Pool referenziert,
113 										   jedoch kein Eigent"umer"ubergang */
114 #ifndef TF_POOLABLE
115 	sal_uInt16*             pSlotIdArray,   /* Zuordnung von Slot-Ids zu Which-Ids */
116 #endif
117 	FASTBOOL            bLoadRefCounts  /* Ref-Counts mitladen oder auf 1 setzen */
118 )
119 
120 /*  [Beschreibung]
121 
122 	Der im Normalfall verwendete Konstruktor der Klasse SfxItemPool. Es
123 	wird eine SfxItemPool-Instanz initialisiert, die Items im b"undigen
124 	Which-Bereich von 'nStartWhich' bis 'nEndWhich' verwalten kann.
125 
126 	F"ur jede dieser Which-Ids mu\s ein statischer Default im Array 'pDefaults'
127 	vorhanden sein, die dort beginnend mit einem <SfxPoolItem> mit der
128 	Which-Id 'nStartWhich' nach Which-Ids sortiert aufeinanderfolgend
129 	eingetragen sein m"ussen.
130 
131 	'pItemInfos' ist ein identisch angeordnetes Array von USHORTs, die
132 	Slot-Ids darstellen und Flags. Die Slot-Ids k"onnen 0 sein, wenn die
133 	betreffenden Items ausschlie\slich in der Core verwendet werden.
134 	"Uber die Flags kann z.B. bestimmt werden, ob Value-Sharing
135 	(SFX_ITEM_POOLABLE) stattfinden soll.
136 
137 	[Anmerkung]
138 
139 	Wenn der Pool <SfxSetItem>s enthalten soll, k"onnen im Konstruktor noch
140 	keine static-Defaults angegeben werden. Dies mu\s dann nachtr"aglich
141 	mit <SfxItemPool::SetDefaults(SfxItemPool**)> geschehen.
142 
143 
144 	[Querverweise]
145 
146 	<SfxItemPool::SetDefaults(SfxItemPool**)>
147 	<SfxItemPool::ReleaseDefaults(SfxPoolItem**,sal_uInt16,sal_Bool)>
148 	<SfxItemPool::ReldaseDefaults(sal_Bool)>
149 */
150 
151 :   aName(rName),
152 	nStart(nStartWhich),
153 	nEnd(nEndWhich),
154 #ifdef TF_POOLABLE
155 	pItemInfos(pInfos),
156 #else
157 	pSlotIds(pSlotIdArray),
158 #endif
159 	pImp( new SfxItemPool_Impl( nStart, nEnd ) ),
160 	ppStaticDefaults(0),
161 	ppPoolDefaults(new SfxPoolItem* [ nEndWhich - nStartWhich + 1]),
162 	pSecondary(0),
163 	pMaster(this),
164 	_pPoolRanges( 0 ),
165 	bPersistentRefCounts(bLoadRefCounts),
166     maSfxItemPoolUsers()
167 {
168 	DBG_CTOR(SfxItemPool, 0);
169 	DBG_ASSERT(nStart, "Start-Which-Id must be greater 0" );
170 
171 	pImp->eDefMetric = SFX_MAPUNIT_TWIP;
172 	pImp->nVersion = 0;
173 	pImp->bStreaming = sal_False;
174 	pImp->nLoadingVersion = 0;
175 	pImp->nInitRefCount = 1;
176 	pImp->nVerStart = nStart;
177 	pImp->nVerEnd = nEnd;
178 	pImp->bInSetItem = sal_False;
179 	pImp->nStoringStart = nStartWhich;
180 	pImp->nStoringEnd = nEndWhich;
181 
182 	memset( ppPoolDefaults, 0, sizeof( SfxPoolItem* ) * (nEnd - nStart + 1));
183 
184 	if ( pDefaults )
185 		SetDefaults(pDefaults);
186 }
187 
188 // -----------------------------------------------------------------------
189 
190 
191 SfxItemPool::SfxItemPool
192 (
193 	const SfxItemPool&  rPool,                  //  von dieser Instanz kopieren
194 	sal_Bool                bCloneStaticDefaults    /*  sal_True
195 													statische Defaults kopieren
196 
197 													sal_False
198 													statische Defaults
199 													"ubernehehmen */
200 )
201 
202 /*  [Beschreibung]
203 
204 	Copy-Konstruktor der Klasse SfxItemPool.
205 
206 
207 	[Querverweise]
208 
209 	<SfxItemPool::Clone()const>
210 */
211 
212 :   aName(rPool.aName),
213 	nStart(rPool.nStart),
214 	nEnd(rPool.nEnd),
215 #ifdef TF_POOLABLE
216 	pItemInfos(rPool.pItemInfos),
217 #else
218 	pSlotIds(rPool.pSlotIds),
219 #endif
220 	pImp( new SfxItemPool_Impl( nStart, nEnd ) ),
221 	ppStaticDefaults(0),
222 	ppPoolDefaults(new SfxPoolItem* [ nEnd - nStart + 1]),
223 	pSecondary(0),
224 	pMaster(this),
225 	_pPoolRanges( 0 ),
226 	bPersistentRefCounts(rPool.bPersistentRefCounts ),
227     maSfxItemPoolUsers()
228 {
229 	DBG_CTOR(SfxItemPool, 0);
230 	pImp->eDefMetric = rPool.pImp->eDefMetric;
231 	pImp->nVersion = rPool.pImp->nVersion;
232 	pImp->bStreaming = sal_False;
233 	pImp->nLoadingVersion = 0;
234 	pImp->nInitRefCount = 1;
235 	pImp->nVerStart = rPool.pImp->nVerStart;
236 	pImp->nVerEnd = rPool.pImp->nVerEnd;
237 	pImp->bInSetItem = sal_False;
238 	pImp->nStoringStart = nStart;
239 	pImp->nStoringEnd = nEnd;
240 
241 	memset( ppPoolDefaults, 0, sizeof( SfxPoolItem* ) * (nEnd - nStart + 1));
242 
243 	// Static Defaults "ubernehmen
244 	if ( bCloneStaticDefaults )
245 	{
246 		SfxPoolItem **ppDefaults = new SfxPoolItem*[nEnd-nStart+1];
247 		for ( sal_uInt16 n = 0; n <= nEnd - nStart; ++n )
248 		{
249 			(*( ppDefaults + n )) = (*( rPool.ppStaticDefaults + n ))->Clone(this);
250 			(*( ppDefaults + n ))->SetKind( SFX_ITEMS_STATICDEFAULT );
251 		}
252 
253 		SetDefaults( ppDefaults );
254 	}
255 	else
256 		SetDefaults( rPool.ppStaticDefaults );
257 
258 	// Pool Defaults kopieren
259 	for ( sal_uInt16 n = 0; n <= nEnd - nStart; ++n )
260 		if ( (*( rPool.ppPoolDefaults + n )) )
261 		{
262 			(*( ppPoolDefaults + n )) = (*( rPool.ppPoolDefaults + n ))->Clone(this);
263 			(*( ppPoolDefaults + n ))->SetKind( SFX_ITEMS_POOLDEFAULT );
264 		}
265 
266 	// Copy Version-Map
267 	for ( size_t nVer = 0; nVer < rPool.pImp->aVersions.size(); ++nVer )
268 	{
269 		const SfxPoolVersion_ImplPtr pOld = rPool.pImp->aVersions[nVer];
270 		SfxPoolVersion_ImplPtr pNew = SfxPoolVersion_ImplPtr( new SfxPoolVersion_Impl( *pOld ) );
271 		pImp->aVersions.push_back( pNew );
272 	}
273 
274 	// Verkettung wiederherstellen
275 	if ( rPool.pSecondary )
276 		SetSecondaryPool( rPool.pSecondary->Clone() );
277 }
278 
279 // -----------------------------------------------------------------------
280 
281 void SfxItemPool::SetDefaults( SfxPoolItem **pDefaults )
282 {
283 	DBG_CHKTHIS(SfxItemPool, 0);
284 	DBG_ASSERT( pDefaults, "erst wollen, dann nichts geben..." );
285 	DBG_ASSERT( !ppStaticDefaults, "habe schon defaults" );
286 
287 	ppStaticDefaults = pDefaults;
288 	//! if ( (*ppStaticDefaults)->GetKind() != SFX_ITEMS_STATICDEFAULT )
289 	//! geht wohl nicht im Zshg mit SetItems, die hinten stehen
290 	{
291 		DBG_ASSERT( (*ppStaticDefaults)->GetRefCount() == 0 ||
292 					IsDefaultItem( (*ppStaticDefaults) ),
293 					"das sind keine statics" );
294 		for ( sal_uInt16 n = 0; n <= nEnd - nStart; ++n )
295 		{
296 			SFX_ASSERT( (*( ppStaticDefaults + n ))->Which() == n + nStart,
297 						n + nStart, "static defaults not sorted" );
298 			(*( ppStaticDefaults + n ))->SetKind( SFX_ITEMS_STATICDEFAULT );
299 			DBG_ASSERT( !(pImp->ppPoolItems[n]), "defaults with setitems with items?!" );
300 		}
301 	}
302 }
303 
304 // -----------------------------------------------------------------------
305 
306 void SfxItemPool::ReleaseDefaults
307 (
308 	sal_Bool    bDelete     /*  sal_True
309 							l"oscht sowohl das Array als auch die einzelnen
310 							statischen Defaults
311 
312 							sal_False
313 							l"oscht weder das Array noch die einzelnen
314 							statischen Defaults */
315 )
316 
317 /*  [Beschreibung]
318 
319 	Gibt die statischen Defaults der betreffenden SfxItemPool-Instanz frei
320 	und l"oscht ggf. die statischen Defaults.
321 
322 	Nach Aufruf dieser Methode darf die SfxItemPool-Instanz nicht mehr
323 	verwendet werden, einzig ist der Aufruf des Destruktors zu"lassig.
324 */
325 
326 {
327 	DBG_ASSERT( ppStaticDefaults, "keine Arme keine Kekse" );
328 	ReleaseDefaults( ppStaticDefaults, nEnd - nStart + 1, bDelete );
329 
330 	// KSO (22.10.98): ppStaticDefaults zeigt auf geloeschten Speicher,
331 	// wenn bDelete == sal_True.
332 	if ( bDelete )
333 		ppStaticDefaults = 0;
334 }
335 
336 // -----------------------------------------------------------------------
337 
338 void SfxItemPool::ReleaseDefaults
339 (
340 	SfxPoolItem**   pDefaults,  /*  freizugebende statische Defaults */
341 
342 	sal_uInt16          nCount,     /*  Anzahl der statischen Defaults */
343 
344 	sal_Bool            bDelete     /*  sal_True
345 									l"oscht sowohl das Array als auch die
346 									einzelnen statischen Defaults
347 
348 									sal_False
349 									l"oscht weder das Array noch die
350 									einzelnen statischen Defaults */
351 )
352 
353 /*  [Beschreibung]
354 
355 	Gibt die angegebenen statischen Defaults frei und l"oscht ggf.
356 	die statischen Defaults.
357 
358 	Diese Methode darf erst nach Zerst"orung aller SfxItemPool-Instanzen,
359 	welche die angegebenen statischen Defaults 'pDefault' verwenden,
360 	aufgerufen werden.
361 */
362 
363 {
364 	DBG_ASSERT( pDefaults, "erst wollen, dann nichts geben..." );
365 
366 	for ( sal_uInt16 n = 0; n < nCount; ++n )
367 	{
368 		SFX_ASSERT( IsStaticDefaultItem( *(pDefaults+n) ),
369 					n, "das ist kein static-default" );
370 		(*( pDefaults + n ))->SetRefCount( 0 );
371 		if ( bDelete )
372 			{ delete *( pDefaults + n ); *(pDefaults + n) = 0; }
373 	}
374 
375 	if ( bDelete )
376 		{ delete[] pDefaults; pDefaults = 0; }
377 }
378 
379 // -----------------------------------------------------------------------
380 
381 SfxItemPool::~SfxItemPool()
382 {
383 	DBG_DTOR(SfxItemPool, 0);
384 	DBG_ASSERT( pMaster == this, "destroying active Secondary-Pool" );
385 
386     if ( pImp->ppPoolItems && ppPoolDefaults )
387 		Delete();
388 	delete[] _pPoolRanges;
389 	delete pImp;
390 }
391 
392 void SfxItemPool::Free(SfxItemPool* pPool)
393 {
394     if(pPool)
395     {
396 	    // tell all the registered SfxItemPoolUsers that the pool is in destruction
397 	    SfxItemPoolUserVector aListCopy(pPool->maSfxItemPoolUsers.begin(), pPool->maSfxItemPoolUsers.end());
398 	    for(SfxItemPoolUserVector::iterator aIterator = aListCopy.begin(); aIterator != aListCopy.end(); aIterator++)
399 	    {
400 		    SfxItemPoolUser* pSfxItemPoolUser = *aIterator;
401 		    DBG_ASSERT(pSfxItemPoolUser, "corrupt SfxItemPoolUser list (!)");
402 		    pSfxItemPoolUser->ObjectInDestruction(*pPool);
403 	    }
404 
405 	    // Clear the vector. This means that user do not need to call RemoveSfxItemPoolUser()
406 	    // when they get called from ObjectInDestruction().
407 	    pPool->maSfxItemPoolUsers.clear();
408 
409         // delete pool
410         delete pPool;
411     }
412 }
413 
414 // -----------------------------------------------------------------------
415 
416 
417 void SfxItemPool::SetSecondaryPool( SfxItemPool *pPool )
418 {
419 	// ggf. an abgeh"angten Pools den Master zur"ucksetzen
420 	if ( pSecondary )
421 	{
422 #ifdef DBG_UTIL
423 		HACK( "fuer Image, dort gibt es derzeit keine Statics - Bug" )
424 		if ( ppStaticDefaults )
425 		{
426 			// Delete() ist noch nicht gelaufen?
427 			if ( pImp->ppPoolItems && pSecondary->pImp->ppPoolItems )
428 			{
429 				// hat der master SetItems?
430 				sal_Bool bHasSetItems = sal_False;
431 				for ( sal_uInt16 i = 0; !bHasSetItems && i < nEnd-nStart; ++i )
432 					bHasSetItems = ppStaticDefaults[i]->ISA(SfxSetItem);
433 
434 				// abgehaengte Pools muessen leer sein
435 				sal_Bool bOK = bHasSetItems;
436 				for ( sal_uInt16 n = 0;
437 					  bOK && n <= pSecondary->nEnd - pSecondary->nStart;
438 					  ++n )
439 				{
440 					SfxPoolItemArray_Impl** ppItemArr =
441 												pSecondary->pImp->ppPoolItems + n;
442 					if ( *ppItemArr )
443 					{
444 						SfxPoolItemArrayBase_Impl::iterator ppHtArr =	(*ppItemArr)->begin();
445 						for( size_t i = (*ppItemArr)->size(); i; ++ppHtArr, --i )
446 							if ( !(*ppHtArr) )
447 							{
448 								DBG_ERROR( "old secondary pool must be empty" );
449 								bOK = sal_False;
450 								break;
451 							}
452 					}
453 				}
454 			}
455 		}
456 #endif
457 
458 		pSecondary->pMaster = pSecondary;
459 		for ( SfxItemPool *p = pSecondary->pSecondary; p; p = p->pSecondary )
460 			p->pMaster = pSecondary;
461 	}
462 
463 	// ggf. den Master der neuen Secondary-Pools setzen
464 	DBG_ASSERT( !pPool || pPool->pMaster == pPool, "Secondary tanzt auf zwei Hochzeiten " );
465 	SfxItemPool *pNewMaster = pMaster ? pMaster : this;
466 	for ( SfxItemPool *p = pPool; p; p = p->pSecondary )
467 		p->pMaster = pNewMaster;
468 
469 	// neuen Secondary-Pool merken
470 	pSecondary = pPool;
471 }
472 
473 // -----------------------------------------------------------------------
474 
475 SfxMapUnit SfxItemPool::GetMetric( sal_uInt16 ) const
476 {
477 	DBG_CHKTHIS(SfxItemPool, 0);
478 
479 	return pImp->eDefMetric;
480 }
481 
482 // -----------------------------------------------------------------------
483 
484 void SfxItemPool::SetDefaultMetric( SfxMapUnit eNewMetric )
485 {
486 	DBG_CHKTHIS(SfxItemPool, 0);
487 
488 	pImp->eDefMetric = eNewMetric;
489 }
490 
491 // -----------------------------------------------------------------------
492 
493 SfxItemPresentation SfxItemPool::GetPresentation
494 (
495 	const SfxPoolItem&  rItem,      /*  IN: <SfxPoolItem>, dessen textuelle
496 											Wert-Darstellung geliefert werden
497 											soll */
498 	SfxItemPresentation ePresent,   /*  IN: gew"unschte Art der Darstellung;
499 											siehe <SfxItemPresentation> */
500 	SfxMapUnit          eMetric,    /*  IN: gew"unschte Ma\seinheit der Darstellung */
501 	XubString&           rText,      /*  OUT: textuelle Darstellung von 'rItem' */
502     const IntlWrapper * pIntlWrapper
503 )   const
504 
505 /*  [Beschreibung]
506 
507 	"Uber diese virtuelle Methode k"onnen textuelle Darstellungen der
508 	von der jeweilige SfxItemPool-Subklasse verwalteten SfxPoolItems
509 	angefordert werden.
510 
511 	In Ableitungen sollte diese Methode "uberladen werden und auf
512 	SfxPoolItems reagiert werden, die bei <SfxPoolItem::GetPresentation()const>
513 	keine vollst"andige Information liefern k"onnen.
514 
515 	Die Basisklasse liefert die unver"anderte Presentation von 'rItem'.
516 */
517 
518 {
519 	DBG_CHKTHIS(SfxItemPool, 0);
520 	return rItem.GetPresentation(
521         ePresent, GetMetric(rItem.Which()), eMetric, rText, pIntlWrapper );
522 }
523 
524 
525 // -----------------------------------------------------------------------
526 
527 SfxItemPool* SfxItemPool::Clone() const
528 {
529 	DBG_CHKTHIS(SfxItemPool, 0);
530 
531 	SfxItemPool *pPool = new SfxItemPool( *this );
532 	return pPool;
533 }
534 
535 // ----------------------------------------------------------------------
536 
537 void SfxItemPool::Delete()
538 {
539 	DBG_CHKTHIS(SfxItemPool, 0);
540 
541 	// schon deleted?
542 	if ( !pImp->ppPoolItems || !ppPoolDefaults )
543 		return;
544 
545 	// z.B. laufenden Requests bescheidsagen
546 	pImp->aBC.Broadcast( SfxSimpleHint( SFX_HINT_DYING ) );
547 
548 	//MA 16. Apr. 97: Zweimal durchlaufen, in der ersten Runde fuer die SetItems.
549 	//Der Klarheit halber wird das jetzt in zwei besser lesbare Schleifen aufgeteilt.
550 
551 	SfxPoolItemArray_Impl** ppItemArr = pImp->ppPoolItems;
552 	SfxPoolItem** ppDefaultItem = ppPoolDefaults;
553 	SfxPoolItem** ppStaticDefaultItem = ppStaticDefaults;
554 	sal_uInt16 nArrCnt;
555 
556 	//Erst die SetItems abraeumen
557 	HACK( "fuer Image, dort gibt es derzeit keine Statics - Bug" )
558 	if ( ppStaticDefaults )
559 	{
560 		for ( nArrCnt = GetSize_Impl();
561 				nArrCnt;
562 				--nArrCnt, ++ppItemArr, ++ppDefaultItem, ++ppStaticDefaultItem )
563 		{
564 			// KSO (22.10.98): *ppStaticDefaultItem kann im dtor einer
565 			// von SfxItemPool abgeleiteten Klasse bereits geloescht worden
566 			// sein! -> CHAOS Itempool
567 			if ( *ppStaticDefaultItem && (*ppStaticDefaultItem)->ISA(SfxSetItem) )
568 			{
569 				if ( *ppItemArr )
570 				{
571 					SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*ppItemArr)->begin();
572 					for ( size_t n = (*ppItemArr)->size(); n; --n, ++ppHtArr )
573 						if (*ppHtArr)
574 						{
575 #ifdef DBG_UTIL
576 							ReleaseRef( **ppHtArr, (*ppHtArr)->GetRefCount() );
577 #endif
578 							delete *ppHtArr;
579 						}
580 					DELETEZ( *ppItemArr );
581 				}
582 				if ( *ppDefaultItem )
583 				{
584 #ifdef DBG_UTIL
585 					SetRefCount( **ppDefaultItem, 0 );
586 #endif
587 					DELETEZ( *ppDefaultItem );
588 				}
589 			}
590 		}
591 	}
592 
593 	ppItemArr = pImp->ppPoolItems;
594 	ppDefaultItem = ppPoolDefaults;
595 
596 	//Jetzt die 'einfachen' Items
597 	for ( nArrCnt = GetSize_Impl();
598 			nArrCnt;
599 			--nArrCnt, ++ppItemArr, ++ppDefaultItem )
600 	{
601 		if ( *ppItemArr )
602 		{
603 			SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*ppItemArr)->begin();
604 			for ( size_t n = (*ppItemArr)->size(); n; --n, ++ppHtArr )
605 				if (*ppHtArr)
606 				{
607 #ifdef DBG_UTIL
608 					ReleaseRef( **ppHtArr, (*ppHtArr)->GetRefCount() );
609 #endif
610 					delete *ppHtArr;
611 				}
612 			delete *ppItemArr;
613 		}
614 		if ( *ppDefaultItem )
615 		{
616 #ifdef DBG_UTIL
617 			SetRefCount( **ppDefaultItem, 0 );
618 #endif
619 			delete *ppDefaultItem;
620 		}
621 	}
622 
623 	pImp->DeleteItems();
624 	delete[] ppPoolDefaults; ppPoolDefaults = 0;
625 }
626 
627 // ----------------------------------------------------------------------
628 
629 void SfxItemPool::Cleanup()
630 {
631 	DBG_CHKTHIS(SfxItemPool, 0);
632 
633 	//MA 16. Apr. 97: siehe ::Delete()
634 
635 	SfxPoolItemArray_Impl** ppItemArr = pImp->ppPoolItems;
636 	SfxPoolItem** ppDefaultItem = ppPoolDefaults;
637 	SfxPoolItem** ppStaticDefaultItem = ppStaticDefaults;
638 	sal_uInt16 nArrCnt;
639 
640 	HACK( "fuer Image, dort gibt es derzeit keine Statics - Bug" )
641 	if ( ppStaticDefaults ) //HACK fuer Image, dort gibt es keine Statics!!
642 	{
643 		for ( nArrCnt = GetSize_Impl();
644 				nArrCnt;
645 				--nArrCnt, ++ppItemArr, ++ppDefaultItem, ++ppStaticDefaultItem )
646 		{
647 			//Fuer jedes Item gibt es entweder ein Default oder ein static Default!
648 			if ( *ppItemArr &&
649 				 ((*ppDefaultItem && (*ppDefaultItem)->ISA(SfxSetItem)) ||
650 				  (*ppStaticDefaultItem)->ISA(SfxSetItem)) )
651 			{
652 				SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*ppItemArr)->begin();
653 				for ( size_t n = (*ppItemArr)->size(); n; --n, ++ppHtArr )
654 					if ( *ppHtArr && !(*ppHtArr)->GetRefCount() )
655 					{
656 						 DELETEZ(*ppHtArr);
657 					}
658 			}
659 		}
660 	}
661 
662 	ppItemArr = pImp->ppPoolItems;
663 
664 	for ( nArrCnt = GetSize_Impl();
665 		  nArrCnt;
666 		  --nArrCnt, ++ppItemArr )
667 	{
668 		if ( *ppItemArr )
669 		{
670 			SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*ppItemArr)->begin();
671 			for ( size_t n = (*ppItemArr)->size(); n; --n, ++ppHtArr )
672 				if ( *ppHtArr && !(*ppHtArr)->GetRefCount() )
673 					DELETEZ( *ppHtArr );
674 		}
675 	}
676 }
677 
678 // ----------------------------------------------------------------------
679 
680 void SfxItemPool::SetPoolDefaultItem(const SfxPoolItem &rItem)
681 {
682 	DBG_CHKTHIS(SfxItemPool, 0);
683 	if ( IsInRange(rItem.Which()) )
684 	{
685 		SfxPoolItem **ppOldDefault =
686 			ppPoolDefaults + GetIndex_Impl(rItem.Which());
687 		SfxPoolItem *pNewDefault = rItem.Clone(this);
688 		pNewDefault->SetKind(SFX_ITEMS_POOLDEFAULT);
689 		if ( *ppOldDefault )
690 		{
691 			(*ppOldDefault)->SetRefCount(0);
692 			DELETEZ( *ppOldDefault );
693 		}
694 		*ppOldDefault = pNewDefault;
695 	}
696 	else if ( pSecondary )
697 		pSecondary->SetPoolDefaultItem(rItem);
698 	else
699 	{
700 		SFX_ASSERT( 0, rItem.Which(), "unknown Which-Id - cannot set pool default" );
701 	}
702 }
703 
704 /*
705  * Resets the default of the given <Which-Id> back to the static default.
706  * If a pool default exists it is removed.
707  */
708 void SfxItemPool::ResetPoolDefaultItem( sal_uInt16 nWhichId )
709 {
710 	DBG_CHKTHIS(SfxItemPool, 0);
711 	if ( IsInRange(nWhichId) )
712 	{
713 		SfxPoolItem **ppOldDefault =
714 			ppPoolDefaults + GetIndex_Impl( nWhichId );
715 		if ( *ppOldDefault )
716 		{
717 			(*ppOldDefault)->SetRefCount(0);
718 			DELETEZ( *ppOldDefault );
719 		}
720 	}
721 	else if ( pSecondary )
722 		pSecondary->ResetPoolDefaultItem(nWhichId);
723 	else
724 	{
725 		SFX_ASSERT( 0, nWhichId, "unknown Which-Id - cannot set pool default" );
726 	}
727 }
728 
729 // -----------------------------------------------------------------------
730 
731 const SfxPoolItem& SfxItemPool::Put( const SfxPoolItem& rItem, sal_uInt16 nWhich )
732 {
733 	DBG_ASSERT( !rItem.ISA(SfxSetItem) ||
734 				0 != &((const SfxSetItem&)rItem).GetItemSet(),
735 				"SetItem without ItemSet" );
736 
737 	DBG_CHKTHIS(SfxItemPool, 0);
738 	if ( 0 == nWhich )
739 		nWhich = rItem.Which();
740 
741 	// richtigen Secondary-Pool finden
742 	sal_Bool bSID = nWhich > SFX_WHICH_MAX;
743 	if ( !bSID && !IsInRange(nWhich) )
744 	{
745 		if ( pSecondary )
746 			return pSecondary->Put( rItem, nWhich );
747 		DBG_ERROR( "unknown Which-Id - cannot put item" );
748 	}
749 
750 	// SID oder nicht poolable (neue Definition)?
751 	sal_uInt16 nIndex = bSID ? USHRT_MAX : GetIndex_Impl(nWhich);
752 	if ( USHRT_MAX == nIndex ||
753 		 IsItemFlag_Impl( nIndex, SFX_ITEM_NOT_POOLABLE ) )
754 	{
755 		SFX_ASSERT( USHRT_MAX != nIndex || rItem.Which() != nWhich ||
756 					!IsDefaultItem(&rItem) || rItem.GetKind() == SFX_ITEMS_DELETEONIDLE,
757 					nWhich, "ein nicht Pool-Item ist Default?!" );
758 		SfxPoolItem *pPoolItem = rItem.Clone(pMaster);
759 		pPoolItem->SetWhich(nWhich);
760 		AddRef( *pPoolItem );
761 		return *pPoolItem;
762 	}
763 
764 	SFX_ASSERT( rItem.IsA(GetDefaultItem(nWhich).Type()), nWhich,
765 				"SFxItemPool: wrong item type in Put" );
766 
767 	SfxPoolItemArray_Impl** ppItemArr = pImp->ppPoolItems + nIndex;
768 	if( !*ppItemArr )
769 		*ppItemArr = new SfxPoolItemArray_Impl;
770 
771 	SfxPoolItemArrayBase_Impl::iterator ppFree;
772 	sal_Bool ppFreeIsSet = sal_False;
773 	SfxPoolItemArrayBase_Impl::iterator ppHtArray = (*ppItemArr)->begin();
774 	if ( IsItemFlag_Impl( nIndex, SFX_ITEM_POOLABLE ) )
775 	{
776 		// wenn es ueberhaupt gepoolt ist, koennte es schon drin sein
777 		if ( IsPooledItem(&rItem) )
778 		{
779 			// 1. Schleife: teste ob der Pointer vorhanden ist.
780 			for( size_t n = (*ppItemArr)->size(); n; ++ppHtArray, --n )
781 				if( &rItem == (*ppHtArray) )
782 				{
783 					AddRef( **ppHtArray );
784 					return **ppHtArray;
785 				}
786 		}
787 
788 		// 2. Schleife: dann muessen eben die Attribute verglichen werden
789 		size_t n;
790 		for ( n = (*ppItemArr)->size(), ppHtArray = (*ppItemArr)->begin();
791 			  n; ++ppHtArray, --n )
792 		{
793 			if ( *ppHtArray )
794 			{
795 				if( **ppHtArray == rItem )
796 				{
797 					AddRef( **ppHtArray );
798 					return **ppHtArray;
799 				}
800 			}
801 			else
802 				if ( ppFreeIsSet == sal_False )
803 				{
804 					ppFree = ppHtArray;
805 					ppFreeIsSet = sal_True;
806 				}
807 		}
808 	}
809 	else
810 	{
811 		// freien Platz suchen
812 		SfxPoolItemArrayBase_Impl::iterator ppHtArr;
813 		size_t n, nCount = (*ppItemArr)->size();
814 		for ( n = (*ppItemArr)->nFirstFree,
815 				  ppHtArr = (*ppItemArr)->begin() + n;
816 			  n < nCount;
817 			  ++ppHtArr, ++n )
818 			if ( !*ppHtArr )
819 			{
820 				ppFree = ppHtArr;
821 				ppFreeIsSet = sal_True;
822 				break;
823 			}
824 
825 		// naechstmoeglichen freien Platz merken
826 		(*ppItemArr)->nFirstFree = n;
827 	}
828 
829 	// nicht vorhanden, also im PtrArray eintragen
830 	SfxPoolItem* pNewItem = rItem.Clone(pMaster);
831 	pNewItem->SetWhich(nWhich);
832 #ifdef DBG_UTIL
833 	SFX_ASSERT( rItem.Type() == pNewItem->Type(), nWhich, "unequal types in Put(): no Clone()?" )
834 #ifdef TF_POOLABLE
835 	if ( !rItem.ISA(SfxSetItem) )
836 	{
837 		SFX_ASSERT( !IsItemFlag(nWhich, SFX_ITEM_POOLABLE) ||
838 					rItem == *pNewItem,
839 					nWhich, "unequal items in Put(): no operator==?" );
840 		SFX_ASSERT( !IsItemFlag(*pNewItem, SFX_ITEM_POOLABLE) ||
841 					*pNewItem == rItem,
842 					nWhich, "unequal items in Put(): no operator==?" );
843 	}
844 #endif
845 #endif
846 	AddRef( *pNewItem, pImp->nInitRefCount );
847 	SfxPoolItem* pTemp = pNewItem;
848 	if ( ppFreeIsSet == sal_False )
849 		(*ppItemArr)->push_back( pTemp );
850 	else
851 	{
852 		DBG_ASSERT( *ppFree == 0, "using surrogate in use" );
853 		*ppFree = pNewItem;
854 	}
855 	return *pNewItem;
856 }
857 
858 // -----------------------------------------------------------------------
859 
860 void SfxItemPool::Remove( const SfxPoolItem& rItem )
861 {
862 	DBG_CHKTHIS(SfxItemPool, 0);
863 
864 	DBG_ASSERT( !rItem.ISA(SfxSetItem) ||
865 				0 != &((const SfxSetItem&)rItem).GetItemSet(),
866 				"SetItem without ItemSet" );
867 
868 	SFX_ASSERT( !IsPoolDefaultItem(&rItem), rItem.Which(),
869 				"wo kommt denn hier ein Pool-Default her" );
870 
871 	// richtigen Secondary-Pool finden
872 	const sal_uInt16 nWhich = rItem.Which();
873 	sal_Bool bSID = nWhich > SFX_WHICH_MAX;
874 	if ( !bSID && !IsInRange(nWhich) )
875 	{
876 		if ( pSecondary )
877 		{
878 			pSecondary->Remove( rItem );
879 			return;
880 		}
881 		DBG_ERROR( "unknown Which-Id - cannot remove item" );
882 	}
883 
884 	// SID oder nicht poolable (neue Definition)?
885 	sal_uInt16 nIndex = bSID ? USHRT_MAX : GetIndex_Impl(nWhich);
886 	if ( bSID || IsItemFlag_Impl( nIndex, SFX_ITEM_NOT_POOLABLE ) )
887 	{
888 		SFX_ASSERT( USHRT_MAX != nIndex ||
889 					!IsDefaultItem(&rItem), rItem.Which(),
890 					"ein nicht Pool-Item ist Default?!" );
891 		if ( 0 == ReleaseRef(rItem) )
892 		{
893 			SfxPoolItem *pItem = &(SfxPoolItem &)rItem;
894 			delete pItem;
895 		}
896 		return;
897 	}
898 
899 	SFX_ASSERT( rItem.GetRefCount(), rItem.Which(), "RefCount == 0, Remove unmoeglich" );
900 
901 	// statische Defaults sind eben einfach da
902 	if ( rItem.GetKind() == SFX_ITEMS_STATICDEFAULT &&
903 		 &rItem == *( ppStaticDefaults + GetIndex_Impl(nWhich) ) )
904 		return;
905 
906 	// Item im eigenen Pool suchen
907 	SfxPoolItemArray_Impl** ppItemArr = (pImp->ppPoolItems + nIndex);
908 	SFX_ASSERT( *ppItemArr, rItem.Which(), "removing Item not in Pool" );
909 	SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*ppItemArr)->begin();
910 	for( size_t n = (*ppItemArr)->size(); n; ++ppHtArr, --n )
911 		if( *ppHtArr == &rItem )
912 		{
913 			if ( (*ppHtArr)->GetRefCount() ) //!
914 				ReleaseRef( **ppHtArr );
915 			else
916 			{
917 				SFX_ASSERT( 0, rItem.Which(), "removing Item without ref" );
918 				SFX_TRACE( "to be removed, but not no refs: ", *ppHtArr );
919 			}
920 
921 			// ggf. kleinstmoegliche freie Position merken
922 			size_t nPos = (*ppItemArr)->size() - n;
923 			if ( (*ppItemArr)->nFirstFree > nPos )
924 				(*ppItemArr)->nFirstFree = nPos;
925 
926 			//! MI: Hack, solange wir das Problem mit dem Outliner haben
927 			//! siehe anderes MI-REF
928 			if ( 0 == (*ppHtArr)->GetRefCount() && nWhich < 4000 )
929 				DELETEZ(*ppHtArr);
930 			return;
931 		}
932 
933 	// nicht vorhanden
934 	SFX_ASSERT( 0, rItem.Which(), "removing Item not in Pool" );
935 	SFX_TRACE( "to be removed, but not in pool: ", &rItem );
936 }
937 
938 // -----------------------------------------------------------------------
939 
940 const SfxPoolItem& SfxItemPool::GetDefaultItem( sal_uInt16 nWhich ) const
941 {
942 	DBG_CHKTHIS(SfxItemPool, 0);
943 
944 	if ( !IsInRange(nWhich) )
945 	{
946 		if ( pSecondary )
947 			return pSecondary->GetDefaultItem( nWhich );
948 		SFX_ASSERT( 0, nWhich, "unknown which - dont ask me for defaults" );
949 	}
950 
951 	DBG_ASSERT( ppStaticDefaults, "no defaults known - dont ask me for defaults" );
952 	sal_uInt16 nPos = GetIndex_Impl(nWhich);
953 	SfxPoolItem *pDefault = *(ppPoolDefaults + nPos);
954 	if ( pDefault )
955 		return *pDefault;
956 	return **(ppStaticDefaults + nPos);
957 }
958 
959 // -----------------------------------------------------------------------
960 
961 
962 void SfxItemPool::FreezeIdRanges()
963 
964 /*	[Beschreibung]
965 
966 	This method should be called at the master pool, when all secondary
967 	pools are appended to it.
968 
969 	It calculates the ranges of 'which-ids' for fast construction of
970 	item-sets, which contains all 'which-ids'.
971 */
972 
973 {
974 	FillItemIdRanges_Impl( _pPoolRanges );
975 }
976 
977 
978 // -----------------------------------------------------------------------
979 
980 void SfxItemPool::FillItemIdRanges_Impl( sal_uInt16*& pWhichRanges ) const
981 {
982 	DBG_CHKTHIS(SfxItemPool, 0);
983 	DBG_ASSERT( !_pPoolRanges, "GetFrozenRanges() would be faster!" );
984 
985 	const SfxItemPool *pPool;
986 	sal_uInt16 nLevel = 0;
987 	for( pPool = this; pPool; pPool = pPool->pSecondary )
988 		++nLevel;
989 
990 	pWhichRanges = new sal_uInt16[ 2*nLevel + 1 ];
991 
992 	nLevel = 0;
993 	for( pPool = this; pPool; pPool = pPool->pSecondary )
994 	{
995 		*(pWhichRanges+(nLevel++)) = pPool->nStart;
996 		*(pWhichRanges+(nLevel++)) = pPool->nEnd;
997 		*(pWhichRanges+nLevel) = 0;
998 	}
999 }
1000 
1001 // -----------------------------------------------------------------------
1002 
1003 const SfxPoolItem *SfxItemPool::GetItem2(sal_uInt16 nWhich, sal_uInt32 nOfst) const
1004 {
1005 	DBG_CHKTHIS(SfxItemPool, 0);
1006 
1007 	if ( !IsInRange(nWhich) )
1008 	{
1009 		if ( pSecondary )
1010 			return pSecondary->GetItem2( nWhich, nOfst );
1011 		SFX_ASSERT( 0, nWhich, "unknown Which-Id - cannot resolve surrogate" );
1012 		return 0;
1013 	}
1014 
1015 	// dflt-Attribut?
1016 	if ( nOfst == SFX_ITEMS_DEFAULT )
1017 		return *(ppStaticDefaults + GetIndex_Impl(nWhich));
1018 
1019 	SfxPoolItemArray_Impl* pItemArr = *(pImp->ppPoolItems + GetIndex_Impl(nWhich));
1020 	if( pItemArr && nOfst < pItemArr->size() )
1021 		return (*pItemArr)[nOfst];
1022 
1023 	return 0;
1024 }
1025 
1026 // -----------------------------------------------------------------------
1027 
1028 sal_uInt32 SfxItemPool::GetItemCount2(sal_uInt16 nWhich) const
1029 {
1030 	DBG_CHKTHIS(SfxItemPool, 0);
1031 
1032 	if ( !IsInRange(nWhich) )
1033 	{
1034 		if ( pSecondary )
1035 			return pSecondary->GetItemCount2( nWhich );
1036 		SFX_ASSERT( 0, nWhich, "unknown Which-Id - cannot resolve surrogate" );
1037 		return 0;
1038 	}
1039 
1040 	SfxPoolItemArray_Impl* pItemArr = *(pImp->ppPoolItems + GetIndex_Impl(nWhich));
1041 	if  ( pItemArr )
1042 		return pItemArr->size();
1043 	return 0;
1044 }
1045 
1046 // -----------------------------------------------------------------------
1047 
1048 sal_uInt16 SfxItemPool::GetWhich( sal_uInt16 nSlotId, sal_Bool bDeep ) const
1049 {
1050 	if ( !IsSlot(nSlotId) )
1051 		return nSlotId;
1052 
1053 #ifdef TF_POOLABLE
1054 	sal_uInt16 nCount = nEnd - nStart + 1;
1055 	for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs )
1056 		if ( pItemInfos[nOfs]._nSID == nSlotId )
1057 			return nOfs + nStart;
1058 #else
1059 	if ( pSlotIds )
1060 	{
1061 		sal_uInt16 nCount = nEnd - nStart + 1;
1062 		for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs )
1063 			if ( pSlotIds[nOfs] == nSlotId )
1064 				return nOfs + nStart;
1065 	}
1066 #endif
1067 	if ( pSecondary && bDeep )
1068 		return pSecondary->GetWhich(nSlotId);
1069 	return nSlotId;
1070 }
1071 
1072 // -----------------------------------------------------------------------
1073 
1074 sal_uInt16 SfxItemPool::GetSlotId( sal_uInt16 nWhich, sal_Bool bDeep ) const
1075 {
1076 	if ( !IsWhich(nWhich) )
1077 		return nWhich;
1078 
1079 	if ( !IsInRange( nWhich ) )
1080 	{
1081 		if ( pSecondary && bDeep )
1082 			return pSecondary->GetSlotId(nWhich);
1083 		SFX_ASSERT( 0, nWhich, "unknown Which-Id - cannot get slot-id" );
1084 		return 0;
1085 	}
1086 #ifdef TF_POOLABLE
1087 
1088 	sal_uInt16 nSID = pItemInfos[nWhich - nStart]._nSID;
1089 	return nSID ? nSID : nWhich;
1090 #else
1091 	else if ( pSlotIds )
1092 		return pSlotIds[nWhich - nStart];
1093 	return nWhich;
1094 #endif
1095 }
1096 
1097 // -----------------------------------------------------------------------
1098 
1099 sal_uInt16 SfxItemPool::GetTrueWhich( sal_uInt16 nSlotId, sal_Bool bDeep ) const
1100 {
1101 	if ( !IsSlot(nSlotId) )
1102 		return 0;
1103 
1104 #ifdef TF_POOLABLE
1105 	sal_uInt16 nCount = nEnd - nStart + 1;
1106 	for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs )
1107 		if ( pItemInfos[nOfs]._nSID == nSlotId )
1108 			return nOfs + nStart;
1109 #else
1110 	if ( pSlotIds )
1111 	{
1112 		sal_uInt16 nCount = nEnd - nStart + 1;
1113 		for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs )
1114 			if ( pSlotIds[nOfs] == nSlotId )
1115 				return nOfs + nStart;
1116 	}
1117 #endif
1118 	if ( pSecondary && bDeep )
1119 		return pSecondary->GetTrueWhich(nSlotId);
1120 	return 0;
1121 }
1122 
1123 // -----------------------------------------------------------------------
1124 
1125 sal_uInt16 SfxItemPool::GetTrueSlotId( sal_uInt16 nWhich, sal_Bool bDeep ) const
1126 {
1127 	if ( !IsWhich(nWhich) )
1128 		return 0;
1129 
1130 	if ( !IsInRange( nWhich ) )
1131 	{
1132 		if ( pSecondary && bDeep )
1133 			return pSecondary->GetTrueSlotId(nWhich);
1134 		SFX_ASSERT( 0, nWhich, "unknown Which-Id - cannot get slot-id" );
1135 		return 0;
1136 	}
1137 #ifdef TF_POOLABLE
1138 	return pItemInfos[nWhich - nStart]._nSID;
1139 #else
1140 	else if ( pSlotIds )
1141 		return pSlotIds[nWhich - nStart];
1142 	else
1143 		return 0;
1144 #endif
1145 }
1146 // -----------------------------------------------------------------------
1147 void SfxItemPool::SetFileFormatVersion( sal_uInt16 nFileFormatVersion )
1148 
1149 /*  [Description]
1150 
1151 	You must call this function to set the file format version after
1152 	concatenating your secondary-pools but before you store any
1153 	pool, itemset or item. Only set the version at the master pool,
1154 	never at any secondary pool.
1155 */
1156 
1157 {
1158 	DBG_ASSERT( this == pMaster,
1159 				"SfxItemPool::SetFileFormatVersion() but not a master pool" );
1160 	for ( SfxItemPool *pPool = this; pPool; pPool = pPool->pSecondary )
1161 		pPool->_nFileFormatVersion = nFileFormatVersion;
1162 }
1163 
1164 
1165