lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / svl / source / items / itemset.cxx
blobba5df7559def32c1c08caaac7719a548a7547f3f
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 <algorithm>
24 #include <cassert>
25 #include <cstddef>
27 #include <libxml/xmlwriter.h>
29 #include <sal/log.hxx>
30 #include <svl/itemset.hxx>
31 #include <svl/itempool.hxx>
32 #include <svl/itemiter.hxx>
33 #include <svl/whiter.hxx>
35 #include <tools/stream.hxx>
36 #include <tools/solar.h>
37 #include <rtl/string.hxx>
39 #include <poolio.hxx>
41 static const sal_uInt16 nInitCount = 10; // Single USHORTs => 5 pairs without '0'
43 namespace
46 /**
47 * Determines the number of sal_uInt16s in a 0-terminated array of pairs of
48 * sal_uInt16s.
49 * The terminating 0 is not included in the count.
51 sal_uInt16 Count_Impl( const sal_uInt16 *pRanges )
53 sal_uInt16 nCount = 0;
54 while ( *pRanges )
56 nCount += 2;
57 pRanges += 2;
59 return nCount;
62 /**
63 * Determines the total number of sal_uInt16s described in a 0-terminated
64 * array of pairs of sal_uInt16s, each representing an range of sal_uInt16s.
66 sal_uInt16 Capacity_Impl( const sal_uInt16 *pRanges )
68 sal_uInt16 nCount = 0;
70 if ( pRanges )
72 while ( *pRanges )
74 nCount += pRanges[1] - pRanges[0] + 1;
75 pRanges += 2;
78 return nCount;
83 /**
84 * Ctor for a SfxItemSet with exactly the Which Ranges, which are known to
85 * the supplied SfxItemPool.
87 * For Sfx programmers: an SfxItemSet constructed in this way cannot
88 * contain any Items with SlotIds as Which values.
90 SfxItemSet::SfxItemSet(SfxItemPool& rPool)
91 : m_pPool( &rPool )
92 , m_pParent(nullptr)
93 , m_nCount(0)
95 m_pWhichRanges = const_cast<sal_uInt16*>(m_pPool->GetFrozenIdRanges());
96 assert( m_pWhichRanges && "don't create ItemSets with full range before FreezeIdRanges()" );
97 if (!m_pWhichRanges)
99 std::unique_ptr<sal_uInt16[]> tmp;
100 m_pPool->FillItemIdRanges_Impl(tmp);
101 m_pWhichRanges = tmp.release();
104 const sal_uInt16 nSize = TotalCount();
105 m_pItems.reset(new const SfxPoolItem*[nSize]{});
108 void SfxItemSet::InitRanges_Impl(const sal_uInt16 *pWhichPairTable)
110 sal_uInt16 nCnt = 0;
111 const sal_uInt16* pPtr = pWhichPairTable;
112 while( *pPtr )
114 nCnt += ( *(pPtr+1) - *pPtr ) + 1;
115 pPtr += 2;
118 m_pItems.reset( new const SfxPoolItem*[nCnt]{} );
120 std::ptrdiff_t cnt = pPtr - pWhichPairTable +1;
121 m_pWhichRanges = new sal_uInt16[ cnt ];
122 memcpy( m_pWhichRanges, pWhichPairTable, sizeof( sal_uInt16 ) * cnt );
125 SfxItemSet::SfxItemSet(
126 SfxItemPool & pool, std::initializer_list<sal_uInt16> wids,
127 std::size_t items):
128 m_pPool(&pool), m_pParent(nullptr),
129 m_pItems(new SfxPoolItem const *[items]{}),
130 m_pWhichRanges(new sal_uInt16[wids.size() + 1]),
131 // cannot overflow, assuming std::size_t is no smaller than sal_uInt16,
132 // as wids.size() must be substantially smaller than
133 // std::numeric_limits<sal_uInt16>::max() by construction in
134 // SfxItemSet::create
135 m_nCount(0)
137 assert(wids.size() != 0);
138 assert(wids.size() % 2 == 0);
139 std::copy(wids.begin(), wids.end(), m_pWhichRanges);
140 m_pWhichRanges[wids.size()] = 0;
143 SfxItemSet::SfxItemSet(
144 SfxItemPool & pool, std::initializer_list<Pair> wids):
145 m_pPool(&pool), m_pParent(nullptr),
146 m_pWhichRanges(new sal_uInt16[2 * wids.size() + 1]), //TODO: overflow
147 m_nCount(0)
149 assert(wids.size() != 0);
150 std::size_t i = 0;
151 std::size_t size = 0;
152 #if !defined NDEBUG
153 //TODO: sal_uInt16 prev = 0;
154 #endif
155 for (auto const & p: wids) {
156 assert(svl::detail::validRange(p.wid1, p.wid2));
157 //TODO: assert(prev == 0 || svl::detail::validGap(prev, p.wid1));
158 m_pWhichRanges[i++] = p.wid1;
159 m_pWhichRanges[i++] = p.wid2;
160 size += svl::detail::rangeSize(p.wid1, p.wid2);
161 // cannot overflow, assuming std::size_t is no smaller than
162 // sal_uInt16
163 #if !defined NDEBUG
164 //TODO: prev = p.wid2;
165 #endif
167 m_pWhichRanges[i] = 0;
168 m_pItems.reset( new SfxPoolItem const *[size]{} );
171 SfxItemSet::SfxItemSet( SfxItemPool& rPool, const sal_uInt16* pWhichPairTable )
172 : m_pPool(&rPool)
173 , m_pParent(nullptr)
174 , m_pWhichRanges(nullptr)
175 , m_nCount(0)
177 // pWhichPairTable == 0 is for the SfxAllEnumItemSet
178 if ( pWhichPairTable )
179 InitRanges_Impl(pWhichPairTable);
182 SfxItemSet::SfxItemSet( const SfxItemSet& rASet )
183 : m_pPool( rASet.m_pPool )
184 , m_pParent( rASet.m_pParent )
185 , m_nCount( rASet.m_nCount )
187 // Calculate the attribute count
188 sal_uInt16 nCnt = 0;
189 sal_uInt16* pPtr = rASet.m_pWhichRanges;
190 while( *pPtr )
192 nCnt += ( *(pPtr+1) - *pPtr ) + 1;
193 pPtr += 2;
196 m_pItems.reset( new const SfxPoolItem* [ nCnt ] );
198 // Copy attributes
199 SfxPoolItem const** ppDst = m_pItems.get();
200 SfxPoolItem const** ppSrc = rASet.m_pItems.get();
201 for( sal_uInt16 n = nCnt; n; --n, ++ppDst, ++ppSrc )
202 if ( nullptr == *ppSrc || // Current Default?
203 IsInvalidItem(*ppSrc) || // DontCare?
204 IsStaticDefaultItem(*ppSrc) ) // Defaults that are not to be pooled?
205 // Just copy the pointer
206 *ppDst = *ppSrc;
207 else if (m_pPool->IsItemPoolable( **ppSrc ))
209 // Just copy the pointer and increase RefCount
210 *ppDst = *ppSrc;
211 (*ppDst)->AddRef();
213 else if ( !(*ppSrc)->Which() )
214 *ppDst = (*ppSrc)->Clone();
215 else
216 // !IsPoolable() => assign via Pool
217 *ppDst = &m_pPool->Put( **ppSrc );
219 // Copy the WhichRanges
220 std::ptrdiff_t cnt = pPtr - rASet.m_pWhichRanges+1;
221 m_pWhichRanges = new sal_uInt16[ cnt ];
222 memcpy( m_pWhichRanges, rASet.m_pWhichRanges, sizeof( sal_uInt16 ) * cnt);
225 SfxItemSet::~SfxItemSet()
227 sal_uInt16 nCount = TotalCount();
228 if( Count() )
230 SfxPoolItem const** ppFnd = m_pItems.get();
231 for( sal_uInt16 nCnt = nCount; nCnt; --nCnt, ++ppFnd )
232 if( *ppFnd && !IsInvalidItem(*ppFnd) )
234 if( !(*ppFnd)->Which() )
235 delete *ppFnd;
236 else {
237 // Still multiple references present, so just alter the RefCount
238 if ( 1 < (*ppFnd)->GetRefCount() && !IsDefaultItem(*ppFnd) )
239 (*ppFnd)->ReleaseRef();
240 else
241 if ( !IsDefaultItem(*ppFnd) )
242 // Delete from Pool
243 m_pPool->Remove( **ppFnd );
248 m_pItems.reset();
249 if (m_pWhichRanges != m_pPool->GetFrozenIdRanges())
250 delete[] m_pWhichRanges;
251 m_pWhichRanges = nullptr; // for invariant-testing
255 * Delete single Items or all Items (nWhich == 0)
257 sal_uInt16 SfxItemSet::ClearItem( sal_uInt16 nWhich )
259 if( !Count() )
260 return 0;
262 sal_uInt16 nDel = 0;
263 SfxPoolItem const** ppFnd = m_pItems.get();
265 if( nWhich )
267 const sal_uInt16* pPtr = m_pWhichRanges;
268 while( *pPtr )
270 // Within this range?
271 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
273 // Actually set?
274 ppFnd += nWhich - *pPtr;
275 if( *ppFnd )
277 // Due to the assertions in the sub calls, we need to do the following
278 --m_nCount;
279 const SfxPoolItem *pItemToClear = *ppFnd;
280 *ppFnd = nullptr;
282 if ( !IsInvalidItem(pItemToClear) )
284 if (SfxItemPool::IsWhich(nWhich))
286 const SfxPoolItem& rNew = m_pParent
287 ? m_pParent->Get( nWhich )
288 : m_pPool->GetDefaultItem( nWhich );
290 Changed( *pItemToClear, rNew );
292 if ( pItemToClear->Which() )
293 m_pPool->Remove( *pItemToClear );
295 ++nDel;
298 // found => break
299 break;
301 ppFnd += *(pPtr+1) - *pPtr + 1;
302 pPtr += 2;
305 else
307 nDel = m_nCount;
309 sal_uInt16* pPtr = m_pWhichRanges;
310 while( *pPtr )
312 for( nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
313 if( *ppFnd )
315 // Due to the assertions in the sub calls, we need to do this
316 --m_nCount;
317 const SfxPoolItem *pItemToClear = *ppFnd;
318 *ppFnd = nullptr;
320 if ( !IsInvalidItem(pItemToClear) )
322 if (SfxItemPool::IsWhich(nWhich))
324 const SfxPoolItem& rNew = m_pParent
325 ? m_pParent->Get( nWhich )
326 : m_pPool->GetDefaultItem( nWhich );
328 Changed( *pItemToClear, rNew );
331 // #i32448#
332 // Take care of disabled items, too.
333 if (!pItemToClear->m_nWhich)
335 // item is disabled, delete it
336 delete pItemToClear;
338 else
340 // remove item from pool
341 m_pPool->Remove( *pItemToClear );
345 pPtr += 2;
348 return nDel;
351 void SfxItemSet::ClearInvalidItems()
353 sal_uInt16* pPtr = m_pWhichRanges;
354 SfxPoolItem const** ppFnd = m_pItems.get();
355 while( *pPtr )
357 for( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
358 if( IsInvalidItem(*ppFnd) )
360 *ppFnd = nullptr;
361 --m_nCount;
363 pPtr += 2;
367 void SfxItemSet::InvalidateAllItems()
369 assert( !m_nCount && "There are still Items set" );
370 m_nCount = TotalCount();
371 memset(static_cast<void*>(m_pItems.get()), -1, m_nCount * sizeof(SfxPoolItem*));
374 SfxItemState SfxItemSet::GetItemState( sal_uInt16 nWhich,
375 bool bSrchInParent,
376 const SfxPoolItem **ppItem ) const
378 // Find the range in which the Which is located
379 const SfxItemSet* pCurrentSet = this;
380 SfxItemState eRet = SfxItemState::UNKNOWN;
383 SfxPoolItem const** ppFnd = pCurrentSet->m_pItems.get();
384 const sal_uInt16* pPtr = pCurrentSet->m_pWhichRanges;
385 if (pPtr)
387 while ( *pPtr )
389 if ( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
391 // Within this range
392 ppFnd += nWhich - *pPtr;
393 if ( !*ppFnd )
395 eRet = SfxItemState::DEFAULT;
396 if( !bSrchInParent )
397 return eRet; // Not present
398 break; // Keep searching in the parents!
401 if ( IsInvalidItem(*ppFnd) )
402 // Different ones are present
403 return SfxItemState::DONTCARE;
405 if ( (*ppFnd)->IsVoidItem() )
406 return SfxItemState::DISABLED;
408 if (ppItem)
410 *ppItem = *ppFnd;
412 return SfxItemState::SET;
414 ppFnd += *(pPtr+1) - *pPtr + 1;
415 pPtr += 2;
418 } while (bSrchInParent && nullptr != (pCurrentSet = pCurrentSet->m_pParent));
419 return eRet;
422 bool SfxItemSet::HasItem(sal_uInt16 nWhich, const SfxPoolItem** ppItem) const
424 bool bRet = SfxItemState::SET == GetItemState(nWhich, true, ppItem);
425 if (!bRet && ppItem)
426 *ppItem = nullptr;
427 return bRet;
430 const SfxPoolItem* SfxItemSet::Put( const SfxPoolItem& rItem, sal_uInt16 nWhich )
432 if ( !nWhich )
433 return nullptr; //FIXME: Only because of Outliner bug
435 SfxPoolItem const** ppFnd = m_pItems.get();
436 const sal_uInt16* pPtr = m_pWhichRanges;
437 while( *pPtr )
439 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
441 // Within this range
442 ppFnd += nWhich - *pPtr;
443 if( *ppFnd ) // Already one present
445 // Same Item already present?
446 if ( *ppFnd == &rItem )
447 return nullptr;
449 // Will 'dontcare' or 'disabled' be overwritten with some real value?
450 if ( rItem.Which() && ( IsInvalidItem(*ppFnd) || !(*ppFnd)->Which() ) )
452 auto const old = *ppFnd;
453 *ppFnd = &m_pPool->Put( rItem, nWhich );
454 if (!IsInvalidItem(old)) {
455 assert(old->Which() == 0);
456 delete old;
458 return *ppFnd;
461 // Turns into disabled?
462 if( !rItem.Which() )
464 if (IsInvalidItem(*ppFnd) || (*ppFnd)->Which() != 0) {
465 *ppFnd = rItem.Clone(m_pPool);
467 return nullptr;
469 else
471 // Same value already present?
472 if ( rItem == **ppFnd )
473 return nullptr;
475 // Add the new one, remove the old one
476 const SfxPoolItem& rNew = m_pPool->Put( rItem, nWhich );
477 const SfxPoolItem* pOld = *ppFnd;
478 *ppFnd = &rNew;
479 if (SfxItemPool::IsWhich(nWhich))
480 Changed( *pOld, rNew );
481 m_pPool->Remove( *pOld );
484 else
486 ++m_nCount;
487 if( !rItem.Which() )
488 *ppFnd = rItem.Clone(m_pPool);
489 else {
490 const SfxPoolItem& rNew = m_pPool->Put( rItem, nWhich );
491 *ppFnd = &rNew;
492 if (SfxItemPool::IsWhich(nWhich))
494 const SfxPoolItem& rOld = m_pParent
495 ? m_pParent->Get( nWhich )
496 : m_pPool->GetDefaultItem( nWhich );
497 Changed( rOld, rNew );
501 SAL_WARN_IF(m_pPool->IsItemPoolable(nWhich) &&
502 dynamic_cast<const SfxSetItem*>( &rItem ) == nullptr &&
503 **ppFnd != rItem,
504 "svl.items", "putted Item unequal, with ID/pos " << nWhich );
505 return *ppFnd;
507 ppFnd += *(pPtr+1) - *pPtr + 1;
508 pPtr += 2;
510 return nullptr;
513 bool SfxItemSet::Put( const SfxItemSet& rSet, bool bInvalidAsDefault )
515 bool bRet = false;
516 if( rSet.Count() )
518 SfxPoolItem const** ppFnd = rSet.m_pItems.get();
519 const sal_uInt16* pPtr = rSet.m_pWhichRanges;
520 while ( *pPtr )
522 for ( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
523 if( *ppFnd )
525 if ( IsInvalidItem( *ppFnd ) )
527 if ( bInvalidAsDefault )
528 bRet |= 0 != ClearItem( nWhich );
529 // FIXME: Caused a SEGFAULT on non Windows-platforms:
530 // bRet |= 0 != Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
531 else
532 InvalidateItem( nWhich );
534 else
535 bRet |= nullptr != Put( **ppFnd, nWhich );
537 pPtr += 2;
540 return bRet;
544 * This method takes the Items from the 'rSet' and adds to '*this'.
545 * Which ranges in '*this' that are non-existent in 'rSet' will not
546 * be altered. The Which range of '*this' is also not changed.
548 * Items set in 'rSet' are also set in '*this'.
549 * Default (0 pointer) and Invalid (-1 pointer) Items are processed
550 * according to their parameter 'eDontCareAs' and 'eDefaultAs':
552 * SfxItemState::SET: Hard set to the default of the Pool
553 * SfxItemState::DEFAULT: Deleted (0 pointer)
554 * SfxItemState::DONTCARE: Invalid (-1 pointer)
556 * NB: All other values for 'eDontCareAs' and 'eDefaultAs' are invalid
558 void SfxItemSet::PutExtended
560 const SfxItemSet& rSet, // Source of the Items to be put
561 SfxItemState eDontCareAs, // What will happen to the DontCare Items
562 SfxItemState eDefaultAs // What will happen to the Default Items
565 // don't "optimize" with "if( rSet.Count()" because of dont-care + defaults
566 SfxPoolItem const** ppFnd = rSet.m_pItems.get();
567 const sal_uInt16* pPtr = rSet.m_pWhichRanges;
568 while ( *pPtr )
570 for ( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
571 if( *ppFnd )
573 if ( IsInvalidItem( *ppFnd ) )
575 // Item is DontCare:
576 switch ( eDontCareAs )
578 case SfxItemState::SET:
579 Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
580 break;
582 case SfxItemState::DEFAULT:
583 ClearItem( nWhich );
584 break;
586 case SfxItemState::DONTCARE:
587 InvalidateItem( nWhich );
588 break;
590 default:
591 assert(!"invalid Argument for eDontCareAs");
594 else
595 // Item is set:
596 Put( **ppFnd, nWhich );
598 else
600 // Item is default:
601 switch ( eDefaultAs )
603 case SfxItemState::SET:
604 Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
605 break;
607 case SfxItemState::DEFAULT:
608 ClearItem( nWhich );
609 break;
611 case SfxItemState::DONTCARE:
612 InvalidateItem( nWhich );
613 break;
615 default:
616 assert(!"invalid Argument for eDefaultAs");
619 pPtr += 2;
624 * Expands the ranges of settable items by 'nFrom' to 'nTo'. Keeps state of
625 * items which are new ranges too.
627 void SfxItemSet::MergeRange( sal_uInt16 nFrom, sal_uInt16 nTo )
629 // special case: exactly one sal_uInt16 which is already included?
630 SfxItemState eItemState = GetItemState(nFrom, false);
631 if ( nFrom == nTo && ( eItemState == SfxItemState::DEFAULT || eItemState == SfxItemState::SET ) )
632 return;
634 #ifdef DBG_UTIL
635 assert(nFrom <= nTo);
636 for (const sal_uInt16 *pRange = m_pWhichRanges; *pRange; pRange += 2)
638 assert(pRange[0] <= pRange[1]);
639 // ranges must be sorted and discrete
640 assert(
641 !pRange[2] || (pRange[2] > pRange[1] && pRange[2] - pRange[1] > 1));
643 #endif
645 // create vector of ranges (sal_uInt16 pairs of lower and upper bound)
646 const size_t nOldCount = Count_Impl(m_pWhichRanges);
647 std::vector<std::pair<sal_uInt16, sal_uInt16>> aRangesTable;
648 aRangesTable.reserve(nOldCount/2 + 1);
649 bool bAdded = false;
650 for (size_t i = 0; i < nOldCount; i += 2)
652 if (!bAdded && m_pWhichRanges[i] >= nFrom)
653 { // insert new range, keep ranges sorted
654 aRangesTable.emplace_back(std::pair<sal_uInt16, sal_uInt16>(nFrom, nTo));
655 bAdded = true;
657 // insert current range
658 aRangesTable.emplace_back(std::pair<sal_uInt16, sal_uInt16>(m_pWhichRanges[i], m_pWhichRanges[i+1]));
660 if (!bAdded)
661 aRangesTable.emplace_back(std::pair<sal_uInt16, sal_uInt16>(nFrom, nTo));
663 // true if ranges overlap or adjoin, false if ranges are separate
664 auto needMerge = [](std::pair<sal_uInt16, sal_uInt16> lhs, std::pair<sal_uInt16, sal_uInt16> rhs)
665 {return (lhs.first-1) <= rhs.second && (rhs.first-1) <= lhs.second;};
667 std::vector<std::pair<sal_uInt16, sal_uInt16> >::iterator it = aRangesTable.begin();
668 std::vector<std::pair<sal_uInt16, sal_uInt16> >::iterator itNext;
669 // we got at least one range
670 while ((itNext = std::next(it)) != aRangesTable.end())
672 // check neighbouring ranges, find first range which overlaps or adjoins a previous range
673 if (needMerge(*it, *itNext))
675 // lower bounds are sorted, implies: it->first = min(it[0].first, it[1].first)
676 it->second = std::max(it->second, itNext->second);
677 aRangesTable.erase(itNext);
679 else
680 ++it;
683 // construct range array
684 const size_t nNewSize = 2 * aRangesTable.size() + 1;
685 std::vector<sal_uInt16> aRanges(nNewSize);
686 for (size_t i = 0; i < (nNewSize - 1); i +=2)
687 std::tie(aRanges[i], aRanges[i+1]) = aRangesTable[i/2];
689 // null terminate to be compatible with sal_uInt16* array pointers
690 aRanges.back() = 0;
692 SetRanges( aRanges.data() );
696 * Modifies the ranges of settable items. Keeps state of items which
697 * are new ranges too.
699 void SfxItemSet::SetRanges( const sal_uInt16 *pNewRanges )
701 // Identical Ranges?
702 if (m_pWhichRanges == pNewRanges)
703 return;
704 const sal_uInt16* pOld = m_pWhichRanges;
705 const sal_uInt16* pNew = pNewRanges;
706 while ( *pOld == *pNew )
708 if ( !*pOld && !*pNew )
709 return;
710 ++pOld;
711 ++pNew;
714 // create new item-array (by iterating through all new ranges)
715 sal_uInt16 nSize = Capacity_Impl(pNewRanges);
716 SfxPoolItem const** aNewItems = new const SfxPoolItem* [ nSize ];
717 sal_uInt16 nNewCount = 0;
718 if (m_nCount == 0)
719 memset( aNewItems, 0, nSize * sizeof( SfxPoolItem* ) );
720 else
722 sal_uInt16 n = 0;
723 for ( const sal_uInt16 *pRange = pNewRanges; *pRange; pRange += 2 )
725 // iterate through all ids in the range
726 for ( sal_uInt16 nWID = *pRange; nWID <= pRange[1]; ++nWID, ++n )
728 // direct move of pointer (not via pool)
729 SfxItemState eState = GetItemState( nWID, false, aNewItems+n );
730 if ( SfxItemState::SET == eState )
732 // increment new item count and possibly increment ref count
733 ++nNewCount;
734 aNewItems[n]->AddRef();
736 else if ( SfxItemState::DISABLED == eState )
738 // put "disabled" item
739 ++nNewCount;
740 aNewItems[n] = new SfxVoidItem(0);
742 else if ( SfxItemState::DONTCARE == eState )
744 ++nNewCount;
745 aNewItems[n] = INVALID_POOL_ITEM;
747 else
749 // default
750 aNewItems[n] = nullptr;
754 // free old items
755 sal_uInt16 nOldTotalCount = TotalCount();
756 for ( sal_uInt16 nItem = 0; nItem < nOldTotalCount; ++nItem )
758 const SfxPoolItem *pItem = m_pItems[nItem];
759 if ( pItem && !IsInvalidItem(pItem) && pItem->Which() )
760 m_pPool->Remove(*pItem);
764 // replace old items-array and ranges
765 m_pItems.reset( aNewItems );
766 m_nCount = nNewCount;
768 if( pNewRanges == GetPool()->GetFrozenIdRanges() )
770 delete[] m_pWhichRanges;
771 m_pWhichRanges = const_cast<sal_uInt16*>(pNewRanges);
773 else
775 sal_uInt16 nCount = Count_Impl(pNewRanges) + 1;
776 if (m_pWhichRanges != m_pPool->GetFrozenIdRanges())
777 delete[] m_pWhichRanges;
778 m_pWhichRanges = new sal_uInt16[ nCount ];
779 memcpy( m_pWhichRanges, pNewRanges, sizeof( sal_uInt16 ) * nCount );
784 * The SfxItemSet takes over exactly those SfxPoolItems that are
785 * set in rSet and are in their own Which range. All others are removed.
786 * The SfxItemPool is retained, such that SfxPoolItems that have been
787 * taken over, are moved from the rSet's SfxItemPool to the SfxItemPool
788 * of *this.
790 * SfxPoolItems in rSet, for which holds 'IsInvalidItem() == true' are
791 * taken over as invalid items.
793 * @return bool true
794 * SfxPoolItems have been taken over
796 * false
797 * No SfxPoolItems have been taken over, because
798 * e.g. the Which ranges of SfxItemSets are not intersecting
799 * or the intersection does not contain SfxPoolItems that are
800 * set in rSet
802 bool SfxItemSet::Set
804 const SfxItemSet& rSet, /* The SfxItemSet, whose SfxPoolItems are
805 to been taken over */
807 bool bDeep /* true (default)
809 The SfxPoolItems from the parents that may
810 be present in rSet, are also taken over into
811 this SfxPoolItemSet
813 false
814 The SfxPoolItems from the parents of
815 rSet are not taken into account */
818 bool bRet = false;
819 if (m_nCount)
820 ClearItem();
821 if ( bDeep )
823 SfxWhichIter aIter(*this);
824 sal_uInt16 nWhich = aIter.FirstWhich();
825 while ( nWhich )
827 const SfxPoolItem* pItem;
828 if( SfxItemState::SET == rSet.GetItemState( nWhich, true, &pItem ) )
829 bRet |= nullptr != Put( *pItem, pItem->Which() );
830 nWhich = aIter.NextWhich();
833 else
834 bRet = Put(rSet, false);
836 return bRet;
839 const SfxPoolItem* SfxItemSet::GetItem(sal_uInt16 nId, bool bSearchInParent) const
841 // Convert to WhichId
842 sal_uInt16 nWhich = GetPool()->GetWhich(nId);
844 // Is the Item set or 'bDeep == true' available?
845 const SfxPoolItem *pItem = nullptr;
846 SfxItemState eState = GetItemState(nWhich, bSearchInParent, &pItem);
847 if (bSearchInParent && SfxItemState::DEFAULT == eState && SfxItemPool::IsWhich(nWhich))
849 pItem = &m_pPool->GetDefaultItem(nWhich);
852 return pItem;
855 const SfxPoolItem& SfxItemSet::Get( sal_uInt16 nWhich, bool bSrchInParent) const
857 // Search the Range in which the Which is located in:
858 const SfxItemSet* pCurrentSet = this;
861 if( pCurrentSet->Count() )
863 SfxPoolItem const** ppFnd = pCurrentSet->m_pItems.get();
864 const sal_uInt16* pPtr = pCurrentSet->m_pWhichRanges;
865 while( *pPtr )
867 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
869 // In this Range
870 ppFnd += nWhich - *pPtr;
871 if( *ppFnd )
873 if( IsInvalidItem(*ppFnd) ) {
874 //FIXME: The following code is duplicated further down
875 SAL_WARN_IF(!m_pPool, "svl.items", "no Pool, but status is ambiguous, with ID/pos " << nWhich);
876 //!((SfxAllItemSet *)this)->aDefault.SetWhich(nWhich);
877 //!return aDefault;
878 return m_pPool->GetDefaultItem( nWhich );
880 #ifdef DBG_UTIL
881 const SfxPoolItem *pItem = *ppFnd;
882 if ( pItem->IsVoidItem() || !pItem->Which() )
883 SAL_INFO("svl.items", "SFX_WARNING: Getting disabled Item");
884 #endif
885 return **ppFnd;
887 break; // Continue with Parent
889 ppFnd += *(pPtr+1) - *pPtr + 1;
890 pPtr += 2;
893 //TODO: Search until end of Range: What are we supposed to do now? To the Parent or Default??
894 // if( !*pPtr ) // Until the end of the search Range?
895 // break;
896 } while (bSrchInParent && nullptr != (pCurrentSet = pCurrentSet->m_pParent));
898 // Get the Default from the Pool and return
899 SAL_WARN_IF(!m_pPool, "svl.items", "no Pool, but status is ambiguous, with ID/pos " << nWhich);
900 const SfxPoolItem *pItem = &m_pPool->GetDefaultItem( nWhich );
901 return *pItem;
905 * Notification callback
907 void SfxItemSet::Changed( const SfxPoolItem&, const SfxPoolItem& )
911 sal_uInt16 SfxItemSet::TotalCount() const
913 sal_uInt16 nRet = 0;
914 sal_uInt16* pPtr = m_pWhichRanges;
915 while( *pPtr )
917 nRet += ( *(pPtr+1) - *pPtr ) + 1;
918 pPtr += 2;
920 return nRet;
924 * Only retain the Items that are also present in rSet
925 * (nevermind their value).
927 void SfxItemSet::Intersect( const SfxItemSet& rSet )
929 assert(m_pPool && "Not implemented without Pool");
930 if( !Count() ) // None set?
931 return;
933 // Delete all Items not contained in rSet
934 if( !rSet.Count() )
936 ClearItem(); // Delete everything
937 return;
940 // Test whether the Which Ranges are different
941 sal_uInt16* pWh1 = m_pWhichRanges;
942 sal_uInt16* pWh2 = rSet.m_pWhichRanges;
943 sal_uInt16 nSize = 0;
945 for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
947 if( *pWh1 != *pWh2 )
949 break;
951 if( n & 1 )
952 nSize += ( *pWh1 - *(pWh1-1) ) + 1;
954 bool bEqual = *pWh1 == *pWh2; // Also check for 0
956 // If the Ranges are identical, we can easily process it
957 if( bEqual )
959 SfxPoolItem const** ppFnd1 = m_pItems.get();
960 SfxPoolItem const** ppFnd2 = rSet.m_pItems.get();
962 for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
963 if( *ppFnd1 && !*ppFnd2 )
965 // Delete from Pool
966 if( !IsInvalidItem( *ppFnd1 ) )
968 sal_uInt16 nWhich = (*ppFnd1)->Which();
969 if (SfxItemPool::IsWhich(nWhich))
971 const SfxPoolItem& rNew = m_pParent
972 ? m_pParent->Get( nWhich )
973 : m_pPool->GetDefaultItem( nWhich );
975 Changed( **ppFnd1, rNew );
977 m_pPool->Remove( **ppFnd1 );
979 *ppFnd1 = nullptr;
980 --m_nCount;
983 else
985 SfxItemIter aIter( *this );
986 const SfxPoolItem* pItem = aIter.GetCurItem();
987 while( true )
989 sal_uInt16 nWhich = IsInvalidItem( pItem )
990 ? GetWhichByPos( aIter.GetCurPos() )
991 : pItem->Which();
992 if( SfxItemState::UNKNOWN == rSet.GetItemState( nWhich, false ) )
993 ClearItem( nWhich ); // Delete
994 if( aIter.IsAtEnd() )
995 break;
996 pItem = aIter.NextItem();
1001 void SfxItemSet::Differentiate( const SfxItemSet& rSet )
1003 if( !Count() || !rSet.Count() )// None set?
1004 return;
1006 // Test whether the Which Ranges are different
1007 sal_uInt16* pWh1 = m_pWhichRanges;
1008 sal_uInt16* pWh2 = rSet.m_pWhichRanges;
1009 sal_uInt16 nSize = 0;
1011 for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
1013 if( *pWh1 != *pWh2 )
1015 break;
1017 if( n & 1 )
1018 nSize += ( *pWh1 - *(pWh1-1) ) + 1;
1020 bool bEqual = *pWh1 == *pWh2; // Also test for 0
1022 // If the Ranges are identical, we can easily process it
1023 if( bEqual )
1025 SfxPoolItem const** ppFnd1 = m_pItems.get();
1026 SfxPoolItem const** ppFnd2 = rSet.m_pItems.get();
1028 for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
1029 if( *ppFnd1 && *ppFnd2 )
1031 // Delete from Pool
1032 if( !IsInvalidItem( *ppFnd1 ) )
1034 sal_uInt16 nWhich = (*ppFnd1)->Which();
1035 if (SfxItemPool::IsWhich(nWhich))
1037 const SfxPoolItem& rNew = m_pParent
1038 ? m_pParent->Get( nWhich )
1039 : m_pPool->GetDefaultItem( nWhich );
1041 Changed( **ppFnd1, rNew );
1043 m_pPool->Remove( **ppFnd1 );
1045 *ppFnd1 = nullptr;
1046 --m_nCount;
1049 else
1051 SfxItemIter aIter( *this );
1052 const SfxPoolItem* pItem = aIter.GetCurItem();
1053 while( true )
1055 sal_uInt16 nWhich = IsInvalidItem( pItem )
1056 ? GetWhichByPos( aIter.GetCurPos() )
1057 : pItem->Which();
1058 if( SfxItemState::SET == rSet.GetItemState( nWhich, false ) )
1059 ClearItem( nWhich ); // Delete
1060 if( aIter.IsAtEnd() )
1061 break;
1062 pItem = aIter.NextItem();
1069 * Decision table for MergeValue(s)
1071 * Principles:
1072 * 1. If the Which value in the 1st set is "unknown", there's never any action
1073 * 2. If the Which value in the 2nd set is "unknown", it's made the "default"
1074 * 3. For comparisons the values of the "default" Items are take into account
1076 * 1st Item 2nd Item Values bIgnoreDefs Remove Assign Add
1078 * set set == sal_False - - -
1079 * default set == sal_False - - -
1080 * dontcare set == sal_False - - -
1081 * unknown set == sal_False - - -
1082 * set default == sal_False - - -
1083 * default default == sal_False - - -
1084 * dontcare default == sal_False - - -
1085 * unknown default == sal_False - - -
1086 * set dontcare == sal_False 1st Item -1 -
1087 * default dontcare == sal_False - -1 -
1088 * dontcare dontcare == sal_False - - -
1089 * unknown dontcare == sal_False - - -
1090 * set unknown == sal_False 1st Item -1 -
1091 * default unknown == sal_False - - -
1092 * dontcare unknown == sal_False - - -
1093 * unknown unknown == sal_False - - -
1095 * set set != sal_False 1st Item -1 -
1096 * default set != sal_False - -1 -
1097 * dontcare set != sal_False - - -
1098 * unknown set != sal_False - - -
1099 * set default != sal_False 1st Item -1 -
1100 * default default != sal_False - - -
1101 * dontcare default != sal_False - - -
1102 * unknown default != sal_False - - -
1103 * set dontcare != sal_False 1st Item -1 -
1104 * default dontcare != sal_False - -1 -
1105 * dontcare dontcare != sal_False - - -
1106 * unknown dontcare != sal_False - - -
1107 * set unknown != sal_False 1st Item -1 -
1108 * default unknown != sal_False - - -
1109 * dontcare unknown != sal_False - - -
1110 * unknown unknown != sal_False - - -
1112 * set set == sal_True - - -
1113 * default set == sal_True - 2nd Item 2nd Item
1114 * dontcare set == sal_True - - -
1115 * unknown set == sal_True - - -
1116 * set default == sal_True - - -
1117 * default default == sal_True - - -
1118 * dontcare default == sal_True - - -
1119 * unknown default == sal_True - - -
1120 * set dontcare == sal_True - - -
1121 * default dontcare == sal_True - -1 -
1122 * dontcare dontcare == sal_True - - -
1123 * unknown dontcare == sal_True - - -
1124 * set unknown == sal_True - - -
1125 * default unknown == sal_True - - -
1126 * dontcare unknown == sal_True - - -
1127 * unknown unknown == sal_True - - -
1129 * set set != sal_True 1st Item -1 -
1130 * default set != sal_True - 2nd Item 2nd Item
1131 * dontcare set != sal_True - - -
1132 * unknown set != sal_True - - -
1133 * set default != sal_True - - -
1134 * default default != sal_True - - -
1135 * dontcare default != sal_True - - -
1136 * unknown default != sal_True - - -
1137 * set dontcare != sal_True 1st Item -1 -
1138 * default dontcare != sal_True - -1 -
1139 * dontcare dontcare != sal_True - - -
1140 * unknown dontcare != sal_True - - -
1141 * set unknown != sal_True - - -
1142 * default unknown != sal_True - - -
1143 * dontcare unknown != sal_True - - -
1144 * unknown unknown != sal_True - - -
1146 static void MergeItem_Impl( SfxItemPool *_pPool, sal_uInt16 &rCount,
1147 const SfxPoolItem **ppFnd1, const SfxPoolItem *pFnd2,
1148 bool bIgnoreDefaults )
1150 assert(ppFnd1 != nullptr && "Merging to 0-Item");
1152 // 1st Item is Default?
1153 if ( !*ppFnd1 )
1155 if ( IsInvalidItem(pFnd2) )
1156 // Decision table: default, dontcare, doesn't matter, doesn't matter
1157 *ppFnd1 = INVALID_POOL_ITEM;
1159 else if ( pFnd2 && !bIgnoreDefaults &&
1160 _pPool->GetDefaultItem(pFnd2->Which()) != *pFnd2 )
1161 // Decision table: default, set, !=, sal_False
1162 *ppFnd1 = INVALID_POOL_ITEM;
1164 else if ( pFnd2 && bIgnoreDefaults )
1165 // Decision table: default, set, doesn't matter, sal_True
1166 *ppFnd1 = &_pPool->Put( *pFnd2 );
1168 if ( *ppFnd1 )
1169 ++rCount;
1172 // 1st Item set?
1173 else if ( !IsInvalidItem(*ppFnd1) )
1175 if ( !pFnd2 )
1177 // 2nd Item is Default
1178 if ( !bIgnoreDefaults &&
1179 **ppFnd1 != _pPool->GetDefaultItem((*ppFnd1)->Which()) )
1181 // Decision table: set, default, !=, sal_False
1182 _pPool->Remove( **ppFnd1 );
1183 *ppFnd1 = INVALID_POOL_ITEM;
1186 else if ( IsInvalidItem(pFnd2) )
1188 // 2nd Item is dontcare
1189 if ( !bIgnoreDefaults ||
1190 **ppFnd1 != _pPool->GetDefaultItem( (*ppFnd1)->Which()) )
1192 // Decision table: set, dontcare, doesn't matter, sal_False
1193 // or: set, dontcare, !=, sal_True
1194 _pPool->Remove( **ppFnd1 );
1195 *ppFnd1 = INVALID_POOL_ITEM;
1198 else
1200 // 2nd Item is set
1201 if ( **ppFnd1 != *pFnd2 )
1203 // Decision table: set, set, !=, doesn't matter
1204 _pPool->Remove( **ppFnd1 );
1205 *ppFnd1 = INVALID_POOL_ITEM;
1211 void SfxItemSet::MergeValues( const SfxItemSet& rSet )
1213 // WARNING! When making changes/fixing bugs, always update the table above!!
1214 assert( GetPool() == rSet.GetPool() && "MergeValues with different Pools" );
1216 // Test if the which Ranges are different
1217 sal_uInt16* pWh1 = m_pWhichRanges;
1218 sal_uInt16* pWh2 = rSet.m_pWhichRanges;
1219 sal_uInt16 nSize = 0;
1221 for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
1223 if( *pWh1 != *pWh2 )
1225 break;
1227 if( n & 1 )
1228 nSize += ( *pWh1 - *(pWh1-1) ) + 1;
1230 bool bEqual = *pWh1 == *pWh2; // Also check for 0
1232 // If the Ranges match, they are easier to process!
1233 if( bEqual )
1235 SfxPoolItem const** ppFnd1 = m_pItems.get();
1236 SfxPoolItem const** ppFnd2 = rSet.m_pItems.get();
1238 for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
1239 MergeItem_Impl(m_pPool, m_nCount, ppFnd1, *ppFnd2, false/*bIgnoreDefaults*/);
1241 else
1243 SfxWhichIter aIter( rSet );
1244 sal_uInt16 nWhich;
1245 while( 0 != ( nWhich = aIter.NextWhich() ) )
1247 const SfxPoolItem* pItem = nullptr;
1248 (void)rSet.GetItemState( nWhich, true, &pItem );
1249 if( !pItem )
1251 // Not set, so default
1252 MergeValue( rSet.GetPool()->GetDefaultItem( nWhich ) );
1254 else if( IsInvalidItem( pItem ) )
1255 // don't care
1256 InvalidateItem( nWhich );
1257 else
1258 MergeValue( *pItem );
1263 void SfxItemSet::MergeValue( const SfxPoolItem& rAttr, bool bIgnoreDefaults )
1265 SfxPoolItem const** ppFnd = m_pItems.get();
1266 const sal_uInt16* pPtr = m_pWhichRanges;
1267 const sal_uInt16 nWhich = rAttr.Which();
1268 while( *pPtr )
1270 // In this Range??
1271 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1273 ppFnd += nWhich - *pPtr;
1274 MergeItem_Impl(m_pPool, m_nCount, ppFnd, &rAttr, bIgnoreDefaults);
1275 break;
1277 ppFnd += *(pPtr+1) - *pPtr + 1;
1278 pPtr += 2;
1282 void SfxItemSet::InvalidateItem( sal_uInt16 nWhich )
1284 SfxPoolItem const** ppFnd = m_pItems.get();
1285 const sal_uInt16* pPtr = m_pWhichRanges;
1286 while( *pPtr )
1288 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1290 // In this Range?
1291 ppFnd += nWhich - *pPtr;
1293 if( *ppFnd ) // Set for me
1295 if( !IsInvalidItem(*ppFnd) )
1297 m_pPool->Remove( **ppFnd );
1298 *ppFnd = INVALID_POOL_ITEM;
1301 else
1303 *ppFnd = INVALID_POOL_ITEM;
1304 ++m_nCount;
1306 break;
1308 ppFnd += *(pPtr+1) - *pPtr + 1;
1309 pPtr += 2;
1313 sal_uInt16 SfxItemSet::GetWhichByPos( sal_uInt16 nPos ) const
1315 sal_uInt16 n = 0;
1316 sal_uInt16* pPtr = m_pWhichRanges;
1317 while( *pPtr )
1319 n = ( *(pPtr+1) - *pPtr ) + 1;
1320 if( nPos < n )
1321 return *pPtr + nPos;
1322 nPos = nPos - n;
1323 pPtr += 2;
1325 assert(false);
1326 return 0;
1329 bool SfxItemSet::operator==(const SfxItemSet &rCmp) const
1331 return Equals( rCmp, true);
1334 bool SfxItemSet::Equals(const SfxItemSet &rCmp, bool bComparePool) const
1336 // Values we can get quickly need to be the same
1337 const bool bDifferentPools = (m_pPool != rCmp.m_pPool);
1338 if ( (bComparePool && m_pParent != rCmp.m_pParent) ||
1339 (bComparePool && bDifferentPools) ||
1340 Count() != rCmp.Count() )
1341 return false;
1343 // If we reach here and bDifferentPools==true that means bComparePool==false.
1345 // Counting Ranges takes longer; they also need to be the same, however
1346 sal_uInt16 nCount1 = TotalCount();
1347 sal_uInt16 nCount2 = rCmp.TotalCount();
1348 if ( nCount1 != nCount2 )
1349 return false;
1351 // Are the Ranges themselves unequal?
1352 for (sal_uInt16 nRange = 0; m_pWhichRanges[nRange]; nRange += 2)
1354 if (m_pWhichRanges[nRange] != rCmp.m_pWhichRanges[nRange] ||
1355 m_pWhichRanges[nRange+1] != rCmp.m_pWhichRanges[nRange+1])
1357 // We must use the slow method then
1358 SfxWhichIter aIter( *this );
1359 for ( sal_uInt16 nWh = aIter.FirstWhich();
1360 nWh;
1361 nWh = aIter.NextWhich() )
1363 // If the pointer of the poolable Items are unequal, the Items must match
1364 const SfxPoolItem *pItem1 = nullptr, *pItem2 = nullptr;
1365 if ( GetItemState( nWh, false, &pItem1 ) !=
1366 rCmp.GetItemState( nWh, false, &pItem2 ) ||
1367 ( pItem1 != pItem2 &&
1368 ( !pItem1 || IsInvalidItem(pItem1) ||
1369 (m_pPool->IsItemPoolable(*pItem1) &&
1370 *pItem1 != *pItem2 ) ) ) )
1371 return false;
1374 return true;
1378 // Are all pointers the same?
1379 if (0 == memcmp( m_pItems.get(), rCmp.m_pItems.get(), nCount1 * sizeof(m_pItems[0]) ))
1380 return true;
1382 // We need to compare each one separately then
1383 const SfxPoolItem **ppItem1 = m_pItems.get();
1384 const SfxPoolItem **ppItem2 = rCmp.m_pItems.get();
1385 for ( sal_uInt16 nPos = 0; nPos < nCount1; ++nPos )
1387 // If the pointers of the poolable Items are not the same, the Items
1388 // must match
1389 if ( *ppItem1 != *ppItem2 &&
1390 ( ( !*ppItem1 || !*ppItem2 ) ||
1391 ( IsInvalidItem(*ppItem1) || IsInvalidItem(*ppItem2) ) ||
1392 (!bDifferentPools && m_pPool->IsItemPoolable(**ppItem1)) ||
1393 **ppItem1 != **ppItem2 ) )
1394 return false;
1396 ++ppItem1;
1397 ++ppItem2;
1400 return true;
1403 std::unique_ptr<SfxItemSet> SfxItemSet::Clone(bool bItems, SfxItemPool *pToPool ) const
1405 if (pToPool && pToPool != m_pPool)
1407 std::unique_ptr<SfxItemSet> pNewSet(new SfxItemSet(*pToPool, m_pWhichRanges));
1408 if ( bItems )
1410 SfxWhichIter aIter(*pNewSet);
1411 sal_uInt16 nWhich = aIter.FirstWhich();
1412 while ( nWhich )
1414 const SfxPoolItem* pItem;
1415 if ( SfxItemState::SET == GetItemState( nWhich, false, &pItem ) )
1416 pNewSet->Put( *pItem, pItem->Which() );
1417 nWhich = aIter.NextWhich();
1420 return pNewSet;
1422 else
1423 return std::unique_ptr<SfxItemSet>(bItems
1424 ? new SfxItemSet(*this)
1425 : new SfxItemSet(*m_pPool, m_pWhichRanges));
1428 void SfxItemSet::PutDirect(const SfxPoolItem &rItem)
1430 SfxPoolItem const** ppFnd = m_pItems.get();
1431 const sal_uInt16* pPtr = m_pWhichRanges;
1432 const sal_uInt16 nWhich = rItem.Which();
1433 #ifdef DBG_UTIL
1434 IsPoolDefaultItem(&rItem) || m_pPool->CheckItemInPool(&rItem);
1435 // Only cause assertion in the callees
1436 #endif
1437 while( *pPtr )
1439 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1441 // In this Range?
1442 ppFnd += nWhich - *pPtr;
1443 const SfxPoolItem* pOld = *ppFnd;
1444 if( pOld ) // One already present
1446 if( rItem == **ppFnd )
1447 return; // Already present!
1448 m_pPool->Remove( *pOld );
1450 else
1451 ++m_nCount;
1453 // Add the new one
1454 if( IsPoolDefaultItem(&rItem) )
1455 *ppFnd = &m_pPool->Put( rItem );
1456 else
1458 *ppFnd = &rItem;
1459 if( !IsStaticDefaultItem( &rItem ) )
1460 rItem.AddRef();
1463 return;
1465 ppFnd += *(pPtr+1) - *pPtr + 1;
1466 pPtr += 2;
1470 void SfxItemSet::dumpAsXml(xmlTextWriterPtr pWriter) const
1472 xmlTextWriterStartElement(pWriter, BAD_CAST("SfxItemSet"));
1473 SfxItemIter aIter(*this);
1474 for (const SfxPoolItem* pItem = aIter.FirstItem(); pItem; pItem = aIter.NextItem())
1475 pItem->dumpAsXml(pWriter);
1476 xmlTextWriterEndElement(pWriter);
1480 // ----------------------------------------------- class SfxAllItemSet
1482 SfxAllItemSet::SfxAllItemSet( SfxItemPool &rPool )
1483 : SfxItemSet(rPool, nullptr),
1484 nFree(nInitCount)
1486 // Initially no Items
1487 m_pItems = nullptr;
1489 // Allocate nInitCount pairs at USHORTs for Ranges
1490 m_pWhichRanges = new sal_uInt16[nInitCount + 1]{};
1493 SfxAllItemSet::SfxAllItemSet(const SfxItemSet &rCopy)
1494 : SfxItemSet(rCopy),
1495 nFree(0)
1500 * Explicitly define this ctor to avoid auto-generation by the compiler.
1501 * The compiler does not take the ctor with the 'const SfxItemSet&'!
1503 SfxAllItemSet::SfxAllItemSet(const SfxAllItemSet &rCopy)
1504 : SfxItemSet(rCopy),
1505 nFree(0)
1510 * This internal function creates a new WhichRanges array, which is copied
1511 * from the 'nOldSize'-USHORTs long 'pUS'. It has new USHORTs at the end instead
1512 * of 'nIncr'.
1513 * The terminating sal_uInt16 with the '0' is neither accounted for in 'nOldSize'
1514 * nor in 'nIncr', but always explicitly added.
1516 * @returns the new WhichRanges array (the old 'pUS' is freed)
1518 static sal_uInt16 *AddRanges_Impl(
1519 sal_uInt16 *pUS, std::ptrdiff_t nOldSize, sal_uInt16 nIncr)
1521 // Create new WhichRanges array
1522 sal_uInt16 *pNew = new sal_uInt16[ nOldSize + nIncr + 1 ];
1524 // Take over the old Ranges
1525 memcpy( pNew, pUS, nOldSize * sizeof(sal_uInt16) );
1527 // Initialize the new one to 0
1528 memset( pNew + nOldSize, 0, ( nIncr + 1 ) * sizeof(sal_uInt16) );
1530 // Free the old array
1531 delete[] pUS;
1533 return pNew;
1537 * This internal function creates a new ItemArray, which is copied from 'pItems',
1538 * but has room for a new ItemPointer at 'nPos'.
1540 * @returns the new ItemArray (the old 'pItems' is freed)
1542 static void AddItem_Impl(std::unique_ptr<SfxPoolItem const*[]> & rpItems, sal_uInt16 nOldSize, sal_uInt16 nPos)
1544 // Create new ItemArray
1545 SfxPoolItem const** pNew = new const SfxPoolItem*[nOldSize+1];
1547 // Was there one before?
1548 if ( rpItems )
1550 // Copy all Items before nPos
1551 if ( nPos )
1552 memcpy( static_cast<void*>(pNew), rpItems.get(), nPos * sizeof(SfxPoolItem *) );
1554 // Copy all Items after nPos
1555 if ( nPos < nOldSize )
1556 memcpy( static_cast<void*>(pNew + nPos + 1), rpItems.get() + nPos,
1557 (nOldSize-nPos) * sizeof(SfxPoolItem *) );
1560 // Initialize new Item
1561 *(pNew + nPos) = nullptr;
1563 rpItems.reset(pNew);
1567 * Putting with automatic extension of the WhichId with the ID of the Item.
1569 const SfxPoolItem* SfxAllItemSet::Put( const SfxPoolItem& rItem, sal_uInt16 nWhich )
1571 sal_uInt16 nPos = 0; // Position for 'rItem' in 'm_pItems'
1572 const sal_uInt16 nItemCount = TotalCount();
1574 // Let's see first whether there's a suitable Range already
1575 sal_uInt16 *pPtr = m_pWhichRanges;
1576 while ( *pPtr )
1578 // WhichId is within this Range?
1579 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1581 // Insert
1582 nPos += nWhich - *pPtr;
1583 break;
1586 // Carry over the position of the Item in m_pItems
1587 nPos += *(pPtr+1) - *pPtr + 1;
1589 // To the next Range
1590 pPtr += 2;
1593 // WhichId not yet present?
1594 if ( !*pPtr )
1596 // Let's see if we can attach it somewhere
1597 pPtr = m_pWhichRanges;
1598 nPos = 0;
1599 while ( *pPtr )
1601 // WhichId is right before this Range?
1602 if ( (nWhich+1) == *pPtr )
1604 // Range grows downwards
1605 (*pPtr)--;
1607 // Make room before first Item of this Range
1608 AddItem_Impl(m_pItems, nItemCount, nPos);
1609 break;
1612 // WhichId is right after this Range?
1613 else if ( (nWhich-1) == *(pPtr+1) )
1615 // Range grows upwards?
1616 (*(pPtr+1))++;
1618 // Make room after last Item of this Range
1619 nPos += nWhich - *pPtr;
1620 AddItem_Impl(m_pItems, nItemCount, nPos);
1621 break;
1624 // Carry over position of the Item in m_pItems
1625 nPos += *(pPtr+1) - *pPtr + 1;
1627 // To the next Range
1628 pPtr += 2;
1632 // No extensible Range found?
1633 if ( !*pPtr )
1635 // No room left in m_pWhichRanges? => Expand!
1636 std::ptrdiff_t nSize = pPtr - m_pWhichRanges;
1637 if( !nFree )
1639 m_pWhichRanges = AddRanges_Impl(m_pWhichRanges, nSize, nInitCount);
1640 nFree += nInitCount;
1643 // Attach new WhichRange
1644 pPtr = m_pWhichRanges + nSize;
1645 *pPtr++ = nWhich;
1646 *pPtr = nWhich;
1647 nFree -= 2;
1649 // Expand ItemArray
1650 nPos = nItemCount;
1651 AddItem_Impl(m_pItems, nItemCount, nPos);
1654 // Add new Item to Pool
1655 const SfxPoolItem& rNew = m_pPool->Put( rItem, nWhich );
1657 // Remember old Item
1658 bool bIncrementCount = false;
1659 const SfxPoolItem* pOld = m_pItems[nPos];
1660 if ( IsInvalidItem(pOld) ) // state "dontcare"
1661 pOld = nullptr;
1662 if ( !pOld )
1664 bIncrementCount = true;
1665 pOld = (m_pParent)
1666 ? &m_pParent->Get( nWhich )
1667 : (SfxItemPool::IsWhich(nWhich)
1668 ? &m_pPool->GetDefaultItem(nWhich)
1669 : nullptr);
1672 // Add new Item to ItemSet
1673 m_pItems[nPos] = &rNew;
1675 // Send Changed Notification
1676 if ( pOld )
1678 Changed( *pOld, rNew );
1679 if ( !IsDefaultItem(pOld) )
1680 m_pPool->Remove( *pOld );
1683 if ( bIncrementCount )
1684 ++m_nCount;
1686 return &rNew;
1690 * Disable Item
1691 * Using a VoidItem with Which value 0
1693 void SfxItemSet::DisableItem(sal_uInt16 nWhich)
1695 Put( SfxVoidItem(0), nWhich );
1698 std::unique_ptr<SfxItemSet> SfxAllItemSet::Clone(bool bItems, SfxItemPool *pToPool ) const
1700 if (pToPool && pToPool != m_pPool)
1702 std::unique_ptr<SfxAllItemSet> pNewSet(new SfxAllItemSet( *pToPool ));
1703 if ( bItems )
1704 pNewSet->Set( *this );
1705 return std::unique_ptr<SfxItemSet>(pNewSet.release()); // clang3.8 does not seem to be able to upcast std::unique_ptr
1707 else
1708 return std::unique_ptr<SfxItemSet>(bItems ? new SfxAllItemSet(*this) : new SfxAllItemSet(*m_pPool));
1711 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */