bump product version to 5.0.4.1
[LibreOffice.git] / svl / source / items / itemset.cxx
blob48627064aca97eb0b5a63bdf3767e94780432374
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <string.h>
23 #include <cstdarg>
24 #include <libxml/xmlwriter.h>
26 #include <sal/log.hxx>
27 #include <svl/itemset.hxx>
28 #include <svl/itempool.hxx>
29 #include <svl/itemiter.hxx>
30 #include <svl/whiter.hxx>
31 #include <svl/nranges.hxx>
32 #include "whassert.hxx"
34 #include <tools/stream.hxx>
35 #include <tools/solar.h>
36 #include <rtl/string.hxx>
38 // STATIC DATA
40 static const sal_uInt16 nInitCount = 10; // Single USHORTs => 5 pairs without '0'
41 #include "nranges.cxx"
42 #include "poolio.hxx"
45 #ifdef DBG_UTIL
48 const sal_Char *DbgCheckItemSet( const void* pVoid )
50 const SfxItemSet *pSet = static_cast<const SfxItemSet*>(pVoid);
51 SfxWhichIter aIter( *pSet );
52 sal_uInt16 nCount = 0, n = 0;
53 for ( sal_uInt16 nWh = aIter.FirstWhich(); nWh; nWh = aIter.NextWhich(), ++n )
55 const SfxPoolItem *pItem = pSet->m_pItems[n];
56 if ( pItem )
58 ++nCount;
59 assert((IsInvalidItem(pItem) ||
60 pItem->Which() == 0 || pItem->Which() == nWh
61 ) && "SfxItemSet: invalid which-id" );
62 assert((IsInvalidItem(pItem) || !pItem->Which() ||
63 !SfxItemPool::IsWhich(pItem->Which()) ||
64 pSet->GetPool()->IsItemFlag(nWh, SfxItemPoolFlags::NOT_POOLABLE) ||
65 SFX_ITEMS_NULL != pSet->GetPool()->GetSurrogate(pItem)
66 ) && "SfxItemSet: item in set which is not in pool" );
70 assert(pSet->m_nCount == nCount);
72 return 0;
75 #endif
77 /**
78 * Ctor for a SfxItemSet with exactly the Which Ranges, which are known to
79 * the supplied SfxItemPool.
81 * For Sfx programmers: an SfxItemSet constructed in this way cannot
82 * contain any Items with SlotIds as Which values.
84 SfxItemSet::SfxItemSet
86 SfxItemPool& rPool, /* Target Pool for the SfxPoolItems which are
87 added to this SfxItemSet */
88 bool bTotalRanges /* Take over complete pool ranges? */
90 : m_pPool( &rPool )
91 , m_pParent(nullptr)
92 , m_nCount(0)
94 // DBG_ASSERT( bTotalRanges || abs( &bTotalRanges - this ) < 1000,
95 // "please use suitable ranges" );
96 #if defined DBG_UTIL && defined SFX_ITEMSET_NO_DEFAULT_CTOR
97 if ( !bTotalRanges )
98 *(int*)0 = 0; // GPF
99 #else
100 (void) bTotalRanges; // avoid warnings
101 #endif
103 m_pWhichRanges = const_cast<sal_uInt16*>(m_pPool->GetFrozenIdRanges());
104 assert( m_pWhichRanges && "don't create ItemSets with full range before FreezeIdRanges()" );
105 if (!m_pWhichRanges)
106 m_pPool->FillItemIdRanges_Impl( m_pWhichRanges );
108 const sal_uInt16 nSize = TotalCount();
109 m_pItems = new const SfxPoolItem* [ nSize ];
110 memset(static_cast<void*>(m_pItems), 0, nSize * sizeof(SfxPoolItem*));
113 SfxItemSet::SfxItemSet(SfxItemPool& rPool, sal_uInt16 nWhich1, sal_uInt16 nWhich2)
114 : m_pPool( &rPool )
115 , m_pParent(nullptr)
116 , m_nCount(0)
118 assert(nWhich1 <= nWhich2);
120 InitRanges_Impl(nWhich1, nWhich2);
123 void SfxItemSet::InitRanges_Impl(sal_uInt16 nWh1, sal_uInt16 nWh2)
125 m_pWhichRanges = new sal_uInt16[ 3 ];
126 *(m_pWhichRanges+0) = nWh1;
127 *(m_pWhichRanges+1) = nWh2;
128 *(m_pWhichRanges+2) = 0;
129 const sal_uInt16 nRg = nWh2 - nWh1 + 1;
130 m_pItems = new const SfxPoolItem* [ nRg ];
131 memset(static_cast<void*>(m_pItems), 0, nRg * sizeof(SfxPoolItem*));
134 void SfxItemSet::InitRanges_Impl(va_list pArgs, sal_uInt16 nWh1, sal_uInt16 nWh2, sal_uInt16 nNull)
136 sal_uInt16 nSize = InitializeRanges_Impl(m_pWhichRanges, pArgs, nWh1, nWh2, nNull);
137 m_pItems = new const SfxPoolItem* [ nSize ];
138 memset(static_cast<void*>(m_pItems), 0, sizeof(SfxPoolItem*) * nSize);
141 SfxItemSet::SfxItemSet(SfxItemPool& rPool,
142 USHORT_ARG nWh1, USHORT_ARG nWh2, USHORT_ARG nNull, ...)
143 : m_pPool( &rPool )
144 , m_pParent(nullptr)
145 , m_pWhichRanges(nullptr)
146 , m_nCount(0)
148 assert(nWh1 <= nWh2);
150 if(!nNull)
151 InitRanges_Impl(
152 sal::static_int_cast< sal_uInt16 >(nWh1),
153 sal::static_int_cast< sal_uInt16 >(nWh2));
154 else {
155 va_list pArgs;
156 va_start( pArgs, nNull );
157 InitRanges_Impl(
158 pArgs, sal::static_int_cast< sal_uInt16 >(nWh1),
159 sal::static_int_cast< sal_uInt16 >(nWh2),
160 sal::static_int_cast< sal_uInt16 >(nNull));
161 va_end(pArgs);
165 void SfxItemSet::InitRanges_Impl(const sal_uInt16 *pWhichPairTable)
167 sal_uInt16 nCnt = 0;
168 const sal_uInt16* pPtr = pWhichPairTable;
169 while( *pPtr )
171 nCnt += ( *(pPtr+1) - *pPtr ) + 1;
172 pPtr += 2;
175 m_pItems = new const SfxPoolItem* [ nCnt ];
176 memset(static_cast<void*>(m_pItems), 0, sizeof(SfxPoolItem*) * nCnt);
178 std::ptrdiff_t cnt = pPtr - pWhichPairTable +1;
179 m_pWhichRanges = new sal_uInt16[ cnt ];
180 memcpy( m_pWhichRanges, pWhichPairTable, sizeof( sal_uInt16 ) * cnt );
183 SfxItemSet::SfxItemSet( SfxItemPool& rPool, const sal_uInt16* pWhichPairTable )
184 : m_pPool(&rPool)
185 , m_pParent(nullptr)
186 , m_pItems(nullptr)
187 , m_pWhichRanges(nullptr)
188 , m_nCount(0)
190 // pWhichPairTable == 0 is for the SfxAllEnumItemSet
191 if ( pWhichPairTable )
192 InitRanges_Impl(pWhichPairTable);
195 SfxItemSet::SfxItemSet( const SfxItemSet& rASet )
196 : m_pPool( rASet.m_pPool )
197 , m_pParent( rASet.m_pParent )
198 , m_nCount( rASet.m_nCount )
200 // Calculate the attribute count
201 sal_uInt16 nCnt = 0;
202 sal_uInt16* pPtr = rASet.m_pWhichRanges;
203 while( *pPtr )
205 nCnt += ( *(pPtr+1) - *pPtr ) + 1;
206 pPtr += 2;
209 m_pItems = new const SfxPoolItem* [ nCnt ];
211 // Copy attributes
212 SfxItemArray ppDst = m_pItems, ppSrc = rASet.m_pItems;
213 for( sal_uInt16 n = nCnt; n; --n, ++ppDst, ++ppSrc )
214 if ( 0 == *ppSrc || // Current Default?
215 IsInvalidItem(*ppSrc) || // DontCare?
216 IsStaticDefaultItem(*ppSrc) ) // Defaults that are not to be pooled?
217 // Just copy the pointer
218 *ppDst = *ppSrc;
219 else if (m_pPool->IsItemFlag( **ppSrc, SfxItemPoolFlags::POOLABLE ))
221 // Just copy the pointer and increase RefCount
222 *ppDst = *ppSrc;
223 (*ppDst)->AddRef();
225 else if ( !(*ppSrc)->Which() )
226 *ppDst = (*ppSrc)->Clone();
227 else
228 // !IsPoolable() => assign via Pool
229 *ppDst = &m_pPool->Put( **ppSrc );
231 // Copy the WhichRanges
232 std::ptrdiff_t cnt = pPtr - rASet.m_pWhichRanges+1;
233 m_pWhichRanges = new sal_uInt16[ cnt ];
234 memcpy( m_pWhichRanges, rASet.m_pWhichRanges, sizeof( sal_uInt16 ) * cnt);
237 SfxItemSet::~SfxItemSet()
239 sal_uInt16 nCount = TotalCount();
240 if( Count() )
242 SfxItemArray ppFnd = m_pItems;
243 for( sal_uInt16 nCnt = nCount; nCnt; --nCnt, ++ppFnd )
244 if( *ppFnd && !IsInvalidItem(*ppFnd) )
246 if( !(*ppFnd)->Which() )
247 delete *ppFnd;
248 else {
249 // Still multiple references present, so just alter the RefCount
250 if ( 1 < (*ppFnd)->GetRefCount() && !IsDefaultItem(*ppFnd) )
251 (*ppFnd)->ReleaseRef();
252 else
253 if ( !IsDefaultItem(*ppFnd) )
254 // Delete from Pool
255 m_pPool->Remove( **ppFnd );
260 delete[] m_pItems;
261 if (m_pWhichRanges != m_pPool->GetFrozenIdRanges())
262 delete[] m_pWhichRanges;
263 m_pWhichRanges = nullptr; // for invariant-testing
267 * Delete single Items or all Items (nWhich == 0)
269 sal_uInt16 SfxItemSet::ClearItem( sal_uInt16 nWhich )
271 if( !Count() )
272 return 0;
274 sal_uInt16 nDel = 0;
275 SfxItemArray ppFnd = m_pItems;
277 if( nWhich )
279 const sal_uInt16* pPtr = m_pWhichRanges;
280 while( *pPtr )
282 // Within this range?
283 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
285 // Actually set?
286 ppFnd += nWhich - *pPtr;
287 if( *ppFnd )
289 // Due to the assertions in the sub calls, we need to do the following
290 --m_nCount;
291 const SfxPoolItem *pItemToClear = *ppFnd;
292 *ppFnd = 0;
294 if ( !IsInvalidItem(pItemToClear) )
296 if ( nWhich <= SFX_WHICH_MAX )
298 const SfxPoolItem& rNew = m_pParent
299 ? m_pParent->Get( nWhich, true )
300 : m_pPool->GetDefaultItem( nWhich );
302 Changed( *pItemToClear, rNew );
304 if ( pItemToClear->Which() )
305 m_pPool->Remove( *pItemToClear );
307 ++nDel;
310 // found => break
311 break;
313 ppFnd += *(pPtr+1) - *pPtr + 1;
314 pPtr += 2;
317 else
319 nDel = m_nCount;
321 sal_uInt16* pPtr = m_pWhichRanges;
322 while( *pPtr )
324 for( nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
325 if( *ppFnd )
327 // Due to the assertions in the sub calls, we need to do this
328 --m_nCount;
329 const SfxPoolItem *pItemToClear = *ppFnd;
330 *ppFnd = 0;
332 if ( !IsInvalidItem(pItemToClear) )
334 if ( nWhich <= SFX_WHICH_MAX )
336 const SfxPoolItem& rNew = m_pParent
337 ? m_pParent->Get( nWhich, true )
338 : m_pPool->GetDefaultItem( nWhich );
340 Changed( *pItemToClear, rNew );
343 // #i32448#
344 // Take care of disabled items, too.
345 if (!pItemToClear->m_nWhich)
347 // item is disabled, delete it
348 delete pItemToClear;
350 else
352 // remove item from pool
353 m_pPool->Remove( *pItemToClear );
357 pPtr += 2;
360 return nDel;
363 void SfxItemSet::ClearInvalidItems( bool bHardDefault )
365 sal_uInt16* pPtr = m_pWhichRanges;
366 SfxItemArray ppFnd = m_pItems;
367 if ( bHardDefault )
368 while( *pPtr )
370 for ( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
371 if ( IsInvalidItem(*ppFnd) )
372 *ppFnd = &m_pPool->Put( m_pPool->GetDefaultItem(nWhich) );
373 pPtr += 2;
375 else
376 while( *pPtr )
378 for( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
379 if( IsInvalidItem(*ppFnd) )
381 *ppFnd = 0;
382 --m_nCount;
384 pPtr += 2;
388 void SfxItemSet::InvalidateDefaultItems()
390 sal_uInt16* pPtr = m_pWhichRanges;
391 SfxItemArray ppFnd = m_pItems;
393 while( *pPtr )
395 for ( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
396 if (*ppFnd && *ppFnd != reinterpret_cast<SfxPoolItem *>(-1)
397 && **ppFnd == m_pPool->GetDefaultItem(nWhich))
399 m_pPool->Remove( **ppFnd );
400 *ppFnd = reinterpret_cast<SfxPoolItem*>(-1);
402 pPtr += 2;
406 void SfxItemSet::InvalidateAllItems()
408 assert( !m_nCount && "There are still Items set" );
409 m_nCount = TotalCount();
410 memset(static_cast<void*>(m_pItems), -1, m_nCount * sizeof(SfxPoolItem*));
413 SfxItemState SfxItemSet::GetItemState( sal_uInt16 nWhich,
414 bool bSrchInParent,
415 const SfxPoolItem **ppItem ) const
417 // Find the range in which the Which is located
418 const SfxItemSet* pAktSet = this;
419 SfxItemState eRet = SfxItemState::UNKNOWN;
422 SfxItemArray ppFnd = pAktSet->m_pItems;
423 const sal_uInt16* pPtr = pAktSet->m_pWhichRanges;
424 if (pPtr)
426 while ( *pPtr )
428 if ( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
430 // Within this range
431 ppFnd += nWhich - *pPtr;
432 if ( !*ppFnd )
434 eRet = SfxItemState::DEFAULT;
435 if( !bSrchInParent )
436 return eRet; // Not present
437 break; // Keep searching in the parents!
440 if ( reinterpret_cast<SfxPoolItem*>(-1) == *ppFnd )
441 // Different ones are present
442 return SfxItemState::DONTCARE;
444 if ( (*ppFnd)->Type() == TYPE(SfxVoidItem) )
445 return SfxItemState::DISABLED;
447 if (ppItem)
449 *ppItem = *ppFnd;
451 return SfxItemState::SET;
453 ppFnd += *(pPtr+1) - *pPtr + 1;
454 pPtr += 2;
457 } while (bSrchInParent && nullptr != (pAktSet = pAktSet->m_pParent));
458 return eRet;
461 bool SfxItemSet::HasItem(sal_uInt16 nWhich, const SfxPoolItem** ppItem) const
463 bool bRet = SfxItemState::SET == GetItemState(nWhich, true, ppItem);
464 if (!bRet && ppItem)
465 *ppItem = NULL;
466 return bRet;
469 const SfxPoolItem* SfxItemSet::Put( const SfxPoolItem& rItem, sal_uInt16 nWhich )
471 if ( !nWhich )
472 return 0; //FIXME: Only because of Outliner bug
474 SfxItemArray ppFnd = m_pItems;
475 const sal_uInt16* pPtr = m_pWhichRanges;
476 while( *pPtr )
478 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
480 // Within this range
481 ppFnd += nWhich - *pPtr;
482 if( *ppFnd ) // Already one present
484 // Same Item already present?
485 if ( *ppFnd == &rItem )
486 return 0;
488 // Will 'dontcare' or 'disabled' be overwritten with some real value?
489 if ( rItem.Which() && ( IsInvalidItem(*ppFnd) || !(*ppFnd)->Which() ) )
491 *ppFnd = &m_pPool->Put( rItem, nWhich );
492 return *ppFnd;
495 // Turns into disabled?
496 if( !rItem.Which() )
498 *ppFnd = rItem.Clone(m_pPool);
499 return 0;
501 else
503 // Same value already present?
504 if ( rItem == **ppFnd )
505 return 0;
507 // Add the new one, remove the old one
508 const SfxPoolItem& rNew = m_pPool->Put( rItem, nWhich );
509 const SfxPoolItem* pOld = *ppFnd;
510 *ppFnd = &rNew;
511 if(nWhich <= SFX_WHICH_MAX)
512 Changed( *pOld, rNew );
513 m_pPool->Remove( *pOld );
516 else
518 ++m_nCount;
519 if( !rItem.Which() )
520 *ppFnd = rItem.Clone(m_pPool);
521 else {
522 const SfxPoolItem& rNew = m_pPool->Put( rItem, nWhich );
523 *ppFnd = &rNew;
524 if (nWhich <= SFX_WHICH_MAX )
526 const SfxPoolItem& rOld = m_pParent
527 ? m_pParent->Get( nWhich, true )
528 : m_pPool->GetDefaultItem( nWhich );
529 Changed( rOld, rNew );
533 SFX_ASSERT( !m_pPool->IsItemFlag(nWhich, SfxItemPoolFlags::POOLABLE) ||
534 rItem.ISA(SfxSetItem) || **ppFnd == rItem,
535 nWhich, "putted Item unequal" );
536 return *ppFnd;
538 ppFnd += *(pPtr+1) - *pPtr + 1;
539 pPtr += 2;
541 return 0;
544 bool SfxItemSet::Put( const SfxItemSet& rSet, bool bInvalidAsDefault )
546 bool bRet = false;
547 if( rSet.Count() )
549 SfxItemArray ppFnd = rSet.m_pItems;
550 const sal_uInt16* pPtr = rSet.m_pWhichRanges;
551 while ( *pPtr )
553 for ( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
554 if( *ppFnd )
556 if ( IsInvalidItem( *ppFnd ) )
558 if ( bInvalidAsDefault )
559 bRet |= 0 != ClearItem( nWhich );
560 // FIXME: Caused a SEGFAULT on non Windows-platforms:
561 // bRet |= 0 != Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
562 else
563 InvalidateItem( nWhich );
565 else
566 bRet |= 0 != Put( **ppFnd, nWhich );
568 pPtr += 2;
571 return bRet;
575 * This method takes the Items from the 'rSet' and adds to '*this'.
576 * Which ranges in '*this' that are non-existent in 'rSet' will not
577 * be altered. The Which range of '*this' is also not changed.
579 * Items set in 'rSet' are also set in '*this'.
580 * Default (0 pointer) and Invalid (-1 pointer) Items are processed
581 * according to their parameter 'eDontCareAs' and 'eDefaultAs':
583 * SfxItemState::SET: Hard set to the default of the Pool
584 * SfxItemState::DEFAULT: Deleted (0 pointer)
585 * SfxItemState::DONTCARE: Invalid (-1 pointer)
587 * NB: All other values for 'eDontCareAs' and 'eDefaultAs' are invalid
589 void SfxItemSet::PutExtended
591 const SfxItemSet& rSet, // Source of the Items to be put
592 SfxItemState eDontCareAs, // What will happen to the DontCare Items
593 SfxItemState eDefaultAs // What will happen to the Default Items
596 // don't "optimize" with "if( rSet.Count()" because of dont-care + defaults
597 SfxItemArray ppFnd = rSet.m_pItems;
598 const sal_uInt16* pPtr = rSet.m_pWhichRanges;
599 while ( *pPtr )
601 for ( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
602 if( *ppFnd )
604 if ( IsInvalidItem( *ppFnd ) )
606 // Item ist DontCare:
607 switch ( eDontCareAs )
609 case SfxItemState::SET:
610 Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
611 break;
613 case SfxItemState::DEFAULT:
614 ClearItem( nWhich );
615 break;
617 case SfxItemState::DONTCARE:
618 InvalidateItem( nWhich );
619 break;
621 default:
622 assert(!"invalid Argument for eDontCareAs");
625 else
626 // Item is set:
627 Put( **ppFnd, nWhich );
629 else
631 // Item is default:
632 switch ( eDefaultAs )
634 case SfxItemState::SET:
635 Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
636 break;
638 case SfxItemState::DEFAULT:
639 ClearItem( nWhich );
640 break;
642 case SfxItemState::DONTCARE:
643 InvalidateItem( nWhich );
644 break;
646 default:
647 assert(!"invalid Argument for eDefaultAs");
650 pPtr += 2;
655 * Expands the ranges of settable items by 'nFrom' to 'nTo'. Keeps state of
656 * items which are new ranges too.
658 void SfxItemSet::MergeRange( sal_uInt16 nFrom, sal_uInt16 nTo )
660 // special case: exactly one sal_uInt16 which is already included?
661 SfxItemState eItemState = GetItemState(nFrom, false);
662 if ( nFrom == nTo && ( eItemState == SfxItemState::DEFAULT || eItemState == SfxItemState::SET ) )
663 return;
665 // merge new range
666 SfxUShortRanges aRanges( m_pWhichRanges );
667 aRanges += SfxUShortRanges( nFrom, nTo );
668 SetRanges( aRanges );
672 * Modifies the ranges of settable items. Keeps state of items which
673 * are new ranges too.
675 void SfxItemSet::SetRanges( const sal_uInt16 *pNewRanges )
677 // Identical Ranges?
678 if (m_pWhichRanges == pNewRanges)
679 return;
680 const sal_uInt16* pOld = m_pWhichRanges;
681 const sal_uInt16* pNew = pNewRanges;
682 while ( *pOld == *pNew )
684 if ( !*pOld && !*pNew )
685 return;
686 ++pOld, ++pNew;
689 // create new item-array (by iterating through all new ranges)
690 sal_uLong nSize = Capacity_Impl(pNewRanges);
691 SfxItemArray aNewItems = new const SfxPoolItem* [ nSize ];
692 sal_uInt16 nNewCount = 0;
693 if (m_nCount == 0)
694 memset( aNewItems, 0, nSize * sizeof( SfxPoolItem* ) );
695 else
697 sal_uInt16 n = 0;
698 for ( const sal_uInt16 *pRange = pNewRanges; *pRange; pRange += 2 )
700 // iterate through all ids in the range
701 for ( sal_uInt16 nWID = *pRange; nWID <= pRange[1]; ++nWID, ++n )
703 // direct move of pointer (not via pool)
704 SfxItemState eState = GetItemState( nWID, false, aNewItems+n );
705 if ( SfxItemState::SET == eState )
707 // increment new item count and possibly increment ref count
708 ++nNewCount;
709 aNewItems[n]->AddRef();
711 else if ( SfxItemState::DISABLED == eState )
713 // put "disabled" item
714 ++nNewCount;
715 aNewItems[n] = new SfxVoidItem(0);
717 else if ( SfxItemState::DONTCARE == eState )
719 ++nNewCount;
720 aNewItems[n] = reinterpret_cast<SfxPoolItem*>(-1);
722 else
724 // default
725 aNewItems[n] = 0;
729 // free old items
730 sal_uInt16 nOldTotalCount = TotalCount();
731 for ( sal_uInt16 nItem = 0; nItem < nOldTotalCount; ++nItem )
733 const SfxPoolItem *pItem = m_pItems[nItem];
734 if ( pItem && !IsInvalidItem(pItem) && pItem->Which() )
735 m_pPool->Remove(*pItem);
739 // replace old items-array and ranges
740 delete[] m_pItems;
741 m_pItems = aNewItems;
742 m_nCount = nNewCount;
744 if( pNewRanges == GetPool()->GetFrozenIdRanges() )
746 delete[] m_pWhichRanges;
747 m_pWhichRanges = const_cast<sal_uInt16*>(pNewRanges);
749 else
751 sal_uInt16 nCount = Count_Impl(pNewRanges) + 1;
752 if (m_pWhichRanges != m_pPool->GetFrozenIdRanges())
753 delete[] m_pWhichRanges;
754 m_pWhichRanges = new sal_uInt16[ nCount ];
755 memcpy( m_pWhichRanges, pNewRanges, sizeof( sal_uInt16 ) * nCount );
760 * The SfxItemSet takes over exactly those SfxPoolItems that are
761 * set in rSet and are in their own Which range. All others are removed.
762 * The SfxItemPool is retained, such that SfxPoolItems that have been
763 * taken over, are moved from the rSet's SfxItemPool to the SfxItemPool
764 * of *this.
766 * SfxPoolItems in rSet, for which holds 'IsInvalidItem() == true' are
767 * taken over as invalid items.
769 * @return bool true
770 * SfxPoolItems have been taken over
772 * false
773 * No SfxPoolItems have been taken over, because
774 * e.g. the Which ranges of SfxItemSets are not intersecting
775 * or the intersection does not contain SfxPoolItems that are
776 * set in rSet
778 bool SfxItemSet::Set
780 const SfxItemSet& rSet, /* The SfxItemSet, whose SfxPoolItems are
781 to been taken over */
783 bool bDeep /* true (default)
785 The SfxPoolItems from the parents that may
786 be present in rSet, are also taken over into
787 this SfxPoolItemSet
789 false
790 The SfxPoolItems from the parents of
791 rSet are not taken into account */
794 bool bRet = false;
795 if (m_nCount)
796 ClearItem();
797 if ( bDeep )
799 SfxWhichIter aIter(*this);
800 sal_uInt16 nWhich = aIter.FirstWhich();
801 while ( nWhich )
803 const SfxPoolItem* pItem;
804 if( SfxItemState::SET == rSet.GetItemState( nWhich, true, &pItem ) )
805 bRet |= 0 != Put( *pItem, pItem->Which() );
806 nWhich = aIter.NextWhich();
809 else
810 bRet = Put(rSet, false);
812 return bRet;
816 * This method eases accessing single Items in the SfxItemSet.
817 * Type checking is done via assertion, which makes client code
818 * much more readable.
820 * The PRODUCT version returns 0, if the Item found is not of the
821 * specified class.
823 * @returns 0 if the ItemSet does not contain an Item with the Id 'nWhich'
825 const SfxPoolItem* SfxItemSet::GetItem
827 sal_uInt16 nId, // SlotId or the Item's WhichId
828 bool bSrchInParent, // sal_True: also search in Parent ItemSets
829 TypeId aItemType // != 0 => RTTI check using assertion
830 ) const
832 // Convert to WhichId
833 sal_uInt16 nWhich = GetPool()->GetWhich(nId);
835 // Is the Item set or 'bDeep == true' available?
836 const SfxPoolItem *pItem = 0;
837 SfxItemState eState = GetItemState( nWhich, bSrchInParent, &pItem );
838 if ( bSrchInParent && SfxItemState::DEFAULT == eState &&
839 nWhich <= SFX_WHICH_MAX )
841 pItem = &m_pPool->GetDefaultItem(nWhich);
844 if ( pItem )
846 // Does the type match?
847 if ( !aItemType || pItem->IsA(aItemType) )
848 return pItem;
850 // Else report error
851 assert(!"invalid argument type");
854 // No Item of wrong type found
855 return 0;
858 const SfxPoolItem& SfxItemSet::Get( sal_uInt16 nWhich, bool bSrchInParent) const
860 // Search the Range in which the Which is located in:
861 const SfxItemSet* pAktSet = this;
864 if( pAktSet->Count() )
866 SfxItemArray ppFnd = pAktSet->m_pItems;
867 const sal_uInt16* pPtr = pAktSet->m_pWhichRanges;
868 while( *pPtr )
870 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
872 // In this Range
873 ppFnd += nWhich - *pPtr;
874 if( *ppFnd )
876 if( reinterpret_cast<SfxPoolItem*>(-1) == *ppFnd ) {
877 //FIXME: The following code is duplicated further down
878 SFX_ASSERT(m_pPool, nWhich, "no Pool, but status is ambiguous");
879 //!((SfxAllItemSet *)this)->aDefault.SetWhich(nWhich);
880 //!return aDefault;
881 return m_pPool->GetDefaultItem( nWhich );
883 #ifdef DBG_UTIL
884 const SfxPoolItem *pItem = *ppFnd;
885 if ( pItem->ISA(SfxVoidItem) || !pItem->Which() )
886 SAL_INFO("svl.items", "SFX_WARNING: Getting disabled Item");
887 #endif
888 return **ppFnd;
890 break; // Continue with Parent
892 ppFnd += *(pPtr+1) - *pPtr + 1;
893 pPtr += 2;
896 //TODO: Search until end of Range: What are we supposed to do now? To the Parent or Default??
897 // if( !*pPtr ) // Until the end of the search Range?
898 // break;
899 } while (bSrchInParent && nullptr != (pAktSet = pAktSet->m_pParent));
901 // Get the Default from the Pool and return
902 SFX_ASSERT(m_pPool, nWhich, "no Pool, but status is ambiguous");
903 const SfxPoolItem *pItem = &m_pPool->GetDefaultItem( nWhich );
904 return *pItem;
908 * Notification callback
910 void SfxItemSet::Changed( const SfxPoolItem&, const SfxPoolItem& )
914 sal_uInt16 SfxItemSet::TotalCount() const
916 sal_uInt16 nRet = 0;
917 sal_uInt16* pPtr = m_pWhichRanges;
918 while( *pPtr )
920 nRet += ( *(pPtr+1) - *pPtr ) + 1;
921 pPtr += 2;
923 return nRet;
927 * Only retain the Items that are also present in rSet
928 * (nevermind their value).
930 void SfxItemSet::Intersect( const SfxItemSet& rSet )
932 assert(m_pPool && "Not implemented without Pool");
933 if( !Count() ) // None set?
934 return;
936 // Delete all Items not contained in rSet
937 if( !rSet.Count() )
939 ClearItem(); // Delete everything
940 return;
943 // Test whether the Which Ranges are different
944 bool bEqual = true;
945 sal_uInt16* pWh1 = m_pWhichRanges;
946 sal_uInt16* pWh2 = rSet.m_pWhichRanges;
947 sal_uInt16 nSize = 0;
949 for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
951 if( *pWh1 != *pWh2 )
953 bEqual = false;
954 break;
956 if( n & 1 )
957 nSize += ( *(pWh1) - *(pWh1-1) ) + 1;
959 bEqual = *pWh1 == *pWh2; // Also check for 0
961 // If the Ranges are identical, we can easily process it
962 if( bEqual )
964 SfxItemArray ppFnd1 = m_pItems;
965 SfxItemArray ppFnd2 = rSet.m_pItems;
967 for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
968 if( *ppFnd1 && !*ppFnd2 )
970 // Delete from Pool
971 if( !IsInvalidItem( *ppFnd1 ) )
973 sal_uInt16 nWhich = (*ppFnd1)->Which();
974 if(nWhich <= SFX_WHICH_MAX)
976 const SfxPoolItem& rNew = m_pParent
977 ? m_pParent->Get( nWhich, true )
978 : m_pPool->GetDefaultItem( nWhich );
980 Changed( **ppFnd1, rNew );
982 m_pPool->Remove( **ppFnd1 );
984 *ppFnd1 = 0;
985 --m_nCount;
988 else
990 SfxItemIter aIter( *this );
991 const SfxPoolItem* pItem = aIter.GetCurItem();
992 while( true )
994 sal_uInt16 nWhich = IsInvalidItem( pItem )
995 ? GetWhichByPos( aIter.GetCurPos() )
996 : pItem->Which();
997 if( SfxItemState::UNKNOWN == rSet.GetItemState( nWhich, false ) )
998 ClearItem( nWhich ); // Delete
999 if( aIter.IsAtEnd() )
1000 break;
1001 pItem = aIter.NextItem();
1006 void SfxItemSet::Differentiate( const SfxItemSet& rSet )
1008 if( !Count() || !rSet.Count() )// None set?
1009 return;
1011 // Test whether the Which Ranges are different
1012 bool bEqual = true;
1013 sal_uInt16* pWh1 = m_pWhichRanges;
1014 sal_uInt16* pWh2 = rSet.m_pWhichRanges;
1015 sal_uInt16 nSize = 0;
1017 for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
1019 if( *pWh1 != *pWh2 )
1021 bEqual = false;
1022 break;
1024 if( n & 1 )
1025 nSize += ( *(pWh1) - *(pWh1-1) ) + 1;
1027 bEqual = *pWh1 == *pWh2; // Also test for 0
1029 // If the Ranges are identical, we can easily process it
1030 if( bEqual )
1032 SfxItemArray ppFnd1 = m_pItems;
1033 SfxItemArray ppFnd2 = rSet.m_pItems;
1035 for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
1036 if( *ppFnd1 && *ppFnd2 )
1038 // Delete from Pool
1039 if( !IsInvalidItem( *ppFnd1 ) )
1041 sal_uInt16 nWhich = (*ppFnd1)->Which();
1042 if(nWhich <= SFX_WHICH_MAX)
1044 const SfxPoolItem& rNew = m_pParent
1045 ? m_pParent->Get( nWhich, true )
1046 : m_pPool->GetDefaultItem( nWhich );
1048 Changed( **ppFnd1, rNew );
1050 m_pPool->Remove( **ppFnd1 );
1052 *ppFnd1 = 0;
1053 --m_nCount;
1056 else
1058 SfxItemIter aIter( *this );
1059 const SfxPoolItem* pItem = aIter.GetCurItem();
1060 while( true )
1062 sal_uInt16 nWhich = IsInvalidItem( pItem )
1063 ? GetWhichByPos( aIter.GetCurPos() )
1064 : pItem->Which();
1065 if( SfxItemState::SET == rSet.GetItemState( nWhich, false ) )
1066 ClearItem( nWhich ); // Delete
1067 if( aIter.IsAtEnd() )
1068 break;
1069 pItem = aIter.NextItem();
1076 * Decision table for MergeValue(s)
1078 * Principles:
1079 * 1. If the Which value in the 1st set is "unknown", there's never any action
1080 * 2. If the Which value in the 2nd set is "unknown", it's made the "default"
1081 * 3. For comparisons the values of the "default" Items are take into account
1083 * 1st Item 2nd Item Values bIgnoreDefs Remove Assign Add
1085 * set set == sal_False - - -
1086 * default set == sal_False - - -
1087 * dontcare set == sal_False - - -
1088 * unknown set == sal_False - - -
1089 * set default == sal_False - - -
1090 * default default == sal_False - - -
1091 * dontcare default == sal_False - - -
1092 * unknown default == sal_False - - -
1093 * set dontcare == sal_False 1st Item -1 -
1094 * default dontcare == sal_False - -1 -
1095 * dontcare dontcare == sal_False - - -
1096 * unknown dontcare == sal_False - - -
1097 * set unknown == sal_False 1st Item -1 -
1098 * default unknown == sal_False - - -
1099 * dontcare unknown == sal_False - - -
1100 * unknown unknown == sal_False - - -
1102 * set set != sal_False 1st Item -1 -
1103 * default set != sal_False - -1 -
1104 * dontcare set != sal_False - - -
1105 * unknown set != sal_False - - -
1106 * set default != sal_False 1st Item -1 -
1107 * default default != sal_False - - -
1108 * dontcare default != sal_False - - -
1109 * unknown default != sal_False - - -
1110 * set dontcare != sal_False 1st Item -1 -
1111 * default dontcare != sal_False - -1 -
1112 * dontcare dontcare != sal_False - - -
1113 * unknown dontcare != sal_False - - -
1114 * set unknown != sal_False 1st Item -1 -
1115 * default unknown != sal_False - - -
1116 * dontcare unknown != sal_False - - -
1117 * unknown unknown != sal_False - - -
1119 * set set == sal_True - - -
1120 * default set == sal_True - 2nd Item 2nd Item
1121 * dontcare set == sal_True - - -
1122 * unknown set == sal_True - - -
1123 * set default == sal_True - - -
1124 * default default == sal_True - - -
1125 * dontcare default == sal_True - - -
1126 * unknown default == sal_True - - -
1127 * set dontcare == sal_True - - -
1128 * default dontcare == sal_True - -1 -
1129 * dontcare dontcare == sal_True - - -
1130 * unknown dontcare == sal_True - - -
1131 * set unknown == sal_True - - -
1132 * default unknown == sal_True - - -
1133 * dontcare unknown == sal_True - - -
1134 * unknown unknown == sal_True - - -
1136 * set set != sal_True 1st Item -1 -
1137 * default set != sal_True - 2nd Item 2nd Item
1138 * dontcare set != sal_True - - -
1139 * unknown set != sal_True - - -
1140 * set default != sal_True - - -
1141 * default default != sal_True - - -
1142 * dontcare default != sal_True - - -
1143 * unknown default != sal_True - - -
1144 * set dontcare != sal_True 1st Item -1 -
1145 * default dontcare != sal_True - -1 -
1146 * dontcare dontcare != sal_True - - -
1147 * unknown dontcare != sal_True - - -
1148 * set unknown != sal_True - - -
1149 * default unknown != sal_True - - -
1150 * dontcare unknown != sal_True - - -
1151 * unknown unknown != sal_True - - -
1153 static void MergeItem_Impl( SfxItemPool *_pPool, sal_uInt16 &rCount,
1154 const SfxPoolItem **ppFnd1, const SfxPoolItem *pFnd2,
1155 bool bIgnoreDefaults )
1157 assert(ppFnd1 != 0 && "Merging to 0-Item");
1159 // 1st Item is Default?
1160 if ( !*ppFnd1 )
1162 if ( IsInvalidItem(pFnd2) )
1163 // Decision table: default, dontcare, doesn't matter, doesn't matter
1164 *ppFnd1 = reinterpret_cast<SfxPoolItem*>(-1);
1166 else if ( pFnd2 && !bIgnoreDefaults &&
1167 _pPool->GetDefaultItem(pFnd2->Which()) != *pFnd2 )
1168 // Decision table: default, set, !=, sal_False
1169 *ppFnd1 = reinterpret_cast<SfxPoolItem*>(-1);
1171 else if ( pFnd2 && bIgnoreDefaults )
1172 // Decision table: default, set, doesn't matter, sal_True
1173 *ppFnd1 = &_pPool->Put( *pFnd2 );
1175 if ( *ppFnd1 )
1176 ++rCount;
1179 // 1st Item set?
1180 else if ( !IsInvalidItem(*ppFnd1) )
1182 if ( !pFnd2 )
1184 // 2nd Item is Default
1185 if ( !bIgnoreDefaults &&
1186 **ppFnd1 != _pPool->GetDefaultItem((*ppFnd1)->Which()) )
1188 // Decision table: set, default, !=, sal_False
1189 _pPool->Remove( **ppFnd1 );
1190 *ppFnd1 = reinterpret_cast<SfxPoolItem*>(-1);
1193 else if ( IsInvalidItem(pFnd2) )
1195 // 2nd Item is dontcare
1196 if ( !bIgnoreDefaults ||
1197 **ppFnd1 != _pPool->GetDefaultItem( (*ppFnd1)->Which()) )
1199 // Decision table: set, dontcare, doesn't matter, sal_False
1200 // or: set, dontcare, !=, sal_True
1201 _pPool->Remove( **ppFnd1 );
1202 *ppFnd1 = reinterpret_cast<SfxPoolItem*>(-1);
1205 else
1207 // 2nd Item is set
1208 if ( **ppFnd1 != *pFnd2 )
1210 // Decision table: set, set, !=, doesn't matter
1211 _pPool->Remove( **ppFnd1 );
1212 *ppFnd1 = reinterpret_cast<SfxPoolItem*>(-1);
1218 void SfxItemSet::MergeValues( const SfxItemSet& rSet, bool bIgnoreDefaults )
1220 // WARNING! When making changes/fixing bugs, always update the table above!!
1221 assert( GetPool() == rSet.GetPool() && "MergeValues with different Pools" );
1223 // Test if the which Ranges are different
1224 bool bEqual = true;
1225 sal_uInt16* pWh1 = m_pWhichRanges;
1226 sal_uInt16* pWh2 = rSet.m_pWhichRanges;
1227 sal_uInt16 nSize = 0;
1229 for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
1231 if( *pWh1 != *pWh2 )
1233 bEqual = false;
1234 break;
1236 if( n & 1 )
1237 nSize += ( *(pWh1) - *(pWh1-1) ) + 1;
1239 bEqual = *pWh1 == *pWh2; // Also check for 0
1241 // If the Ranges match, they are easier to process!
1242 if( bEqual )
1244 SfxItemArray ppFnd1 = m_pItems;
1245 SfxItemArray ppFnd2 = rSet.m_pItems;
1247 for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
1248 MergeItem_Impl(m_pPool, m_nCount, ppFnd1, *ppFnd2, bIgnoreDefaults);
1250 else
1252 SfxWhichIter aIter( rSet );
1253 sal_uInt16 nWhich;
1254 while( 0 != ( nWhich = aIter.NextWhich() ) )
1256 const SfxPoolItem* pItem = 0;
1257 rSet.GetItemState( nWhich, true, &pItem );
1258 if( !pItem )
1260 // Not set, so default
1261 if ( !bIgnoreDefaults )
1262 MergeValue( rSet.GetPool()->GetDefaultItem( nWhich ), bIgnoreDefaults );
1264 else if( IsInvalidItem( pItem ) )
1265 // dont care
1266 InvalidateItem( nWhich );
1267 else
1268 MergeValue( *pItem, bIgnoreDefaults );
1273 void SfxItemSet::MergeValue( const SfxPoolItem& rAttr, bool bIgnoreDefaults )
1275 SfxItemArray ppFnd = m_pItems;
1276 const sal_uInt16* pPtr = m_pWhichRanges;
1277 const sal_uInt16 nWhich = rAttr.Which();
1278 while( *pPtr )
1280 // In this Range??
1281 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1283 ppFnd += nWhich - *pPtr;
1284 MergeItem_Impl(m_pPool, m_nCount, ppFnd, &rAttr, bIgnoreDefaults);
1285 break;
1287 ppFnd += *(pPtr+1) - *pPtr + 1;
1288 pPtr += 2;
1292 void SfxItemSet::InvalidateItem( sal_uInt16 nWhich )
1294 SfxItemArray ppFnd = m_pItems;
1295 const sal_uInt16* pPtr = m_pWhichRanges;
1296 while( *pPtr )
1298 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1300 // In this Range?
1301 ppFnd += nWhich - *pPtr;
1303 if( *ppFnd ) // Set for me
1305 if( reinterpret_cast<SfxPoolItem*>(-1) != *ppFnd ) // Not yet dontcare!
1307 m_pPool->Remove( **ppFnd );
1308 *ppFnd = reinterpret_cast<SfxPoolItem*>(-1);
1311 else
1313 *ppFnd = reinterpret_cast<SfxPoolItem*>(-1);
1314 ++m_nCount;
1316 break;
1318 ppFnd += *(pPtr+1) - *pPtr + 1;
1319 pPtr += 2;
1323 sal_uInt16 SfxItemSet::GetWhichByPos( sal_uInt16 nPos ) const
1325 sal_uInt16 n = 0;
1326 sal_uInt16* pPtr = m_pWhichRanges;
1327 while( *pPtr )
1329 n = ( *(pPtr+1) - *pPtr ) + 1;
1330 if( nPos < n )
1331 return *(pPtr)+nPos;
1332 nPos = nPos - n;
1333 pPtr += 2;
1335 assert(false);
1336 return 0;
1340 * Saves the SfxItemSet instance to the supplied Stream.
1341 * The surrogates as well as the ones with 'bDirect == true' are saved
1342 * to the stream in the following way:
1344 * sal_uInt16 ... Count of the set Items
1345 * Count* m_pPool->StoreItem()
1347 * @see SfxItemPool::StoreItem() const
1348 * @see SfxItemSet::Load(SvStream&,bool,const SfxItemPool*)
1350 SvStream &SfxItemSet::Store
1352 SvStream& rStream, // Target stream for normal Items
1353 bool bDirect /* true: Save Items directly
1354 false: Surrogates */
1355 ) const
1357 assert(m_pPool);
1359 // Remember position of the count (to be able to correct it, if need be)
1360 sal_uLong nCountPos = rStream.Tell();
1361 rStream.WriteUInt16( m_nCount );
1363 // If there's nothing to save, don't construct an ItemIter
1364 if (m_nCount)
1366 // Keep record of how many Items are really saved
1367 sal_uInt16 nWrittenCount = 0; // Count of Items streamed in 'rStream'
1369 // Iterate over all set Items
1370 SfxItemIter aIter(*this);
1371 for ( const SfxPoolItem *pItem = aIter.FirstItem();
1372 pItem;
1373 pItem = aIter.NextItem() )
1375 // Let Items (if need be as a Surrogate) be saved via Pool
1376 SAL_WARN_IF(IsInvalidItem(pItem), "svl.items", "can't store invalid items");
1377 if ( !IsInvalidItem(pItem) &&
1378 m_pPool->StoreItem( rStream, *pItem, bDirect ) )
1379 // Item was streamed in 'rStream'
1380 ++nWrittenCount;
1383 // Fewer written than read (e.g. old format)
1384 if (nWrittenCount != m_nCount)
1386 // Store real count in the stream
1387 sal_uLong nPos = rStream.Tell();
1388 rStream.Seek( nCountPos );
1389 rStream.WriteUInt16( nWrittenCount );
1390 rStream.Seek( nPos );
1394 return rStream;
1398 * This method loads an SfxItemSet from a stream.
1399 * If the SfxItemPool was loaded without RefCounts the loaded Item
1400 * references are counted, else we assume the they were accounted for
1401 * when loadig the SfxItemPool.
1403 * @see SfxItemSet::Store(Stream&,bool) const
1405 SvStream &SfxItemSet::Load
1407 SvStream& rStream, // Stream we're loading from
1409 bool bDirect, /* true
1410 Items are directly read form the stream
1411 and not via Surrogates
1413 false (default)
1414 Items are read via Surrogates */
1416 const SfxItemPool* pRefPool /* Pool that can resolve the Surrogates
1417 (e.g. when inserting documents) */
1420 assert(m_pPool);
1422 // No RefPool => Resolve Surrogates with ItemSet's Pool
1423 if ( !pRefPool )
1424 pRefPool = m_pPool;
1426 // Load Item count and as many Items
1427 sal_uInt16 nCount = 0;
1428 rStream.ReadUInt16( nCount );
1430 const size_t nMinRecordSize = sizeof(sal_uInt16) * 2;
1431 const size_t nMaxRecords = rStream.remainingSize() / nMinRecordSize;
1432 if (nCount > nMaxRecords)
1434 SAL_WARN("svl", "Parsing error: " << nMaxRecords <<
1435 " max possible entries, but " << nCount << " claimed, truncating");
1436 nCount = nMaxRecords;
1439 for ( sal_uInt16 i = 0; i < nCount; ++i )
1441 // Load Surrogate/Item and resolve Surrogate
1442 const SfxPoolItem *pItem =
1443 m_pPool->LoadItem( rStream, bDirect, pRefPool );
1445 // Did we load an Item or resolve a Surrogate?
1446 if ( pItem )
1448 // Find position for Item pointer in the set
1449 sal_uInt16 nWhich = pItem->Which();
1450 SfxItemArray ppFnd = m_pItems;
1451 const sal_uInt16* pPtr = m_pWhichRanges;
1452 while ( *pPtr )
1454 // In this Range??
1455 if ( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1457 // Remember Item pointer in the set
1458 ppFnd += nWhich - *pPtr;
1459 SFX_ASSERT( !*ppFnd, nWhich, "Item is present twice");
1460 *ppFnd = pItem;
1461 ++m_nCount;
1462 break;
1465 // In the range array and Item array to the next Which range
1466 ppFnd += *(pPtr+1) - *pPtr + 1;
1467 pPtr += 2;
1472 return rStream;
1475 bool SfxItemSet::operator==(const SfxItemSet &rCmp) const
1477 // Values we can get quickly need to be the same
1478 if ( m_pParent != rCmp.m_pParent ||
1479 m_pPool != rCmp.m_pPool ||
1480 Count() != rCmp.Count() )
1481 return false;
1483 // Counting Ranges takes longer; they also need to be the same, however
1484 sal_uInt16 nCount1 = TotalCount();
1485 sal_uInt16 nCount2 = rCmp.TotalCount();
1486 if ( nCount1 != nCount2 )
1487 return false;
1489 // Are the Ranges themselves unequal?
1490 for (sal_uInt16 nRange = 0; m_pWhichRanges[nRange]; nRange += 2)
1492 if (m_pWhichRanges[nRange] != rCmp.m_pWhichRanges[nRange] ||
1493 m_pWhichRanges[nRange+1] != rCmp.m_pWhichRanges[nRange+1])
1495 // We must use the slow method then
1496 SfxWhichIter aIter( *this );
1497 for ( sal_uInt16 nWh = aIter.FirstWhich();
1498 nWh;
1499 nWh = aIter.NextWhich() )
1501 // If the pointer of the poolable Items are unequal, the Items must match
1502 const SfxPoolItem *pItem1 = 0, *pItem2 = 0;
1503 if ( GetItemState( nWh, false, &pItem1 ) !=
1504 rCmp.GetItemState( nWh, false, &pItem2 ) ||
1505 ( pItem1 != pItem2 &&
1506 ( !pItem1 || IsInvalidItem(pItem1) ||
1507 (m_pPool->IsItemFlag(*pItem1, SfxItemPoolFlags::POOLABLE) &&
1508 *pItem1 != *pItem2 ) ) ) )
1509 return false;
1512 return true;
1516 // Are all pointers the same?
1517 if (0 == memcmp( m_pItems, rCmp.m_pItems, nCount1 * sizeof(m_pItems[0]) ))
1518 return true;
1520 // We need to compare each one separately then
1521 const SfxPoolItem **ppItem1 = m_pItems;
1522 const SfxPoolItem **ppItem2 = rCmp.m_pItems;
1523 for ( sal_uInt16 nPos = 0; nPos < nCount1; ++nPos )
1525 // If the pointers of the poolable Items are not the same, the Items
1526 // must match
1527 if ( *ppItem1 != *ppItem2 &&
1528 ( ( !*ppItem1 || !*ppItem2 ) ||
1529 ( IsInvalidItem(*ppItem1) || IsInvalidItem(*ppItem2) ) ||
1530 (m_pPool->IsItemFlag(**ppItem1, SfxItemPoolFlags::POOLABLE)) ||
1531 **ppItem1 != **ppItem2 ) )
1532 return false;
1534 ++ppItem1;
1535 ++ppItem2;
1538 return true;
1541 SfxItemSet *SfxItemSet::Clone(bool bItems, SfxItemPool *pToPool ) const
1543 if (pToPool && pToPool != m_pPool)
1545 SfxItemSet *pNewSet = new SfxItemSet(*pToPool, m_pWhichRanges);
1546 if ( bItems )
1548 SfxWhichIter aIter(*pNewSet);
1549 sal_uInt16 nWhich = aIter.FirstWhich();
1550 while ( nWhich )
1552 const SfxPoolItem* pItem;
1553 if ( SfxItemState::SET == GetItemState( nWhich, false, &pItem ) )
1554 pNewSet->Put( *pItem, pItem->Which() );
1555 nWhich = aIter.NextWhich();
1558 return pNewSet;
1560 else
1561 return bItems
1562 ? new SfxItemSet(*this)
1563 : new SfxItemSet(*m_pPool, m_pWhichRanges);
1566 void SfxItemSet::PutDirect(const SfxPoolItem &rItem)
1568 SfxItemArray ppFnd = m_pItems;
1569 const sal_uInt16* pPtr = m_pWhichRanges;
1570 const sal_uInt16 nWhich = rItem.Which();
1571 #ifdef DBG_UTIL
1572 IsPoolDefaultItem(&rItem) || m_pPool->GetSurrogate(&rItem);
1573 // Only cause assertion in the callees
1574 #endif
1575 while( *pPtr )
1577 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1579 // In this Range?
1580 ppFnd += nWhich - *pPtr;
1581 const SfxPoolItem* pOld = *ppFnd;
1582 if( pOld ) // One already present
1584 if( rItem == **ppFnd )
1585 return; // Already present!
1586 m_pPool->Remove( *pOld );
1588 else
1589 ++m_nCount;
1591 // Add the new one
1592 if( IsPoolDefaultItem(&rItem) )
1593 *ppFnd = &m_pPool->Put( rItem );
1594 else
1596 *ppFnd = &rItem;
1597 if( !IsStaticDefaultItem( &rItem ) )
1598 rItem.AddRef();
1601 return;
1603 ppFnd += *(pPtr+1) - *pPtr + 1;
1604 pPtr += 2;
1608 sal_Int32 SfxItemSet::getHash() const
1610 return stringify().hashCode();
1613 OString SfxItemSet::stringify() const
1615 SvMemoryStream aStream;
1616 SfxItemSet aSet(*this);
1617 aSet.InvalidateDefaultItems();
1618 aSet.Store(aStream, true);
1619 aStream.Flush();
1620 return OString(
1621 static_cast<char const *>(aStream.GetData()), aStream.GetEndOfData());
1624 void SfxItemSet::dumpAsXml(xmlTextWriterPtr pWriter) const
1626 xmlTextWriterStartElement(pWriter, BAD_CAST("sfxItemSet"));
1627 SfxItemIter aIter(*this);
1628 for (const SfxPoolItem* pItem = aIter.FirstItem(); pItem; pItem = aIter.NextItem())
1629 pItem->dumpAsXml(pWriter);
1630 xmlTextWriterEndElement(pWriter);
1634 // ----------------------------------------------- class SfxAllItemSet
1636 SfxAllItemSet::SfxAllItemSet( SfxItemPool &rPool )
1637 : SfxItemSet(rPool, (const sal_uInt16*) 0),
1638 aDefault(0),
1639 nFree(nInitCount)
1641 // Initially no Items
1642 m_pItems = nullptr;
1644 // Allocate nInitCount pairs at USHORTs for Ranges
1645 m_pWhichRanges = new sal_uInt16[ nInitCount + 1 ];
1646 memset( m_pWhichRanges, 0, (nInitCount + 1) * sizeof(sal_uInt16) );
1649 SfxAllItemSet::SfxAllItemSet(const SfxItemSet &rCopy)
1650 : SfxItemSet(rCopy),
1651 aDefault(0),
1652 nFree(0)
1657 * Explicitly define this ctor to avoid auto-generation by the compiler.
1658 * The compiler does not take the ctor with the 'const SfxItemSet&'!
1660 SfxAllItemSet::SfxAllItemSet(const SfxAllItemSet &rCopy)
1661 : SfxItemSet(rCopy),
1662 aDefault(0),
1663 nFree(0)
1668 * This internal function creates a new WhichRanges array, which is copied
1669 * from the 'nOldSize'-USHORTs long 'pUS'. It has new USHORTs at the end instead
1670 * of 'nIncr'.
1671 * The terminating sal_uInt16 with the '0' is neither accounted for in 'nOldSize'
1672 * nor in 'nIncr', but always explicitly added.
1674 * @returns the new WhichRanges array (the old 'pUS' is freed)
1676 static sal_uInt16 *AddRanges_Impl(
1677 sal_uInt16 *pUS, std::ptrdiff_t nOldSize, sal_uInt16 nIncr)
1679 // Create new WhichRanges array
1680 sal_uInt16 *pNew = new sal_uInt16[ nOldSize + nIncr + 1 ];
1682 // Take over the old Ranges
1683 memcpy( pNew, pUS, nOldSize * sizeof(sal_uInt16) );
1685 // Initialize the new one to 0
1686 memset( pNew + nOldSize, 0, ( nIncr + 1 ) * sizeof(sal_uInt16) );
1688 // Free the old array
1689 delete[] pUS;
1691 return pNew;
1695 * This internal function creates a new ItemArray, which is copied from 'pItems',
1696 * but has room for a new ItemPointer at 'nPos'.
1698 * @returns the new ItemArray (the old 'pItems' is freed)
1700 static SfxItemArray AddItem_Impl(SfxItemArray pItems, sal_uInt16 nOldSize, sal_uInt16 nPos)
1702 // Create new ItemArray
1703 SfxItemArray pNew = new const SfxPoolItem*[nOldSize+1];
1705 // Was there one before?
1706 if ( pItems )
1708 // Copy all Items before nPos
1709 if ( nPos )
1710 memcpy( (void*) pNew, pItems, nPos * sizeof(SfxPoolItem *) );
1712 // Copy all Items after nPos
1713 if ( nPos < nOldSize )
1714 memcpy( (void*) (pNew + nPos + 1), pItems + nPos,
1715 (nOldSize-nPos) * sizeof(SfxPoolItem *) );
1718 // Initialize new Item
1719 *(pNew + nPos) = 0;
1721 // Free old ItemArray
1722 delete[] pItems;
1724 return pNew;
1728 * Putting with automatic extension of the WhichId with the ID of the Item.
1730 const SfxPoolItem* SfxAllItemSet::Put( const SfxPoolItem& rItem, sal_uInt16 nWhich )
1732 sal_uInt16 nPos = 0; // Position for 'rItem' in 'm_pItems'
1733 const sal_uInt16 nItemCount = TotalCount();
1735 // Let's see first whether there's a suitable Range already
1736 sal_uInt16 *pPtr = m_pWhichRanges;
1737 while ( *pPtr )
1739 // WhichId is within this Range?
1740 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1742 // Insert
1743 nPos += nWhich - *pPtr;
1744 break;
1747 // Carry over the position of the Item in m_pItems
1748 nPos += *(pPtr+1) - *pPtr + 1;
1750 // To the next Range
1751 pPtr += 2;
1754 // WhichId not yet present?
1755 if ( !*pPtr )
1757 // Let's see if we can attach it somewhere
1758 pPtr = m_pWhichRanges;
1759 nPos = 0;
1760 while ( *pPtr )
1762 // WhichId is right before this Range?
1763 if ( (nWhich+1) == *pPtr )
1765 // Range grows downwards
1766 (*pPtr)--;
1768 // Make room before first Item of this Range
1769 m_pItems = AddItem_Impl(m_pItems, nItemCount, nPos);
1770 break;
1773 // WhichId is right after this Range?
1774 else if ( (nWhich-1) == *(pPtr+1) )
1776 // Range grows upwards?
1777 (*(pPtr+1))++;
1779 // Make room after last Item of this Range
1780 nPos += nWhich - *pPtr;
1781 m_pItems = AddItem_Impl(m_pItems, nItemCount, nPos);
1782 break;
1785 // Carry over position of the Item in m_pItems
1786 nPos += *(pPtr+1) - *pPtr + 1;
1788 // To the next Range
1789 pPtr += 2;
1793 // No extensible Range found?
1794 if ( !*pPtr )
1796 // No room left in m_pWhichRanges? => Expand!
1797 std::ptrdiff_t nSize = pPtr - m_pWhichRanges;
1798 if( !nFree )
1800 m_pWhichRanges = AddRanges_Impl(m_pWhichRanges, nSize, nInitCount);
1801 nFree += nInitCount;
1804 // Attach new WhichRange
1805 pPtr = m_pWhichRanges + nSize;
1806 *pPtr++ = nWhich;
1807 *pPtr = nWhich;
1808 nFree -= 2;
1810 // Expand ItemArray
1811 nPos = nItemCount;
1812 m_pItems = AddItem_Impl(m_pItems, nItemCount, nPos);
1815 // Add new Item to Pool
1816 const SfxPoolItem& rNew = m_pPool->Put( rItem, nWhich );
1818 // Remember old Item
1819 bool bIncrementCount = false;
1820 const SfxPoolItem* pOld = *( m_pItems + nPos );
1821 if ( reinterpret_cast< SfxPoolItem* >( -1 ) == pOld ) // state "dontcare"
1822 pOld = NULL;
1823 if ( !pOld )
1825 bIncrementCount = true;
1826 pOld = (m_pParent)
1827 ? &m_pParent->Get( nWhich, true )
1828 : ((nWhich <= SFX_WHICH_MAX)
1829 ? &m_pPool->GetDefaultItem(nWhich)
1830 : nullptr);
1833 // Add new Item to ItemSet
1834 *(m_pItems + nPos) = &rNew;
1836 // Send Changed Notification
1837 if ( pOld )
1839 Changed( *pOld, rNew );
1840 if ( !IsDefaultItem(pOld) )
1841 m_pPool->Remove( *pOld );
1844 if ( bIncrementCount )
1845 ++m_nCount;
1847 return &rNew;
1851 * Disable Item
1852 * Using a VoidItem with Which value 0
1854 void SfxItemSet::DisableItem(sal_uInt16 nWhich)
1856 Put( SfxVoidItem(0), nWhich );
1859 SfxItemSet *SfxAllItemSet::Clone(bool bItems, SfxItemPool *pToPool ) const
1861 if (pToPool && pToPool != m_pPool)
1863 SfxAllItemSet *pNewSet = new SfxAllItemSet( *pToPool );
1864 if ( bItems )
1865 pNewSet->Set( *this );
1866 return pNewSet;
1868 else
1869 return bItems ? new SfxAllItemSet(*this) : new SfxAllItemSet(*m_pPool);
1872 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */