bump product version to 6.3.0.0.beta1
[LibreOffice.git] / svl / source / items / itempool.cxx
blob70809ac65ad462bb0443f2caa27d016c8cbb6aeb
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 .
20 #include <svl/itempool.hxx>
22 #include <string.h>
23 #include <libxml/xmlwriter.h>
25 #include <tools/solar.h>
26 #include <osl/diagnose.h>
27 #include <sal/log.hxx>
28 #include <svl/SfxBroadcaster.hxx>
29 #include <svl/hint.hxx>
30 #include <svl/itemset.hxx>
31 #include <poolio.hxx>
33 #include <algorithm>
34 #include <cassert>
35 #include <vector>
38 #if OSL_DEBUG_LEVEL > 0
39 #include <map>
41 static void
42 lcl_CheckSlots2(std::map<sal_uInt16, sal_uInt16> & rSlotMap,
43 SfxItemPool const& rPool, SfxItemInfo const* pInfo)
45 if (!pInfo)
46 return; // may not be initialized yet
47 if (rPool.GetName() == "EditEngineItemPool")
48 return; // HACK: this one has loads of duplicates already, ignore it :(
49 sal_uInt16 const nFirst(rPool.GetFirstWhich());
50 sal_uInt16 const nCount(rPool.GetLastWhich() - rPool.GetFirstWhich() + 1);
51 for (sal_uInt16 n = 0; n < nCount; ++n)
53 sal_uInt16 const nSlotId(pInfo[n]._nSID);
54 if (nSlotId != 0
55 && nSlotId != 10883 // preexisting duplicate SID_ATTR_GRAF_CROP
56 && nSlotId != 10023 // preexisting duplicate SID_ATTR_BORDER_INNER
57 && nSlotId != 10024 // preexisting duplicate SID_ATTR_BORDER_OUTER
58 && nSlotId != 11013 // preexisting duplicate SID_ATTR_BORDER_DIAG_TLBR
59 && nSlotId != 11014) // preexisting duplicate SID_ATTR_BORDER_DIAG_BLTR
60 { // check for duplicate slot-id mapping
61 std::map<sal_uInt16, sal_uInt16>::const_iterator const iter(
62 rSlotMap.find(nSlotId));
63 sal_uInt16 const nWhich(nFirst + n);
64 if (iter != rSlotMap.end())
66 SAL_WARN("svl", "SfxItemPool: duplicate SlotId " << nSlotId
67 << " mapped to " << iter->second << " and " << nWhich);
68 assert(false);
70 rSlotMap.insert(std::make_pair(nSlotId, nWhich));
75 #define CHECK_SLOTS() \
76 do { \
77 std::map<sal_uInt16, sal_uInt16> slotmap; \
78 for (SfxItemPool * p = pImpl->mpMaster; p; p = p->pImpl->mpSecondary) \
79 { \
80 lcl_CheckSlots2(slotmap, *p, p->pItemInfos); \
81 } \
82 } while (false)
84 #else
85 #define CHECK_SLOTS() do {} while (false)
86 #endif
89 void SfxItemPool::AddSfxItemPoolUser(SfxItemPoolUser& rNewUser)
91 // maintain sorted to reduce cost of remove
92 const auto insertIt = ::std::lower_bound(
93 pImpl->maSfxItemPoolUsers.begin(), pImpl->maSfxItemPoolUsers.end(), &rNewUser);
94 pImpl->maSfxItemPoolUsers.insert(insertIt, &rNewUser);
97 void SfxItemPool::RemoveSfxItemPoolUser(SfxItemPoolUser& rOldUser)
99 const auto aFindResult = ::std::lower_bound(
100 pImpl->maSfxItemPoolUsers.begin(), pImpl->maSfxItemPoolUsers.end(), &rOldUser);
101 if(aFindResult != pImpl->maSfxItemPoolUsers.end() && *aFindResult == &rOldUser)
103 pImpl->maSfxItemPoolUsers.erase(aFindResult);
107 const SfxPoolItem* SfxItemPool::GetPoolDefaultItem( sal_uInt16 nWhich ) const
109 const SfxPoolItem* pRet;
110 if( IsInRange( nWhich ) )
111 pRet = pImpl->maPoolDefaults[GetIndex_Impl(nWhich)];
112 else if( pImpl->mpSecondary )
113 pRet = pImpl->mpSecondary->GetPoolDefaultItem( nWhich );
114 else
116 assert(false && "unknown WhichId - cannot get pool default");
117 pRet = nullptr;
119 return pRet;
123 bool SfxItemPool::IsItemPoolable_Impl( sal_uInt16 nPos ) const
125 return pItemInfos[nPos]._bPoolable;
129 bool SfxItemPool::IsItemPoolable( sal_uInt16 nWhich ) const
131 for ( const SfxItemPool *pPool = this; pPool; pPool = pPool->pImpl->mpSecondary )
133 if ( pPool->IsInRange(nWhich) )
134 return pPool->IsItemPoolable_Impl( pPool->GetIndex_Impl(nWhich));
136 DBG_ASSERT( !IsWhich(nWhich), "unknown which-id" );
137 return false;
141 SfxBroadcaster& SfxItemPool::BC()
143 return pImpl->aBC;
148 * This is the regular ctor to be used for this class.
149 * An SfxItemPool instance is initialized, which can manage Items in the
150 * range from 'nStartWhich' to 'nEndWhich'.
152 * For every one of these WhichIds a static Default must be present in the
153 * 'pDefaults' array. They start with an SfxPoolItem (with the WhichId
154 * 'nStartWhich'), are sorted by WhichId and consecutively stored.
156 * 'pItemInfos' is a USHORT array arranged in the same way, which holds
157 * SlotIds and Flags. These SlotIds can be 0, if the affected Items are
158 * exclusively used in the Core.
159 * The flags allow for e.g. enabling value sharing (poolable).
161 * If the Pool is supposed to hold SfxSetItems, the ctor cannot yet contain
162 * static Defaults. This needs to be done afterwards, using
163 * @see SfxItemPool::SetDefaults(std::vector<SfxPoolItem*>*).
165 * @see SfxItemPool::SetDefaults(std::vector<SfxPoolItem*>*)
166 * @see SfxItemPool::ReleaseDefaults(std::vector<SfxPoolItem*>*,sal_uInt16,sal_Bool)
167 * @see SfxItemPool::ReldaseDefaults(sal_Bool)
169 SfxItemPool::SfxItemPool
171 const OUString& rName, /* Pool name to identify in the file format */
172 sal_uInt16 nStartWhich, /* First WhichId of the Pool (must be > 0) */
173 sal_uInt16 nEndWhich, /* Last WhichId of the Pool */
174 const SfxItemInfo* pInfo, /* SID Map and Item flags */
175 std::vector<SfxPoolItem*>*
176 pDefaults /* Pointer to static Defaults;
177 is directly referenced by the Pool,
178 but no transfer of ownership */
180 pItemInfos(pInfo),
181 pImpl( new SfxItemPool_Impl( this, rName, nStartWhich, nEndWhich ) )
183 pImpl->eDefMetric = MapUnit::MapTwip;
185 if ( pDefaults )
186 SetDefaults(pDefaults);
191 * Copy ctor
193 * @see SfxItemPool::Clone() const
195 SfxItemPool::SfxItemPool
197 const SfxItemPool& rPool, // Copy from this instance
198 bool bCloneStaticDefaults /* true
199 Copy static Defaults
201 false
202 Take over static Defaults */
204 pItemInfos(rPool.pItemInfos),
205 pImpl( new SfxItemPool_Impl( this, rPool.pImpl->aName, rPool.pImpl->mnStart, rPool.pImpl->mnEnd ) )
207 pImpl->eDefMetric = rPool.pImpl->eDefMetric;
209 // Take over static Defaults
210 if ( bCloneStaticDefaults )
212 std::vector<SfxPoolItem *>* ppDefaults = new std::vector<SfxPoolItem*>(pImpl->mnEnd-pImpl->mnStart+1);
213 for ( sal_uInt16 n = 0; n <= pImpl->mnEnd - pImpl->mnStart; ++n )
215 (*ppDefaults)[n] = (*rPool.pImpl->mpStaticDefaults)[n]->Clone(this);
216 (*ppDefaults)[n]->SetKind(SfxItemKind::StaticDefault);
219 SetDefaults( ppDefaults );
221 else
222 SetDefaults( rPool.pImpl->mpStaticDefaults );
224 // Copy Pool Defaults
225 for (size_t n = 0; n < pImpl->maPoolDefaults.size(); ++n )
226 if (rPool.pImpl->maPoolDefaults[n])
228 pImpl->maPoolDefaults[n] = rPool.pImpl->maPoolDefaults[n]->Clone(this); //resets kind
229 pImpl->maPoolDefaults[n]->SetKind(SfxItemKind::PoolDefault);
232 // Repair linkage
233 if ( rPool.pImpl->mpSecondary )
234 SetSecondaryPool( rPool.pImpl->mpSecondary->Clone() );
237 void SfxItemPool::SetDefaults( std::vector<SfxPoolItem*>* pDefaults )
239 DBG_ASSERT( pDefaults, "first we ask for it, and then we don't give back..." );
240 DBG_ASSERT( !pImpl->mpStaticDefaults, "already have Defaults" );
242 pImpl->mpStaticDefaults = pDefaults;
243 //! if ((*mpStaticDefaults)->GetKind() != SfxItemKind::StaticDefault)
244 //! FIXME: Probably doesn't work with SetItems at the end
246 DBG_ASSERT( (*pImpl->mpStaticDefaults)[0]->GetRefCount() == 0 ||
247 IsDefaultItem( (*pImpl->mpStaticDefaults)[0] ),
248 "these are not static" );
249 for ( sal_uInt16 n = 0; n <= pImpl->mnEnd - pImpl->mnStart; ++n )
251 assert( ((*pImpl->mpStaticDefaults)[n]->Which() == n + pImpl->mnStart)
252 && "static defaults not sorted" );
253 (*pImpl->mpStaticDefaults)[n]->SetKind(SfxItemKind::StaticDefault);
254 DBG_ASSERT( pImpl->maPoolItemArrays[n].empty(), "defaults with setitems with items?!" );
259 void SfxItemPool::ClearDefaults()
261 pImpl->mpStaticDefaults = nullptr;
265 * Frees the static Defaults of the corresponding SfxItemPool instance
266 * and deletes them if specified.
268 * The SfxItemPool instance MUST NOT BE USED after this function has
269 * been called; only the dtor must be called.
271 void SfxItemPool::ReleaseDefaults
273 bool bDelete /* true
274 Deletes the array as well as the single static Defaults
276 false
277 Neither deletes the array not the single static Defaults */
282 DBG_ASSERT( pImpl->mpStaticDefaults, "requirements not met" );
283 ReleaseDefaults( pImpl->mpStaticDefaults, bDelete );
285 // mpStaticDefaults points to deleted memory if bDelete == true.
286 if ( bDelete )
287 pImpl->mpStaticDefaults = nullptr;
292 * Frees the specified static Defaults and also deletes them, if so
293 * specified.
295 * This method MUST be called AFTER all SfxItemPool instances (which
296 * use the specified static Defaults 'pDefault') have been destroyed.
298 void SfxItemPool::ReleaseDefaults
300 std::vector<SfxPoolItem*>*
301 pDefaults, /* Static Defaults that are to be freed */
303 bool bDelete /* true
304 Deletes the array as well as the specified
305 static Defaults
307 false
308 Neither deletes the array nor the single
309 static Defaults */
312 DBG_ASSERT( pDefaults, "we first ask for it and the return nothing ..." );
314 for ( auto & rpItem : *pDefaults )
316 assert(IsStaticDefaultItem(rpItem));
317 rpItem->SetRefCount(0);
318 if ( bDelete )
320 delete rpItem;
321 rpItem = nullptr;
325 if ( bDelete )
327 delete pDefaults;
328 pDefaults = nullptr;
333 SfxItemPool::~SfxItemPool()
335 if ( !pImpl->maPoolItemArrays.empty() && !pImpl->maPoolDefaults.empty() )
336 Delete();
338 if (pImpl->mpMaster != nullptr && pImpl->mpMaster != this)
340 // This condition indicates an error.
341 // A pImpl->mpMaster->SetSecondaryPool(...) call should have been made
342 // earlier to prevent this. At this point we can only try to
343 // prevent a crash later on.
344 DBG_ASSERT( pImpl->mpMaster == this, "destroying active Secondary-Pool" );
345 if (pImpl->mpMaster->pImpl->mpSecondary == this)
346 pImpl->mpMaster->pImpl->mpSecondary = nullptr;
350 void SfxItemPool::Free(SfxItemPool* pPool)
352 if(!pPool)
353 return;
355 // tell all the registered SfxItemPoolUsers that the pool is in destruction
356 std::vector<SfxItemPoolUser*> aListCopy(pPool->pImpl->maSfxItemPoolUsers);
357 for(SfxItemPoolUser* pSfxItemPoolUser : aListCopy)
359 DBG_ASSERT(pSfxItemPoolUser, "corrupt SfxItemPoolUser list (!)");
360 pSfxItemPoolUser->ObjectInDestruction(*pPool);
363 // Clear the vector. This means that user do not need to call RemoveSfxItemPoolUser()
364 // when they get called from ObjectInDestruction().
365 pPool->pImpl->maSfxItemPoolUsers.clear();
367 // delete pool
368 delete pPool;
372 void SfxItemPool::SetSecondaryPool( SfxItemPool *pPool )
374 // Reset Master in attached Pools
375 if ( pImpl->mpSecondary )
377 #ifdef DBG_UTIL
378 if (pImpl->mpStaticDefaults != nullptr && !pImpl->maPoolItemArrays.empty()
379 && !pImpl->mpSecondary->pImpl->maPoolItemArrays.empty())
380 // Delete() did not yet run?
382 // Does the Master have SetItems?
383 bool bHasSetItems = false;
384 for ( sal_uInt16 i = 0; !bHasSetItems && i < pImpl->mnEnd - pImpl->mnStart; ++i )
385 bHasSetItems = dynamic_cast<const SfxSetItem *>((*pImpl->mpStaticDefaults)[i]) != nullptr;
387 // Detached Pools must be empty
388 bool bOK = bHasSetItems;
389 for (auto const& rSecArray : pImpl->mpSecondary->pImpl->maPoolItemArrays)
391 if (!bOK)
392 break;
393 if (rSecArray.size()>0)
395 SAL_WARN("svl.items", "old secondary pool: " << pImpl->mpSecondary->pImpl->aName
396 << " of pool: " << pImpl->aName << " must be empty.");
397 break;
401 #endif
403 pImpl->mpSecondary->pImpl->mpMaster = pImpl->mpSecondary;
404 for ( SfxItemPool *p = pImpl->mpSecondary->pImpl->mpSecondary; p; p = p->pImpl->mpSecondary )
405 p->pImpl->mpMaster = pImpl->mpSecondary;
408 // Set Master of new Secondary Pools
409 DBG_ASSERT( !pPool || pPool->pImpl->mpMaster == pPool, "Secondary is present in two Pools" );
410 SfxItemPool *pNewMaster = GetMasterPool() ? pImpl->mpMaster : this;
411 for ( SfxItemPool *p = pPool; p; p = p->pImpl->mpSecondary )
412 p->pImpl->mpMaster = pNewMaster;
414 // Remember new Secondary Pool
415 pImpl->mpSecondary = pPool;
417 CHECK_SLOTS();
420 void SfxItemPool::SetItemInfos(SfxItemInfo const*const pInfo)
422 pItemInfos = pInfo;
423 CHECK_SLOTS();
427 MapUnit SfxItemPool::GetMetric( sal_uInt16 ) const
429 return pImpl->eDefMetric;
433 void SfxItemPool::SetDefaultMetric( MapUnit eNewMetric )
435 pImpl->eDefMetric = eNewMetric;
438 const OUString& SfxItemPool::GetName() const
440 return pImpl->aName;
444 bool SfxItemPool::GetPresentation
446 const SfxPoolItem& rItem,
447 MapUnit eMetric,
448 OUString& rText,
449 const IntlWrapper& rIntlWrapper
450 ) const
452 return rItem.GetPresentation(
453 SfxItemPresentation::Complete, GetMetric(rItem.Which()), eMetric, rText, rIntlWrapper );
457 SfxItemPool* SfxItemPool::Clone() const
459 SfxItemPool *pPool = new SfxItemPool( *this );
460 return pPool;
464 void SfxItemPool::Delete()
466 // Already deleted?
467 if (pImpl->maPoolItemArrays.empty() || pImpl->maPoolDefaults.empty())
468 return;
470 // Inform e.g. running Requests
471 pImpl->aBC.Broadcast( SfxHint( SfxHintId::Dying ) );
473 // Iterate through twice: first for the SetItems.
474 if (pImpl->mpStaticDefaults != nullptr) {
475 for (size_t n = 0; n < GetSize_Impl(); ++n)
477 // *mpStaticDefaultItem could've already been deleted in a class derived
478 // from SfxItemPool
479 // This causes chaos in Itempool!
480 const SfxPoolItem* pStaticDefaultItem = (*pImpl->mpStaticDefaults)[n];
481 if (dynamic_cast<const SfxSetItem*>(pStaticDefaultItem))
483 // SfxSetItem found, remove PoolItems (and defaults) with same ID
484 auto& rArray = pImpl->maPoolItemArrays[n];
485 for (auto& rItemPtr : rArray)
487 ReleaseRef(*rItemPtr, rItemPtr->GetRefCount()); // for RefCount check in dtor
488 delete rItemPtr;
490 rArray.clear();
491 // let pImpl->DeleteItems() delete item arrays in maPoolItems
492 auto& rItemPtr = pImpl->maPoolDefaults[n];
493 if (rItemPtr)
495 #ifdef DBG_UTIL
496 ClearRefCount(*rItemPtr);
497 #endif
498 delete rItemPtr;
499 rItemPtr = nullptr;
505 // now remove remaining PoolItems (and defaults) who didn't have SetItems
506 for (auto& rArray : pImpl->maPoolItemArrays)
508 for (auto& rItemPtr : rArray)
510 ReleaseRef(*rItemPtr, rItemPtr->GetRefCount()); // for RefCount check in dtor
511 delete rItemPtr;
513 rArray.clear();
514 // let pImpl->DeleteItems() delete item arrays in maPoolItems
516 pImpl->maPoolItemArrays.clear();
517 // default items
518 for (auto rItemPtr : pImpl->maPoolDefaults)
520 if (rItemPtr)
522 #ifdef DBG_UTIL
523 ClearRefCount(*rItemPtr);
524 #endif
525 delete rItemPtr;
526 rItemPtr = nullptr;
530 pImpl->DeleteItems();
534 void SfxItemPool::SetPoolDefaultItem(const SfxPoolItem &rItem)
536 if ( IsInRange(rItem.Which()) )
538 auto& rOldDefault =
539 pImpl->maPoolDefaults[GetIndex_Impl(rItem.Which())];
540 SfxPoolItem *pNewDefault = rItem.Clone(this);
541 pNewDefault->SetKind(SfxItemKind::PoolDefault);
542 if (rOldDefault)
544 rOldDefault->SetRefCount(0);
545 DELETEZ(rOldDefault);
547 rOldDefault = pNewDefault;
549 else if ( pImpl->mpSecondary )
550 pImpl->mpSecondary->SetPoolDefaultItem(rItem);
551 else
553 assert(false && "unknown WhichId - cannot set pool default");
558 * Resets the default of the given WhichId back to the static Default.
559 * If a pool default exists, it is removed.
561 void SfxItemPool::ResetPoolDefaultItem( sal_uInt16 nWhichId )
563 if ( IsInRange(nWhichId) )
565 auto& rOldDefault =
566 pImpl->maPoolDefaults[GetIndex_Impl(nWhichId)];
567 if (rOldDefault)
569 rOldDefault->SetRefCount(0);
570 DELETEZ(rOldDefault);
573 else if ( pImpl->mpSecondary )
574 pImpl->mpSecondary->ResetPoolDefaultItem(nWhichId);
575 else
577 assert(false && "unknown WhichId - cannot reset pool default");
582 const SfxPoolItem& SfxItemPool::PutImpl( const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership )
584 if ( 0 == nWhich )
585 nWhich = rItem.Which();
587 // Find correct Secondary Pool
588 bool bSID = IsSlot(nWhich);
589 if ( !bSID && !IsInRange(nWhich) )
591 if ( pImpl->mpSecondary )
592 return pImpl->mpSecondary->PutImpl( rItem, nWhich, bPassingOwnership );
593 OSL_FAIL( "unknown WhichId - cannot put item" );
596 // SID ?
597 if (bSID)
599 assert((rItem.Which() != nWhich ||
600 !IsDefaultItem(&rItem) || rItem.GetKind() == SfxItemKind::DeleteOnIdle)
601 && "a non Pool Item is Default?!");
602 SfxPoolItem *pPoolItem = rItem.Clone(pImpl->mpMaster);
603 pPoolItem->SetWhich(nWhich);
604 AddRef( *pPoolItem );
605 if (bPassingOwnership)
606 delete &rItem;
607 return *pPoolItem;
610 assert(!pImpl->mpStaticDefaults ||
611 typeid(rItem) == typeid(GetDefaultItem(nWhich)));
613 const sal_uInt16 nIndex = GetIndex_Impl(nWhich);
614 SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[nIndex];
616 // Is this a 'poolable' item - ie. should we re-use and return
617 // the same underlying item for equivalent (==) SfxPoolItems?
618 if ( IsItemPoolable_Impl( nIndex ) )
620 // if is already in a pool, then it is worth checking if it is in this one.
621 if ( IsPooledItem(&rItem) )
623 // 1. search for an identical pointer in the pool
624 auto it = rItemArr.find(const_cast<SfxPoolItem *>(&rItem));
625 if (it != rItemArr.end())
627 AddRef(rItem);
628 assert(!bPassingOwnership && "can't be passing ownership and have the item already in the pool");
629 return rItem;
633 const SfxPoolItem* pFoundItem = nullptr;
634 // 2. search for an item with matching attributes.
635 if (rItem.IsSortable())
637 pFoundItem = rItemArr.findByLessThan(&rItem);
638 if (pFoundItem)
639 assert(*pFoundItem == rItem);
641 else
643 for (auto itr = rItemArr.begin(); itr != rItemArr.end(); ++itr)
645 if (**itr == rItem)
647 pFoundItem = *itr;
648 break;
652 if (pFoundItem)
654 assert((!bPassingOwnership || (&rItem != pFoundItem)) && "can't be passing ownership and have the item already in the pool");
655 AddRef(*pFoundItem);
656 if (bPassingOwnership)
657 delete &rItem;
658 return *pFoundItem;
662 // 3. not found, so clone to insert into the pointer array.
663 SfxPoolItem* pNewItem;
664 if (bPassingOwnership)
666 assert(!dynamic_cast<const SfxItemSet*>(&rItem) && "can't pass ownership of SfxItem, they need to be cloned to the master pool");
667 pNewItem = const_cast<SfxPoolItem*>(&rItem);
669 else
670 pNewItem = rItem.Clone(pImpl->mpMaster);
671 pNewItem->SetWhich(nWhich);
672 assert(typeid(rItem) == typeid(*pNewItem) && "SfxItemPool::Put(): unequal types, no Clone() override?");
673 if (dynamic_cast<const SfxSetItem*>(&rItem) == nullptr)
675 assert((!IsItemPoolable(nWhich) || rItem == *pNewItem)
676 && "SfxItemPool::Put(): unequal items: no operator== override?");
677 assert((!IsItemPoolable(*pNewItem) || *pNewItem == rItem)
678 && "SfxItemPool::Put(): unequal items: no operator== override?");
680 AddRef( *pNewItem );
682 // 4. finally insert into the pointer array
683 assert( rItemArr.find(pNewItem) == rItemArr.end() );
684 rItemArr.insert( pNewItem );
685 return *pNewItem;
688 void SfxItemPool::Remove( const SfxPoolItem& rItem )
690 assert(!IsPoolDefaultItem(&rItem) && "cannot remove Pool Default");
692 // Find correct Secondary Pool
693 const sal_uInt16 nWhich = rItem.Which();
694 bool bSID = IsSlot(nWhich);
695 if ( !bSID && !IsInRange(nWhich) )
697 if ( pImpl->mpSecondary )
699 pImpl->mpSecondary->Remove( rItem );
700 return;
702 OSL_FAIL( "unknown WhichId - cannot remove item" );
705 // SID ?
706 if ( bSID )
708 assert(!IsDefaultItem(&rItem) && "a non Pool Item is Default?!");
709 if ( 0 == ReleaseRef(rItem) )
711 delete &rItem;
713 return;
716 assert(rItem.GetRefCount() && "RefCount == 0, Remove impossible");
718 const sal_uInt16 nIndex = GetIndex_Impl(nWhich);
719 // Static Defaults are just there
720 if ( IsStaticDefaultItem(&rItem) &&
721 &rItem == (*pImpl->mpStaticDefaults)[nIndex])
722 return;
724 // Find Item in own Pool
725 SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[nIndex];
727 auto it = rItemArr.find(const_cast<SfxPoolItem *>(&rItem));
728 if (it != rItemArr.end())
730 if ( rItem.GetRefCount() ) //!
731 ReleaseRef( rItem );
732 else
734 assert(false && "removing Item without ref");
737 // FIXME: Hack, for as long as we have problems with the Outliner
738 // See other MI-REF
739 if ( 0 == rItem.GetRefCount() && nWhich < 4000 )
741 rItemArr.erase(it);
742 delete &rItem;
745 return;
748 // not found
749 assert(false && "removing Item not in Pool");
753 const SfxPoolItem& SfxItemPool::GetDefaultItem( sal_uInt16 nWhich ) const
755 if ( !IsInRange(nWhich) )
757 if ( pImpl->mpSecondary )
758 return pImpl->mpSecondary->GetDefaultItem( nWhich );
759 assert(!"unknown which - don't ask me for defaults");
762 DBG_ASSERT( pImpl->mpStaticDefaults, "no defaults known - don't ask me for defaults" );
763 sal_uInt16 nPos = GetIndex_Impl(nWhich);
764 SfxPoolItem* pDefault = pImpl->maPoolDefaults[nPos];
765 if ( pDefault )
766 return *pDefault;
767 return *(*pImpl->mpStaticDefaults)[nPos];
770 SfxItemPool* SfxItemPool::GetSecondaryPool() const
772 return pImpl->mpSecondary;
775 SfxItemPool* SfxItemPool::GetMasterPool() const
777 return pImpl->mpMaster;
781 * This method should be called at the master pool, when all secondary
782 * pools are appended to it.
784 * It calculates the ranges of 'which-ids' for fast construction of
785 * item-sets, which contains all 'which-ids'.
787 void SfxItemPool::FreezeIdRanges()
789 FillItemIdRanges_Impl( pImpl->mpPoolRanges );
793 void SfxItemPool::FillItemIdRanges_Impl( std::unique_ptr<sal_uInt16[]>& pWhichRanges ) const
795 DBG_ASSERT( !pImpl->mpPoolRanges, "GetFrozenRanges() would be faster!" );
797 const SfxItemPool *pPool;
798 sal_uInt16 nLevel = 0;
799 for( pPool = this; pPool; pPool = pPool->pImpl->mpSecondary )
800 ++nLevel;
802 pWhichRanges.reset(new sal_uInt16[ 2*nLevel + 1 ]);
804 nLevel = 0;
805 for( pPool = this; pPool; pPool = pPool->pImpl->mpSecondary )
807 pWhichRanges[nLevel++] = pPool->pImpl->mnStart;
808 pWhichRanges[nLevel++] = pPool->pImpl->mnEnd;
809 pWhichRanges[nLevel] = 0;
813 const sal_uInt16* SfxItemPool::GetFrozenIdRanges() const
815 return pImpl->mpPoolRanges.get();
818 const SfxPoolItem *SfxItemPool::GetItem2Default(sal_uInt16 nWhich) const
820 if ( !IsInRange(nWhich) )
822 if ( pImpl->mpSecondary )
823 return pImpl->mpSecondary->GetItem2Default( nWhich );
824 assert(false && "unknown WhichId - cannot resolve surrogate");
825 return nullptr;
827 return (*pImpl->mpStaticDefaults)[ GetIndex_Impl(nWhich) ];
830 SfxItemPool::Item2Range SfxItemPool::GetItemSurrogates(sal_uInt16 nWhich) const
832 static const o3tl::sorted_vector<SfxPoolItem*> EMPTY;
834 if ( !IsInRange(nWhich) )
836 if ( pImpl->mpSecondary )
837 return pImpl->mpSecondary->GetItemSurrogates( nWhich );
838 assert(false && "unknown WhichId - cannot resolve surrogate");
839 return { EMPTY.end(), EMPTY.end() };
842 SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(nWhich)];
843 return { rItemArr.begin(), rItemArr.end() };
846 /* This is only valid for SfxPoolItem that override IsSortable and operator< */
847 std::vector<const SfxPoolItem*> SfxItemPool::FindItemSurrogate(sal_uInt16 nWhich, SfxPoolItem const & rSample) const
849 if ( !IsInRange(nWhich) )
851 if ( pImpl->mpSecondary )
852 return pImpl->mpSecondary->FindItemSurrogate( nWhich, rSample );
853 assert(false && "unknown WhichId - cannot resolve surrogate");
854 return std::vector<const SfxPoolItem*>();
857 SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(nWhich)];
858 return rItemArr.findSurrogateRange(&rSample);
861 sal_uInt32 SfxItemPool::GetItemCount2(sal_uInt16 nWhich) const
863 if ( !IsInRange(nWhich) )
865 if ( pImpl->mpSecondary )
866 return pImpl->mpSecondary->GetItemCount2( nWhich );
867 assert(false && "unknown WhichId - cannot resolve surrogate");
868 return 0;
871 SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(nWhich)];
872 return rItemArr.size();
876 sal_uInt16 SfxItemPool::GetWhich( sal_uInt16 nSlotId, bool bDeep ) const
878 if ( !IsSlot(nSlotId) )
879 return nSlotId;
881 sal_uInt16 nCount = pImpl->mnEnd - pImpl->mnStart + 1;
882 for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs )
883 if ( pItemInfos[nOfs]._nSID == nSlotId )
884 return nOfs + pImpl->mnStart;
885 if ( pImpl->mpSecondary && bDeep )
886 return pImpl->mpSecondary->GetWhich(nSlotId);
887 return nSlotId;
891 sal_uInt16 SfxItemPool::GetSlotId( sal_uInt16 nWhich ) const
893 if ( !IsWhich(nWhich) )
894 return nWhich;
896 if ( !IsInRange( nWhich ) )
898 if ( pImpl->mpSecondary )
899 return pImpl->mpSecondary->GetSlotId(nWhich);
900 assert(false && "unknown WhichId - cannot get slot-id");
901 return 0;
904 sal_uInt16 nSID = pItemInfos[nWhich - pImpl->mnStart]._nSID;
905 return nSID ? nSID : nWhich;
909 sal_uInt16 SfxItemPool::GetTrueWhich( sal_uInt16 nSlotId, bool bDeep ) const
911 if ( !IsSlot(nSlotId) )
912 return 0;
914 sal_uInt16 nCount = pImpl->mnEnd - pImpl->mnStart + 1;
915 for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs )
916 if ( pItemInfos[nOfs]._nSID == nSlotId )
917 return nOfs + pImpl->mnStart;
918 if ( pImpl->mpSecondary && bDeep )
919 return pImpl->mpSecondary->GetTrueWhich(nSlotId);
920 return 0;
924 sal_uInt16 SfxItemPool::GetTrueSlotId( sal_uInt16 nWhich ) const
926 if ( !IsWhich(nWhich) )
927 return 0;
929 if ( !IsInRange( nWhich ) )
931 if ( pImpl->mpSecondary )
932 return pImpl->mpSecondary->GetTrueSlotId(nWhich);
933 assert(false && "unknown WhichId - cannot get slot-id");
934 return 0;
936 return pItemInfos[nWhich - pImpl->mnStart]._nSID;
939 void SfxItemPool::dumpAsXml(xmlTextWriterPtr pWriter) const
941 xmlTextWriterStartElement(pWriter, BAD_CAST("SfxItemPool"));
942 for (auto const & rArray : pImpl->maPoolItemArrays)
943 for (auto const & rItem : rArray)
944 rItem->dumpAsXml(pWriter);
945 xmlTextWriterEndElement(pWriter);
948 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */