xref: /trunk/main/svl/source/items/itemset.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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_svl.hxx"
30 
31 #include <string.h>
32 
33 #if STLPORT_VERSION>=321
34 #include <cstdarg>
35 #endif
36 
37 #define _SVSTDARR_USHORTS
38 #define _SVSTDARR_ULONGS
39 
40 #include <svl/svstdarr.hxx>
41 #include <svl/itemset.hxx>
42 #include <svl/itempool.hxx>
43 #include <svl/itemiter.hxx>
44 #include <svl/whiter.hxx>
45 #include <svl/nranges.hxx>
46 #include "whassert.hxx"
47 
48 #include <tools/stream.hxx>
49 #include <tools/solar.h>
50 
51 // STATIC DATA -----------------------------------------------------------
52 
53 static const sal_uInt16 nInitCount = 10; // einzelne USHORTs => 5 Paare ohne '0'
54 #ifdef DBG_UTIL
55 static sal_uLong nRangesCopyCount = 0;   // wie oft wurden Ranges kopiert
56 #endif
57 
58 DBG_NAME(SfxItemSet)
59 
60 //========================================================================
61 
62 #define NUMTYPE         sal_uInt16
63 #define SvNums          SvUShorts
64 #define SfxNumRanges    SfxUShortRanges
65 #include "nranges.cxx"
66 #undef NUMTYPE
67 #undef SvNums
68 #undef SfxNumRanges
69 
70 #define NUMTYPE         sal_uLong
71 #define SvNums          SvULongs
72 #define SfxNumRanges    SfxULongRanges
73 #include "nranges.cxx"
74 #undef NUMTYPE
75 #undef SvNums
76 #undef SfxNumRanges
77 
78 //========================================================================
79 
80 #ifdef DBG_UTIL
81 
82 
83 const sal_Char *DbgCheckItemSet( const void* pVoid )
84 {
85     const SfxItemSet *pSet = (const SfxItemSet*) pVoid;
86     SfxWhichIter aIter( *pSet );
87     sal_uInt16 nCount = 0, n = 0;
88     for ( sal_uInt16 nWh = aIter.FirstWhich(); nWh; nWh = aIter.NextWhich(), ++n )
89     {
90         const SfxPoolItem *pItem = pSet->_aItems[n];
91         if ( pItem )
92         {
93             ++nCount;
94             DBG_ASSERT( IsInvalidItem(pItem) ||
95                         pItem->Which() == 0 || pItem->Which() == nWh,
96                         "SfxItemSet: invalid which-id" );
97             DBG_ASSERT( IsInvalidItem(pItem) || !pItem->Which() ||
98                     !SfxItemPool::IsWhich(pItem->Which()) ||
99                     pSet->GetPool()->IsItemFlag(nWh, SFX_ITEM_NOT_POOLABLE) ||
100                     SFX_ITEMS_NULL != pSet->GetPool()->GetSurrogate(pItem),
101                     "SfxItemSet: item in set which is not in pool" );
102         }
103 
104     }
105     DBG_ASSERT( pSet->_nCount == nCount, "wrong SfxItemSet::nCount detected" );
106 
107     return 0;
108 }
109 
110 #endif
111 // -----------------------------------------------------------------------
112 
113 SfxItemSet::SfxItemSet
114 (
115     SfxItemPool&    rPool,          /* der Pool, in dem die SfxPoolItems,
116                                        welche in dieses SfxItemSet gelangen,
117                                        aufgenommen werden sollen */
118     sal_Bool
119 #ifdef DBG_UTIL
120 #ifdef SFX_ITEMSET_NO_DEFAULT_CTOR
121 
122                     bTotalRanges    /* komplette Pool-Ranges uebernehmen,
123                                        muss auf sal_True gesetzt werden */
124 #endif
125 #endif
126 )
127 /*  [Beschreibung]
128 
129     Konstruktor fuer ein SfxItemSet mit genau den Which-Bereichen, welche
130     dem angegebenen <SfxItemPool> bekannt sind.
131 
132 
133     [Anmerkung]
134 
135     F"ur Sfx-Programmierer ein derart konstruiertes SfxItemSet kann
136     keinerlei Items mit Slot-Ids als Which-Werte aufnehmen!
137 */
138 
139 :   _pPool( &rPool ),
140     _pParent( 0 ),
141     _nCount( 0 )
142 {
143     DBG_CTOR(SfxItemSet, DbgCheckItemSet);
144     DBG_ASSERTWARNING( _pPool == _pPool->GetMasterPool(), "kein Master-Pool" );
145     DBG( _pChildCountCtor; *_pChildCount(this) = 0 );
146 //  DBG_ASSERT( bTotalRanges || abs( &bTotalRanges - this ) < 1000,
147 //              "please use suitable ranges" );
148 #ifdef DBG_UTIL
149 #ifdef SFX_ITEMSET_NO_DEFAULT_CTOR
150     if ( !bTotalRanges )
151         *(int*)0 = 0; // GPF
152 #endif
153 #endif
154 
155     _pWhichRanges = (sal_uInt16*) _pPool->GetFrozenIdRanges();
156     DBG_ASSERT( _pWhichRanges, "don't create ItemSets with full range before FreezeIdRanges()" );
157     if ( !_pWhichRanges )
158         _pPool->FillItemIdRanges_Impl( _pWhichRanges );
159 
160     const sal_uInt16 nSize = TotalCount();
161     _aItems = new const SfxPoolItem* [ nSize ];
162     memset( (void*) _aItems, 0, nSize * sizeof( SfxPoolItem* ) );
163 }
164 
165 // -----------------------------------------------------------------------
166 
167 SfxItemSet::SfxItemSet( SfxItemPool& rPool, sal_uInt16 nWhich1, sal_uInt16 nWhich2 ):
168     _pPool( &rPool ),
169     _pParent( 0 ),
170     _nCount( 0 )
171 {
172     DBG_CTOR(SfxItemSet, DbgCheckItemSet);
173     DBG_ASSERT( nWhich1 <= nWhich2, "Ungueltiger Bereich" );
174     DBG_ASSERTWARNING( _pPool == _pPool->GetMasterPool(), "kein Master-Pool" );
175     DBG( _pChildCountCtor; *_pChildCount(this) = 0 );
176 
177     InitRanges_Impl(nWhich1, nWhich2);
178 }
179 
180 // -----------------------------------------------------------------------
181 
182 void SfxItemSet::InitRanges_Impl(sal_uInt16 nWh1, sal_uInt16 nWh2)
183 {
184     DBG_CHKTHIS(SfxItemSet, 0);
185     _pWhichRanges = new sal_uInt16[ 3 ];
186     *(_pWhichRanges+0) = nWh1;
187     *(_pWhichRanges+1) = nWh2;
188     *(_pWhichRanges+2) = 0;
189     const sal_uInt16 nRg = nWh2 - nWh1 + 1;
190     _aItems = new const SfxPoolItem* [ nRg ];
191     memset( (void*) _aItems, 0, nRg * sizeof( SfxPoolItem* ) );
192 }
193 
194 // -----------------------------------------------------------------------
195 
196 void SfxItemSet::InitRanges_Impl(va_list pArgs, sal_uInt16 nWh1, sal_uInt16 nWh2, sal_uInt16 nNull)
197 {
198     DBG_CHKTHIS(SfxItemSet, 0);
199 
200     sal_uInt16 nSize = InitializeRanges_Impl( _pWhichRanges, pArgs, nWh1, nWh2, nNull );
201     _aItems = new const SfxPoolItem* [ nSize ];
202     memset( (void*) _aItems, 0, sizeof( SfxPoolItem* ) * nSize );
203 }
204 
205 // -----------------------------------------------------------------------
206 
207 SfxItemSet::SfxItemSet( SfxItemPool& rPool,
208                         USHORT_ARG nWh1, USHORT_ARG nWh2, USHORT_ARG nNull, ... ):
209     _pPool( &rPool ),
210     _pParent( 0 ),
211     _pWhichRanges( 0 ),
212     _nCount( 0 )
213 {
214     DBG_CTOR(SfxItemSet, DbgCheckItemSet);
215     DBG_ASSERT( nWh1 <= nWh2, "Ungueltiger Bereich" );
216     DBG_ASSERTWARNING( _pPool == _pPool->GetMasterPool(), "kein Master-Pool" );
217     DBG( _pChildCountCtor; *_pChildCount(this) = 0 );
218 
219     if(!nNull)
220         InitRanges_Impl(
221             sal::static_int_cast< sal_uInt16 >(nWh1),
222             sal::static_int_cast< sal_uInt16 >(nWh2));
223     else {
224         va_list pArgs;
225         va_start( pArgs, nNull );
226         InitRanges_Impl(
227             pArgs, sal::static_int_cast< sal_uInt16 >(nWh1),
228             sal::static_int_cast< sal_uInt16 >(nWh2),
229             sal::static_int_cast< sal_uInt16 >(nNull));
230     }
231 }
232 
233 // -----------------------------------------------------------------------
234 
235 void SfxItemSet::InitRanges_Impl(const sal_uInt16 *pWhichPairTable)
236 {
237     DBG_CHKTHIS(SfxItemSet, 0);
238     DBG_TRACE1("SfxItemSet: Ranges-CopyCount==%ul", ++nRangesCopyCount);
239 
240     sal_uInt16 nCnt = 0;
241     const sal_uInt16* pPtr = pWhichPairTable;
242     while( *pPtr )
243     {
244         nCnt += ( *(pPtr+1) - *pPtr ) + 1;
245         pPtr += 2;
246     }
247 
248     _aItems = new const SfxPoolItem* [ nCnt ];
249     memset( (void*) _aItems, 0, sizeof( SfxPoolItem* ) * nCnt );
250 
251     std::ptrdiff_t cnt = pPtr - pWhichPairTable +1;
252     _pWhichRanges = new sal_uInt16[ cnt ];
253     memcpy( _pWhichRanges, pWhichPairTable, sizeof( sal_uInt16 ) * cnt );
254 }
255 
256 
257 // -----------------------------------------------------------------------
258 
259 SfxItemSet::SfxItemSet( SfxItemPool& rPool, const sal_uInt16* pWhichPairTable ):
260     _pPool( &rPool ),
261     _pParent( 0 ),
262     _pWhichRanges(0),
263     _nCount( 0 )
264 {
265     DBG_CTOR(SfxItemSet, 0);
266     DBG_ASSERTWARNING( _pPool == _pPool->GetMasterPool(), "kein Master-Pool" );
267     DBG( _pChildCountCtor; *_pChildCount(this) = 0 );
268 
269     // pWhichPairTable == 0 ist f"ur das SfxAllEnumItemSet
270     if ( pWhichPairTable )
271         InitRanges_Impl(pWhichPairTable);
272 }
273 
274 // -----------------------------------------------------------------------
275 
276 SfxItemSet::SfxItemSet( const SfxItemSet& rASet ):
277     _pPool( rASet._pPool ),
278     _pParent( rASet._pParent ),
279     _nCount( rASet._nCount )
280 {
281     DBG_CTOR(SfxItemSet, DbgCheckItemSet);
282     DBG_ASSERTWARNING( _pPool == _pPool->GetMasterPool(), "kein Master-Pool" );
283     DBG( _pChildCountCtor; *_pChildCount(this) = 0 );
284     DBG( ++*_pChildCount(_pParent) );
285 
286     // errechne die Anzahl von Attributen
287     sal_uInt16 nCnt = 0;
288     sal_uInt16* pPtr = rASet._pWhichRanges;
289     while( *pPtr )
290     {
291         nCnt += ( *(pPtr+1) - *pPtr ) + 1;
292         pPtr += 2;
293     }
294 
295     _aItems = new const SfxPoolItem* [ nCnt ];
296 
297     // Attribute kopieren
298     SfxItemArray ppDst = _aItems, ppSrc = rASet._aItems;
299     for( sal_uInt16 n = nCnt; n; --n, ++ppDst, ++ppSrc )
300         if ( 0 == *ppSrc ||                 // aktueller Default?
301              IsInvalidItem(*ppSrc) ||       // Dont Care?
302              IsStaticDefaultItem(*ppSrc) )  // nicht zu poolende Defaults
303             // einfach Pointer kopieren
304             *ppDst = *ppSrc;
305         else if ( _pPool->IsItemFlag( **ppSrc, SFX_ITEM_POOLABLE ) )
306         {
307             // einfach Pointer kopieren und Ref-Count erh"ohen
308             *ppDst = *ppSrc;
309             ( (SfxPoolItem*) (*ppDst) )->AddRef();
310         }
311         else if ( !(*ppSrc)->Which() )
312             *ppDst = (*ppSrc)->Clone();
313         else
314             // !IsPoolable() => via Pool zuweisen
315             *ppDst = &_pPool->Put( **ppSrc );
316 
317     // dann noch die Which Ranges kopieren
318     DBG_TRACE1("SfxItemSet: Ranges-CopyCount==%ul", ++nRangesCopyCount);
319     std::ptrdiff_t cnt = pPtr - rASet._pWhichRanges+1;
320     _pWhichRanges = new sal_uInt16[ cnt ];
321     memcpy( _pWhichRanges, rASet._pWhichRanges, sizeof( sal_uInt16 ) * cnt);
322 }
323 
324 // -----------------------------------------------------------------------
325 
326 SfxItemSet::~SfxItemSet()
327 {
328     DBG_DTOR(SfxItemSet, DbgCheckItemSet);
329 #ifdef DBG_UTIL
330     DBG( DBG_ASSERT( 0 == *_pChildCount(this), "SfxItemSet: deleting parent-itemset" ) )
331 #endif
332 
333     sal_uInt16 nCount = TotalCount();
334     if( Count() )
335     {
336         SfxItemArray ppFnd = _aItems;
337         for( sal_uInt16 nCnt = nCount; nCnt; --nCnt, ++ppFnd )
338             if( *ppFnd && !IsInvalidItem(*ppFnd) )
339             {
340                 if( !(*ppFnd)->Which() )
341                     delete (SfxPoolItem*) *ppFnd;
342                 else {
343                     // noch mehrer Referenzen vorhanden, also nur den
344                     // ReferenzCounter manipulieren
345                     if ( 1 < (*ppFnd)->GetRefCount() && !IsDefaultItem(*ppFnd) )
346                         (*ppFnd)->ReleaseRef();
347                     else
348                         if ( !IsDefaultItem(*ppFnd) )
349                             // aus dem Pool loeschen
350                             _pPool->Remove( **ppFnd );
351                 }
352             }
353     }
354 
355     // FIXME: could be delete[] (SfxPoolItem **)_aItems;
356     delete[] _aItems;
357     if ( _pWhichRanges != _pPool->GetFrozenIdRanges() )
358         delete[] _pWhichRanges;
359     _pWhichRanges = 0; // for invariant-testing
360 
361     DBG( --*_pChildCount(_pParent) );
362     DBG( delete _pChildCount(this); _pChildCountDtor );
363 }
364 
365 // -----------------------------------------------------------------------
366 
367 sal_uInt16 SfxItemSet::ClearItem( sal_uInt16 nWhich )
368 
369 // einzelnes Item oder alle Items (nWhich==0) l"oschen
370 
371 {
372     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
373     if( !Count() )
374         return 0;
375 
376     sal_uInt16 nDel = 0;
377     SfxItemArray ppFnd = _aItems;
378 
379     if( nWhich )
380     {
381         const sal_uInt16* pPtr = _pWhichRanges;
382         while( *pPtr )
383         {
384             // in diesem Bereich?
385             if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
386             {
387                 // "uberhaupt gesetzt?
388                 ppFnd += nWhich - *pPtr;
389                 if( *ppFnd )
390                 {
391                     // wegen der Assertions ins Sub-Calls mu\s das hier sein
392                     --_nCount;
393                     const SfxPoolItem *pItemToClear = *ppFnd;
394                     *ppFnd = 0;
395 
396                     if ( !IsInvalidItem(pItemToClear) )
397                     {
398                         if ( nWhich <= SFX_WHICH_MAX )
399                         {
400                             const SfxPoolItem& rNew = _pParent
401                                     ? _pParent->Get( nWhich, sal_True )
402                                     : _pPool->GetDefaultItem( nWhich );
403 
404                             Changed( *pItemToClear, rNew );
405                         }
406                         if ( pItemToClear->Which() )
407                             _pPool->Remove( *pItemToClear );
408                     }
409                     ++nDel;
410                 }
411 
412                 // gefunden => raus
413                 break;
414             }
415             ppFnd += *(pPtr+1) - *pPtr + 1;
416             pPtr += 2;
417         }
418     }
419     else
420     {
421         nDel = _nCount;
422 
423         sal_uInt16* pPtr = _pWhichRanges;
424         while( *pPtr )
425         {
426             for( nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
427                 if( *ppFnd )
428                 {
429                     // wegen der Assertions ins Sub-Calls mu\s das hier sein
430                     --_nCount;
431                     const SfxPoolItem *pItemToClear = *ppFnd;
432                     *ppFnd = 0;
433 
434                     if ( !IsInvalidItem(pItemToClear) )
435                     {
436                         if ( nWhich <= SFX_WHICH_MAX )
437                         {
438                             const SfxPoolItem& rNew = _pParent
439                                     ? _pParent->Get( nWhich, sal_True )
440                                     : _pPool->GetDefaultItem( nWhich );
441 
442                             Changed( *pItemToClear, rNew );
443                         }
444 
445                         // #i32448#
446                         // Take care of disabled items, too.
447                         if(!pItemToClear->nWhich)
448                         {
449                             // item is disabled, delete it
450                             delete pItemToClear;
451                         }
452                         else
453                         {
454                             // remove item from pool
455                             _pPool->Remove( *pItemToClear );
456                         }
457                     }
458                 }
459             pPtr += 2;
460         }
461     }
462     return nDel;
463 }
464 
465 // -----------------------------------------------------------------------
466 
467 void SfxItemSet::ClearInvalidItems( sal_Bool bHardDefault )
468 {
469     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
470     sal_uInt16* pPtr = _pWhichRanges;
471     SfxItemArray ppFnd = _aItems;
472     if ( bHardDefault )
473         while( *pPtr )
474         {
475             for ( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
476                 if ( IsInvalidItem(*ppFnd) )
477                      *ppFnd = &_pPool->Put( _pPool->GetDefaultItem(nWhich) );
478             pPtr += 2;
479         }
480     else
481         while( *pPtr )
482         {
483             for( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
484                 if( IsInvalidItem(*ppFnd) )
485                 {
486                     *ppFnd = 0;
487                     --_nCount;
488                 }
489             pPtr += 2;
490         }
491 }
492 
493 //------------------------------------------------------------------------
494 
495 
496 void SfxItemSet::InvalidateAllItems()
497 {
498     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
499     DBG_ASSERT( !_nCount, "Es sind noch Items gesetzt" );
500 
501     memset( (void*)_aItems, -1, ( _nCount = TotalCount() ) * sizeof( SfxPoolItem*) );
502 }
503 
504 // -----------------------------------------------------------------------
505 
506 SfxItemState SfxItemSet::GetItemState( sal_uInt16 nWhich,
507                                         sal_Bool bSrchInParent,
508                                         const SfxPoolItem **ppItem ) const
509 {
510     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
511     // suche den Bereich in dem das Which steht:
512     const SfxItemSet* pAktSet = this;
513     SfxItemState eRet = SFX_ITEM_UNKNOWN;
514     do
515     {
516         SfxItemArray ppFnd = pAktSet->_aItems;
517         const sal_uInt16* pPtr = pAktSet->_pWhichRanges;
518         if (pPtr)
519         {
520             while ( *pPtr )
521             {
522                 if ( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
523                 {
524                     // in diesem Bereich
525                     ppFnd += nWhich - *pPtr;
526                     if ( !*ppFnd )
527                     {
528                         eRet = SFX_ITEM_DEFAULT;
529                         if( !bSrchInParent )
530                             return eRet;  // nicht vorhanden
531                         break; // JP: in den Parents weitersuchen !!!
532                     }
533 
534                     if ( (SfxPoolItem*) -1 == *ppFnd )
535                         // Unterschiedlich vorhanden
536                         return SFX_ITEM_DONTCARE;
537 
538                     if ( (*ppFnd)->Type() == TYPE(SfxVoidItem) )
539                         return SFX_ITEM_DISABLED;
540 
541                     if (ppItem)
542                     {
543                         #ifdef DBG_UTIL
544                         const SfxPoolItem *pItem = *ppFnd;
545                         DBG_ASSERT( !pItem->ISA(SfxSetItem) ||
546                                 0 != &((const SfxSetItem*)pItem)->GetItemSet(),
547                                 "SetItem without ItemSet" );
548                         #endif
549                         *ppItem = *ppFnd;
550                     }
551                     return SFX_ITEM_SET;
552                 }
553                 ppFnd += *(pPtr+1) - *pPtr + 1;
554                 pPtr += 2;
555             }
556         }
557     } while( bSrchInParent && 0 != ( pAktSet = pAktSet->_pParent ));
558     return eRet;
559 }
560 
561 // -----------------------------------------------------------------------
562 
563 const SfxPoolItem* SfxItemSet::Put( const SfxPoolItem& rItem, sal_uInt16 nWhich )
564 {
565     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
566     DBG_ASSERT( !rItem.ISA(SfxSetItem) ||
567             0 != &((const SfxSetItem&)rItem).GetItemSet(),
568             "SetItem without ItemSet" );
569     if ( !nWhich )
570         return 0; //! nur wegen Outliner-Bug
571     SfxItemArray ppFnd = _aItems;
572     const sal_uInt16* pPtr = _pWhichRanges;
573     while( *pPtr )
574     {
575         if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
576         {
577             // in diesem Bereich
578             ppFnd += nWhich - *pPtr;
579             if( *ppFnd )        // schon einer vorhanden
580             {
581                 // selbes Item bereits vorhanden?
582                 if ( *ppFnd == &rItem )
583                     return 0;
584 
585                 // wird dontcare oder disabled mit was echtem ueberschrieben?
586                 if ( rItem.Which() && ( IsInvalidItem(*ppFnd) || !(*ppFnd)->Which() ) )
587                 {
588                     *ppFnd = &_pPool->Put( rItem, nWhich );
589                     return *ppFnd;
590                 }
591 
592                 // wird disabled?
593                 if( !rItem.Which() )
594                 {
595                     *ppFnd = rItem.Clone(_pPool);
596                     return 0;
597                 }
598                 else
599                 {
600                     // selber Wert bereits vorhanden?
601                     if ( rItem == **ppFnd )
602                         return 0;
603 
604                     // den neuen eintragen, den alten austragen
605                     const SfxPoolItem& rNew = _pPool->Put( rItem, nWhich );
606                     const SfxPoolItem* pOld = *ppFnd;
607                     *ppFnd = &rNew;
608                     if(nWhich <= SFX_WHICH_MAX)
609                         Changed( *pOld, rNew );
610                     _pPool->Remove( *pOld );
611                 }
612             }
613             else
614             {
615                 ++_nCount;
616                 if( !rItem.Which() )
617                     *ppFnd = rItem.Clone(_pPool);
618                 else {
619                     const SfxPoolItem& rNew = _pPool->Put( rItem, nWhich );
620                     *ppFnd = &rNew;
621                     if (nWhich <= SFX_WHICH_MAX )
622                     {
623                         const SfxPoolItem& rOld = _pParent
624                             ? _pParent->Get( nWhich, sal_True )
625                             : _pPool->GetDefaultItem( nWhich );
626                         Changed( rOld, rNew );
627                     }
628                 }
629             }
630             SFX_ASSERT( !_pPool->IsItemFlag(nWhich, SFX_ITEM_POOLABLE) ||
631                         rItem.ISA(SfxSetItem) || **ppFnd == rItem,
632                         nWhich, "putted Item unequal" );
633             return *ppFnd;
634         }
635         ppFnd += *(pPtr+1) - *pPtr + 1;
636         pPtr += 2;
637     }
638     return 0;
639 }
640 
641 // -----------------------------------------------------------------------
642 
643 int SfxItemSet::Put( const SfxItemSet& rSet, sal_Bool bInvalidAsDefault )
644 {
645     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
646     sal_Bool bRet = sal_False;
647     if( rSet.Count() )
648     {
649         SfxItemArray ppFnd = rSet._aItems;
650         const sal_uInt16* pPtr = rSet._pWhichRanges;
651         while ( *pPtr )
652         {
653             for ( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
654                 if( *ppFnd )
655                 {
656                     if ( IsInvalidItem( *ppFnd ) )
657                     {
658                         if ( bInvalidAsDefault )
659                             bRet |= 0 != ClearItem( nWhich );
660                             // gab GPF bei non.WIDs:
661                             // bRet |= 0 != Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
662                         else
663                             InvalidateItem( nWhich );
664                     }
665                     else
666                         bRet |= 0 != Put( **ppFnd, nWhich );
667                 }
668             pPtr += 2;
669         }
670     }
671     return bRet;
672 }
673 
674 // -----------------------------------------------------------------------
675 
676 void SfxItemSet::PutExtended
677 (
678     const SfxItemSet&   rSet,           // Quelle der zu puttenden Items
679     SfxItemState        eDontCareAs,    // was mit DontCare-Items passiert
680     SfxItemState        eDefaultAs      // was mit Default-Items passiert
681 )
682 
683 /*  [Beschreibung]
684 
685     Diese Methode "ubernimmt die Items aus 'rSet' in '*this'. Die
686     Which-Bereiche in '*this', die in 'rSet' nicht vorkommen bleiben unver-
687     "andert. Der Which-Bereich von '*this' bleibt auch unver"andert.
688 
689     In 'rSet' gesetzte Items werden auch in '*this*' gesetzt. Default-
690     (0 Pointer) und Invalid- (-1 Pointer) Items werden je nach Parameter
691     ('eDontCareAs' und 'eDefaultAs' behandelt:
692 
693     SFX_ITEM_SET:       hart auf Default des Pools gesetzt
694     SFX_ITEM_DEFAULT:   gel"oscht (0 Pointer)
695     SFX_ITEM_DONTCARE:  invalidiert (-1 Pointer)
696 
697     Alle anderen Werte f"ur 'eDontCareAs' und 'eDefaultAs' sind ung"ultig.
698 */
699 
700 {
701     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
702 
703     // don't "optimize" with "if( rSet.Count()" because of dont-care + defaults
704     SfxItemArray ppFnd = rSet._aItems;
705     const sal_uInt16* pPtr = rSet._pWhichRanges;
706     while ( *pPtr )
707     {
708         for ( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
709             if( *ppFnd )
710             {
711                 if ( IsInvalidItem( *ppFnd ) )
712                 {
713                     // Item ist DontCare:
714                     switch ( eDontCareAs )
715                     {
716                         case SFX_ITEM_SET:
717                             Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
718                             break;
719 
720                         case SFX_ITEM_DEFAULT:
721                             ClearItem( nWhich );
722                             break;
723 
724                         case SFX_ITEM_DONTCARE:
725                             InvalidateItem( nWhich );
726                             break;
727 
728                         default:
729                             DBG_ERROR( "invalid Argument for eDontCareAs" );
730                     }
731                 }
732                 else
733                     // Item ist gesetzt:
734                     Put( **ppFnd, nWhich );
735             }
736             else
737             {
738                 // Item ist Default:
739                 switch ( eDefaultAs )
740                 {
741                     case SFX_ITEM_SET:
742                         Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
743                         break;
744 
745                     case SFX_ITEM_DEFAULT:
746                         ClearItem( nWhich );
747                         break;
748 
749                     case SFX_ITEM_DONTCARE:
750                         InvalidateItem( nWhich );
751                         break;
752 
753                     default:
754                         DBG_ERROR( "invalid Argument for eDefaultAs" );
755                 }
756             }
757         pPtr += 2;
758     }
759 }
760 
761 // -----------------------------------------------------------------------
762 
763 void SfxItemSet::MergeRange( sal_uInt16 nFrom, sal_uInt16 nTo )
764 /** <H3>Description</H3>
765 
766     Expands the ranges of settable items by 'nFrom' to 'nTo'. Keeps state of
767     items which are new ranges too.
768 */
769 
770 {
771     // special case: exactly one sal_uInt16 which is already included?
772     if ( nFrom == nTo && SFX_ITEM_AVAILABLE <= GetItemState(nFrom, sal_False) )
773         return;
774 
775     // merge new range
776     SfxUShortRanges aRanges( _pWhichRanges );
777     aRanges += SfxUShortRanges( nFrom, nTo );
778     SetRanges( aRanges );
779 }
780 
781 // -----------------------------------------------------------------------
782 
783 void SfxItemSet::SetRanges( const sal_uInt16 *pNewRanges )
784 
785 /** <H3>Description</H3>
786 
787     Modifies the ranges of settable items. Keeps state of items which
788     are new ranges too.
789 */
790 
791 {
792     // identische Ranges?
793     if ( _pWhichRanges == pNewRanges )
794         return;
795     const sal_uInt16* pOld = _pWhichRanges;
796     const sal_uInt16* pNew = pNewRanges;
797     while ( *pOld == *pNew )
798     {
799         if ( !*pOld && !*pNew )
800             return;
801         ++pOld, ++pNew;
802     }
803 
804     // create new item-array (by iterating through all new ranges)
805     sal_uLong        nSize = Capacity_Impl(pNewRanges);
806     SfxItemArray aNewItems = new const SfxPoolItem* [ nSize ];
807     sal_uInt16       n = 0, nNewCount = 0;
808     if ( _nCount == 0 )
809         memset( aNewItems, 0, nSize * sizeof( SfxPoolItem* ) );
810     else
811     {
812         for ( const sal_uInt16 *pRange = pNewRanges; *pRange; pRange += 2 )
813         {
814             // iterate through all ids in the range
815             for ( sal_uInt16 nWID = *pRange; nWID <= pRange[1]; ++nWID, ++n )
816             {
817                 // direct move of pointer (not via pool)
818                 SfxItemState eState = GetItemState( nWID, sal_False, aNewItems+n );
819                 if ( SFX_ITEM_SET == eState )
820                 {
821                     // increment new item count and possibly increment ref count
822                     ++nNewCount;
823                     aNewItems[n]->AddRef();
824                 }
825                 else if ( SFX_ITEM_DISABLED == eState )
826                 {
827                     // put "disabled" item
828                     ++nNewCount;
829                     aNewItems[n] = new SfxVoidItem(0);
830                 }
831                 else if ( SFX_ITEM_DONTCARE == eState )
832                 {
833                     ++nNewCount;
834                     aNewItems[n] = (SfxPoolItem*)-1;
835                 }
836                 else
837                 {
838                     // default
839                     aNewItems[n] = 0;
840                 }
841             }
842         }
843         // free old items
844         sal_uInt16 nOldTotalCount = TotalCount();
845         for ( sal_uInt16 nItem = 0; nItem < nOldTotalCount; ++nItem )
846         {
847             const SfxPoolItem *pItem = _aItems[nItem];
848             if ( pItem && !IsInvalidItem(pItem) && pItem->Which() )
849                 _pPool->Remove(*pItem);
850         }
851     }
852 
853     // replace old items-array and ranges
854     delete[] _aItems;
855     _aItems = aNewItems;
856     _nCount = nNewCount;
857 
858     if( pNewRanges == GetPool()->GetFrozenIdRanges() )
859     {
860         delete[] _pWhichRanges;
861         _pWhichRanges = ( sal_uInt16* ) pNewRanges;
862     }
863     else
864     {
865         sal_uInt16 nCount = Count_Impl(pNewRanges) + 1;
866         if ( _pWhichRanges != _pPool->GetFrozenIdRanges() )
867             delete[] _pWhichRanges;
868         _pWhichRanges = new sal_uInt16[ nCount ];
869         memcpy( _pWhichRanges, pNewRanges, sizeof( sal_uInt16 ) * nCount );
870     }
871 }
872 
873 // -----------------------------------------------------------------------
874 
875 int SfxItemSet::Set
876 (
877     const SfxItemSet&   rSet,   /*  das SfxItemSet, dessen SfxPoolItems
878                                     "ubernommen werden sollen */
879 
880     sal_Bool                bDeep   /*  sal_True (default)
881                                     auch die SfxPoolItems aus den ggf. an
882                                     rSet vorhandenen Parents werden direkt
883                                     in das SfxItemSet "ubernommen
884 
885                                     sal_False
886                                     die SfxPoolItems aus den Parents von
887                                     rSet werden nicht ber"ucksichtigt */
888 )
889 
890 /*  [Beschreibung]
891 
892     Das SfxItemSet nimmt genau die SfxPoolItems an, die auch in
893     rSet gesetzt sind und im eigenen <Which-Bereich> liegen. Alle
894     anderen werden entfernt. Der SfxItemPool wird dabei beibehalten,
895     so da"s die "ubernommenen SfxPoolItems dabei ggf. vom SfxItemPool
896     von rSet in den SfxItemPool von *this "ubernommen werden.
897 
898     SfxPoolItems, f"ur die in rSet IsInvalidItem() == sal_True gilt,
899     werden als Invalid-Item "ubernommen.
900 
901 
902     [R"uckgabewert]
903 
904     int                             sal_True
905                                     es wurden SfxPoolItems "ubernommen
906 
907                                     sal_False
908                                     es wurden keine SfxPoolItems "ubernommen,
909                                     da z.B. die Which-Bereiche der SfxItemSets
910                                     keine Schnittmenge haben oder in der
911                                     Schnittmenge keine SfxPoolItems in rSet
912                                     gesetzt sind
913 
914 */
915 
916 {
917     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
918     int bRet = sal_False;
919     if ( _nCount )
920         ClearItem();
921     if ( bDeep )
922     {
923         SfxWhichIter aIter(*this);
924         sal_uInt16 nWhich = aIter.FirstWhich();
925         while ( nWhich )
926         {
927             const SfxPoolItem* pItem;
928             if( SFX_ITEM_SET == rSet.GetItemState( nWhich, sal_True, &pItem ) )
929                 bRet |= 0 != Put( *pItem, pItem->Which() );
930             nWhich = aIter.NextWhich();
931         }
932     }
933     else
934         bRet = Put(rSet, sal_False);
935 
936     return bRet;
937 }
938 
939 //------------------------------------------------------------------------
940 
941 const SfxPoolItem* SfxItemSet::GetItem
942 (
943     sal_uInt16              nId,            // Slot-Id oder Which-Id des Items
944     sal_Bool                bSrchInParent,  // sal_True: auch in Parent-ItemSets suchen
945     TypeId              aItemType       // != 0 =>  RTTI Pruefung mit Assertion
946 )   const
947 
948 /*  [Beschreibung]
949 
950     Mit dieser Methode wird der Zugriff auf einzelne Items im
951     SfxItemSet wesentlich vereinfacht. Insbesondere wird die Typpr"ufung
952     (per Assertion) durchgef"uhrt, wodurch die Applikations-Sourcen
953     wesentlich "ubersichtlicher werden. In der PRODUCT-Version wird
954     eine 0 zur"uckgegeben, wenn das gefundene Item nicht von der
955     angegebenen Klasse ist. Ist kein Item mit der Id 'nWhich' in dem ItemSet,
956     so wird 0 zurueckgegeben.
957 */
958 
959 {
960     // ggf. in Which-Id umrechnen
961     sal_uInt16 nWhich = GetPool()->GetWhich(nId);
962 
963     // ist das Item gesetzt oder bei bDeep==sal_True verf"ugbar?
964     const SfxPoolItem *pItem = 0;
965     SfxItemState eState = GetItemState( nWhich, bSrchInParent, &pItem );
966     if ( bSrchInParent && SFX_ITEM_AVAILABLE == eState &&
967          nWhich <= SFX_WHICH_MAX )
968         pItem = &_pPool->GetDefaultItem(nWhich);
969     if ( pItem )
970     {
971         // stimmt der Typ "uberein?
972         if ( !aItemType || pItem->IsA(aItemType) )
973             return pItem;
974 
975         // sonst Fehler melden
976         DBG_ERROR( "invalid argument type" );
977     }
978 
979     // kein Item gefunden oder falschen Typ gefunden
980     return 0;
981 }
982 
983 
984 //------------------------------------------------------------------------
985 
986 
987 const SfxPoolItem& SfxItemSet::Get( sal_uInt16 nWhich, sal_Bool bSrchInParent) const
988 {
989     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
990     // suche den Bereich in dem das Which steht:
991     const SfxItemSet* pAktSet = this;
992     do
993     {
994         if( pAktSet->Count() )
995         {
996             SfxItemArray ppFnd = pAktSet->_aItems;
997             const sal_uInt16* pPtr = pAktSet->_pWhichRanges;
998             while( *pPtr )
999             {
1000                 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1001                 {
1002                     // in diesem Bereich
1003                     ppFnd += nWhich - *pPtr;
1004                     if( *ppFnd )
1005                     {
1006                         if( (SfxPoolItem*)-1 == *ppFnd ) {
1007                             //?MI: folgender code ist Doppelt (unten)
1008                             SFX_ASSERT(_pPool, nWhich, "kein Pool, aber Status uneindeutig");
1009                             //!((SfxAllItemSet *)this)->aDefault.SetWhich(nWhich);
1010                             //!return aDefault;
1011                             return _pPool->GetDefaultItem( nWhich );
1012                         }
1013 #ifdef DBG_UTIL
1014                         const SfxPoolItem *pItem = *ppFnd;
1015                         DBG_ASSERT( !pItem->ISA(SfxSetItem) ||
1016                                 0 != &((const SfxSetItem*)pItem)->GetItemSet(),
1017                                 "SetItem without ItemSet" );
1018                         if ( pItem->ISA(SfxVoidItem) || !pItem->Which() )
1019                             DBG_WARNING( "SFX_WARNING: Getting disabled Item" );
1020 #endif
1021                         return **ppFnd;
1022                     }
1023                     break;          // dann beim Parent suchen
1024                 }
1025                 ppFnd += *(pPtr+1) - *pPtr + 1;
1026                 pPtr += 2;
1027             }
1028         }
1029 // bis zum Ende vom Such-Bereich: was nun ? zum Parent, oder Default ??
1030 //      if( !*pPtr )            // bis zum Ende vom Such-Bereich ?
1031 //      break;
1032     } while( bSrchInParent && 0 != ( pAktSet = pAktSet->_pParent ));
1033 
1034     // dann das Default vom Pool holen und returnen
1035     SFX_ASSERT(_pPool, nWhich, "kein Pool, aber Status uneindeutig");
1036     const SfxPoolItem *pItem = &_pPool->GetDefaultItem( nWhich );
1037     DBG_ASSERT( !pItem->ISA(SfxSetItem) ||
1038             0 != &((const SfxSetItem*)pItem)->GetItemSet(),
1039             "SetItem without ItemSet" );
1040     return *pItem;
1041 }
1042 
1043     // Notification-Callback
1044 // -----------------------------------------------------------------------
1045 
1046 void SfxItemSet::Changed( const SfxPoolItem&, const SfxPoolItem& )
1047 {
1048     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
1049 }
1050 
1051 // -----------------------------------------------------------------------
1052 
1053 sal_uInt16 SfxItemSet::TotalCount() const
1054 {
1055     DBG_CHKTHIS(SfxItemSet, 0); // wird im Ctor benutzt bevor vollst. init.
1056     sal_uInt16 nRet = 0;
1057     sal_uInt16* pPtr = _pWhichRanges;
1058     while( *pPtr )
1059     {
1060         nRet += ( *(pPtr+1) - *pPtr ) + 1;
1061         pPtr += 2;
1062     }
1063     return nRet;
1064 }
1065 // -----------------------------------------------------------------------
1066 
1067 // behalte nur die Items, die auch in rSet enthalten sein (Wert egal)
1068 
1069 void SfxItemSet::Intersect( const SfxItemSet& rSet )
1070 {
1071     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
1072     DBG_ASSERT(_pPool, "nicht implementiert ohne Pool");
1073     if( !Count() )       // gar keine gesetzt ?
1074         return;
1075 
1076     // loesche alle Items, die im rSet nicht mehr vorhanden sind
1077     if( !rSet.Count() )
1078     {
1079         ClearItem();        // alles loeschen
1080         return;
1081     }
1082 
1083     // teste mal, ob sich die Which-Bereiche unterscheiden.
1084     sal_Bool bEqual = sal_True;
1085     sal_uInt16* pWh1 = _pWhichRanges;
1086     sal_uInt16* pWh2 = rSet._pWhichRanges;
1087     sal_uInt16 nSize = 0;
1088 
1089     for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
1090     {
1091         if( *pWh1 != *pWh2 )
1092         {
1093             bEqual = sal_False;
1094             break;
1095         }
1096         if( n & 1 )
1097             nSize += ( *(pWh1) - *(pWh1-1) ) + 1;
1098     }
1099     bEqual = *pWh1 == *pWh2;        // auch die 0 abpruefen
1100 
1101     // sind die Bereiche identisch, ist es einfacher zu handhaben !
1102     if( bEqual )
1103     {
1104         SfxItemArray ppFnd1 = _aItems;
1105         SfxItemArray ppFnd2 = rSet._aItems;
1106 
1107         for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
1108             if( *ppFnd1 && !*ppFnd2 )
1109             {
1110                 // aus dem Pool loeschen
1111                 if( !IsInvalidItem( *ppFnd1 ) )
1112                 {
1113                     sal_uInt16 nWhich = (*ppFnd1)->Which();
1114                     if(nWhich <= SFX_WHICH_MAX)
1115                     {
1116                         const SfxPoolItem& rNew = _pParent
1117                             ? _pParent->Get( nWhich, sal_True )
1118                             : _pPool->GetDefaultItem( nWhich );
1119 
1120                         Changed( **ppFnd1, rNew );
1121                     }
1122                     _pPool->Remove( **ppFnd1 );
1123                 }
1124                 *ppFnd1 = 0;
1125                 --_nCount;
1126             }
1127     }
1128     else
1129     {
1130         SfxItemIter aIter( *this );
1131         const SfxPoolItem* pItem = aIter.GetCurItem();
1132         while( sal_True )
1133         {
1134             sal_uInt16 nWhich = IsInvalidItem( pItem )
1135                                 ? GetWhichByPos( aIter.GetCurPos() )
1136                                 : pItem->Which();
1137             if( 0 == rSet.GetItemState( nWhich, sal_False ) )
1138                 ClearItem( nWhich );        // loeschen
1139             if( aIter.IsAtEnd() )
1140                 break;
1141             pItem = aIter.NextItem();
1142         }
1143     }
1144 }
1145 
1146 // -----------------------------------------------------------------------
1147 
1148 void SfxItemSet::Differentiate( const SfxItemSet& rSet )
1149 {
1150     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
1151     if( !Count() || !rSet.Count() )  // gar keine gesetzt ?
1152         return;
1153 
1154     // teste mal, ob sich die Which-Bereiche unterscheiden.
1155     sal_Bool bEqual = sal_True;
1156     sal_uInt16* pWh1 = _pWhichRanges;
1157     sal_uInt16* pWh2 = rSet._pWhichRanges;
1158     sal_uInt16 nSize = 0;
1159 
1160     for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
1161     {
1162         if( *pWh1 != *pWh2 )
1163         {
1164             bEqual = sal_False;
1165             break;
1166         }
1167         if( n & 1 )
1168             nSize += ( *(pWh1) - *(pWh1-1) ) + 1;
1169     }
1170     bEqual = *pWh1 == *pWh2;        // auch die 0 abpruefen
1171 
1172     // sind die Bereiche identisch, ist es einfacher zu handhaben !
1173     if( bEqual )
1174     {
1175         SfxItemArray ppFnd1 = _aItems;
1176         SfxItemArray ppFnd2 = rSet._aItems;
1177 
1178         for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
1179             if( *ppFnd1 && *ppFnd2 )
1180             {
1181                 // aus dem Pool loeschen
1182                 if( !IsInvalidItem( *ppFnd1 ) )
1183                 {
1184                     sal_uInt16 nWhich = (*ppFnd1)->Which();
1185                     if(nWhich <= SFX_WHICH_MAX)
1186                     {
1187                         const SfxPoolItem& rNew = _pParent
1188                             ? _pParent->Get( nWhich, sal_True )
1189                             : _pPool->GetDefaultItem( nWhich );
1190 
1191                         Changed( **ppFnd1, rNew );
1192                     }
1193                     _pPool->Remove( **ppFnd1 );
1194                 }
1195                 *ppFnd1 = 0;
1196                 --_nCount;
1197             }
1198     }
1199     else
1200     {
1201         SfxItemIter aIter( *this );
1202         const SfxPoolItem* pItem = aIter.GetCurItem();
1203         while( sal_True )
1204         {
1205             sal_uInt16 nWhich = IsInvalidItem( pItem )
1206                                 ? GetWhichByPos( aIter.GetCurPos() )
1207                                 : pItem->Which();
1208             if( SFX_ITEM_SET == rSet.GetItemState( nWhich, sal_False ) )
1209                 ClearItem( nWhich );        // loeschen
1210             if( aIter.IsAtEnd() )
1211                 break;
1212             pItem = aIter.NextItem();
1213         }
1214 
1215     }
1216 }
1217 
1218 // -----------------------------------------------------------------------
1219 /* Entscheidungstabelle fuer MergeValue[s]
1220 
1221 Grundsaetze:
1222     1. Ist der Which-Wert im 1.Set "unknown", dann folgt niemals eine Aktion.
1223     2. Ist der Which-Wert im 2.Set "unknown", dann gilt er als "default".
1224     3. Es gelten fuer Vergleiche die Werte der "default"-Items.
1225 
1226 1.-Item     2.-Item     Values  bIgnoreDefs     Remove      Assign      Add
1227 
1228 set         set         ==      sal_False           -           -           -
1229 default     set         ==      sal_False           -           -           -
1230 dontcare    set         ==      sal_False           -           -           -
1231 unknown     set         ==      sal_False           -           -           -
1232 set         default     ==      sal_False           -           -           -
1233 default     default     ==      sal_False           -           -           -
1234 dontcare    default     ==      sal_False           -           -           -
1235 unknown     default     ==      sal_False           -           -           -
1236 set         dontcare    ==      sal_False           1.-Item     -1          -
1237 default     dontcare    ==      sal_False           -           -1          -
1238 dontcare    dontcare    ==      sal_False           -           -           -
1239 unknown     dontcare    ==      sal_False           -           -           -
1240 set         unknown     ==      sal_False           1.-Item     -1          -
1241 default     unknown     ==      sal_False           -           -           -
1242 dontcare    unknown     ==      sal_False           -           -           -
1243 unknown     unknown     ==      sal_False           -           -           -
1244 
1245 set         set         !=      sal_False           1.-Item     -1          -
1246 default     set         !=      sal_False           -           -1          -
1247 dontcare    set         !=      sal_False           -           -           -
1248 unknown     set         !=      sal_False           -           -           -
1249 set         default     !=      sal_False           1.-Item     -1          -
1250 default     default     !=      sal_False           -           -           -
1251 dontcare    default     !=      sal_False           -           -           -
1252 unknown     default     !=      sal_False           -           -           -
1253 set         dontcare    !=      sal_False           1.-Item     -1          -
1254 default     dontcare    !=      sal_False           -           -1          -
1255 dontcare    dontcare    !=      sal_False           -           -           -
1256 unknown     dontcare    !=      sal_False           -           -           -
1257 set         unknown     !=      sal_False           1.-Item     -1          -
1258 default     unknown     !=      sal_False           -           -           -
1259 dontcare    unknown     !=      sal_False           -           -           -
1260 unknown     unknown     !=      sal_False           -           -           -
1261 
1262 set         set         ==      sal_True            -           -           -
1263 default     set         ==      sal_True            -           2.-Item     2.-Item
1264 dontcare    set         ==      sal_True            -           -           -
1265 unknown     set         ==      sal_True            -           -           -
1266 set         default     ==      sal_True            -           -           -
1267 default     default     ==      sal_True            -           -           -
1268 dontcare    default     ==      sal_True            -           -           -
1269 unknown     default     ==      sal_True            -           -           -
1270 set         dontcare    ==      sal_True            -           -           -
1271 default     dontcare    ==      sal_True            -           -1          -
1272 dontcare    dontcare    ==      sal_True            -           -           -
1273 unknown     dontcare    ==      sal_True            -           -           -
1274 set         unknown     ==      sal_True            -           -           -
1275 default     unknown     ==      sal_True            -           -           -
1276 dontcare    unknown     ==      sal_True            -           -           -
1277 unknown     unknown     ==      sal_True            -           -           -
1278 
1279 set         set         !=      sal_True            1.-Item     -1          -
1280 default     set         !=      sal_True            -           2.-Item     2.-Item
1281 dontcare    set         !=      sal_True            -           -           -
1282 unknown     set         !=      sal_True            -           -           -
1283 set         default     !=      sal_True            -           -           -
1284 default     default     !=      sal_True            -           -           -
1285 dontcare    default     !=      sal_True            -           -           -
1286 unknown     default     !=      sal_True            -           -           -
1287 set         dontcare    !=      sal_True            1.-Item     -1          -
1288 default     dontcare    !=      sal_True            -           -1          -
1289 dontcare    dontcare    !=      sal_True            -           -           -
1290 unknown     dontcare    !=      sal_True            -           -           -
1291 set         unknown     !=      sal_True            -           -           -
1292 default     unknown     !=      sal_True            -           -           -
1293 dontcare    unknown     !=      sal_True            -           -           -
1294 unknown     unknown     !=      sal_True            -           -           -
1295 */
1296 
1297 
1298 static void MergeItem_Impl( SfxItemPool *_pPool, sal_uInt16 &rCount,
1299                             const SfxPoolItem **ppFnd1, const SfxPoolItem *pFnd2,
1300                             sal_Bool bIgnoreDefaults )
1301 {
1302     DBG_ASSERT( ppFnd1 != 0, "Merging to 0-Item" );
1303 
1304     // 1. Item ist default?
1305     if ( !*ppFnd1 )
1306     {
1307         if ( IsInvalidItem(pFnd2) )
1308             // Entscheidungstabelle: default, dontcare, egal, egal
1309             *ppFnd1 = (SfxPoolItem*) -1;
1310 
1311         else if ( pFnd2 && !bIgnoreDefaults &&
1312                   _pPool->GetDefaultItem(pFnd2->Which()) != *pFnd2 )
1313             // Entscheidungstabelle: default, set, !=, sal_False
1314             *ppFnd1 = (SfxPoolItem*) -1;
1315 
1316         else if ( pFnd2 && bIgnoreDefaults )
1317             // Entscheidungstabelle: default, set, egal, sal_True
1318             *ppFnd1 = &_pPool->Put( *pFnd2 );
1319 
1320         if ( *ppFnd1 )
1321             ++rCount;
1322     }
1323 
1324     // 1. Item ist gesetzt?
1325     else if ( !IsInvalidItem(*ppFnd1) )
1326     {
1327         if ( !pFnd2 )
1328         {
1329             // 2. Item ist default
1330             if ( !bIgnoreDefaults &&
1331                  **ppFnd1 != _pPool->GetDefaultItem((*ppFnd1)->Which()) )
1332             {
1333                 // Entscheidungstabelle: set, default, !=, sal_False
1334                 _pPool->Remove( **ppFnd1 );
1335                 *ppFnd1 = (SfxPoolItem*) -1;
1336             }
1337         }
1338         else if ( IsInvalidItem(pFnd2) )
1339         {
1340             // 2. Item ist dontcare
1341             if ( !bIgnoreDefaults ||
1342                  **ppFnd1 != _pPool->GetDefaultItem( (*ppFnd1)->Which()) )
1343             {
1344                 // Entscheidungstabelle: set, dontcare, egal, sal_False
1345                 // oder:                 set, dontcare, !=, sal_True
1346                 _pPool->Remove( **ppFnd1 );
1347                 *ppFnd1 = (SfxPoolItem*) -1;
1348             }
1349         }
1350         else
1351         {
1352             // 2. Item ist gesetzt
1353             if ( **ppFnd1 != *pFnd2 )
1354             {
1355                 // Entscheidungstabelle: set, set, !=, egal
1356                 _pPool->Remove( **ppFnd1 );
1357                 *ppFnd1 = (SfxPoolItem*) -1;
1358             }
1359         }
1360     }
1361 }
1362 
1363 // -----------------------------------------------------------------------
1364 
1365 void SfxItemSet::MergeValues( const SfxItemSet& rSet, sal_Bool bIgnoreDefaults )
1366 {
1367     // Achtung!!! Bei Aenderungen/Bugfixes immer obenstehende Tabelle pflegen!
1368     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
1369     DBG_ASSERT( GetPool() == rSet.GetPool(), "MergeValues mit verschiedenen Pools" );
1370 
1371     // teste mal, ob sich die Which-Bereiche unterscheiden.
1372     sal_Bool bEqual = sal_True;
1373     sal_uInt16* pWh1 = _pWhichRanges;
1374     sal_uInt16* pWh2 = rSet._pWhichRanges;
1375     sal_uInt16 nSize = 0;
1376 
1377     for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
1378     {
1379         if( *pWh1 != *pWh2 )
1380         {
1381             bEqual = sal_False;
1382             break;
1383         }
1384         if( n & 1 )
1385             nSize += ( *(pWh1) - *(pWh1-1) ) + 1;
1386     }
1387     bEqual = *pWh1 == *pWh2; // auch die 0 abpruefen
1388 
1389     // sind die Bereiche identisch, ist es effizieter zu handhaben !
1390     if( bEqual )
1391     {
1392         SfxItemArray ppFnd1 = _aItems;
1393         SfxItemArray ppFnd2 = rSet._aItems;
1394 
1395         for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
1396             MergeItem_Impl( _pPool, _nCount, ppFnd1, *ppFnd2, bIgnoreDefaults );
1397     }
1398     else
1399     {
1400         SfxWhichIter aIter( rSet );
1401         register sal_uInt16 nWhich;
1402         while( 0 != ( nWhich = aIter.NextWhich() ) )
1403         {
1404             const SfxPoolItem* pItem = 0;
1405             rSet.GetItemState( nWhich, sal_True, &pItem );
1406             if( !pItem )
1407             {
1408                 // nicht gesetzt, also default
1409                 if ( !bIgnoreDefaults )
1410                     MergeValue( rSet.GetPool()->GetDefaultItem( nWhich ), bIgnoreDefaults );
1411             }
1412             else if( IsInvalidItem( pItem ) )
1413                 // dont care
1414                 InvalidateItem( nWhich );
1415             else
1416                 MergeValue( *pItem, bIgnoreDefaults );
1417         }
1418     }
1419 }
1420 
1421 // -----------------------------------------------------------------------
1422 
1423 void SfxItemSet::MergeValue( const SfxPoolItem& rAttr, sal_Bool bIgnoreDefaults )
1424 {
1425     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
1426     SfxItemArray ppFnd = _aItems;
1427     const sal_uInt16* pPtr = _pWhichRanges;
1428     const sal_uInt16 nWhich = rAttr.Which();
1429     while( *pPtr )
1430     {
1431         // in diesem Bereich?
1432         if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1433         {
1434             ppFnd += nWhich - *pPtr;
1435             MergeItem_Impl( _pPool, _nCount, ppFnd, &rAttr, bIgnoreDefaults );
1436             break;
1437         }
1438         ppFnd += *(pPtr+1) - *pPtr + 1;
1439         pPtr += 2;
1440     }
1441 }
1442 
1443 // -----------------------------------------------------------------------
1444 
1445 void SfxItemSet::InvalidateItem( sal_uInt16 nWhich )
1446 {
1447     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
1448     SfxItemArray ppFnd = _aItems;
1449     const sal_uInt16* pPtr = _pWhichRanges;
1450     while( *pPtr )
1451     {
1452         if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1453         {
1454             // in diesem Bereich
1455             ppFnd += nWhich - *pPtr;
1456 
1457             if( *ppFnd )    // bei mir gesetzt
1458             {
1459                 if( (SfxPoolItem*)-1 != *ppFnd )        // noch nicht dontcare !
1460                 {
1461                     _pPool->Remove( **ppFnd );
1462                     *ppFnd = (SfxPoolItem*)-1;
1463                 }
1464             }
1465             else
1466             {
1467                 *ppFnd = (SfxPoolItem*)-1;
1468                 ++_nCount;
1469             }
1470             break;
1471         }
1472         ppFnd += *(pPtr+1) - *pPtr + 1;
1473         pPtr += 2;
1474     }
1475 }
1476 
1477 // -----------------------------------------------------------------------
1478 
1479 sal_uInt16 SfxItemSet::GetWhichByPos( sal_uInt16 nPos ) const
1480 {
1481     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
1482     sal_uInt16 n = 0;
1483     sal_uInt16* pPtr  = _pWhichRanges;
1484     while( *pPtr )
1485     {
1486         n = ( *(pPtr+1) - *pPtr ) + 1;
1487         if( nPos < n )
1488             return *(pPtr)+nPos;
1489         nPos = nPos - n;
1490         pPtr += 2;
1491     }
1492     DBG_ASSERT( sal_False, "Hier sind wir falsch" );
1493     return 0;
1494 }
1495 
1496 // -----------------------------------------------------------------------
1497 
1498 SvStream &SfxItemSet::Store
1499 (
1500     SvStream&   rStream,        // Zielstream f"ur normale Items
1501     FASTBOOL    bDirect         // sal_True: Items direkt speicher, sal_False: Surrogate
1502 )   const
1503 
1504 /*  [Beschreibung]
1505 
1506     Speichert die <SfxItemSet>-Instanz in den angegebenen Stream. Dabei
1507     werden die Surrorage der gesetzten <SfxPoolItem>s bzw. ('bDirect==sal_True')
1508     die gesetzten Items selbst wie folgt im Stream abgelegt:
1509 
1510             sal_uInt16              (Count) Anzahl der gesetzten Items
1511     Count*  _pPool->StoreItem()  siehe <SfxItemPool::StoreItem()const>
1512 
1513 
1514     [Querverweise]
1515 
1516     <SfxItemSet::Load(SvStream&,sal_Bool,const SfxItemPool*)>
1517 */
1518 
1519 {
1520     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
1521     DBG_ASSERT( _pPool, "Kein Pool" );
1522     DBG_ASSERTWARNING( _pPool == _pPool->GetMasterPool(), "kein Master-Pool" );
1523 
1524     // Position des Counts merken, um ggf. zu korrigieren
1525     sal_uLong nCountPos = rStream.Tell();
1526     rStream << _nCount;
1527 
1528     // wenn nichts zu speichern ist, auch keinen ItemIter aufsetzen!
1529     if ( _nCount )
1530     {
1531         // mitz"ahlen wieviel Items tats"achlich gespeichert werden
1532         sal_uInt16 nWrittenCount = 0;  // Anzahl in 'rStream' gestreamter Items
1533 
1534         // "uber alle gesetzten Items iterieren
1535         SfxItemIter aIter(*this);
1536         for ( const SfxPoolItem *pItem = aIter.FirstItem();
1537               pItem;
1538               pItem = aIter.NextItem() )
1539         {
1540             // Item (ggf. als Surrogat) via Pool speichern lassen
1541             DBG_ASSERT( !IsInvalidItem(pItem), "can't store invalid items" );
1542             if ( !IsInvalidItem(pItem) &&
1543                  _pPool->StoreItem( rStream, *pItem, bDirect ) )
1544                 // Item wurde in 'rStream' gestreamt
1545                 ++nWrittenCount;
1546         };
1547 
1548         // weniger geschrieben als enthalten (z.B. altes Format)
1549         if ( nWrittenCount != _nCount )
1550         {
1551             // tats"achlichen Count im Stream ablegen
1552             sal_uLong nPos = rStream.Tell();
1553             rStream.Seek( nCountPos );
1554             rStream << nWrittenCount;
1555             rStream.Seek( nPos );
1556         }
1557     }
1558 
1559     return rStream;
1560 }
1561 
1562 // -----------------------------------------------------------------------
1563 
1564 SvStream &SfxItemSet::Load
1565 (
1566     SvStream&           rStream,    //  Stream, aus dem geladen werden soll
1567 
1568     FASTBOOL            bDirect,    /*  sal_True
1569                                         Items werden direkt aus dem Stream
1570                                         gelesen, nicht "uber Surrogate
1571 
1572                                         sal_False (default)
1573                                         Items werden "uber Surrogate gelesen */
1574 
1575     const SfxItemPool*  pRefPool    /*  Pool, der die Surrogate aufl"osen kann
1576                                         (z.B. zum Einf"ugen von Dokumenten) */
1577 )
1578 
1579 /*  [Beschreibung]
1580 
1581     Diese Methode l"adt ein <SfxItemSet> aus einem Stream. Falls der
1582     <SfxItemPool> ohne Ref-Counts geladen wurde, werden die geladenen
1583     Item-Referenzen in den Items hochgez"ahlt, ansonsten wird vorausgesetzt,
1584     da\s sie schon beim Laden des SfxItemPools ber"ucksichtigt waren.
1585 
1586     [Querverweise]
1587 
1588     <SfxItemSet::Store(Stream&,sal_Bool)const>
1589 */
1590 
1591 {
1592     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
1593     DBG_ASSERT( _pPool, "Kein Pool");
1594     DBG_ASSERTWARNING( _pPool == _pPool->GetMasterPool(), "Kein Master-Pool");
1595 
1596     // kein Ref-Pool => Surrogate mit Pool des ItemSets aufl"osen
1597     if ( !pRefPool )
1598         pRefPool = _pPool;
1599 
1600     // Anzahl der zu ladenden Items laden und dann ebensoviele Items
1601     sal_uInt16 nCount = 0;
1602     rStream >> nCount;
1603     for ( sal_uInt16 i = 0; i < nCount; ++i )
1604     {
1605         // Surrogat/Item laden und (Surrogat) aufl"osen lassen
1606         const SfxPoolItem *pItem =
1607                 _pPool->LoadItem( rStream, bDirect, pRefPool );
1608 
1609         // konnte ein Item geladen oder via Surrogat aufgel"ost werden?
1610         if ( pItem )
1611         {
1612             // Position f"ur Item-Pointer im Set suchen
1613             sal_uInt16 nWhich = pItem->Which();
1614             SfxItemArray ppFnd = _aItems;
1615             const sal_uInt16* pPtr = _pWhichRanges;
1616             while ( *pPtr )
1617             {
1618                 // in diesem Bereich?
1619                 if ( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1620                 {
1621                     // Item-Pointer im Set merken
1622                     ppFnd += nWhich - *pPtr;
1623                     SFX_ASSERT( !*ppFnd, nWhich, "Item doppelt eingetragen");
1624                     *ppFnd = pItem;
1625                     ++_nCount;
1626                     break;
1627                 }
1628 
1629                 // im Range-Array und Item-Array zum n"achsten Which-Range
1630                 ppFnd += *(pPtr+1) - *pPtr + 1;
1631                 pPtr += 2;
1632             }
1633         }
1634     }
1635 
1636     return rStream;
1637 }
1638 
1639 // -----------------------------------------------------------------------
1640 
1641 int SfxItemSet::operator==(const SfxItemSet &rCmp) const
1642 {
1643     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
1644     DBG_CHKOBJ(&rCmp, SfxItemSet, DbgCheckItemSet);
1645 
1646     // besonders schnell zu ermittelnde Werte muessen gleich sein
1647     if ( _pParent != rCmp._pParent ||
1648          _pPool != rCmp._pPool ||
1649          Count() != rCmp.Count() )
1650         return sal_False;
1651 
1652     // Ranges durchzaehlen lassen dauert laenger, muss aber auch gleich sein
1653     sal_uInt16 nCount1 = TotalCount();
1654     sal_uInt16 nCount2 = rCmp.TotalCount();
1655     if ( nCount1 != nCount2 )
1656         return sal_False;
1657 
1658     // sind die Ranges selbst ungleich?
1659     for ( sal_uInt16 nRange = 0; _pWhichRanges[nRange]; nRange += 2 )
1660         if ( _pWhichRanges[nRange] != rCmp._pWhichRanges[nRange] ||
1661              _pWhichRanges[nRange+1] != rCmp._pWhichRanges[nRange+1] )
1662         {
1663             // dann m"ussen wir die langsame Methode verwenden
1664             SfxWhichIter aIter( *this );
1665             for ( sal_uInt16 nWh = aIter.FirstWhich();
1666                   nWh;
1667                   nWh = aIter.NextWhich() )
1668             {
1669                 // wenn die Pointer von poolable Items ungleich sind,
1670                 // muessen die Items gleich sein
1671                 const SfxPoolItem *pItem1 = 0, *pItem2 = 0;
1672                 if ( GetItemState( nWh, sal_False, &pItem1 ) !=
1673                         rCmp.GetItemState( nWh, sal_False, &pItem2 ) ||
1674                      ( pItem1 != pItem2 &&
1675                         ( !pItem1 || IsInvalidItem(pItem1) ||
1676                           ( _pPool->IsItemFlag(*pItem1, SFX_ITEM_POOLABLE) &&
1677                             *pItem1 != *pItem2 ) ) ) )
1678                     return sal_False;
1679             }
1680 
1681             return sal_True;
1682         }
1683 
1684     // Pointer alle gleich?
1685     if ( 0 == memcmp( _aItems, rCmp._aItems, nCount1 * sizeof(_aItems[0]) ) )
1686         return sal_True;
1687 
1688     // dann werden wir wohl alle einzeln vergleichen muessen
1689     const SfxPoolItem **ppItem1 = (const SfxPoolItem**) _aItems;
1690     const SfxPoolItem **ppItem2 = (const SfxPoolItem**) rCmp._aItems;
1691     for ( sal_uInt16 nPos = 0; nPos < nCount1; ++nPos )
1692     {
1693         // wenn die Pointer von poolable Items ungleich sind,
1694         // muessen die Items gleich sein
1695         if ( *ppItem1 != *ppItem2 &&
1696              ( ( !*ppItem1 || !*ppItem2 ) ||
1697                ( IsInvalidItem(*ppItem1) || IsInvalidItem(*ppItem2) ) ||
1698                ( _pPool->IsItemFlag(**ppItem1, SFX_ITEM_POOLABLE) ) ||
1699                  **ppItem1 != **ppItem2 ) )
1700             return sal_False;
1701 
1702         ++ppItem1;
1703         ++ppItem2;
1704     }
1705 
1706     return sal_True;
1707 }
1708 
1709 // -----------------------------------------------------------------------
1710 
1711 SfxItemSet *SfxItemSet::Clone(sal_Bool bItems, SfxItemPool *pToPool ) const
1712 {
1713     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
1714     if ( pToPool && pToPool != _pPool )
1715     {
1716         SfxItemSet *pNewSet = new SfxItemSet( *pToPool, _pWhichRanges );
1717         if ( bItems )
1718         {
1719             SfxWhichIter aIter(*pNewSet);
1720             sal_uInt16 nWhich = aIter.FirstWhich();
1721             while ( nWhich )
1722             {
1723                 const SfxPoolItem* pItem;
1724                 if ( SFX_ITEM_SET == GetItemState( nWhich, sal_False, &pItem ) )
1725                     pNewSet->Put( *pItem, pItem->Which() );
1726                 nWhich = aIter.NextWhich();
1727             }
1728         }
1729         return pNewSet;
1730     }
1731     else
1732         return bItems
1733                 ? new SfxItemSet(*this)
1734                 : new SfxItemSet(*_pPool, _pWhichRanges);
1735 }
1736 
1737 // -----------------------------------------------------------------------
1738 
1739 int SfxItemSet::PutDirect(const SfxPoolItem &rItem)
1740 {
1741     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
1742     SfxItemArray ppFnd = _aItems;
1743     const sal_uInt16* pPtr = _pWhichRanges;
1744     const sal_uInt16 nWhich = rItem.Which();
1745 #ifdef DBG_UTIL
1746     IsPoolDefaultItem(&rItem) || _pPool->GetSurrogate(&rItem);
1747         // nur Assertion in den callees provozieren
1748 #endif
1749     while( *pPtr )
1750     {
1751         if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1752         {
1753             // in diesem Bereich
1754             ppFnd += nWhich - *pPtr;
1755             const SfxPoolItem* pOld = *ppFnd;
1756             if( pOld )      // schon einer vorhanden
1757             {
1758                 if( rItem == **ppFnd )
1759                     return sal_False;       // schon vorhanden !
1760                 _pPool->Remove( *pOld );
1761             }
1762             else
1763                 ++_nCount;
1764 
1765             // den neuen eintragen
1766             if( IsPoolDefaultItem(&rItem) )
1767                 *ppFnd = &_pPool->Put( rItem );
1768             else
1769             {
1770                 *ppFnd = &rItem;
1771                 if( !IsStaticDefaultItem( &rItem ) )
1772                     rItem.AddRef();
1773             }
1774 
1775             return sal_True;
1776         }
1777         ppFnd += *(pPtr+1) - *pPtr + 1;
1778         pPtr += 2;
1779     }
1780     return sal_False;
1781 }
1782 
1783 // -----------------------------------------------------------------------
1784 
1785 SfxAllItemSet::SfxAllItemSet( SfxItemPool &rPool )
1786 :   SfxItemSet(rPool, (const sal_uInt16*) 0),
1787     aDefault(0),
1788     nFree(nInitCount)
1789 {
1790     // initial keine Items
1791     _aItems = 0;
1792 
1793     // nInitCount Paare an USHORTs fuer Ranges allozieren
1794     _pWhichRanges = new sal_uInt16[ nInitCount + 1 ];
1795     memset( _pWhichRanges, 0, ( nInitCount + 1 ) * sizeof(sal_uInt16) );
1796 }
1797 
1798 
1799 // -----------------------------------------------------------------------
1800 
1801 
1802 SfxAllItemSet::SfxAllItemSet(const SfxItemSet &rCopy)
1803 :   SfxItemSet(rCopy),
1804     aDefault(0),
1805     nFree(0)
1806 {
1807 }
1808 
1809 // -----------------------------------------------------------------------
1810 
1811 
1812 
1813 SfxAllItemSet::SfxAllItemSet(const SfxAllItemSet &rCopy)
1814 :   SfxItemSet(rCopy),
1815     aDefault(0),
1816     nFree(0)
1817 /*  [Anmerkung]
1818 
1819     Der mu\s sein, da sonst vom Compiler einer generiert wird, er nimmt
1820     nicht den Ctor mit der 'const SfxItemSet&'!
1821 */
1822 {
1823 }
1824 
1825 // -----------------------------------------------------------------------
1826 
1827 static sal_uInt16 *AddRanges_Impl(
1828     sal_uInt16 *pUS, std::ptrdiff_t nOldSize, sal_uInt16 nIncr)
1829 
1830 /*  Diese interne Funktion erzeugt ein neues Which-Range-Array, welches von
1831     dem 'nOldSize'-USHORTs langen 'pUS' kopiert wird und hinten an Platz
1832     f"ur 'nIncr' neue USHORTs hat. Das terminierende sal_uInt16 mit der '0'
1833     wird weder in 'nOldSize' noch in 'nIncr' mitgez"ahlt, sondern implizit
1834     hinzugerechnet.
1835 
1836     Das neue Which-Range-Array wird als Returnwert zur"uckgegeben, das alte
1837     'pUS' freigegeben.
1838 */
1839 
1840 {
1841     // neues Which-Range-Array anlegen
1842     sal_uInt16 *pNew = new sal_uInt16[ nOldSize + nIncr + 1 ];
1843 
1844     // die alten Ranges "ubernehmen
1845     memcpy( pNew, pUS, nOldSize * sizeof(sal_uInt16) );
1846 
1847     // die neuen auf 0 initialisieren
1848     memset( pNew + nOldSize, 0, ( nIncr + 1 ) * sizeof(sal_uInt16) );
1849 
1850     // das alte Array freigeben
1851     delete[] pUS;
1852 
1853     return pNew;
1854 }
1855 
1856 // -----------------------------------------------------------------------
1857 
1858 static SfxItemArray AddItem_Impl(SfxItemArray pItems, sal_uInt16 nOldSize, sal_uInt16 nPos)
1859 
1860 /*  Diese interne Funktion erzeugt ein neues ItemArray, welches von 'pItems'
1861     kopiert wird, an der Position 'nPos' jedoch Platz f"ur einen neuen
1862     ItemPointer hat.
1863 
1864     Das neue ItemArray wird als Returnwert zur"uckgegeben, das alte 'pItems'
1865     wird freigegeben.
1866 */
1867 
1868 {
1869     // neues ItemArray anlegen
1870     SfxItemArray pNew = new const SfxPoolItem*[nOldSize+1];
1871 
1872     // war schon vorher eins da?
1873     if ( pItems )
1874     {
1875         // alte Items vor nPos kopieren
1876         if ( nPos )
1877             memcpy( (void*) pNew, pItems, nPos * sizeof(SfxPoolItem **) );
1878 
1879         // alte Items hinter nPos kopieren
1880         if ( nPos < nOldSize )
1881             memcpy( (void*) (pNew + nPos + 1), pItems + nPos,
1882                     (nOldSize-nPos) * sizeof(SfxPoolItem **) );
1883     }
1884 
1885     // neues Item initialisieren
1886     *(pNew + nPos) = 0;
1887 
1888     // altes ItemArray freigeben
1889     delete[] pItems;
1890 
1891     return pNew;
1892 }
1893 
1894 // -----------------------------------------------------------------------
1895 
1896 const SfxPoolItem* SfxAllItemSet::Put( const SfxPoolItem& rItem, sal_uInt16 nWhich )
1897 
1898 // Putten mit automatischer Erweiterung der Whichs-Ids um die ID
1899 // des Items.
1900 
1901 {
1902     sal_uInt16 nPos = 0; // Position f"ur 'rItem' in '_aItems'
1903     const sal_uInt16 nItemCount = TotalCount();
1904 
1905     // erstmal sehen, ob es schon einen passenden Bereich gibt
1906     sal_uInt16 *pPtr = _pWhichRanges;
1907     while ( *pPtr )
1908     {
1909         // Which-Id liegt in diesem Bereich?
1910         if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1911         {
1912             // Einfuegen
1913             nPos += nWhich - *pPtr;
1914             break;
1915         }
1916 
1917         // Position des Items in _aItems mitf"uhren
1918         nPos += *(pPtr+1) - *pPtr + 1;
1919 
1920         // zum n"achsten Bereich
1921         pPtr += 2;
1922     }
1923 
1924     // Which-Id noch nicht vorhanden?
1925     if ( !*pPtr )
1926     {
1927         // suchen, ob man sie irgendwo dranpacken kann
1928         pPtr = _pWhichRanges;
1929         nPos = 0;
1930         while ( *pPtr )
1931         {
1932             // Which-Id liegt exakt vor diesem Bereich?
1933             if ( (nWhich+1) == *pPtr )
1934             {
1935                 // Bereich waechst nach unten
1936                 (*pPtr)--;
1937 
1938                 // vor erstem Item dieses Bereichs Platz schaffen
1939                 _aItems = AddItem_Impl(_aItems, nItemCount, nPos);
1940                 break;
1941             }
1942 
1943             // Which-Id liegt exakt hinter diesem Bereich?
1944             else if ( (nWhich-1) == *(pPtr+1) )
1945             {
1946                 // Bereich waechst nach oben
1947                 (*(pPtr+1))++;
1948 
1949                 // hinter letztem Item dieses Bereichs Platz schaffen
1950                 nPos += nWhich - *pPtr;
1951                 _aItems = AddItem_Impl(_aItems, nItemCount, nPos);
1952                 break;
1953             }
1954 
1955             // Position des Items in _aItems mitf"uhren
1956             nPos += *(pPtr+1) - *pPtr + 1;
1957 
1958             // zum n"achsten Bereich
1959             pPtr += 2;
1960         }
1961     }
1962 
1963     // keinen erweiterbaren Bereich gefunden?
1964     if ( !*pPtr )
1965     {
1966         // kein Platz mehr in _pWhichRanges => erweitern
1967         std::ptrdiff_t nSize = pPtr - _pWhichRanges;
1968         if( !nFree )
1969         {
1970             _pWhichRanges = AddRanges_Impl(_pWhichRanges, nSize, nInitCount);
1971             nFree += nInitCount;
1972         }
1973 
1974         // neuen Which-Range anh"angen
1975         pPtr = _pWhichRanges + nSize;
1976         *pPtr++ = nWhich;
1977         *pPtr = nWhich;
1978         nFree -= 2;
1979 
1980         // Itemarray vergroessern
1981         nPos = nItemCount;
1982         _aItems = AddItem_Impl(_aItems, nItemCount, nPos);
1983     }
1984 
1985     // neues Item in Pool aufnehmen
1986     const SfxPoolItem& rNew = _pPool->Put( rItem, nWhich );
1987 
1988     // altes Item merken
1989     sal_Bool bIncrementCount = sal_False;
1990     const SfxPoolItem* pOld = *( _aItems + nPos );
1991     if ( reinterpret_cast< SfxPoolItem* >( -1 ) == pOld )   // state "dontcare"
1992         pOld = NULL;
1993     if ( !pOld )
1994     {
1995         bIncrementCount = sal_True;
1996         pOld = _pParent ?
1997                 &_pParent->Get( nWhich, sal_True )
1998                 : nWhich <= SFX_WHICH_MAX ? &_pPool->GetDefaultItem( nWhich ) : 0;
1999     }
2000 
2001     // neue Item in ItemSet aufnehmen
2002     *(_aItems + nPos) = &rNew;
2003 
2004     // Changed Notification versenden
2005     if ( pOld )
2006     {
2007         Changed( *pOld, rNew );
2008         if ( !IsDefaultItem(pOld) )
2009             _pPool->Remove( *pOld );
2010     }
2011 
2012     if ( bIncrementCount )
2013         ++_nCount;
2014 
2015     return &rNew;
2016 }
2017 
2018 // -----------------------------------------------------------------------
2019 
2020 
2021 /*  Diese Methode wird forwarded, damit sie nicht durch die anderen
2022     Put-Methoden dieser SubClass gehided wird.
2023 */
2024 
2025 int SfxAllItemSet::Put( const SfxItemSet& rSet, sal_Bool bInvalidAsDefault )
2026 {
2027     //? pruefen, ob Which-Ranges erweitert werden
2028     return SfxItemSet::Put( rSet, bInvalidAsDefault );
2029 }
2030 
2031 // -----------------------------------------------------------------------
2032 // Item disablen, wenn durch ein VoidItem mit dem Which-Wert 0 ausgedrueckt
2033 
2034 void SfxItemSet::DisableItem(sal_uInt16 nWhich)
2035 {
2036     DBG_CHKTHIS(SfxItemSet, 0);
2037     Put( SfxVoidItem(0), nWhich );
2038 }
2039 
2040 // -----------------------------------------------------------------------
2041 
2042 #if 0
2043 sal_Bool SfxAllItemSet::Remove(sal_uInt16 nWhich)
2044 {
2045     DBG_CHKTHIS(SfxAllItemSet, 0);
2046     sal_uInt16 *pPtr = _pWhichRanges;
2047     sal_uInt16 nPos = 0;
2048     while( *pPtr )
2049     {
2050         if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
2051         {
2052             sal_uInt16 *pTmp = pPtr;
2053             sal_uInt16 nLeft = 0;
2054             sal_uInt16 nRest = 0;
2055             while(*++pTmp){
2056                 if( nLeft & 1 )
2057                     nRest = *pTmp - *(pTmp-1) + 1;
2058                 ++nLeft;
2059             }
2060 
2061             // in diesem Bereich
2062             nPos += nWhich - *pPtr;
2063             nRest -= nWhich - *pPtr;
2064             // 3,3
2065             if(*pPtr == nWhich && *(pPtr+1) == nWhich) {
2066                 memmove(pPtr, pPtr + 2, nLeft * sizeof(sal_uInt16));
2067                 nFree += 2;
2068             }
2069                 // Anfang
2070             else if(*pPtr == nWhich)
2071                 (*pPtr)++;
2072                 // Ende
2073             else if(*(pPtr+1) == nWhich)
2074                 (*(pPtr+1))--;
2075             else {
2076                 if(nPos + nRest + 2 > nFree) {
2077                     sal_uInt16 nOf = pPtr - _pWhichRanges;
2078                     _pWhichRanges = IncrSize(_pWhichRanges, nPos + nRest, nInitCount);
2079                     nFree += nInitCount;
2080                     pPtr = _pWhichRanges + nOf;
2081                 }
2082                 memmove(pPtr +2, pPtr, (nLeft+2) * sizeof(sal_uInt16));
2083                 *++pPtr  = nWhich-1;
2084                 *++pPtr = nWhich+1;
2085                 nFree -= 2;
2086             }
2087             SfxPoolItem* pItem = *( _aItems + nPos );
2088             if( pItem )
2089             {
2090                 if(_pPool)
2091                     _pPool->Remove(*pItem );
2092                 else
2093                     delete pItem;
2094                 --_nCount;
2095             }
2096             memmove(_aItems + nPos +1, _aItems + nPos,
2097                     sizeof(SfxPoolItem *) * (nRest - 1));
2098             break;          // dann beim Parent suchen
2099         }
2100         nPos += *(pPtr+1) - *pPtr + 1;
2101         pPtr += 2;
2102     }
2103     return *pPtr? sal_True: sal_False;
2104 }
2105 #endif
2106 
2107 // -----------------------------------------------------------------------
2108 
2109 SfxItemSet *SfxAllItemSet::Clone(sal_Bool bItems, SfxItemPool *pToPool ) const
2110 {
2111     DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
2112     if ( pToPool && pToPool != _pPool )
2113     {
2114         SfxAllItemSet *pNewSet = new SfxAllItemSet( *pToPool );
2115         if ( bItems )
2116             pNewSet->Set( *this );
2117         return pNewSet;
2118     }
2119     else
2120         return bItems ? new SfxAllItemSet(*this) : new SfxAllItemSet(*_pPool);
2121 }
2122 
2123