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