1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
41 static const sal_uInt16 nInitCount
= 10; // Single USHORTs => 5 pairs without '0'
47 * Determines the number of sal_uInt16s in a 0-terminated array of pairs of
49 * The terminating 0 is not included in the count.
51 sal_uInt16
Count_Impl( const sal_uInt16
*pRanges
)
53 sal_uInt16 nCount
= 0;
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;
74 nCount
+= pRanges
[1] - pRanges
[0] + 1;
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
)
95 m_pWhichRanges
= const_cast<sal_uInt16
*>(m_pPool
->GetFrozenIdRanges());
96 assert( m_pWhichRanges
&& "don't create ItemSets with full range before FreezeIdRanges()" );
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
)
111 const sal_uInt16
* pPtr
= pWhichPairTable
;
114 nCnt
+= ( *(pPtr
+1) - *pPtr
) + 1;
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
,
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
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
149 assert(wids
.size() != 0);
151 std::size_t size
= 0;
153 //TODO: sal_uInt16 prev = 0;
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
164 //TODO: prev = p.wid2;
167 m_pWhichRanges
[i
] = 0;
168 m_pItems
.reset( new SfxPoolItem
const *[size
]{} );
171 SfxItemSet::SfxItemSet( SfxItemPool
& rPool
, const sal_uInt16
* pWhichPairTable
)
174 , m_pWhichRanges(nullptr)
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
189 sal_uInt16
* pPtr
= rASet
.m_pWhichRanges
;
192 nCnt
+= ( *(pPtr
+1) - *pPtr
) + 1;
196 m_pItems
.reset( new const SfxPoolItem
* [ nCnt
] );
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
207 else if (m_pPool
->IsItemPoolable( **ppSrc
))
209 // Just copy the pointer and increase RefCount
213 else if ( !(*ppSrc
)->Which() )
214 *ppDst
= (*ppSrc
)->Clone();
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;
238 SfxItemSet::~SfxItemSet()
240 if (m_pWhichRanges
) // might be nullptr if we have been moved-from
242 sal_uInt16 nCount
= TotalCount();
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() )
252 // Still multiple references present, so just alter the RefCount
253 if ( 1 < (*ppFnd
)->GetRefCount() && !IsDefaultItem(*ppFnd
) )
254 (*ppFnd
)->ReleaseRef();
256 if ( !IsDefaultItem(*ppFnd
) )
258 m_pPool
->Remove( **ppFnd
);
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
)
279 SfxPoolItem
const** ppFnd
= m_pItems
.get();
283 const sal_uInt16
* pPtr
= m_pWhichRanges
;
286 // Within this range?
287 if( *pPtr
<= nWhich
&& nWhich
<= *(pPtr
+1) )
290 ppFnd
+= nWhich
- *pPtr
;
293 // Due to the assertions in the sub calls, we need to do the following
295 const SfxPoolItem
*pItemToClear
= *ppFnd
;
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
);
317 ppFnd
+= *(pPtr
+1) - *pPtr
+ 1;
325 sal_uInt16
* pPtr
= m_pWhichRanges
;
328 for( nWhich
= *pPtr
; nWhich
<= *(pPtr
+1); ++nWhich
, ++ppFnd
)
331 // Due to the assertions in the sub calls, we need to do this
333 const SfxPoolItem
*pItemToClear
= *ppFnd
;
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
);
348 // Take care of disabled items, too.
349 if (!pItemToClear
->m_nWhich
)
351 // item is disabled, delete it
356 // remove item from pool
357 m_pPool
->Remove( *pItemToClear
);
367 void SfxItemSet::ClearInvalidItems()
369 sal_uInt16
* pPtr
= m_pWhichRanges
;
370 SfxPoolItem
const** ppFnd
= m_pItems
.get();
373 for( sal_uInt16 nWhich
= *pPtr
; nWhich
<= *(pPtr
+1); ++nWhich
, ++ppFnd
)
374 if( IsInvalidItem(*ppFnd
) )
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
,
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
;
405 if ( *pPtr
<= nWhich
&& nWhich
<= *(pPtr
+1) )
408 ppFnd
+= nWhich
- *pPtr
;
411 eRet
= SfxItemState::DEFAULT
;
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
;
428 return SfxItemState::SET
;
430 ppFnd
+= *(pPtr
+1) - *pPtr
+ 1;
434 } while (bSrchInParent
&& nullptr != (pCurrentSet
= pCurrentSet
->m_pParent
));
438 bool SfxItemSet::HasItem(sal_uInt16 nWhich
, const SfxPoolItem
** ppItem
) const
440 bool bRet
= SfxItemState::SET
== GetItemState(nWhich
, true, ppItem
);
446 const SfxPoolItem
* SfxItemSet::PutImpl( const SfxPoolItem
& rItem
, sal_uInt16 nWhich
, bool bPassingOwnership
)
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
;
458 if( *pPtr
<= nWhich
&& nWhich
<= *(pPtr
+1) )
461 ppFnd
+= nWhich
- *pPtr
;
462 if( *ppFnd
) // Already one present
464 // Same Item already present?
465 if ( *ppFnd
== &rItem
)
467 assert(!bPassingOwnership
);
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);
483 // Turns into disabled?
486 if (IsInvalidItem(*ppFnd
) || (*ppFnd
)->Which() != 0) {
487 *ppFnd
= rItem
.Clone(m_pPool
);
489 if (bPassingOwnership
)
495 // Same value already present?
496 if ( rItem
== **ppFnd
)
498 if (bPassingOwnership
)
503 // Add the new one, remove the old one
504 const SfxPoolItem
& rNew
= m_pPool
->PutImpl( rItem
, nWhich
, bPassingOwnership
);
505 const SfxPoolItem
* pOld
= *ppFnd
;
507 if (SfxItemPool::IsWhich(nWhich
))
508 Changed( *pOld
, rNew
);
509 m_pPool
->Remove( *pOld
);
517 *ppFnd
= rItem
.Clone(m_pPool
);
518 if (bPassingOwnership
)
523 const SfxPoolItem
& rNew
= m_pPool
->PutImpl( rItem
, nWhich
, bPassingOwnership
);
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 &&
537 "svl.items", "putted Item unequal, with ID/pos " << nWhich
);
540 ppFnd
+= *(pPtr
+1) - *pPtr
+ 1;
543 if (bPassingOwnership
)
548 bool SfxItemSet::Put( const SfxItemSet
& rSet
, bool bInvalidAsDefault
)
553 SfxPoolItem
const** ppFnd
= rSet
.m_pItems
.get();
554 const sal_uInt16
* pPtr
= rSet
.m_pWhichRanges
;
557 for ( sal_uInt16 nWhich
= *pPtr
; nWhich
<= *(pPtr
+1); ++nWhich
, ++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 );
567 InvalidateItem( nWhich
);
570 bRet
|= nullptr != Put( **ppFnd
, nWhich
);
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
;
605 for ( sal_uInt16 nWhich
= *pPtr
; nWhich
<= *(pPtr
+1); ++nWhich
, ++ppFnd
)
608 if ( IsInvalidItem( *ppFnd
) )
611 switch ( eDontCareAs
)
613 case SfxItemState::SET
:
614 Put( rSet
.GetPool()->GetDefaultItem(nWhich
), nWhich
);
617 case SfxItemState::DEFAULT
:
621 case SfxItemState::DONTCARE
:
622 InvalidateItem( nWhich
);
626 assert(!"invalid Argument for eDontCareAs");
631 Put( **ppFnd
, nWhich
);
636 switch ( eDefaultAs
)
638 case SfxItemState::SET
:
639 Put( rSet
.GetPool()->GetDefaultItem(nWhich
), nWhich
);
642 case SfxItemState::DEFAULT
:
646 case SfxItemState::DONTCARE
:
647 InvalidateItem( nWhich
);
651 assert(!"invalid Argument for eDefaultAs");
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
) )
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
676 !pRange
[2] || (pRange
[2] > pRange
[1] && pRange
[2] - pRange
[1] > 1));
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);
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
));
692 // insert current range
693 aRangesTable
.emplace_back(std::pair
<sal_uInt16
, sal_uInt16
>(m_pWhichRanges
[i
], m_pWhichRanges
[i
+1]));
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
);
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
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
)
737 if (m_pWhichRanges
== pNewRanges
)
739 const sal_uInt16
* pOld
= m_pWhichRanges
;
740 const sal_uInt16
* pNew
= pNewRanges
;
741 while ( *pOld
== *pNew
)
743 if ( !*pOld
&& !*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;
754 memset( aNewItems
, 0, nSize
* sizeof( SfxPoolItem
* ) );
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
769 aNewItems
[n
]->AddRef();
771 else if ( SfxItemState::DISABLED
== eState
)
773 // put "disabled" item
775 aNewItems
[n
] = new SfxVoidItem(0);
777 else if ( SfxItemState::DONTCARE
== eState
)
780 aNewItems
[n
] = INVALID_POOL_ITEM
;
785 aNewItems
[n
] = nullptr;
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
);
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
825 * SfxPoolItems in rSet, for which holds 'IsInvalidItem() == true' are
826 * taken over as invalid items.
829 * SfxPoolItems have been taken over
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
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
849 The SfxPoolItems from the parents of
850 rSet are not taken into account */
858 SfxWhichIter
aIter(*this);
859 sal_uInt16 nWhich
= aIter
.FirstWhich();
862 const SfxPoolItem
* pItem
;
863 if( SfxItemState::SET
== rSet
.GetItemState( nWhich
, true, &pItem
) )
864 bRet
|= nullptr != Put( *pItem
, pItem
->Which() );
865 nWhich
= aIter
.NextWhich();
869 bRet
= Put(rSet
, false);
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
);
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
;
902 if( *pPtr
<= nWhich
&& nWhich
<= *(pPtr
+1) )
905 ppFnd
+= nWhich
- *pPtr
;
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);
913 return m_pPool
->GetDefaultItem( nWhich
);
916 const SfxPoolItem
*pItem
= *ppFnd
;
917 if ( pItem
->IsVoidItem() || !pItem
->Which() )
918 SAL_INFO("svl.items", "SFX_WARNING: Getting disabled Item");
922 break; // Continue with Parent
924 ppFnd
+= *(pPtr
+1) - *pPtr
+ 1;
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?
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
);
940 * Notification callback
942 void SfxItemSet::Changed( const SfxPoolItem
&, const SfxPoolItem
& )
946 sal_uInt16
SfxItemSet::TotalCount() const
949 sal_uInt16
* pPtr
= m_pWhichRanges
;
952 nRet
+= ( *(pPtr
+1) - *pPtr
) + 1;
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?
968 // Delete all Items not contained in rSet
971 ClearItem(); // Delete everything
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
)
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
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
)
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
);
1020 SfxItemIter
aIter( *this );
1021 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
1024 sal_uInt16 nWhich
= IsInvalidItem( pItem
)
1025 ? GetWhichByPos( aIter
.GetCurPos() )
1027 if( SfxItemState::UNKNOWN
== rSet
.GetItemState( nWhich
, false ) )
1028 ClearItem( nWhich
); // Delete
1029 if( aIter
.IsAtEnd() )
1031 pItem
= aIter
.NextItem();
1036 void SfxItemSet::Differentiate( const SfxItemSet
& rSet
)
1038 if( !Count() || !rSet
.Count() )// None set?
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
)
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
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
)
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
);
1086 SfxItemIter
aIter( *this );
1087 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
1090 sal_uInt16 nWhich
= IsInvalidItem( pItem
)
1091 ? GetWhichByPos( aIter
.GetCurPos() )
1093 if( SfxItemState::SET
== rSet
.GetItemState( nWhich
, false ) )
1094 ClearItem( nWhich
); // Delete
1095 if( aIter
.IsAtEnd() )
1097 pItem
= aIter
.NextItem();
1104 * Decision table for MergeValue(s)
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?
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
);
1208 else if ( !IsInvalidItem(*ppFnd1
) )
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
;
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
)
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!
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*/);
1278 SfxWhichIter
aIter( rSet
);
1280 while( 0 != ( nWhich
= aIter
.NextWhich() ) )
1282 const SfxPoolItem
* pItem
= nullptr;
1283 (void)rSet
.GetItemState( nWhich
, true, &pItem
);
1286 // Not set, so default
1287 MergeValue( rSet
.GetPool()->GetDefaultItem( nWhich
) );
1289 else if( IsInvalidItem( pItem
) )
1291 InvalidateItem( nWhich
);
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();
1306 if( *pPtr
<= nWhich
&& nWhich
<= *(pPtr
+1) )
1308 ppFnd
+= nWhich
- *pPtr
;
1309 MergeItem_Impl(m_pPool
, m_nCount
, ppFnd
, &rAttr
, bIgnoreDefaults
);
1312 ppFnd
+= *(pPtr
+1) - *pPtr
+ 1;
1317 void SfxItemSet::InvalidateItem( sal_uInt16 nWhich
)
1319 SfxPoolItem
const** ppFnd
= m_pItems
.get();
1320 const sal_uInt16
* pPtr
= m_pWhichRanges
;
1323 if( *pPtr
<= nWhich
&& nWhich
<= *(pPtr
+1) )
1326 ppFnd
+= nWhich
- *pPtr
;
1328 if( *ppFnd
) // Set for me
1330 if( !IsInvalidItem(*ppFnd
) )
1332 m_pPool
->Remove( **ppFnd
);
1333 *ppFnd
= INVALID_POOL_ITEM
;
1338 *ppFnd
= INVALID_POOL_ITEM
;
1343 ppFnd
+= *(pPtr
+1) - *pPtr
+ 1;
1348 sal_uInt16
SfxItemSet::GetWhichByPos( sal_uInt16 nPos
) const
1351 sal_uInt16
* pPtr
= m_pWhichRanges
;
1354 n
= ( *(pPtr
+1) - *pPtr
) + 1;
1356 return *pPtr
+ nPos
;
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() )
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
)
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();
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
) ) ) )
1413 // Are all pointers the same?
1414 if (0 == memcmp( m_pItems
.get(), rCmp
.m_pItems
.get(), nCount1
* sizeof(m_pItems
[0]) ))
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
1424 if ( *ppItem1
!= *ppItem2
&&
1425 ( ( !*ppItem1
|| !*ppItem2
) ||
1426 ( IsInvalidItem(*ppItem1
) || IsInvalidItem(*ppItem2
) ) ||
1427 (!bDifferentPools
&& m_pPool
->IsItemPoolable(**ppItem1
)) ||
1428 **ppItem1
!= **ppItem2
) )
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
));
1445 SfxWhichIter
aIter(*pNewSet
);
1446 sal_uInt16 nWhich
= aIter
.FirstWhich();
1449 const SfxPoolItem
* pItem
;
1450 if ( SfxItemState::SET
== GetItemState( nWhich
, false, &pItem
) )
1451 pNewSet
->Put( *pItem
, pItem
->Which() );
1452 nWhich
= aIter
.NextWhich();
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();
1469 IsPoolDefaultItem(&rItem
) || m_pPool
->CheckItemInPool(&rItem
);
1470 // Only cause assertion in the callees
1474 if( *pPtr
<= nWhich
&& nWhich
<= *(pPtr
+1) )
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
);
1489 if( IsPoolDefaultItem(&rItem
) )
1490 *ppFnd
= &m_pPool
->Put( rItem
);
1494 if( !IsStaticDefaultItem( &rItem
) )
1500 ppFnd
+= *(pPtr
+1) - *pPtr
+ 1;
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),
1521 // Initially no Items
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
),
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
),
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
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
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?
1585 // Copy all Items before 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
;
1613 // WhichId is within this Range?
1614 if( *pPtr
<= nWhich
&& nWhich
<= *(pPtr
+1) )
1617 nPos
+= nWhich
- *pPtr
;
1621 // Carry over the position of the Item in m_pItems
1622 nPos
+= *(pPtr
+1) - *pPtr
+ 1;
1624 // To the next Range
1628 // WhichId not yet present?
1631 // Let's see if we can attach it somewhere
1632 pPtr
= m_pWhichRanges
;
1636 // WhichId is right before this Range?
1637 if ( (nWhich
+1) == *pPtr
)
1639 // Range grows downwards
1642 // Make room before first Item of this Range
1643 AddItem_Impl(m_pItems
, nItemCount
, nPos
);
1647 // WhichId is right after this Range?
1648 else if ( (nWhich
-1) == *(pPtr
+1) )
1650 // Range grows upwards?
1653 // Make room after last Item of this Range
1654 nPos
+= nWhich
- *pPtr
;
1655 AddItem_Impl(m_pItems
, nItemCount
, nPos
);
1659 // Carry over position of the Item in m_pItems
1660 nPos
+= *(pPtr
+1) - *pPtr
+ 1;
1662 // To the next Range
1667 // No extensible Range found?
1670 // No room left in m_pWhichRanges? => Expand!
1671 std::ptrdiff_t nSize
= pPtr
- m_pWhichRanges
;
1674 m_pWhichRanges
= AddRanges_Impl(m_pWhichRanges
, nSize
, nInitCount
);
1675 nFree
+= nInitCount
;
1678 // Attach new WhichRange
1679 pPtr
= m_pWhichRanges
+ nSize
;
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"
1699 bIncrementCount
= true;
1701 ? &m_pParent
->Get( nWhich
)
1702 : (SfxItemPool::IsWhich(nWhich
)
1703 ? &m_pPool
->GetDefaultItem(nWhich
)
1707 // Add new Item to ItemSet
1708 m_pItems
[nPos
] = &rNew
;
1710 // Send Changed Notification
1713 Changed( *pOld
, rNew
);
1714 if ( !IsDefaultItem(pOld
) )
1715 m_pPool
->Remove( *pOld
);
1718 if ( bIncrementCount
)
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
));
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
1743 return std::unique_ptr
<SfxItemSet
>(bItems
? new SfxAllItemSet(*this) : new SfxAllItemSet(*m_pPool
));
1746 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */