bump product version to 6.3.0.0.beta1
[LibreOffice.git] / svl / source / items / itemset.cxx
blobbed2259d40ea25cb573c48b90867c256ae8e0a55
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( SfxItemSet&& rASet )
226 : m_pPool( rASet.m_pPool )
227 , m_pParent( rASet.m_pParent )
228 , m_pItems( std::move(rASet.m_pItems) )
229 , m_pWhichRanges( rASet.m_pWhichRanges )
230 , m_nCount( rASet.m_nCount )
232 rASet.m_pPool = nullptr;
233 rASet.m_pParent = nullptr;
234 rASet.m_pWhichRanges = nullptr;
235 rASet.m_nCount = 0;
238 SfxItemSet::~SfxItemSet()
240 if (m_pWhichRanges) // might be nullptr if we have been moved-from
242 sal_uInt16 nCount = TotalCount();
243 if( Count() )
245 SfxPoolItem const** ppFnd = m_pItems.get();
246 for( sal_uInt16 nCnt = nCount; nCnt; --nCnt, ++ppFnd )
247 if( *ppFnd && !IsInvalidItem(*ppFnd) )
249 if( !(*ppFnd)->Which() )
250 delete *ppFnd;
251 else {
252 // Still multiple references present, so just alter the RefCount
253 if ( 1 < (*ppFnd)->GetRefCount() && !IsDefaultItem(*ppFnd) )
254 (*ppFnd)->ReleaseRef();
255 else
256 if ( !IsDefaultItem(*ppFnd) )
257 // Delete from Pool
258 m_pPool->Remove( **ppFnd );
264 m_pItems.reset();
265 if (m_pPool && m_pWhichRanges != m_pPool->GetFrozenIdRanges())
266 delete[] m_pWhichRanges;
267 m_pWhichRanges = nullptr; // for invariant-testing
271 * Delete single Items or all Items (nWhich == 0)
273 sal_uInt16 SfxItemSet::ClearItem( sal_uInt16 nWhich )
275 if( !Count() )
276 return 0;
278 sal_uInt16 nDel = 0;
279 SfxPoolItem const** ppFnd = m_pItems.get();
281 if( nWhich )
283 const sal_uInt16* pPtr = m_pWhichRanges;
284 while( *pPtr )
286 // Within this range?
287 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
289 // Actually set?
290 ppFnd += nWhich - *pPtr;
291 if( *ppFnd )
293 // Due to the assertions in the sub calls, we need to do the following
294 --m_nCount;
295 const SfxPoolItem *pItemToClear = *ppFnd;
296 *ppFnd = nullptr;
298 if ( !IsInvalidItem(pItemToClear) )
300 if (SfxItemPool::IsWhich(nWhich))
302 const SfxPoolItem& rNew = m_pParent
303 ? m_pParent->Get( nWhich )
304 : m_pPool->GetDefaultItem( nWhich );
306 Changed( *pItemToClear, rNew );
308 if ( pItemToClear->Which() )
309 m_pPool->Remove( *pItemToClear );
311 ++nDel;
314 // found => break
315 break;
317 ppFnd += *(pPtr+1) - *pPtr + 1;
318 pPtr += 2;
321 else
323 nDel = m_nCount;
325 sal_uInt16* pPtr = m_pWhichRanges;
326 while( *pPtr )
328 for( nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
329 if( *ppFnd )
331 // Due to the assertions in the sub calls, we need to do this
332 --m_nCount;
333 const SfxPoolItem *pItemToClear = *ppFnd;
334 *ppFnd = nullptr;
336 if ( !IsInvalidItem(pItemToClear) )
338 if (SfxItemPool::IsWhich(nWhich))
340 const SfxPoolItem& rNew = m_pParent
341 ? m_pParent->Get( nWhich )
342 : m_pPool->GetDefaultItem( nWhich );
344 Changed( *pItemToClear, rNew );
347 // #i32448#
348 // Take care of disabled items, too.
349 if (!pItemToClear->m_nWhich)
351 // item is disabled, delete it
352 delete pItemToClear;
354 else
356 // remove item from pool
357 m_pPool->Remove( *pItemToClear );
361 pPtr += 2;
364 return nDel;
367 void SfxItemSet::ClearInvalidItems()
369 sal_uInt16* pPtr = m_pWhichRanges;
370 SfxPoolItem const** ppFnd = m_pItems.get();
371 while( *pPtr )
373 for( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
374 if( IsInvalidItem(*ppFnd) )
376 *ppFnd = nullptr;
377 --m_nCount;
379 pPtr += 2;
383 void SfxItemSet::InvalidateAllItems()
385 assert( !m_nCount && "There are still Items set" );
386 m_nCount = TotalCount();
387 memset(static_cast<void*>(m_pItems.get()), -1, m_nCount * sizeof(SfxPoolItem*));
390 SfxItemState SfxItemSet::GetItemState( sal_uInt16 nWhich,
391 bool bSrchInParent,
392 const SfxPoolItem **ppItem ) const
394 // Find the range in which the Which is located
395 const SfxItemSet* pCurrentSet = this;
396 SfxItemState eRet = SfxItemState::UNKNOWN;
399 SfxPoolItem const** ppFnd = pCurrentSet->m_pItems.get();
400 const sal_uInt16* pPtr = pCurrentSet->m_pWhichRanges;
401 if (pPtr)
403 while ( *pPtr )
405 if ( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
407 // Within this range
408 ppFnd += nWhich - *pPtr;
409 if ( !*ppFnd )
411 eRet = SfxItemState::DEFAULT;
412 if( !bSrchInParent )
413 return eRet; // Not present
414 break; // Keep searching in the parents!
417 if ( IsInvalidItem(*ppFnd) )
418 // Different ones are present
419 return SfxItemState::DONTCARE;
421 if ( (*ppFnd)->IsVoidItem() )
422 return SfxItemState::DISABLED;
424 if (ppItem)
426 *ppItem = *ppFnd;
428 return SfxItemState::SET;
430 ppFnd += *(pPtr+1) - *pPtr + 1;
431 pPtr += 2;
434 } while (bSrchInParent && nullptr != (pCurrentSet = pCurrentSet->m_pParent));
435 return eRet;
438 bool SfxItemSet::HasItem(sal_uInt16 nWhich, const SfxPoolItem** ppItem) const
440 bool bRet = SfxItemState::SET == GetItemState(nWhich, true, ppItem);
441 if (!bRet && ppItem)
442 *ppItem = nullptr;
443 return bRet;
446 const SfxPoolItem* SfxItemSet::PutImpl( const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership )
448 if ( !nWhich )
450 assert(!bPassingOwnership);
451 return nullptr; //FIXME: Only because of Outliner bug
454 SfxPoolItem const** ppFnd = m_pItems.get();
455 const sal_uInt16* pPtr = m_pWhichRanges;
456 while( *pPtr )
458 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
460 // Within this range
461 ppFnd += nWhich - *pPtr;
462 if( *ppFnd ) // Already one present
464 // Same Item already present?
465 if ( *ppFnd == &rItem )
467 assert(!bPassingOwnership);
468 return nullptr;
471 // Will 'dontcare' or 'disabled' be overwritten with some real value?
472 if ( rItem.Which() && ( IsInvalidItem(*ppFnd) || !(*ppFnd)->Which() ) )
474 auto const old = *ppFnd;
475 *ppFnd = &m_pPool->PutImpl( rItem, nWhich, bPassingOwnership );
476 if (!IsInvalidItem(old)) {
477 assert(old->Which() == 0);
478 delete old;
480 return *ppFnd;
483 // Turns into disabled?
484 if( !rItem.Which() )
486 if (IsInvalidItem(*ppFnd) || (*ppFnd)->Which() != 0) {
487 *ppFnd = rItem.Clone(m_pPool);
489 if (bPassingOwnership)
490 delete &rItem;
491 return nullptr;
493 else
495 // Same value already present?
496 if ( rItem == **ppFnd )
498 if (bPassingOwnership)
499 delete &rItem;
500 return nullptr;
503 // Add the new one, remove the old one
504 const SfxPoolItem& rNew = m_pPool->PutImpl( rItem, nWhich, bPassingOwnership );
505 const SfxPoolItem* pOld = *ppFnd;
506 *ppFnd = &rNew;
507 if (SfxItemPool::IsWhich(nWhich))
508 Changed( *pOld, rNew );
509 m_pPool->Remove( *pOld );
512 else
514 ++m_nCount;
515 if( !rItem.Which() )
517 *ppFnd = rItem.Clone(m_pPool);
518 if (bPassingOwnership)
519 delete &rItem;
521 else
523 const SfxPoolItem& rNew = m_pPool->PutImpl( rItem, nWhich, bPassingOwnership );
524 *ppFnd = &rNew;
525 if (SfxItemPool::IsWhich(nWhich))
527 const SfxPoolItem& rOld = m_pParent
528 ? m_pParent->Get( nWhich )
529 : m_pPool->GetDefaultItem( nWhich );
530 Changed( rOld, rNew );
534 SAL_WARN_IF(!bPassingOwnership && m_pPool->IsItemPoolable(nWhich) &&
535 dynamic_cast<const SfxSetItem*>( &rItem ) == nullptr &&
536 **ppFnd != rItem,
537 "svl.items", "putted Item unequal, with ID/pos " << nWhich );
538 return *ppFnd;
540 ppFnd += *(pPtr+1) - *pPtr + 1;
541 pPtr += 2;
543 if (bPassingOwnership)
544 delete &rItem;
545 return nullptr;
548 bool SfxItemSet::Put( const SfxItemSet& rSet, bool bInvalidAsDefault )
550 bool bRet = false;
551 if( rSet.Count() )
553 SfxPoolItem const** ppFnd = rSet.m_pItems.get();
554 const sal_uInt16* pPtr = rSet.m_pWhichRanges;
555 while ( *pPtr )
557 for ( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
558 if( *ppFnd )
560 if ( IsInvalidItem( *ppFnd ) )
562 if ( bInvalidAsDefault )
563 bRet |= 0 != ClearItem( nWhich );
564 // FIXME: Caused a SEGFAULT on non Windows-platforms:
565 // bRet |= 0 != Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
566 else
567 InvalidateItem( nWhich );
569 else
570 bRet |= nullptr != Put( **ppFnd, nWhich );
572 pPtr += 2;
575 return bRet;
579 * This method takes the Items from the 'rSet' and adds to '*this'.
580 * Which ranges in '*this' that are non-existent in 'rSet' will not
581 * be altered. The Which range of '*this' is also not changed.
583 * Items set in 'rSet' are also set in '*this'.
584 * Default (0 pointer) and Invalid (-1 pointer) Items are processed
585 * according to their parameter 'eDontCareAs' and 'eDefaultAs':
587 * SfxItemState::SET: Hard set to the default of the Pool
588 * SfxItemState::DEFAULT: Deleted (0 pointer)
589 * SfxItemState::DONTCARE: Invalid (-1 pointer)
591 * NB: All other values for 'eDontCareAs' and 'eDefaultAs' are invalid
593 void SfxItemSet::PutExtended
595 const SfxItemSet& rSet, // Source of the Items to be put
596 SfxItemState eDontCareAs, // What will happen to the DontCare Items
597 SfxItemState eDefaultAs // What will happen to the Default Items
600 // don't "optimize" with "if( rSet.Count()" because of dont-care + defaults
601 SfxPoolItem const** ppFnd = rSet.m_pItems.get();
602 const sal_uInt16* pPtr = rSet.m_pWhichRanges;
603 while ( *pPtr )
605 for ( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
606 if( *ppFnd )
608 if ( IsInvalidItem( *ppFnd ) )
610 // Item is DontCare:
611 switch ( eDontCareAs )
613 case SfxItemState::SET:
614 Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
615 break;
617 case SfxItemState::DEFAULT:
618 ClearItem( nWhich );
619 break;
621 case SfxItemState::DONTCARE:
622 InvalidateItem( nWhich );
623 break;
625 default:
626 assert(!"invalid Argument for eDontCareAs");
629 else
630 // Item is set:
631 Put( **ppFnd, nWhich );
633 else
635 // Item is default:
636 switch ( eDefaultAs )
638 case SfxItemState::SET:
639 Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
640 break;
642 case SfxItemState::DEFAULT:
643 ClearItem( nWhich );
644 break;
646 case SfxItemState::DONTCARE:
647 InvalidateItem( nWhich );
648 break;
650 default:
651 assert(!"invalid Argument for eDefaultAs");
654 pPtr += 2;
659 * Expands the ranges of settable items by 'nFrom' to 'nTo'. Keeps state of
660 * items which are new ranges too.
662 void SfxItemSet::MergeRange( sal_uInt16 nFrom, sal_uInt16 nTo )
664 // special case: exactly one sal_uInt16 which is already included?
665 SfxItemState eItemState = GetItemState(nFrom, false);
666 if ( nFrom == nTo && ( eItemState == SfxItemState::DEFAULT || eItemState == SfxItemState::SET ) )
667 return;
669 #ifdef DBG_UTIL
670 assert(nFrom <= nTo);
671 for (const sal_uInt16 *pRange = m_pWhichRanges; *pRange; pRange += 2)
673 assert(pRange[0] <= pRange[1]);
674 // ranges must be sorted and discrete
675 assert(
676 !pRange[2] || (pRange[2] > pRange[1] && pRange[2] - pRange[1] > 1));
678 #endif
680 // create vector of ranges (sal_uInt16 pairs of lower and upper bound)
681 const size_t nOldCount = Count_Impl(m_pWhichRanges);
682 std::vector<std::pair<sal_uInt16, sal_uInt16>> aRangesTable;
683 aRangesTable.reserve(nOldCount/2 + 1);
684 bool bAdded = false;
685 for (size_t i = 0; i < nOldCount; i += 2)
687 if (!bAdded && m_pWhichRanges[i] >= nFrom)
688 { // insert new range, keep ranges sorted
689 aRangesTable.emplace_back(std::pair<sal_uInt16, sal_uInt16>(nFrom, nTo));
690 bAdded = true;
692 // insert current range
693 aRangesTable.emplace_back(std::pair<sal_uInt16, sal_uInt16>(m_pWhichRanges[i], m_pWhichRanges[i+1]));
695 if (!bAdded)
696 aRangesTable.emplace_back(std::pair<sal_uInt16, sal_uInt16>(nFrom, nTo));
698 // true if ranges overlap or adjoin, false if ranges are separate
699 auto needMerge = [](std::pair<sal_uInt16, sal_uInt16> lhs, std::pair<sal_uInt16, sal_uInt16> rhs)
700 {return (lhs.first-1) <= rhs.second && (rhs.first-1) <= lhs.second;};
702 std::vector<std::pair<sal_uInt16, sal_uInt16> >::iterator it = aRangesTable.begin();
703 std::vector<std::pair<sal_uInt16, sal_uInt16> >::iterator itNext;
704 // we got at least one range
705 while ((itNext = std::next(it)) != aRangesTable.end())
707 // check neighbouring ranges, find first range which overlaps or adjoins a previous range
708 if (needMerge(*it, *itNext))
710 // lower bounds are sorted, implies: it->first = min(it[0].first, it[1].first)
711 it->second = std::max(it->second, itNext->second);
712 aRangesTable.erase(itNext);
714 else
715 ++it;
718 // construct range array
719 const size_t nNewSize = 2 * aRangesTable.size() + 1;
720 std::vector<sal_uInt16> aRanges(nNewSize);
721 for (size_t i = 0; i < (nNewSize - 1); i +=2)
722 std::tie(aRanges[i], aRanges[i+1]) = aRangesTable[i/2];
724 // null terminate to be compatible with sal_uInt16* array pointers
725 aRanges.back() = 0;
727 SetRanges( aRanges.data() );
731 * Modifies the ranges of settable items. Keeps state of items which
732 * are new ranges too.
734 void SfxItemSet::SetRanges( const sal_uInt16 *pNewRanges )
736 // Identical Ranges?
737 if (m_pWhichRanges == pNewRanges)
738 return;
739 const sal_uInt16* pOld = m_pWhichRanges;
740 const sal_uInt16* pNew = pNewRanges;
741 while ( *pOld == *pNew )
743 if ( !*pOld && !*pNew )
744 return;
745 ++pOld;
746 ++pNew;
749 // create new item-array (by iterating through all new ranges)
750 sal_uInt16 nSize = Capacity_Impl(pNewRanges);
751 SfxPoolItem const** aNewItems = new const SfxPoolItem* [ nSize ];
752 sal_uInt16 nNewCount = 0;
753 if (m_nCount == 0)
754 memset( aNewItems, 0, nSize * sizeof( SfxPoolItem* ) );
755 else
757 sal_uInt16 n = 0;
758 for ( const sal_uInt16 *pRange = pNewRanges; *pRange; pRange += 2 )
760 // iterate through all ids in the range
761 for ( sal_uInt16 nWID = *pRange; nWID <= pRange[1]; ++nWID, ++n )
763 // direct move of pointer (not via pool)
764 SfxItemState eState = GetItemState( nWID, false, aNewItems+n );
765 if ( SfxItemState::SET == eState )
767 // increment new item count and possibly increment ref count
768 ++nNewCount;
769 aNewItems[n]->AddRef();
771 else if ( SfxItemState::DISABLED == eState )
773 // put "disabled" item
774 ++nNewCount;
775 aNewItems[n] = new SfxVoidItem(0);
777 else if ( SfxItemState::DONTCARE == eState )
779 ++nNewCount;
780 aNewItems[n] = INVALID_POOL_ITEM;
782 else
784 // default
785 aNewItems[n] = nullptr;
789 // free old items
790 sal_uInt16 nOldTotalCount = TotalCount();
791 for ( sal_uInt16 nItem = 0; nItem < nOldTotalCount; ++nItem )
793 const SfxPoolItem *pItem = m_pItems[nItem];
794 if ( pItem && !IsInvalidItem(pItem) && pItem->Which() )
795 m_pPool->Remove(*pItem);
799 // replace old items-array and ranges
800 m_pItems.reset( aNewItems );
801 m_nCount = nNewCount;
803 if( pNewRanges == GetPool()->GetFrozenIdRanges() )
805 delete[] m_pWhichRanges;
806 m_pWhichRanges = const_cast<sal_uInt16*>(pNewRanges);
808 else
810 sal_uInt16 nCount = Count_Impl(pNewRanges) + 1;
811 if (m_pWhichRanges != m_pPool->GetFrozenIdRanges())
812 delete[] m_pWhichRanges;
813 m_pWhichRanges = new sal_uInt16[ nCount ];
814 memcpy( m_pWhichRanges, pNewRanges, sizeof( sal_uInt16 ) * nCount );
819 * The SfxItemSet takes over exactly those SfxPoolItems that are
820 * set in rSet and are in their own Which range. All others are removed.
821 * The SfxItemPool is retained, such that SfxPoolItems that have been
822 * taken over, are moved from the rSet's SfxItemPool to the SfxItemPool
823 * of *this.
825 * SfxPoolItems in rSet, for which holds 'IsInvalidItem() == true' are
826 * taken over as invalid items.
828 * @return bool true
829 * SfxPoolItems have been taken over
831 * false
832 * No SfxPoolItems have been taken over, because
833 * e.g. the Which ranges of SfxItemSets are not intersecting
834 * or the intersection does not contain SfxPoolItems that are
835 * set in rSet
837 bool SfxItemSet::Set
839 const SfxItemSet& rSet, /* The SfxItemSet, whose SfxPoolItems are
840 to been taken over */
842 bool bDeep /* true (default)
844 The SfxPoolItems from the parents that may
845 be present in rSet, are also taken over into
846 this SfxPoolItemSet
848 false
849 The SfxPoolItems from the parents of
850 rSet are not taken into account */
853 bool bRet = false;
854 if (m_nCount)
855 ClearItem();
856 if ( bDeep )
858 SfxWhichIter aIter(*this);
859 sal_uInt16 nWhich = aIter.FirstWhich();
860 while ( nWhich )
862 const SfxPoolItem* pItem;
863 if( SfxItemState::SET == rSet.GetItemState( nWhich, true, &pItem ) )
864 bRet |= nullptr != Put( *pItem, pItem->Which() );
865 nWhich = aIter.NextWhich();
868 else
869 bRet = Put(rSet, false);
871 return bRet;
874 const SfxPoolItem* SfxItemSet::GetItem(sal_uInt16 nId, bool bSearchInParent) const
876 // Convert to WhichId
877 sal_uInt16 nWhich = GetPool()->GetWhich(nId);
879 // Is the Item set or 'bDeep == true' available?
880 const SfxPoolItem *pItem = nullptr;
881 SfxItemState eState = GetItemState(nWhich, bSearchInParent, &pItem);
882 if (bSearchInParent && SfxItemState::DEFAULT == eState && SfxItemPool::IsWhich(nWhich))
884 pItem = &m_pPool->GetDefaultItem(nWhich);
887 return pItem;
890 const SfxPoolItem& SfxItemSet::Get( sal_uInt16 nWhich, bool bSrchInParent) const
892 // Search the Range in which the Which is located in:
893 const SfxItemSet* pCurrentSet = this;
896 if( pCurrentSet->Count() )
898 SfxPoolItem const** ppFnd = pCurrentSet->m_pItems.get();
899 const sal_uInt16* pPtr = pCurrentSet->m_pWhichRanges;
900 while( *pPtr )
902 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
904 // In this Range
905 ppFnd += nWhich - *pPtr;
906 if( *ppFnd )
908 if( IsInvalidItem(*ppFnd) ) {
909 //FIXME: The following code is duplicated further down
910 SAL_WARN_IF(!m_pPool, "svl.items", "no Pool, but status is ambiguous, with ID/pos " << nWhich);
911 //!((SfxAllItemSet *)this)->aDefault.SetWhich(nWhich);
912 //!return aDefault;
913 return m_pPool->GetDefaultItem( nWhich );
915 #ifdef DBG_UTIL
916 const SfxPoolItem *pItem = *ppFnd;
917 if ( pItem->IsVoidItem() || !pItem->Which() )
918 SAL_INFO("svl.items", "SFX_WARNING: Getting disabled Item");
919 #endif
920 return **ppFnd;
922 break; // Continue with Parent
924 ppFnd += *(pPtr+1) - *pPtr + 1;
925 pPtr += 2;
928 //TODO: Search until end of Range: What are we supposed to do now? To the Parent or Default??
929 // if( !*pPtr ) // Until the end of the search Range?
930 // break;
931 } while (bSrchInParent && nullptr != (pCurrentSet = pCurrentSet->m_pParent));
933 // Get the Default from the Pool and return
934 SAL_WARN_IF(!m_pPool, "svl.items", "no Pool, but status is ambiguous, with ID/pos " << nWhich);
935 const SfxPoolItem *pItem = &m_pPool->GetDefaultItem( nWhich );
936 return *pItem;
940 * Notification callback
942 void SfxItemSet::Changed( const SfxPoolItem&, const SfxPoolItem& )
946 sal_uInt16 SfxItemSet::TotalCount() const
948 sal_uInt16 nRet = 0;
949 sal_uInt16* pPtr = m_pWhichRanges;
950 while( *pPtr )
952 nRet += ( *(pPtr+1) - *pPtr ) + 1;
953 pPtr += 2;
955 return nRet;
959 * Only retain the Items that are also present in rSet
960 * (nevermind their value).
962 void SfxItemSet::Intersect( const SfxItemSet& rSet )
964 assert(m_pPool && "Not implemented without Pool");
965 if( !Count() ) // None set?
966 return;
968 // Delete all Items not contained in rSet
969 if( !rSet.Count() )
971 ClearItem(); // Delete everything
972 return;
975 // Test whether the Which Ranges are different
976 sal_uInt16* pWh1 = m_pWhichRanges;
977 sal_uInt16* pWh2 = rSet.m_pWhichRanges;
978 sal_uInt16 nSize = 0;
980 for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
982 if( *pWh1 != *pWh2 )
984 break;
986 if( n & 1 )
987 nSize += ( *pWh1 - *(pWh1-1) ) + 1;
989 bool bEqual = *pWh1 == *pWh2; // Also check for 0
991 // If the Ranges are identical, we can easily process it
992 if( bEqual )
994 SfxPoolItem const** ppFnd1 = m_pItems.get();
995 SfxPoolItem const** ppFnd2 = rSet.m_pItems.get();
997 for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
998 if( *ppFnd1 && !*ppFnd2 )
1000 // Delete from Pool
1001 if( !IsInvalidItem( *ppFnd1 ) )
1003 sal_uInt16 nWhich = (*ppFnd1)->Which();
1004 if (SfxItemPool::IsWhich(nWhich))
1006 const SfxPoolItem& rNew = m_pParent
1007 ? m_pParent->Get( nWhich )
1008 : m_pPool->GetDefaultItem( nWhich );
1010 Changed( **ppFnd1, rNew );
1012 m_pPool->Remove( **ppFnd1 );
1014 *ppFnd1 = nullptr;
1015 --m_nCount;
1018 else
1020 SfxItemIter aIter( *this );
1021 const SfxPoolItem* pItem = aIter.GetCurItem();
1022 while( true )
1024 sal_uInt16 nWhich = IsInvalidItem( pItem )
1025 ? GetWhichByPos( aIter.GetCurPos() )
1026 : pItem->Which();
1027 if( SfxItemState::UNKNOWN == rSet.GetItemState( nWhich, false ) )
1028 ClearItem( nWhich ); // Delete
1029 if( aIter.IsAtEnd() )
1030 break;
1031 pItem = aIter.NextItem();
1036 void SfxItemSet::Differentiate( const SfxItemSet& rSet )
1038 if( !Count() || !rSet.Count() )// None set?
1039 return;
1041 // Test whether the Which Ranges are different
1042 sal_uInt16* pWh1 = m_pWhichRanges;
1043 sal_uInt16* pWh2 = rSet.m_pWhichRanges;
1044 sal_uInt16 nSize = 0;
1046 for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
1048 if( *pWh1 != *pWh2 )
1050 break;
1052 if( n & 1 )
1053 nSize += ( *pWh1 - *(pWh1-1) ) + 1;
1055 bool bEqual = *pWh1 == *pWh2; // Also test for 0
1057 // If the Ranges are identical, we can easily process it
1058 if( bEqual )
1060 SfxPoolItem const** ppFnd1 = m_pItems.get();
1061 SfxPoolItem const** ppFnd2 = rSet.m_pItems.get();
1063 for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
1064 if( *ppFnd1 && *ppFnd2 )
1066 // Delete from Pool
1067 if( !IsInvalidItem( *ppFnd1 ) )
1069 sal_uInt16 nWhich = (*ppFnd1)->Which();
1070 if (SfxItemPool::IsWhich(nWhich))
1072 const SfxPoolItem& rNew = m_pParent
1073 ? m_pParent->Get( nWhich )
1074 : m_pPool->GetDefaultItem( nWhich );
1076 Changed( **ppFnd1, rNew );
1078 m_pPool->Remove( **ppFnd1 );
1080 *ppFnd1 = nullptr;
1081 --m_nCount;
1084 else
1086 SfxItemIter aIter( *this );
1087 const SfxPoolItem* pItem = aIter.GetCurItem();
1088 while( true )
1090 sal_uInt16 nWhich = IsInvalidItem( pItem )
1091 ? GetWhichByPos( aIter.GetCurPos() )
1092 : pItem->Which();
1093 if( SfxItemState::SET == rSet.GetItemState( nWhich, false ) )
1094 ClearItem( nWhich ); // Delete
1095 if( aIter.IsAtEnd() )
1096 break;
1097 pItem = aIter.NextItem();
1104 * Decision table for MergeValue(s)
1106 * Principles:
1107 * 1. If the Which value in the 1st set is "unknown", there's never any action
1108 * 2. If the Which value in the 2nd set is "unknown", it's made the "default"
1109 * 3. For comparisons the values of the "default" Items are take into account
1111 * 1st Item 2nd Item Values bIgnoreDefs Remove Assign Add
1113 * set set == sal_False - - -
1114 * default set == sal_False - - -
1115 * dontcare set == sal_False - - -
1116 * unknown set == sal_False - - -
1117 * set default == sal_False - - -
1118 * default default == sal_False - - -
1119 * dontcare default == sal_False - - -
1120 * unknown default == sal_False - - -
1121 * set dontcare == sal_False 1st Item -1 -
1122 * default dontcare == sal_False - -1 -
1123 * dontcare dontcare == sal_False - - -
1124 * unknown dontcare == sal_False - - -
1125 * set unknown == sal_False 1st Item -1 -
1126 * default unknown == sal_False - - -
1127 * dontcare unknown == sal_False - - -
1128 * unknown unknown == sal_False - - -
1130 * set set != sal_False 1st Item -1 -
1131 * default set != sal_False - -1 -
1132 * dontcare set != sal_False - - -
1133 * unknown set != sal_False - - -
1134 * set default != sal_False 1st Item -1 -
1135 * default default != sal_False - - -
1136 * dontcare default != sal_False - - -
1137 * unknown default != sal_False - - -
1138 * set dontcare != sal_False 1st Item -1 -
1139 * default dontcare != sal_False - -1 -
1140 * dontcare dontcare != sal_False - - -
1141 * unknown dontcare != sal_False - - -
1142 * set unknown != sal_False 1st Item -1 -
1143 * default unknown != sal_False - - -
1144 * dontcare unknown != sal_False - - -
1145 * unknown unknown != sal_False - - -
1147 * set set == sal_True - - -
1148 * default set == sal_True - 2nd Item 2nd Item
1149 * dontcare set == sal_True - - -
1150 * unknown set == sal_True - - -
1151 * set default == sal_True - - -
1152 * default default == sal_True - - -
1153 * dontcare default == sal_True - - -
1154 * unknown default == sal_True - - -
1155 * set dontcare == sal_True - - -
1156 * default dontcare == sal_True - -1 -
1157 * dontcare dontcare == sal_True - - -
1158 * unknown dontcare == sal_True - - -
1159 * set unknown == sal_True - - -
1160 * default unknown == sal_True - - -
1161 * dontcare unknown == sal_True - - -
1162 * unknown unknown == sal_True - - -
1164 * set set != sal_True 1st Item -1 -
1165 * default set != sal_True - 2nd Item 2nd Item
1166 * dontcare set != sal_True - - -
1167 * unknown set != sal_True - - -
1168 * set default != sal_True - - -
1169 * default default != sal_True - - -
1170 * dontcare default != sal_True - - -
1171 * unknown default != sal_True - - -
1172 * set dontcare != sal_True 1st Item -1 -
1173 * default dontcare != sal_True - -1 -
1174 * dontcare dontcare != sal_True - - -
1175 * unknown dontcare != sal_True - - -
1176 * set unknown != sal_True - - -
1177 * default unknown != sal_True - - -
1178 * dontcare unknown != sal_True - - -
1179 * unknown unknown != sal_True - - -
1181 static void MergeItem_Impl( SfxItemPool *_pPool, sal_uInt16 &rCount,
1182 const SfxPoolItem **ppFnd1, const SfxPoolItem *pFnd2,
1183 bool bIgnoreDefaults )
1185 assert(ppFnd1 != nullptr && "Merging to 0-Item");
1187 // 1st Item is Default?
1188 if ( !*ppFnd1 )
1190 if ( IsInvalidItem(pFnd2) )
1191 // Decision table: default, dontcare, doesn't matter, doesn't matter
1192 *ppFnd1 = INVALID_POOL_ITEM;
1194 else if ( pFnd2 && !bIgnoreDefaults &&
1195 _pPool->GetDefaultItem(pFnd2->Which()) != *pFnd2 )
1196 // Decision table: default, set, !=, sal_False
1197 *ppFnd1 = INVALID_POOL_ITEM;
1199 else if ( pFnd2 && bIgnoreDefaults )
1200 // Decision table: default, set, doesn't matter, sal_True
1201 *ppFnd1 = &_pPool->Put( *pFnd2 );
1203 if ( *ppFnd1 )
1204 ++rCount;
1207 // 1st Item set?
1208 else if ( !IsInvalidItem(*ppFnd1) )
1210 if ( !pFnd2 )
1212 // 2nd Item is Default
1213 if ( !bIgnoreDefaults &&
1214 **ppFnd1 != _pPool->GetDefaultItem((*ppFnd1)->Which()) )
1216 // Decision table: set, default, !=, sal_False
1217 _pPool->Remove( **ppFnd1 );
1218 *ppFnd1 = INVALID_POOL_ITEM;
1221 else if ( IsInvalidItem(pFnd2) )
1223 // 2nd Item is dontcare
1224 if ( !bIgnoreDefaults ||
1225 **ppFnd1 != _pPool->GetDefaultItem( (*ppFnd1)->Which()) )
1227 // Decision table: set, dontcare, doesn't matter, sal_False
1228 // or: set, dontcare, !=, sal_True
1229 _pPool->Remove( **ppFnd1 );
1230 *ppFnd1 = INVALID_POOL_ITEM;
1233 else
1235 // 2nd Item is set
1236 if ( **ppFnd1 != *pFnd2 )
1238 // Decision table: set, set, !=, doesn't matter
1239 _pPool->Remove( **ppFnd1 );
1240 *ppFnd1 = INVALID_POOL_ITEM;
1246 void SfxItemSet::MergeValues( const SfxItemSet& rSet )
1248 // WARNING! When making changes/fixing bugs, always update the table above!!
1249 assert( GetPool() == rSet.GetPool() && "MergeValues with different Pools" );
1251 // Test if the which Ranges are different
1252 sal_uInt16* pWh1 = m_pWhichRanges;
1253 sal_uInt16* pWh2 = rSet.m_pWhichRanges;
1254 sal_uInt16 nSize = 0;
1256 for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
1258 if( *pWh1 != *pWh2 )
1260 break;
1262 if( n & 1 )
1263 nSize += ( *pWh1 - *(pWh1-1) ) + 1;
1265 bool bEqual = *pWh1 == *pWh2; // Also check for 0
1267 // If the Ranges match, they are easier to process!
1268 if( bEqual )
1270 SfxPoolItem const** ppFnd1 = m_pItems.get();
1271 SfxPoolItem const** ppFnd2 = rSet.m_pItems.get();
1273 for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
1274 MergeItem_Impl(m_pPool, m_nCount, ppFnd1, *ppFnd2, false/*bIgnoreDefaults*/);
1276 else
1278 SfxWhichIter aIter( rSet );
1279 sal_uInt16 nWhich;
1280 while( 0 != ( nWhich = aIter.NextWhich() ) )
1282 const SfxPoolItem* pItem = nullptr;
1283 (void)rSet.GetItemState( nWhich, true, &pItem );
1284 if( !pItem )
1286 // Not set, so default
1287 MergeValue( rSet.GetPool()->GetDefaultItem( nWhich ) );
1289 else if( IsInvalidItem( pItem ) )
1290 // don't care
1291 InvalidateItem( nWhich );
1292 else
1293 MergeValue( *pItem );
1298 void SfxItemSet::MergeValue( const SfxPoolItem& rAttr, bool bIgnoreDefaults )
1300 SfxPoolItem const** ppFnd = m_pItems.get();
1301 const sal_uInt16* pPtr = m_pWhichRanges;
1302 const sal_uInt16 nWhich = rAttr.Which();
1303 while( *pPtr )
1305 // In this Range??
1306 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1308 ppFnd += nWhich - *pPtr;
1309 MergeItem_Impl(m_pPool, m_nCount, ppFnd, &rAttr, bIgnoreDefaults);
1310 break;
1312 ppFnd += *(pPtr+1) - *pPtr + 1;
1313 pPtr += 2;
1317 void SfxItemSet::InvalidateItem( sal_uInt16 nWhich )
1319 SfxPoolItem const** ppFnd = m_pItems.get();
1320 const sal_uInt16* pPtr = m_pWhichRanges;
1321 while( *pPtr )
1323 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1325 // In this Range?
1326 ppFnd += nWhich - *pPtr;
1328 if( *ppFnd ) // Set for me
1330 if( !IsInvalidItem(*ppFnd) )
1332 m_pPool->Remove( **ppFnd );
1333 *ppFnd = INVALID_POOL_ITEM;
1336 else
1338 *ppFnd = INVALID_POOL_ITEM;
1339 ++m_nCount;
1341 break;
1343 ppFnd += *(pPtr+1) - *pPtr + 1;
1344 pPtr += 2;
1348 sal_uInt16 SfxItemSet::GetWhichByPos( sal_uInt16 nPos ) const
1350 sal_uInt16 n = 0;
1351 sal_uInt16* pPtr = m_pWhichRanges;
1352 while( *pPtr )
1354 n = ( *(pPtr+1) - *pPtr ) + 1;
1355 if( nPos < n )
1356 return *pPtr + nPos;
1357 nPos = nPos - n;
1358 pPtr += 2;
1360 assert(false);
1361 return 0;
1364 bool SfxItemSet::operator==(const SfxItemSet &rCmp) const
1366 return Equals( rCmp, true);
1369 bool SfxItemSet::Equals(const SfxItemSet &rCmp, bool bComparePool) const
1371 // Values we can get quickly need to be the same
1372 const bool bDifferentPools = (m_pPool != rCmp.m_pPool);
1373 if ( (bComparePool && m_pParent != rCmp.m_pParent) ||
1374 (bComparePool && bDifferentPools) ||
1375 Count() != rCmp.Count() )
1376 return false;
1378 // If we reach here and bDifferentPools==true that means bComparePool==false.
1380 // Counting Ranges takes longer; they also need to be the same, however
1381 sal_uInt16 nCount1 = TotalCount();
1382 sal_uInt16 nCount2 = rCmp.TotalCount();
1383 if ( nCount1 != nCount2 )
1384 return false;
1386 // Are the Ranges themselves unequal?
1387 for (sal_uInt16 nRange = 0; m_pWhichRanges[nRange]; nRange += 2)
1389 if (m_pWhichRanges[nRange] != rCmp.m_pWhichRanges[nRange] ||
1390 m_pWhichRanges[nRange+1] != rCmp.m_pWhichRanges[nRange+1])
1392 // We must use the slow method then
1393 SfxWhichIter aIter( *this );
1394 for ( sal_uInt16 nWh = aIter.FirstWhich();
1395 nWh;
1396 nWh = aIter.NextWhich() )
1398 // If the pointer of the poolable Items are unequal, the Items must match
1399 const SfxPoolItem *pItem1 = nullptr, *pItem2 = nullptr;
1400 if ( GetItemState( nWh, false, &pItem1 ) !=
1401 rCmp.GetItemState( nWh, false, &pItem2 ) ||
1402 ( pItem1 != pItem2 &&
1403 ( !pItem1 || IsInvalidItem(pItem1) ||
1404 (m_pPool->IsItemPoolable(*pItem1) &&
1405 *pItem1 != *pItem2 ) ) ) )
1406 return false;
1409 return true;
1413 // Are all pointers the same?
1414 if (0 == memcmp( m_pItems.get(), rCmp.m_pItems.get(), nCount1 * sizeof(m_pItems[0]) ))
1415 return true;
1417 // We need to compare each one separately then
1418 const SfxPoolItem **ppItem1 = m_pItems.get();
1419 const SfxPoolItem **ppItem2 = rCmp.m_pItems.get();
1420 for ( sal_uInt16 nPos = 0; nPos < nCount1; ++nPos )
1422 // If the pointers of the poolable Items are not the same, the Items
1423 // must match
1424 if ( *ppItem1 != *ppItem2 &&
1425 ( ( !*ppItem1 || !*ppItem2 ) ||
1426 ( IsInvalidItem(*ppItem1) || IsInvalidItem(*ppItem2) ) ||
1427 (!bDifferentPools && m_pPool->IsItemPoolable(**ppItem1)) ||
1428 **ppItem1 != **ppItem2 ) )
1429 return false;
1431 ++ppItem1;
1432 ++ppItem2;
1435 return true;
1438 std::unique_ptr<SfxItemSet> SfxItemSet::Clone(bool bItems, SfxItemPool *pToPool ) const
1440 if (pToPool && pToPool != m_pPool)
1442 std::unique_ptr<SfxItemSet> pNewSet(new SfxItemSet(*pToPool, m_pWhichRanges));
1443 if ( bItems )
1445 SfxWhichIter aIter(*pNewSet);
1446 sal_uInt16 nWhich = aIter.FirstWhich();
1447 while ( nWhich )
1449 const SfxPoolItem* pItem;
1450 if ( SfxItemState::SET == GetItemState( nWhich, false, &pItem ) )
1451 pNewSet->Put( *pItem, pItem->Which() );
1452 nWhich = aIter.NextWhich();
1455 return pNewSet;
1457 else
1458 return std::unique_ptr<SfxItemSet>(bItems
1459 ? new SfxItemSet(*this)
1460 : new SfxItemSet(*m_pPool, m_pWhichRanges));
1463 void SfxItemSet::PutDirect(const SfxPoolItem &rItem)
1465 SfxPoolItem const** ppFnd = m_pItems.get();
1466 const sal_uInt16* pPtr = m_pWhichRanges;
1467 const sal_uInt16 nWhich = rItem.Which();
1468 #ifdef DBG_UTIL
1469 IsPoolDefaultItem(&rItem) || m_pPool->CheckItemInPool(&rItem);
1470 // Only cause assertion in the callees
1471 #endif
1472 while( *pPtr )
1474 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1476 // In this Range?
1477 ppFnd += nWhich - *pPtr;
1478 const SfxPoolItem* pOld = *ppFnd;
1479 if( pOld ) // One already present
1481 if( rItem == **ppFnd )
1482 return; // Already present!
1483 m_pPool->Remove( *pOld );
1485 else
1486 ++m_nCount;
1488 // Add the new one
1489 if( IsPoolDefaultItem(&rItem) )
1490 *ppFnd = &m_pPool->Put( rItem );
1491 else
1493 *ppFnd = &rItem;
1494 if( !IsStaticDefaultItem( &rItem ) )
1495 rItem.AddRef();
1498 return;
1500 ppFnd += *(pPtr+1) - *pPtr + 1;
1501 pPtr += 2;
1505 void SfxItemSet::dumpAsXml(xmlTextWriterPtr pWriter) const
1507 xmlTextWriterStartElement(pWriter, BAD_CAST("SfxItemSet"));
1508 SfxItemIter aIter(*this);
1509 for (const SfxPoolItem* pItem = aIter.FirstItem(); pItem; pItem = aIter.NextItem())
1510 pItem->dumpAsXml(pWriter);
1511 xmlTextWriterEndElement(pWriter);
1515 // ----------------------------------------------- class SfxAllItemSet
1517 SfxAllItemSet::SfxAllItemSet( SfxItemPool &rPool )
1518 : SfxItemSet(rPool, nullptr),
1519 nFree(nInitCount)
1521 // Initially no Items
1522 m_pItems = nullptr;
1524 // Allocate nInitCount pairs at USHORTs for Ranges
1525 m_pWhichRanges = new sal_uInt16[nInitCount + 1]{};
1528 SfxAllItemSet::SfxAllItemSet(const SfxItemSet &rCopy)
1529 : SfxItemSet(rCopy),
1530 nFree(0)
1535 * Explicitly define this ctor to avoid auto-generation by the compiler.
1536 * The compiler does not take the ctor with the 'const SfxItemSet&'!
1538 SfxAllItemSet::SfxAllItemSet(const SfxAllItemSet &rCopy)
1539 : SfxItemSet(rCopy),
1540 nFree(0)
1545 * This internal function creates a new WhichRanges array, which is copied
1546 * from the 'nOldSize'-USHORTs long 'pUS'. It has new USHORTs at the end instead
1547 * of 'nIncr'.
1548 * The terminating sal_uInt16 with the '0' is neither accounted for in 'nOldSize'
1549 * nor in 'nIncr', but always explicitly added.
1551 * @returns the new WhichRanges array (the old 'pUS' is freed)
1553 static sal_uInt16 *AddRanges_Impl(
1554 sal_uInt16 *pUS, std::ptrdiff_t nOldSize, sal_uInt16 nIncr)
1556 // Create new WhichRanges array
1557 sal_uInt16 *pNew = new sal_uInt16[ nOldSize + nIncr + 1 ];
1559 // Take over the old Ranges
1560 memcpy( pNew, pUS, nOldSize * sizeof(sal_uInt16) );
1562 // Initialize the new one to 0
1563 memset( pNew + nOldSize, 0, ( nIncr + 1 ) * sizeof(sal_uInt16) );
1565 // Free the old array
1566 delete[] pUS;
1568 return pNew;
1572 * This internal function creates a new ItemArray, which is copied from 'pItems',
1573 * but has room for a new ItemPointer at 'nPos'.
1575 * @returns the new ItemArray (the old 'pItems' is freed)
1577 static void AddItem_Impl(std::unique_ptr<SfxPoolItem const*[]> & rpItems, sal_uInt16 nOldSize, sal_uInt16 nPos)
1579 // Create new ItemArray
1580 SfxPoolItem const** pNew = new const SfxPoolItem*[nOldSize+1];
1582 // Was there one before?
1583 if ( rpItems )
1585 // Copy all Items before nPos
1586 if ( nPos )
1587 memcpy( static_cast<void*>(pNew), rpItems.get(), nPos * sizeof(SfxPoolItem *) );
1589 // Copy all Items after nPos
1590 if ( nPos < nOldSize )
1591 memcpy( static_cast<void*>(pNew + nPos + 1), rpItems.get() + nPos,
1592 (nOldSize-nPos) * sizeof(SfxPoolItem *) );
1595 // Initialize new Item
1596 *(pNew + nPos) = nullptr;
1598 rpItems.reset(pNew);
1602 * Putting with automatic extension of the WhichId with the ID of the Item.
1604 const SfxPoolItem* SfxAllItemSet::PutImpl( const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership )
1606 sal_uInt16 nPos = 0; // Position for 'rItem' in 'm_pItems'
1607 const sal_uInt16 nItemCount = TotalCount();
1609 // Let's see first whether there's a suitable Range already
1610 sal_uInt16 *pPtr = m_pWhichRanges;
1611 while ( *pPtr )
1613 // WhichId is within this Range?
1614 if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
1616 // Insert
1617 nPos += nWhich - *pPtr;
1618 break;
1621 // Carry over the position of the Item in m_pItems
1622 nPos += *(pPtr+1) - *pPtr + 1;
1624 // To the next Range
1625 pPtr += 2;
1628 // WhichId not yet present?
1629 if ( !*pPtr )
1631 // Let's see if we can attach it somewhere
1632 pPtr = m_pWhichRanges;
1633 nPos = 0;
1634 while ( *pPtr )
1636 // WhichId is right before this Range?
1637 if ( (nWhich+1) == *pPtr )
1639 // Range grows downwards
1640 (*pPtr)--;
1642 // Make room before first Item of this Range
1643 AddItem_Impl(m_pItems, nItemCount, nPos);
1644 break;
1647 // WhichId is right after this Range?
1648 else if ( (nWhich-1) == *(pPtr+1) )
1650 // Range grows upwards?
1651 (*(pPtr+1))++;
1653 // Make room after last Item of this Range
1654 nPos += nWhich - *pPtr;
1655 AddItem_Impl(m_pItems, nItemCount, nPos);
1656 break;
1659 // Carry over position of the Item in m_pItems
1660 nPos += *(pPtr+1) - *pPtr + 1;
1662 // To the next Range
1663 pPtr += 2;
1667 // No extensible Range found?
1668 if ( !*pPtr )
1670 // No room left in m_pWhichRanges? => Expand!
1671 std::ptrdiff_t nSize = pPtr - m_pWhichRanges;
1672 if( !nFree )
1674 m_pWhichRanges = AddRanges_Impl(m_pWhichRanges, nSize, nInitCount);
1675 nFree += nInitCount;
1678 // Attach new WhichRange
1679 pPtr = m_pWhichRanges + nSize;
1680 *pPtr++ = nWhich;
1681 *pPtr = nWhich;
1682 nFree -= 2;
1684 // Expand ItemArray
1685 nPos = nItemCount;
1686 AddItem_Impl(m_pItems, nItemCount, nPos);
1689 // Add new Item to Pool
1690 const SfxPoolItem& rNew = m_pPool->PutImpl( rItem, nWhich, bPassingOwnership );
1692 // Remember old Item
1693 bool bIncrementCount = false;
1694 const SfxPoolItem* pOld = m_pItems[nPos];
1695 if ( IsInvalidItem(pOld) ) // state "dontcare"
1696 pOld = nullptr;
1697 if ( !pOld )
1699 bIncrementCount = true;
1700 pOld = m_pParent
1701 ? &m_pParent->Get( nWhich )
1702 : (SfxItemPool::IsWhich(nWhich)
1703 ? &m_pPool->GetDefaultItem(nWhich)
1704 : nullptr);
1707 // Add new Item to ItemSet
1708 m_pItems[nPos] = &rNew;
1710 // Send Changed Notification
1711 if ( pOld )
1713 Changed( *pOld, rNew );
1714 if ( !IsDefaultItem(pOld) )
1715 m_pPool->Remove( *pOld );
1718 if ( bIncrementCount )
1719 ++m_nCount;
1721 return &rNew;
1725 * Disable Item
1726 * Using a VoidItem with Which value 0
1728 void SfxItemSet::DisableItem(sal_uInt16 nWhich)
1730 Put( SfxVoidItem(0), nWhich );
1733 std::unique_ptr<SfxItemSet> SfxAllItemSet::Clone(bool bItems, SfxItemPool *pToPool ) const
1735 if (pToPool && pToPool != m_pPool)
1737 std::unique_ptr<SfxAllItemSet> pNewSet(new SfxAllItemSet( *pToPool ));
1738 if ( bItems )
1739 pNewSet->Set( *this );
1740 return std::unique_ptr<SfxItemSet>(pNewSet.release()); // clang3.8 does not seem to be able to upcast std::unique_ptr
1742 else
1743 return std::unique_ptr<SfxItemSet>(bItems ? new SfxAllItemSet(*this) : new SfxAllItemSet(*m_pPool));
1746 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */