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/setitem.hxx>
34 #include <svl/whiter.hxx>
36 #include <items_helper.hxx>
39 * Ctor for a SfxItemSet with exactly the Which Ranges, which are known to
40 * the supplied SfxItemPool.
42 * For Sfx programmers: an SfxItemSet constructed in this way cannot
43 * contain any Items with SlotIds as Which values.
45 * Don't create ItemSets with full range before FreezeIdRanges()!
47 SfxItemSet::SfxItemSet(SfxItemPool
& rPool
)
48 : SfxItemSet(rPool
, rPool
.GetFrozenIdRanges())
52 SfxItemSet::SfxItemSet( SfxItemPool
& rPool
, SfxAllItemSetFlag
)
57 , m_bItemsFixed(false)
61 /** special constructor for SfxItemSetFixed */
62 SfxItemSet::SfxItemSet( SfxItemPool
& rPool
, WhichRangesContainer
&& ranges
, SfxPoolItem
const ** ppItems
)
66 , m_pWhichRanges(std::move(ranges
))
71 assert(m_pWhichRanges
.size() > 0);
72 assert(svl::detail::validRanges2(m_pWhichRanges
));
75 SfxItemSet::SfxItemSet(
77 const WhichRangesContainer
& wids
,
79 m_pPool(&pool
), m_pParent(nullptr),
80 m_ppItems(new SfxPoolItem
const *[items
]{}),
85 assert(wids
.size() != 0);
86 assert(svl::detail::validRanges2(m_pWhichRanges
));
89 SfxItemSet::SfxItemSet(SfxItemPool
& pool
, const WhichRangesContainer
& wids
)
90 : SfxItemSet(pool
, wids
, svl::detail::CountRanges(wids
))
94 SfxItemSet::SfxItemSet(SfxItemPool
& pool
, WhichRangesContainer
&& wids
)
95 : SfxItemSet(pool
, wids
, svl::detail::CountRanges(wids
))
99 SfxItemSet::SfxItemSet( const SfxItemSet
& rASet
)
100 : m_pPool( rASet
.m_pPool
)
101 , m_pParent( rASet
.m_pParent
)
102 , m_pWhichRanges( rASet
.m_pWhichRanges
)
103 , m_nCount( rASet
.m_nCount
)
104 , m_bItemsFixed(false)
106 if (rASet
.m_pWhichRanges
.empty())
112 auto nCnt
= svl::detail::CountRanges(m_pWhichRanges
);
113 m_ppItems
= new const SfxPoolItem
* [nCnt
] {};
116 SfxPoolItem
const** ppDst
= m_ppItems
;
117 SfxPoolItem
const** ppSrc
= rASet
.m_ppItems
;
118 for( sal_uInt16 n
= nCnt
; n
; --n
, ++ppDst
, ++ppSrc
)
119 if ( nullptr == *ppSrc
|| // Current Default?
120 IsInvalidItem(*ppSrc
) || // DontCare?
121 IsStaticDefaultItem(*ppSrc
) ) // Defaults that are not to be pooled?
122 // Just copy the pointer
124 else if (m_pPool
->IsItemPoolable( **ppSrc
))
126 // Just copy the pointer and increase RefCount
130 else if ( !(*ppSrc
)->Which() )
131 *ppDst
= (*ppSrc
)->Clone();
133 // !IsPoolable() => assign via Pool
134 *ppDst
= &m_pPool
->Put( **ppSrc
);
136 assert(svl::detail::validRanges2(m_pWhichRanges
));
139 SfxItemSet::SfxItemSet(SfxItemSet
&& rASet
) noexcept
140 : m_pPool( rASet
.m_pPool
)
141 , m_pParent( rASet
.m_pParent
)
142 , m_ppItems( rASet
.m_ppItems
)
143 , m_pWhichRanges( std::move(rASet
.m_pWhichRanges
) )
144 , m_nCount( rASet
.m_nCount
)
145 , m_bItemsFixed(false)
147 if (rASet
.m_bItemsFixed
)
149 // have to make a copy
150 int noItems
= svl::detail::CountRanges(m_pWhichRanges
);
151 m_ppItems
= new const SfxPoolItem
* [noItems
];
152 std::copy(rASet
.m_ppItems
, rASet
.m_ppItems
+ noItems
, m_ppItems
);
155 // taking over ownership
156 rASet
.m_ppItems
= nullptr;
157 rASet
.m_pPool
= nullptr;
158 rASet
.m_pParent
= nullptr;
160 assert(svl::detail::validRanges2(m_pWhichRanges
));
163 SfxItemSet::~SfxItemSet()
165 if (!m_pWhichRanges
.empty()) // might be nullptr if we have been moved-from
167 sal_uInt16 nCount
= TotalCount();
170 SfxPoolItem
const** ppFnd
= m_ppItems
;
171 for( sal_uInt16 nCnt
= nCount
; nCnt
; --nCnt
, ++ppFnd
)
172 if( *ppFnd
&& !IsInvalidItem(*ppFnd
) )
174 if( !(*ppFnd
)->Which() )
177 // Still multiple references present, so just alter the RefCount
178 if ( 1 < (*ppFnd
)->GetRefCount() && !IsDefaultItem(*ppFnd
) )
179 (*ppFnd
)->ReleaseRef();
181 if ( !IsDefaultItem(*ppFnd
) )
183 m_pPool
->Remove( **ppFnd
);
191 m_pWhichRanges
.reset(); // for invariant-testing
195 * Delete single Items or all Items (nWhich == 0)
197 sal_uInt16
SfxItemSet::ClearItem( sal_uInt16 nWhich
)
203 SfxPoolItem
const** ppFnd
= m_ppItems
;
207 for (const WhichPair
& rPair
: m_pWhichRanges
)
209 // Within this range?
210 if( rPair
.first
<= nWhich
&& nWhich
<= rPair
.second
)
213 ppFnd
+= nWhich
- rPair
.first
;
216 // Due to the assertions in the sub calls, we need to do the following
218 const SfxPoolItem
*pItemToClear
= *ppFnd
;
221 if ( !IsInvalidItem(pItemToClear
) )
223 if (SfxItemPool::IsWhich(nWhich
))
225 const SfxPoolItem
& rNew
= m_pParent
226 ? m_pParent
->Get( nWhich
)
227 : m_pPool
->GetDefaultItem( nWhich
);
229 Changed( *pItemToClear
, rNew
);
231 if ( pItemToClear
->Which() )
232 m_pPool
->Remove( *pItemToClear
);
240 ppFnd
+= rPair
.second
- rPair
.first
+ 1;
247 for (const WhichPair
& rPair
: m_pWhichRanges
)
249 for( nWhich
= rPair
.first
; nWhich
<= rPair
.second
; ++nWhich
, ++ppFnd
)
252 // Due to the assertions in the sub calls, we need to do this
254 const SfxPoolItem
*pItemToClear
= *ppFnd
;
257 if ( !IsInvalidItem(pItemToClear
) )
259 if (SfxItemPool::IsWhich(nWhich
))
261 const SfxPoolItem
& rNew
= m_pParent
262 ? m_pParent
->Get( nWhich
)
263 : m_pPool
->GetDefaultItem( nWhich
);
265 Changed( *pItemToClear
, rNew
);
269 // Take care of disabled items, too.
270 if (!pItemToClear
->m_nWhich
)
272 // item is disabled, delete it
277 // remove item from pool
278 m_pPool
->Remove( *pItemToClear
);
287 void SfxItemSet::ClearInvalidItems()
289 SfxPoolItem
const** ppFnd
= m_ppItems
;
290 for (const WhichPair
& rPair
: m_pWhichRanges
)
292 for( sal_uInt16 nWhich
= rPair
.first
; nWhich
<= rPair
.second
; ++nWhich
, ++ppFnd
)
293 if( IsInvalidItem(*ppFnd
) )
301 void SfxItemSet::InvalidateAllItems()
303 assert( !m_nCount
&& "There are still Items set" );
304 m_nCount
= TotalCount();
305 memset(static_cast<void*>(m_ppItems
), -1, m_nCount
* sizeof(SfxPoolItem
*));
308 SfxItemState
SfxItemSet::GetItemState( sal_uInt16 nWhich
,
310 const SfxPoolItem
**ppItem
) const
312 // Find the range in which the Which is located
313 const SfxItemSet
* pCurrentSet
= this;
314 SfxItemState eRet
= SfxItemState::UNKNOWN
;
317 SfxPoolItem
const** ppFnd
= pCurrentSet
->m_ppItems
;
318 for (const WhichPair
& rPair
: pCurrentSet
->m_pWhichRanges
)
320 if ( rPair
.first
<= nWhich
&& nWhich
<= rPair
.second
)
323 ppFnd
+= nWhich
- rPair
.first
;
326 eRet
= SfxItemState::DEFAULT
;
328 return eRet
; // Not present
329 break; // Keep searching in the parents!
332 if ( IsInvalidItem(*ppFnd
) )
333 // Different ones are present
334 return SfxItemState::DONTCARE
;
336 if ( (*ppFnd
)->IsVoidItem() )
337 return SfxItemState::DISABLED
;
343 return SfxItemState::SET
;
345 ppFnd
+= rPair
.second
- rPair
.first
+ 1;
349 pCurrentSet
= pCurrentSet
->m_pParent
;
350 } while (nullptr != pCurrentSet
);
354 bool SfxItemSet::HasItem(sal_uInt16 nWhich
, const SfxPoolItem
** ppItem
) const
356 bool bRet
= SfxItemState::SET
== GetItemState(nWhich
, true, ppItem
);
362 const SfxPoolItem
* SfxItemSet::PutImpl( const SfxPoolItem
& rItem
, sal_uInt16 nWhich
, bool bPassingOwnership
)
366 assert(!bPassingOwnership
);
367 return nullptr; //FIXME: Only because of Outliner bug
370 SfxPoolItem
const** ppFnd
= m_ppItems
;
371 for (const WhichPair
& rPair
: m_pWhichRanges
)
373 if( rPair
.first
<= nWhich
&& nWhich
<= rPair
.second
)
376 ppFnd
+= nWhich
- rPair
.first
;
377 if( *ppFnd
) // Already one present
379 // Same Item already present?
380 if ( *ppFnd
== &rItem
)
382 assert(!bPassingOwnership
);
386 // Will 'dontcare' or 'disabled' be overwritten with some real value?
387 if ( rItem
.Which() && ( IsInvalidItem(*ppFnd
) || !(*ppFnd
)->Which() ) )
389 auto const old
= *ppFnd
;
390 *ppFnd
= &m_pPool
->PutImpl( rItem
, nWhich
, bPassingOwnership
);
391 if (!IsInvalidItem(old
)) {
392 assert(old
->Which() == 0);
398 // Turns into disabled?
401 if (IsInvalidItem(*ppFnd
) || (*ppFnd
)->Which() != 0) {
402 *ppFnd
= rItem
.Clone(m_pPool
);
404 if (bPassingOwnership
)
410 // Same value already present?
411 if ( rItem
== **ppFnd
)
413 if (bPassingOwnership
)
418 // Add the new one, remove the old one
419 const SfxPoolItem
& rNew
= m_pPool
->PutImpl( rItem
, nWhich
, bPassingOwnership
);
420 const SfxPoolItem
* pOld
= *ppFnd
;
422 if (SfxItemPool::IsWhich(nWhich
))
423 Changed( *pOld
, rNew
);
424 m_pPool
->Remove( *pOld
);
432 *ppFnd
= rItem
.Clone(m_pPool
);
433 if (bPassingOwnership
)
438 const SfxPoolItem
& rNew
= m_pPool
->PutImpl( rItem
, nWhich
, bPassingOwnership
);
440 if (SfxItemPool::IsWhich(nWhich
))
442 const SfxPoolItem
& rOld
= m_pParent
443 ? m_pParent
->Get( nWhich
)
444 : m_pPool
->GetDefaultItem( nWhich
);
445 Changed( rOld
, rNew
);
449 SAL_WARN_IF(!bPassingOwnership
&& m_pPool
->IsItemPoolable(nWhich
) &&
450 dynamic_cast<const SfxSetItem
*>( &rItem
) == nullptr &&
452 "svl.items", "putted Item unequal, with ID/pos " << nWhich
);
455 ppFnd
+= rPair
.second
- rPair
.first
+ 1;
457 if (bPassingOwnership
)
462 bool SfxItemSet::Put( const SfxItemSet
& rSet
, bool bInvalidAsDefault
)
467 SfxPoolItem
const** ppFnd
= rSet
.m_ppItems
;
468 for (const WhichPair
& rPair
: rSet
.m_pWhichRanges
)
470 for ( sal_uInt16 nWhich
= rPair
.first
; nWhich
<= rPair
.second
; ++nWhich
, ++ppFnd
)
473 if ( IsInvalidItem( *ppFnd
) )
475 if ( bInvalidAsDefault
)
476 bRet
|= 0 != ClearItem( nWhich
);
477 // FIXME: Caused a SEGFAULT on non Windows-platforms:
478 // bRet |= 0 != Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
480 InvalidateItem( nWhich
);
483 bRet
|= nullptr != Put( **ppFnd
, nWhich
);
491 * This method takes the Items from the 'rSet' and adds to '*this'.
492 * Which ranges in '*this' that are non-existent in 'rSet' will not
493 * be altered. The Which range of '*this' is also not changed.
495 * Items set in 'rSet' are also set in '*this'.
496 * Default (0 pointer) and Invalid (-1 pointer) Items are processed
497 * according to their parameter 'eDontCareAs' and 'eDefaultAs':
499 * SfxItemState::SET: Hard set to the default of the Pool
500 * SfxItemState::DEFAULT: Deleted (0 pointer)
501 * SfxItemState::DONTCARE: Invalid (-1 pointer)
503 * NB: All other values for 'eDontCareAs' and 'eDefaultAs' are invalid
505 void SfxItemSet::PutExtended
507 const SfxItemSet
& rSet
, // Source of the Items to be put
508 SfxItemState eDontCareAs
, // What will happen to the DontCare Items
509 SfxItemState eDefaultAs
// What will happen to the Default Items
512 // don't "optimize" with "if( rSet.Count()" because of dont-care + defaults
513 SfxPoolItem
const** ppFnd
= rSet
.m_ppItems
;
514 for (const WhichPair
& rPair
: rSet
.m_pWhichRanges
)
516 for ( sal_uInt16 nWhich
= rPair
.first
; nWhich
<= rPair
.second
; ++nWhich
, ++ppFnd
)
519 if ( IsInvalidItem( *ppFnd
) )
522 switch ( eDontCareAs
)
524 case SfxItemState::SET
:
525 Put( rSet
.GetPool()->GetDefaultItem(nWhich
), nWhich
);
528 case SfxItemState::DEFAULT
:
532 case SfxItemState::DONTCARE
:
533 InvalidateItem( nWhich
);
537 assert(!"invalid Argument for eDontCareAs");
542 Put( **ppFnd
, nWhich
);
547 switch ( eDefaultAs
)
549 case SfxItemState::SET
:
550 Put( rSet
.GetPool()->GetDefaultItem(nWhich
), nWhich
);
553 case SfxItemState::DEFAULT
:
557 case SfxItemState::DONTCARE
:
558 InvalidateItem( nWhich
);
562 assert(!"invalid Argument for eDefaultAs");
569 * Expands the ranges of settable items by 'nFrom' to 'nTo'. Keeps state of
570 * items which are new ranges too.
572 void SfxItemSet::MergeRange( sal_uInt16 nFrom
, sal_uInt16 nTo
)
574 // special case: exactly one sal_uInt16 which is already included?
576 if (SfxItemState eItemState
= GetItemState(nFrom
, false);
577 eItemState
== SfxItemState::DEFAULT
|| eItemState
== SfxItemState::SET
)
580 auto pNewRanges
= m_pWhichRanges
.MergeRange(nFrom
, nTo
);
581 RecreateRanges_Impl(pNewRanges
);
582 m_pWhichRanges
= std::move(pNewRanges
);
586 * Modifies the ranges of settable items. Keeps state of items which
587 * are new ranges too.
589 void SfxItemSet::SetRanges( const WhichRangesContainer
& pNewRanges
)
592 if (m_pWhichRanges
== pNewRanges
)
594 assert(svl::detail::validRanges2(pNewRanges
));
595 RecreateRanges_Impl(pNewRanges
);
596 m_pWhichRanges
= pNewRanges
;
599 void SfxItemSet::SetRanges( WhichRangesContainer
&& pNewRanges
)
602 if (m_pWhichRanges
== pNewRanges
)
604 assert(svl::detail::validRanges2(pNewRanges
));
605 RecreateRanges_Impl(pNewRanges
);
606 m_pWhichRanges
= std::move(pNewRanges
);
609 void SfxItemSet::RecreateRanges_Impl(const WhichRangesContainer
& pNewRanges
)
611 // create new item-array (by iterating through all new ranges)
612 const auto nSize
= svl::detail::CountRanges(pNewRanges
);
613 SfxPoolItem
const** aNewItems
= new const SfxPoolItem
* [ nSize
];
614 sal_uInt16 nNewCount
= 0;
616 memset( aNewItems
, 0, nSize
* sizeof( SfxPoolItem
* ) );
620 for ( auto const & pRange
: pNewRanges
)
622 // iterate through all ids in the range
623 for ( sal_uInt16 nWID
= pRange
.first
; nWID
<= pRange
.second
; ++nWID
, ++n
)
625 // direct move of pointer (not via pool)
626 SfxItemState eState
= GetItemState( nWID
, false, aNewItems
+n
);
627 if ( SfxItemState::SET
== eState
)
629 // increment new item count and possibly increment ref count
631 aNewItems
[n
]->AddRef();
633 else if ( SfxItemState::DISABLED
== eState
)
635 // put "disabled" item
637 aNewItems
[n
] = new SfxVoidItem(0);
639 else if ( SfxItemState::DONTCARE
== eState
)
642 aNewItems
[n
] = INVALID_POOL_ITEM
;
647 aNewItems
[n
] = nullptr;
652 sal_uInt16 nOldTotalCount
= TotalCount();
653 for ( sal_uInt16 nItem
= 0; nItem
< nOldTotalCount
; ++nItem
)
655 const SfxPoolItem
*pItem
= m_ppItems
[nItem
];
656 if ( pItem
&& !IsInvalidItem(pItem
) && pItem
->Which() )
657 m_pPool
->Remove(*pItem
);
661 // replace old items-array and ranges
663 m_bItemsFixed
= false;
666 m_ppItems
= aNewItems
;
667 m_nCount
= nNewCount
;
671 * The SfxItemSet takes over exactly those SfxPoolItems that are
672 * set in rSet and are in their own Which range. All others are removed.
673 * The SfxItemPool is retained, such that SfxPoolItems that have been
674 * taken over, are moved from the rSet's SfxItemPool to the SfxItemPool
677 * SfxPoolItems in rSet, for which holds 'IsInvalidItem() == true' are
678 * taken over as invalid items.
681 * SfxPoolItems have been taken over
684 * No SfxPoolItems have been taken over, because
685 * e.g. the Which ranges of SfxItemSets are not intersecting
686 * or the intersection does not contain SfxPoolItems that are
691 const SfxItemSet
& rSet
, /* The SfxItemSet, whose SfxPoolItems are
692 to been taken over */
694 bool bDeep
/* true (default)
696 The SfxPoolItems from the parents that may
697 be present in rSet, are also taken over into
701 The SfxPoolItems from the parents of
702 rSet are not taken into account */
710 SfxWhichIter
aIter(*this);
711 sal_uInt16 nWhich
= aIter
.FirstWhich();
714 const SfxPoolItem
* pItem
;
715 if( SfxItemState::SET
== rSet
.GetItemState( nWhich
, true, &pItem
) )
716 bRet
|= nullptr != Put( *pItem
, pItem
->Which() );
717 nWhich
= aIter
.NextWhich();
721 bRet
= Put(rSet
, false);
726 const SfxPoolItem
* SfxItemSet::GetItem(sal_uInt16 nId
, bool bSearchInParent
) const
728 // Convert to WhichId
729 sal_uInt16 nWhich
= GetPool()->GetWhich(nId
);
731 // Is the Item set or 'bDeep == true' available?
732 const SfxPoolItem
*pItem
= nullptr;
733 SfxItemState eState
= GetItemState(nWhich
, bSearchInParent
, &pItem
);
734 if (bSearchInParent
&& SfxItemState::DEFAULT
== eState
&& SfxItemPool::IsWhich(nWhich
))
736 pItem
= &m_pPool
->GetDefaultItem(nWhich
);
742 const SfxPoolItem
& SfxItemSet::Get( sal_uInt16 nWhich
, bool bSrchInParent
) const
744 // Search the Range in which the Which is located in:
745 const SfxItemSet
* pCurrentSet
= this;
748 if( pCurrentSet
->Count() )
750 SfxPoolItem
const** ppFnd
= pCurrentSet
->m_ppItems
;
751 for (auto const & pPtr
: pCurrentSet
->m_pWhichRanges
)
753 if( pPtr
.first
<= nWhich
&& nWhich
<= pPtr
.second
)
756 ppFnd
+= nWhich
- pPtr
.first
;
759 if( IsInvalidItem(*ppFnd
) ) {
760 //FIXME: The following code is duplicated further down
762 //!((SfxAllItemSet *)this)->aDefault.SetWhich(nWhich);
764 return m_pPool
->GetDefaultItem( nWhich
);
767 const SfxPoolItem
*pItem
= *ppFnd
;
768 if ( pItem
->IsVoidItem() || !pItem
->Which() )
769 SAL_INFO("svl.items", "SFX_WARNING: Getting disabled Item");
773 break; // Continue with Parent
775 ppFnd
+= pPtr
.second
- pPtr
.first
+ 1;
778 //TODO: Search until end of Range: What are we supposed to do now? To the Parent or Default??
779 // if( !*pPtr ) // Until the end of the search Range?
783 pCurrentSet
= pCurrentSet
->m_pParent
;
784 } while (nullptr != pCurrentSet
);
786 // Get the Default from the Pool and return
788 return m_pPool
->GetDefaultItem( nWhich
);
792 * Notification callback
794 void SfxItemSet::Changed( const SfxPoolItem
&, const SfxPoolItem
& )
798 sal_uInt16
SfxItemSet::TotalCount() const
800 return svl::detail::CountRanges(m_pWhichRanges
);
804 * Only retain the Items that are also present in rSet
805 * (nevermind their value).
807 void SfxItemSet::Intersect( const SfxItemSet
& rSet
)
809 assert(m_pPool
&& "Not implemented without Pool");
810 if( !Count() ) // None set?
813 // Delete all Items not contained in rSet
816 ClearItem(); // Delete everything
820 // If the Ranges are identical, we can easily process it
821 if( m_pWhichRanges
== rSet
.m_pWhichRanges
)
823 sal_uInt16 nSize
= TotalCount();
824 SfxPoolItem
const** ppFnd1
= m_ppItems
;
825 SfxPoolItem
const** ppFnd2
= rSet
.m_ppItems
;
827 for( ; nSize
; --nSize
, ++ppFnd1
, ++ppFnd2
)
828 if( *ppFnd1
&& !*ppFnd2
)
831 if( !IsInvalidItem( *ppFnd1
) )
833 sal_uInt16 nWhich
= (*ppFnd1
)->Which();
834 if (SfxItemPool::IsWhich(nWhich
))
836 const SfxPoolItem
& rNew
= m_pParent
837 ? m_pParent
->Get( nWhich
)
838 : m_pPool
->GetDefaultItem( nWhich
);
840 Changed( **ppFnd1
, rNew
);
842 m_pPool
->Remove( **ppFnd1
);
850 SfxItemIter
aIter( *this );
851 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
854 sal_uInt16 nWhich
= IsInvalidItem( pItem
)
855 ? GetWhichByPos( aIter
.GetCurPos() )
857 if( SfxItemState::UNKNOWN
== rSet
.GetItemState( nWhich
, false ) )
858 ClearItem( nWhich
); // Delete
859 pItem
= aIter
.NextItem();
864 void SfxItemSet::Differentiate( const SfxItemSet
& rSet
)
866 if( !Count() || !rSet
.Count() )// None set?
869 // If the Ranges are identical, we can easily process it
870 if( m_pWhichRanges
== rSet
.m_pWhichRanges
)
872 sal_uInt16 nSize
= TotalCount();
873 SfxPoolItem
const** ppFnd1
= m_ppItems
;
874 SfxPoolItem
const** ppFnd2
= rSet
.m_ppItems
;
876 for( ; nSize
; --nSize
, ++ppFnd1
, ++ppFnd2
)
877 if( *ppFnd1
&& *ppFnd2
)
880 if( !IsInvalidItem( *ppFnd1
) )
882 sal_uInt16 nWhich
= (*ppFnd1
)->Which();
883 if (SfxItemPool::IsWhich(nWhich
))
885 const SfxPoolItem
& rNew
= m_pParent
886 ? m_pParent
->Get( nWhich
)
887 : m_pPool
->GetDefaultItem( nWhich
);
889 Changed( **ppFnd1
, rNew
);
891 m_pPool
->Remove( **ppFnd1
);
899 SfxItemIter
aIter( *this );
900 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
903 sal_uInt16 nWhich
= IsInvalidItem( pItem
)
904 ? GetWhichByPos( aIter
.GetCurPos() )
906 if( SfxItemState::SET
== rSet
.GetItemState( nWhich
, false ) )
907 ClearItem( nWhich
); // Delete
908 pItem
= aIter
.NextItem();
915 * Decision table for MergeValue(s)
918 * 1. If the Which value in the 1st set is "unknown", there's never any action
919 * 2. If the Which value in the 2nd set is "unknown", it's made the "default"
920 * 3. For comparisons the values of the "default" Items are take into account
922 * 1st Item 2nd Item Values bIgnoreDefs Remove Assign Add
924 * set set == sal_False - - -
925 * default set == sal_False - - -
926 * dontcare set == sal_False - - -
927 * unknown set == sal_False - - -
928 * set default == sal_False - - -
929 * default default == sal_False - - -
930 * dontcare default == sal_False - - -
931 * unknown default == sal_False - - -
932 * set dontcare == sal_False 1st Item -1 -
933 * default dontcare == sal_False - -1 -
934 * dontcare dontcare == sal_False - - -
935 * unknown dontcare == sal_False - - -
936 * set unknown == sal_False 1st Item -1 -
937 * default unknown == sal_False - - -
938 * dontcare unknown == sal_False - - -
939 * unknown unknown == sal_False - - -
941 * set set != sal_False 1st Item -1 -
942 * default set != sal_False - -1 -
943 * dontcare set != sal_False - - -
944 * unknown set != sal_False - - -
945 * set default != sal_False 1st Item -1 -
946 * default default != sal_False - - -
947 * dontcare default != sal_False - - -
948 * unknown default != sal_False - - -
949 * set dontcare != sal_False 1st Item -1 -
950 * default dontcare != sal_False - -1 -
951 * dontcare dontcare != sal_False - - -
952 * unknown dontcare != sal_False - - -
953 * set unknown != sal_False 1st Item -1 -
954 * default unknown != sal_False - - -
955 * dontcare unknown != sal_False - - -
956 * unknown unknown != sal_False - - -
958 * set set == sal_True - - -
959 * default set == sal_True - 2nd Item 2nd Item
960 * dontcare set == sal_True - - -
961 * unknown set == sal_True - - -
962 * set default == sal_True - - -
963 * default default == sal_True - - -
964 * dontcare default == sal_True - - -
965 * unknown default == sal_True - - -
966 * set dontcare == sal_True - - -
967 * default dontcare == sal_True - -1 -
968 * dontcare dontcare == sal_True - - -
969 * unknown dontcare == sal_True - - -
970 * set unknown == sal_True - - -
971 * default unknown == sal_True - - -
972 * dontcare unknown == sal_True - - -
973 * unknown unknown == sal_True - - -
975 * set set != sal_True 1st Item -1 -
976 * default set != sal_True - 2nd Item 2nd Item
977 * dontcare set != sal_True - - -
978 * unknown set != sal_True - - -
979 * set default != sal_True - - -
980 * default default != sal_True - - -
981 * dontcare default != sal_True - - -
982 * unknown default != sal_True - - -
983 * set dontcare != sal_True 1st Item -1 -
984 * default dontcare != sal_True - -1 -
985 * dontcare dontcare != sal_True - - -
986 * unknown dontcare != sal_True - - -
987 * set unknown != sal_True - - -
988 * default unknown != sal_True - - -
989 * dontcare unknown != sal_True - - -
990 * unknown unknown != sal_True - - -
992 static void MergeItem_Impl( SfxItemPool
*_pPool
, sal_uInt16
&rCount
,
993 const SfxPoolItem
**ppFnd1
, const SfxPoolItem
*pFnd2
,
994 bool bIgnoreDefaults
)
996 assert(ppFnd1
!= nullptr && "Merging to 0-Item");
998 // 1st Item is Default?
1001 if ( IsInvalidItem(pFnd2
) )
1002 // Decision table: default, dontcare, doesn't matter, doesn't matter
1003 *ppFnd1
= INVALID_POOL_ITEM
;
1005 else if ( pFnd2
&& !bIgnoreDefaults
&&
1006 _pPool
->GetDefaultItem(pFnd2
->Which()) != *pFnd2
)
1007 // Decision table: default, set, !=, sal_False
1008 *ppFnd1
= INVALID_POOL_ITEM
;
1010 else if ( pFnd2
&& bIgnoreDefaults
)
1011 // Decision table: default, set, doesn't matter, sal_True
1012 *ppFnd1
= &_pPool
->Put( *pFnd2
);
1019 else if ( !IsInvalidItem(*ppFnd1
) )
1023 // 2nd Item is Default
1024 if ( !bIgnoreDefaults
&&
1025 **ppFnd1
!= _pPool
->GetDefaultItem((*ppFnd1
)->Which()) )
1027 // Decision table: set, default, !=, sal_False
1028 _pPool
->Remove( **ppFnd1
);
1029 *ppFnd1
= INVALID_POOL_ITEM
;
1032 else if ( IsInvalidItem(pFnd2
) )
1034 // 2nd Item is dontcare
1035 if ( !bIgnoreDefaults
||
1036 **ppFnd1
!= _pPool
->GetDefaultItem( (*ppFnd1
)->Which()) )
1038 // Decision table: set, dontcare, doesn't matter, sal_False
1039 // or: set, dontcare, !=, sal_True
1040 _pPool
->Remove( **ppFnd1
);
1041 *ppFnd1
= INVALID_POOL_ITEM
;
1047 if ( **ppFnd1
!= *pFnd2
)
1049 // Decision table: set, set, !=, doesn't matter
1050 _pPool
->Remove( **ppFnd1
);
1051 *ppFnd1
= INVALID_POOL_ITEM
;
1057 void SfxItemSet::MergeValues( const SfxItemSet
& rSet
)
1059 // WARNING! When making changes/fixing bugs, always update the table above!!
1060 assert( GetPool() == rSet
.GetPool() && "MergeValues with different Pools" );
1062 // If the Ranges match, they are easier to process!
1063 if( m_pWhichRanges
== rSet
.m_pWhichRanges
)
1065 sal_uInt16 nSize
= TotalCount();
1066 SfxPoolItem
const** ppFnd1
= m_ppItems
;
1067 SfxPoolItem
const** ppFnd2
= rSet
.m_ppItems
;
1069 for( ; nSize
; --nSize
, ++ppFnd1
, ++ppFnd2
)
1070 MergeItem_Impl(m_pPool
, m_nCount
, ppFnd1
, *ppFnd2
, false/*bIgnoreDefaults*/);
1074 SfxWhichIter
aIter( rSet
);
1076 while( 0 != ( nWhich
= aIter
.NextWhich() ) )
1078 const SfxPoolItem
* pItem
= nullptr;
1079 (void)rSet
.GetItemState( nWhich
, true, &pItem
);
1082 // Not set, so default
1083 MergeValue( rSet
.GetPool()->GetDefaultItem( nWhich
) );
1085 else if( IsInvalidItem( pItem
) )
1087 InvalidateItem( nWhich
);
1089 MergeValue( *pItem
);
1094 void SfxItemSet::MergeValue( const SfxPoolItem
& rAttr
, bool bIgnoreDefaults
)
1096 SfxPoolItem
const** ppFnd
= m_ppItems
;
1097 const sal_uInt16 nWhich
= rAttr
.Which();
1098 for( auto const & pPtr
: m_pWhichRanges
)
1101 if( pPtr
.first
<= nWhich
&& nWhich
<= pPtr
.second
)
1103 ppFnd
+= nWhich
- pPtr
.first
;
1104 MergeItem_Impl(m_pPool
, m_nCount
, ppFnd
, &rAttr
, bIgnoreDefaults
);
1107 ppFnd
+= pPtr
.second
- pPtr
.first
+ 1;
1111 void SfxItemSet::InvalidateItem( sal_uInt16 nWhich
)
1113 SfxPoolItem
const** ppFnd
= m_ppItems
;
1114 for( auto const & pPtr
: m_pWhichRanges
)
1116 if( pPtr
.first
<= nWhich
&& nWhich
<= pPtr
.second
)
1119 ppFnd
+= nWhich
- pPtr
.first
;
1121 if( *ppFnd
) // Set for me
1123 if( !IsInvalidItem(*ppFnd
) )
1125 m_pPool
->Remove( **ppFnd
);
1126 *ppFnd
= INVALID_POOL_ITEM
;
1131 *ppFnd
= INVALID_POOL_ITEM
;
1136 ppFnd
+= pPtr
.second
- pPtr
.first
+ 1;
1140 sal_uInt16
SfxItemSet::GetWhichByPos( sal_uInt16 nPos
) const
1143 for( auto const & pPtr
: m_pWhichRanges
)
1145 n
= ( pPtr
.second
- pPtr
.first
) + 1;
1147 return pPtr
.first
+ nPos
;
1154 bool SfxItemSet::operator==(const SfxItemSet
&rCmp
) const
1156 return Equals( rCmp
, true);
1159 bool SfxItemSet::Equals(const SfxItemSet
&rCmp
, bool bComparePool
) const
1161 // Values we can get quickly need to be the same
1162 const bool bDifferentPools
= (m_pPool
!= rCmp
.m_pPool
);
1163 if ( (bComparePool
&& m_pParent
!= rCmp
.m_pParent
) ||
1164 (bComparePool
&& bDifferentPools
) ||
1165 Count() != rCmp
.Count() )
1168 // If we reach here and bDifferentPools==true that means bComparePool==false.
1170 // Counting Ranges takes longer; they also need to be the same, however
1171 sal_uInt16 nCount1
= TotalCount();
1172 sal_uInt16 nCount2
= rCmp
.TotalCount();
1173 if ( nCount1
!= nCount2
)
1176 // Are the Ranges themselves unequal?
1177 for (sal_Int32 i
= 0; i
< m_pWhichRanges
.size(); ++i
)
1179 if (m_pWhichRanges
[i
] != rCmp
.m_pWhichRanges
[i
])
1181 // We must use the slow method then
1182 SfxWhichIter
aIter( *this );
1183 for ( sal_uInt16 nWh
= aIter
.FirstWhich();
1185 nWh
= aIter
.NextWhich() )
1187 // If the pointer of the poolable Items are unequal, the Items must match
1188 const SfxPoolItem
*pItem1
= nullptr, *pItem2
= nullptr;
1189 if ( GetItemState( nWh
, false, &pItem1
) !=
1190 rCmp
.GetItemState( nWh
, false, &pItem2
) ||
1191 ( pItem1
!= pItem2
&&
1192 ( !pItem1
|| IsInvalidItem(pItem1
) ||
1193 (m_pPool
->IsItemPoolable(*pItem1
) &&
1194 *pItem1
!= *pItem2
) ) ) )
1202 // Are all pointers the same?
1203 if (0 == memcmp( m_ppItems
, rCmp
.m_ppItems
, nCount1
* sizeof(m_ppItems
[0]) ))
1206 // We need to compare each one separately then
1207 const SfxPoolItem
**ppItem1
= m_ppItems
;
1208 const SfxPoolItem
**ppItem2
= rCmp
.m_ppItems
;
1209 for ( sal_uInt16 nPos
= 0; nPos
< nCount1
; ++nPos
)
1211 // If the pointers of the poolable Items are not the same, the Items
1213 if ( *ppItem1
!= *ppItem2
&&
1214 ( ( !*ppItem1
|| !*ppItem2
) ||
1215 ( IsInvalidItem(*ppItem1
) || IsInvalidItem(*ppItem2
) ) ||
1216 (!bDifferentPools
&& m_pPool
->IsItemPoolable(**ppItem1
)) ||
1217 **ppItem1
!= **ppItem2
) )
1227 std::unique_ptr
<SfxItemSet
> SfxItemSet::Clone(bool bItems
, SfxItemPool
*pToPool
) const
1229 if (pToPool
&& pToPool
!= m_pPool
)
1231 std::unique_ptr
<SfxItemSet
> pNewSet(new SfxItemSet(*pToPool
, m_pWhichRanges
));
1234 SfxWhichIter
aIter(*pNewSet
);
1235 sal_uInt16 nWhich
= aIter
.FirstWhich();
1238 const SfxPoolItem
* pItem
;
1239 if ( SfxItemState::SET
== GetItemState( nWhich
, false, &pItem
) )
1240 pNewSet
->Put( *pItem
, pItem
->Which() );
1241 nWhich
= aIter
.NextWhich();
1247 return std::unique_ptr
<SfxItemSet
>(bItems
1248 ? new SfxItemSet(*this)
1249 : new SfxItemSet(*m_pPool
, m_pWhichRanges
));
1252 SfxItemSet
SfxItemSet::CloneAsValue(bool bItems
, SfxItemPool
*pToPool
) const
1254 if (pToPool
&& pToPool
!= m_pPool
)
1256 SfxItemSet
aNewSet(*pToPool
, m_pWhichRanges
);
1259 SfxWhichIter
aIter(aNewSet
);
1260 sal_uInt16 nWhich
= aIter
.FirstWhich();
1263 const SfxPoolItem
* pItem
;
1264 if ( SfxItemState::SET
== GetItemState( nWhich
, false, &pItem
) )
1265 aNewSet
.Put( *pItem
, pItem
->Which() );
1266 nWhich
= aIter
.NextWhich();
1274 : SfxItemSet(*m_pPool
, m_pWhichRanges
);
1277 void SfxItemSet::PutDirect(const SfxPoolItem
&rItem
)
1279 SfxPoolItem
const** ppFnd
= m_ppItems
;
1280 const sal_uInt16 nWhich
= rItem
.Which();
1282 IsPoolDefaultItem(&rItem
) || m_pPool
->CheckItemInPool(&rItem
);
1283 // Only cause assertion in the callees
1285 for( auto const & pPtr
: m_pWhichRanges
)
1287 if( pPtr
.first
<= nWhich
&& nWhich
<= pPtr
.second
)
1290 ppFnd
+= nWhich
- pPtr
.first
;
1291 const SfxPoolItem
* pOld
= *ppFnd
;
1292 if( pOld
) // One already present
1294 if( rItem
== **ppFnd
)
1295 return; // Already present!
1296 m_pPool
->Remove( *pOld
);
1302 if( IsPoolDefaultItem(&rItem
) )
1303 *ppFnd
= &m_pPool
->Put( rItem
);
1307 if( !IsStaticDefaultItem( &rItem
) )
1313 ppFnd
+= pPtr
.second
- pPtr
.first
+ 1;
1317 void SfxItemSet::dumpAsXml(xmlTextWriterPtr pWriter
) const
1319 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SfxItemSet"));
1320 SfxItemIter
aIter(*this);
1321 for (const SfxPoolItem
* pItem
= aIter
.GetCurItem(); pItem
; pItem
= aIter
.NextItem())
1323 if (IsInvalidItem(pItem
))
1325 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("invalid"));
1326 (void)xmlTextWriterEndElement(pWriter
);
1330 pItem
->dumpAsXml(pWriter
);
1333 (void)xmlTextWriterEndElement(pWriter
);
1337 // ----------------------------------------------- class SfxAllItemSet
1339 SfxAllItemSet::SfxAllItemSet( SfxItemPool
&rPool
)
1340 : SfxItemSet(rPool
, SfxAllItemSetFlag::Flag
)
1344 SfxAllItemSet::SfxAllItemSet(const SfxItemSet
&rCopy
)
1350 * Explicitly define this ctor to avoid auto-generation by the compiler.
1351 * The compiler does not take the ctor with the 'const SfxItemSet&'!
1353 SfxAllItemSet::SfxAllItemSet(const SfxAllItemSet
&rCopy
)
1359 * Putting with automatic extension of the WhichId with the ID of the Item.
1361 const SfxPoolItem
* SfxAllItemSet::PutImpl( const SfxPoolItem
& rItem
, sal_uInt16 nWhich
, bool bPassingOwnership
)
1363 MergeRange(nWhich
, nWhich
);
1364 return SfxItemSet::PutImpl(rItem
, nWhich
, bPassingOwnership
);
1369 * Using a VoidItem with Which value 0
1371 void SfxItemSet::DisableItem(sal_uInt16 nWhich
)
1373 Put( SfxVoidItem(0), nWhich
);
1376 std::unique_ptr
<SfxItemSet
> SfxAllItemSet::Clone(bool bItems
, SfxItemPool
*pToPool
) const
1378 if (pToPool
&& pToPool
!= m_pPool
)
1380 std::unique_ptr
<SfxAllItemSet
> pNewSet(new SfxAllItemSet( *pToPool
));
1382 pNewSet
->Set( *this );
1386 return std::unique_ptr
<SfxItemSet
>(bItems
? new SfxAllItemSet(*this) : new SfxAllItemSet(*m_pPool
));
1389 SfxItemSet
SfxAllItemSet::CloneAsValue(bool , SfxItemPool
* ) const
1391 // if you are trying to clone, then the thing you are cloning is polymorphic, which means
1392 // it cannot be cloned as a value
1393 throw std::logic_error("cannot do this");
1399 WhichRangesContainer::WhichRangesContainer( const WhichPair
* wids
, sal_Int32 nSize
)
1401 auto p
= new WhichPair
[nSize
];
1402 for (int i
=0; i
<nSize
; ++i
)
1406 m_bOwnRanges
= true;
1409 WhichRangesContainer::WhichRangesContainer(sal_uInt16 nWhichStart
, sal_uInt16 nWhichEnd
)
1410 : m_size(1), m_bOwnRanges(true)
1412 auto p
= new WhichPair
[1];
1413 p
[0] = { nWhichStart
, nWhichEnd
};
1417 WhichRangesContainer::WhichRangesContainer(WhichRangesContainer
&& other
)
1419 std::swap(m_pairs
, other
.m_pairs
);
1420 std::swap(m_size
, other
.m_size
);
1421 std::swap(m_bOwnRanges
, other
.m_bOwnRanges
);
1424 WhichRangesContainer
& WhichRangesContainer::operator=(WhichRangesContainer
&& other
)
1426 std::swap(m_pairs
, other
.m_pairs
);
1427 std::swap(m_size
, other
.m_size
);
1428 std::swap(m_bOwnRanges
, other
.m_bOwnRanges
);
1432 WhichRangesContainer
& WhichRangesContainer::operator=(WhichRangesContainer
const & other
)
1435 m_size
= other
.m_size
;
1436 m_bOwnRanges
= other
.m_bOwnRanges
;
1439 auto p
= new WhichPair
[m_size
];
1440 for (int i
=0; i
<m_size
; ++i
)
1441 p
[i
] = other
.m_pairs
[i
];
1445 m_pairs
= other
.m_pairs
;
1449 WhichRangesContainer::~WhichRangesContainer()
1454 bool WhichRangesContainer::operator==(WhichRangesContainer
const & other
) const
1456 if (m_size
!= other
.m_size
)
1458 if (m_pairs
== other
.m_pairs
)
1460 return std::equal(m_pairs
, m_pairs
+ m_size
, other
.m_pairs
, other
.m_pairs
+ m_size
);
1464 void WhichRangesContainer::reset()
1469 m_bOwnRanges
= false;
1475 // Adds a range to which ranges, keeping the ranges in valid state (sorted, non-overlapping)
1476 WhichRangesContainer
WhichRangesContainer::MergeRange(sal_uInt16 nFrom
,
1477 sal_uInt16 nTo
) const
1479 assert(svl::detail::validRange(nFrom
, nTo
));
1482 return WhichRangesContainer(nFrom
, nTo
);
1484 // create vector of ranges (sal_uInt16 pairs of lower and upper bound)
1485 const size_t nOldCount
= size();
1486 std::vector
<WhichPair
> aRangesTable
;
1487 aRangesTable
.reserve(nOldCount
);
1488 bool bAdded
= false;
1489 for (const auto& rPair
: *this)
1491 if (!bAdded
&& rPair
.first
>= nFrom
)
1492 { // insert new range, keep ranges sorted
1493 aRangesTable
.push_back({ nFrom
, nTo
});
1496 // insert current range
1497 aRangesTable
.emplace_back(rPair
);
1500 aRangesTable
.push_back({ nFrom
, nTo
});
1502 // true if ranges overlap or adjoin, false if ranges are separate
1503 auto needMerge
= [](WhichPair lhs
, WhichPair rhs
) {
1504 return (lhs
.first
- 1) <= rhs
.second
&& (rhs
.first
- 1) <= lhs
.second
;
1507 auto it
= aRangesTable
.begin();
1508 // we got at least one range
1511 auto itNext
= std::next(it
);
1512 if (itNext
== aRangesTable
.end())
1514 // check neighbouring ranges, find first range which overlaps or adjoins a previous range
1515 if (needMerge(*it
, *itNext
))
1517 // lower bounds are sorted, implies: it->first = min(it[0].first, it[1].first)
1518 it
->second
= std::max(it
->second
, itNext
->second
);
1519 aRangesTable
.erase(itNext
);
1525 return WhichRangesContainer(aRangesTable
.data(), aRangesTable
.size());
1528 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */