diff options
Diffstat (limited to '')
-rw-r--r-- | svl/source/items/itempool.cxx | 1009 |
1 files changed, 1009 insertions, 0 deletions
diff --git a/svl/source/items/itempool.cxx b/svl/source/items/itempool.cxx new file mode 100644 index 000000000..781d591ea --- /dev/null +++ b/svl/source/items/itempool.cxx @@ -0,0 +1,1009 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svl/itempool.hxx> +#include <svl/setitem.hxx> + +#include <string.h> +#include <libxml/xmlwriter.h> + +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <svl/SfxBroadcaster.hxx> +#include <svl/hint.hxx> +#include <svl/itemset.hxx> + +#include <poolio.hxx> + +#include <cassert> +#include <vector> + + +#if OSL_DEBUG_LEVEL > 0 +#include <map> + +static void +lcl_CheckSlots2(std::map<sal_uInt16, sal_uInt16> & rSlotMap, + SfxItemPool const& rPool, SfxItemInfo const* pInfo) +{ + if (!pInfo) + return; // may not be initialized yet + if (rPool.GetName() == "EditEngineItemPool") + return; // HACK: this one has loads of duplicates already, ignore it :( + sal_uInt16 const nFirst(rPool.GetFirstWhich()); + sal_uInt16 const nCount(rPool.GetLastWhich() - rPool.GetFirstWhich() + 1); + for (sal_uInt16 n = 0; n < nCount; ++n) + { + sal_uInt16 const nSlotId(pInfo[n]._nSID); + if (nSlotId != 0 + && nSlotId != 10883 // preexisting duplicate SID_ATTR_GRAF_CROP + && nSlotId != 10023 // preexisting duplicate SID_ATTR_BORDER_INNER + && nSlotId != 10024 // preexisting duplicate SID_ATTR_BORDER_OUTER + && nSlotId != 11013 // preexisting duplicate SID_ATTR_BORDER_DIAG_TLBR + && nSlotId != 11014) // preexisting duplicate SID_ATTR_BORDER_DIAG_BLTR + { // check for duplicate slot-id mapping + std::map<sal_uInt16, sal_uInt16>::const_iterator const iter( + rSlotMap.find(nSlotId)); + sal_uInt16 const nWhich(nFirst + n); + if (iter != rSlotMap.end()) + { + SAL_WARN("svl", "SfxItemPool: duplicate SlotId " << nSlotId + << " mapped to " << iter->second << " and " << nWhich); + assert(false); + } + rSlotMap.insert(std::make_pair(nSlotId, nWhich)); + } + } +} + +#define CHECK_SLOTS() \ +do { \ + std::map<sal_uInt16, sal_uInt16> slotmap; \ + for (SfxItemPool * p = pImpl->mpMaster; p; p = p->pImpl->mpSecondary.get()) \ + { \ + lcl_CheckSlots2(slotmap, *p, p->pItemInfos); \ + } \ +} while (false) + +#else +#define CHECK_SLOTS() do {} while (false) +#endif + +/// clear array of PoolItem variants +/// after all PoolItems are deleted +/// or all ref counts are decreased +void SfxPoolItemArray_Impl::clear() +{ + maPoolItemSet.clear(); + maSortablePoolItems.clear(); +} + +sal_uInt16 SfxItemPool::GetFirstWhich() const +{ + return pImpl->mnStart; +} + +sal_uInt16 SfxItemPool::GetLastWhich() const +{ + return pImpl->mnEnd; +} + +bool SfxItemPool::IsInRange( sal_uInt16 nWhich ) const +{ + return nWhich >= pImpl->mnStart && nWhich <= pImpl->mnEnd; +} + +sal_uInt16 SfxItemPool::GetIndex_Impl(sal_uInt16 nWhich) const +{ + if (nWhich < pImpl->mnStart || nWhich > pImpl->mnEnd) + { + assert(false && "missing bounds check before use"); + return 0; + } + return nWhich - pImpl->mnStart; +} + +sal_uInt16 SfxItemPool::GetSize_Impl() const +{ + return pImpl->mnEnd - pImpl->mnStart + 1; +} + + +bool SfxItemPool::CheckItemInPool(const SfxPoolItem *pItem) const +{ + DBG_ASSERT( pItem, "no 0-Pointer Surrogate" ); + DBG_ASSERT( !IsInvalidItem(pItem), "no Invalid-Item Surrogate" ); + DBG_ASSERT( !IsPoolDefaultItem(pItem), "no Pool-Default-Item Surrogate" ); + + if ( !IsInRange(pItem->Which()) ) + { + if ( pImpl->mpSecondary ) + return pImpl->mpSecondary->CheckItemInPool( pItem ); + SAL_WARN( "svl.items", "unknown Which-Id - don't ask me for surrogates, with ID/pos " << pItem->Which()); + } + + // Pointer on static or pool-default attribute? + if( IsStaticDefaultItem(pItem) || IsPoolDefaultItem(pItem) ) + return true; + + SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(pItem->Which())]; + + for ( auto p : rItemArr ) + { + if ( p == pItem ) + return true; + } + SAL_WARN( "svl.items", "Item not in the pool, with ID/pos " << pItem->Which()); + return false; +} + +const SfxPoolItem* SfxItemPool::GetPoolDefaultItem( sal_uInt16 nWhich ) const +{ + const SfxPoolItem* pRet; + if( IsInRange( nWhich ) ) + pRet = pImpl->maPoolDefaults[GetIndex_Impl(nWhich)]; + else if( pImpl->mpSecondary ) + pRet = pImpl->mpSecondary->GetPoolDefaultItem( nWhich ); + else + { + assert(false && "unknown WhichId - cannot get pool default"); + pRet = nullptr; + } + return pRet; +} + + +bool SfxItemPool::IsItemPoolable_Impl( sal_uInt16 nPos ) const +{ + return pItemInfos[nPos]._bPoolable; +} + + +bool SfxItemPool::IsItemPoolable( sal_uInt16 nWhich ) const +{ + for ( const SfxItemPool *pPool = this; pPool; pPool = pPool->pImpl->mpSecondary.get() ) + { + if ( pPool->IsInRange(nWhich) ) + return pPool->IsItemPoolable_Impl( pPool->GetIndex_Impl(nWhich)); + } + DBG_ASSERT( !IsWhich(nWhich), "unknown which-id" ); + return false; +} + + +SfxBroadcaster& SfxItemPool::BC() +{ + return pImpl->aBC; +} + + +/** + * This is the regular ctor to be used for this class. + * An SfxItemPool instance is initialized, which can manage Items in the + * range from 'nStartWhich' to 'nEndWhich'. + * + * For every one of these WhichIds a static Default must be present in the + * 'pDefaults' array. They start with an SfxPoolItem (with the WhichId + * 'nStartWhich'), are sorted by WhichId and consecutively stored. + * + * 'pItemInfos' is a USHORT array arranged in the same way, which holds + * SlotIds and Flags. These SlotIds can be 0, if the affected Items are + * exclusively used in the Core. + * The flags allow for e.g. enabling value sharing (poolable). + * + * If the Pool is supposed to hold SfxSetItems, the ctor cannot yet contain + * static Defaults. This needs to be done afterwards, using + * @see SfxItemPool::SetDefaults(std::vector<SfxPoolItem*>*). + * + * @see SfxItemPool::SetDefaults(std::vector<SfxPoolItem*>*) + * @see SfxItemPool::ReleaseDefaults(std::vector<SfxPoolItem*>*,bool) + * @see SfxItemPool::ReleaseDefaults(bool) + */ +SfxItemPool::SfxItemPool +( + const OUString& rName, /* Pool name to identify in the file format */ + sal_uInt16 nStartWhich, /* First WhichId of the Pool (must be > 0) */ + sal_uInt16 nEndWhich, /* Last WhichId of the Pool */ + const SfxItemInfo* pInfo, /* SID Map and Item flags */ + std::vector<SfxPoolItem*>* + pDefaults /* Pointer to static Defaults; + is directly referenced by the Pool, + but no transfer of ownership */ +) : + pItemInfos(pInfo), + pImpl( new SfxItemPool_Impl( this, rName, nStartWhich, nEndWhich ) ) +{ + pImpl->eDefMetric = MapUnit::MapTwip; + + if ( pDefaults ) + SetDefaults(pDefaults); + +#ifdef DBG_UTIL + if (pItemInfos) + { + auto p = pItemInfos; + auto nWhich = nStartWhich; + while (nWhich <= nEndWhich) + { + if (p->_nSID == nWhich) + { + SAL_WARN("svl.items", "No point mapping a SID to itself, just put a 0 here in the SfxItemInfo array, at index " << (p - pItemInfos)); + assert(false); + } + ++p; + ++nWhich; + } + } +#endif +} + + +/** + * Copy ctor + * + * @see SfxItemPool::Clone() const +*/ +SfxItemPool::SfxItemPool +( + const SfxItemPool& rPool, // Copy from this instance + bool bCloneStaticDefaults /* true + Copy static Defaults + + false + Take over static Defaults */ +) : + salhelper::SimpleReferenceObject(), + pItemInfos(rPool.pItemInfos), + pImpl( new SfxItemPool_Impl( this, rPool.pImpl->aName, rPool.pImpl->mnStart, rPool.pImpl->mnEnd ) ) +{ + pImpl->eDefMetric = rPool.pImpl->eDefMetric; + + // Take over static Defaults + if ( bCloneStaticDefaults ) + { + std::vector<SfxPoolItem *>* ppDefaults = new std::vector<SfxPoolItem*>(pImpl->mnEnd-pImpl->mnStart+1); + for ( sal_uInt16 n = 0; n <= pImpl->mnEnd - pImpl->mnStart; ++n ) + { + (*ppDefaults)[n] = (*rPool.pImpl->mpStaticDefaults)[n]->Clone(this); + (*ppDefaults)[n]->SetKind(SfxItemKind::StaticDefault); + } + + SetDefaults( ppDefaults ); + } + else + SetDefaults( rPool.pImpl->mpStaticDefaults ); + + // Copy Pool Defaults + for (size_t n = 0; n < pImpl->maPoolDefaults.size(); ++n ) + if (rPool.pImpl->maPoolDefaults[n]) + { + pImpl->maPoolDefaults[n] = rPool.pImpl->maPoolDefaults[n]->Clone(this); //resets kind + pImpl->maPoolDefaults[n]->SetKind(SfxItemKind::PoolDefault); + } + + // Repair linkage + if ( rPool.pImpl->mpSecondary ) + SetSecondaryPool( rPool.pImpl->mpSecondary->Clone().get() ); +} + +void SfxItemPool::SetDefaults( std::vector<SfxPoolItem*>* pDefaults ) +{ + DBG_ASSERT( pDefaults, "first we ask for it, and then we don't give back..." ); + DBG_ASSERT( !pImpl->mpStaticDefaults, "already have Defaults" ); + + pImpl->mpStaticDefaults = pDefaults; + //! if ((*mpStaticDefaults)->GetKind() != SfxItemKind::StaticDefault) + //! FIXME: Probably doesn't work with SetItems at the end + { + DBG_ASSERT( (*pImpl->mpStaticDefaults)[0]->GetRefCount() == 0 || + IsDefaultItem( (*pImpl->mpStaticDefaults)[0] ), + "these are not static" ); + for ( sal_uInt16 n = 0; n <= pImpl->mnEnd - pImpl->mnStart; ++n ) + { + assert( ((*pImpl->mpStaticDefaults)[n]->Which() == n + pImpl->mnStart) + && "static defaults not sorted" ); + (*pImpl->mpStaticDefaults)[n]->SetKind(SfxItemKind::StaticDefault); + DBG_ASSERT( pImpl->maPoolItemArrays[n].empty(), "defaults with setitems with items?!" ); + } + } +} + +void SfxItemPool::ClearDefaults() +{ + pImpl->mpStaticDefaults = nullptr; +} + +/** + * Frees the static Defaults of the corresponding SfxItemPool instance + * and deletes them if specified. + * + * The SfxItemPool instance MUST NOT BE USED after this function has + * been called; only the dtor must be called. + */ +void SfxItemPool::ReleaseDefaults +( + bool bDelete /* true + Deletes the array as well as the single static Defaults + + false + Neither deletes the array not the single static Defaults */ +) + + +{ + DBG_ASSERT( pImpl->mpStaticDefaults, "requirements not met" ); + ReleaseDefaults( pImpl->mpStaticDefaults, bDelete ); + + // mpStaticDefaults points to deleted memory if bDelete == true. + if ( bDelete ) + pImpl->mpStaticDefaults = nullptr; +} + + +/** + * Frees the specified static Defaults and also deletes them, if so + * specified. + * + * This method MUST be called AFTER all SfxItemPool instances (which + * use the specified static Defaults 'pDefault') have been destroyed. + */ +void SfxItemPool::ReleaseDefaults +( + std::vector<SfxPoolItem*>* + pDefaults, /* Static Defaults that are to be freed */ + + bool bDelete /* true + Deletes the array as well as the specified + static Defaults + + false + Neither deletes the array nor the single + static Defaults */ +) +{ + DBG_ASSERT( pDefaults, "we first ask for it and the return nothing ..." ); + + for ( auto & rpItem : *pDefaults ) + { + assert(IsStaticDefaultItem(rpItem)); + rpItem->SetRefCount(0); + if ( bDelete ) + { + delete rpItem; + rpItem = nullptr; + } + } + + if ( bDelete ) + { + delete pDefaults; + pDefaults = nullptr; + } +} + + +SfxItemPool::~SfxItemPool() +{ + if ( !pImpl->maPoolItemArrays.empty() && !pImpl->maPoolDefaults.empty() ) + Delete(); + + if (pImpl->mpMaster != nullptr && pImpl->mpMaster != this) + { + // This condition indicates an error. + // A pImpl->mpMaster->SetSecondaryPool(...) call should have been made + // earlier to prevent this. At this point we can only try to + // prevent a crash later on. + DBG_ASSERT( pImpl->mpMaster == this, "destroying active Secondary-Pool" ); + if (pImpl->mpMaster->pImpl->mpSecondary == this) + pImpl->mpMaster->pImpl->mpSecondary = nullptr; + } +} + +void SfxItemPool::SetSecondaryPool( SfxItemPool *pPool ) +{ + // Reset Master in attached Pools + if ( pImpl->mpSecondary ) + { +#ifdef DBG_UTIL + if (pImpl->mpStaticDefaults != nullptr && !pImpl->maPoolItemArrays.empty() + && !pImpl->mpSecondary->pImpl->maPoolItemArrays.empty()) + // Delete() did not yet run? + { + // Does the Master have SetItems? + bool bHasSetItems = false; + for ( sal_uInt16 i = 0; !bHasSetItems && i < pImpl->mnEnd - pImpl->mnStart; ++i ) + bHasSetItems = dynamic_cast<const SfxSetItem *>((*pImpl->mpStaticDefaults)[i]) != nullptr; + + // Detached Pools must be empty + bool bOK = bHasSetItems; + for (auto const& rSecArray : pImpl->mpSecondary->pImpl->maPoolItemArrays) + { + if (!bOK) + break; + if (rSecArray.size()>0) + { + SAL_WARN("svl.items", "old secondary pool: " << pImpl->mpSecondary->pImpl->aName + << " of pool: " << pImpl->aName << " must be empty."); + break; + } + } + } +#endif + + pImpl->mpSecondary->pImpl->mpMaster = pImpl->mpSecondary.get(); + for ( SfxItemPool *p = pImpl->mpSecondary->pImpl->mpSecondary.get(); p; p = p->pImpl->mpSecondary.get() ) + p->pImpl->mpMaster = pImpl->mpSecondary.get(); + } + + // Set Master of new Secondary Pools + DBG_ASSERT( !pPool || pPool->pImpl->mpMaster == pPool, "Secondary is present in two Pools" ); + SfxItemPool *pNewMaster = GetMasterPool() ? pImpl->mpMaster : this; + for ( SfxItemPool *p = pPool; p; p = p->pImpl->mpSecondary.get() ) + p->pImpl->mpMaster = pNewMaster; + + // Remember new Secondary Pool + pImpl->mpSecondary = pPool; + + CHECK_SLOTS(); +} + +void SfxItemPool::SetItemInfos(SfxItemInfo const*const pInfo) +{ + pItemInfos = pInfo; + CHECK_SLOTS(); +} + + +MapUnit SfxItemPool::GetMetric( sal_uInt16 ) const +{ + return pImpl->eDefMetric; +} + + +void SfxItemPool::SetDefaultMetric( MapUnit eNewMetric ) +{ +// assert((pImpl->eDefMetric == eNewMetric || !pImpl->mpPoolRanges) && "pool already frozen, cannot change metric"); + pImpl->eDefMetric = eNewMetric; +} + +MapUnit SfxItemPool::GetDefaultMetric() const +{ + return pImpl->eDefMetric; +} + +const OUString& SfxItemPool::GetName() const +{ + return pImpl->aName; +} + + +bool SfxItemPool::GetPresentation +( + const SfxPoolItem& rItem, + MapUnit eMetric, + OUString& rText, + const IntlWrapper& rIntlWrapper +) const +{ + return rItem.GetPresentation( + SfxItemPresentation::Complete, GetMetric(rItem.Which()), eMetric, rText, rIntlWrapper ); +} + + +rtl::Reference<SfxItemPool> SfxItemPool::Clone() const +{ + return new SfxItemPool( *this ); +} + + +void SfxItemPool::Delete() +{ + // Already deleted? + if (pImpl->maPoolItemArrays.empty() || pImpl->maPoolDefaults.empty()) + return; + + // Inform e.g. running Requests + pImpl->aBC.Broadcast( SfxHint( SfxHintId::Dying ) ); + + // Iterate through twice: first for the SetItems. + if (pImpl->mpStaticDefaults != nullptr) { + for (size_t n = 0; n < GetSize_Impl(); ++n) + { + // *mpStaticDefaultItem could've already been deleted in a class derived + // from SfxItemPool + // This causes chaos in Itempool! + const SfxPoolItem* pStaticDefaultItem = (*pImpl->mpStaticDefaults)[n]; + if (dynamic_cast<const SfxSetItem*>(pStaticDefaultItem)) + { + // SfxSetItem found, remove PoolItems (and defaults) with same ID + auto& rArray = pImpl->maPoolItemArrays[n]; + for (auto& rItemPtr : rArray) + { + ReleaseRef(*rItemPtr, rItemPtr->GetRefCount()); // for RefCount check in dtor + delete rItemPtr; + } + rArray.clear(); + // let pImpl->DeleteItems() delete item arrays in maPoolItems + auto& rItemPtr = pImpl->maPoolDefaults[n]; + if (rItemPtr) + { +#ifdef DBG_UTIL + ClearRefCount(*rItemPtr); +#endif + delete rItemPtr; + rItemPtr = nullptr; + } + } + } + } + + // now remove remaining PoolItems (and defaults) who didn't have SetItems + for (auto& rArray : pImpl->maPoolItemArrays) + { + for (auto& rItemPtr : rArray) + { + ReleaseRef(*rItemPtr, rItemPtr->GetRefCount()); // for RefCount check in dtor + delete rItemPtr; + } + rArray.clear(); + // let pImpl->DeleteItems() delete item arrays in maPoolItems + } + pImpl->maPoolItemArrays.clear(); + // default items + for (auto rItemPtr : pImpl->maPoolDefaults) + { + if (rItemPtr) + { +#ifdef DBG_UTIL + ClearRefCount(*rItemPtr); +#endif + delete rItemPtr; + rItemPtr = nullptr; + } + } + + pImpl->DeleteItems(); +} + + +void SfxItemPool::SetPoolDefaultItem(const SfxPoolItem &rItem) +{ + if ( IsInRange(rItem.Which()) ) + { + auto& rOldDefault = + pImpl->maPoolDefaults[GetIndex_Impl(rItem.Which())]; + SfxPoolItem *pNewDefault = rItem.Clone(this); + pNewDefault->SetKind(SfxItemKind::PoolDefault); + if (rOldDefault) + { + rOldDefault->SetRefCount(0); + delete rOldDefault; + rOldDefault = nullptr; + } + rOldDefault = pNewDefault; + } + else if ( pImpl->mpSecondary ) + pImpl->mpSecondary->SetPoolDefaultItem(rItem); + else + { + assert(false && "unknown WhichId - cannot set pool default"); + } +} + +/** + * Resets the default of the given WhichId back to the static Default. + * If a pool default exists, it is removed. + */ +void SfxItemPool::ResetPoolDefaultItem( sal_uInt16 nWhichId ) +{ + if ( IsInRange(nWhichId) ) + { + auto& rOldDefault = + pImpl->maPoolDefaults[GetIndex_Impl(nWhichId)]; + if (rOldDefault) + { + rOldDefault->SetRefCount(0); + delete rOldDefault; + rOldDefault = nullptr; + } + } + else if ( pImpl->mpSecondary ) + pImpl->mpSecondary->ResetPoolDefaultItem(nWhichId); + else + { + assert(false && "unknown WhichId - cannot reset pool default"); + } +} + + +const SfxPoolItem& SfxItemPool::PutImpl( const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership ) +{ + if ( 0 == nWhich ) + nWhich = rItem.Which(); + + // Find correct Secondary Pool + bool bSID = IsSlot(nWhich); + if ( !bSID && !IsInRange(nWhich) ) + { + if ( pImpl->mpSecondary ) + return pImpl->mpSecondary->PutImpl( rItem, nWhich, bPassingOwnership ); + OSL_FAIL( "unknown WhichId - cannot put item" ); + } + + // SID ? + if (bSID) + { + assert((rItem.Which() != nWhich || + !IsDefaultItem(&rItem) || rItem.GetKind() == SfxItemKind::DeleteOnIdle) + && "a non Pool Item is Default?!"); + SfxPoolItem *pPoolItem = rItem.Clone(pImpl->mpMaster); + pPoolItem->SetWhich(nWhich); + AddRef( *pPoolItem ); + if (bPassingOwnership) + delete &rItem; + return *pPoolItem; + } + + assert(!pImpl->mpStaticDefaults || + typeid(rItem) == typeid(GetDefaultItem(nWhich))); + + const sal_uInt16 nIndex = GetIndex_Impl(nWhich); + SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[nIndex]; + + // Is this a 'poolable' item - ie. should we re-use and return + // the same underlying item for equivalent (==) SfxPoolItems? + if ( IsItemPoolable_Impl( nIndex ) ) + { + // if is already in a pool, then it is worth checking if it is in this one. + if ( IsPooledItem(&rItem) ) + { + // 1. search for an identical pointer in the pool + auto it = rItemArr.find(const_cast<SfxPoolItem *>(&rItem)); + if (it != rItemArr.end()) + { + AddRef(rItem); + assert(!bPassingOwnership && "can't be passing ownership and have the item already in the pool"); + return rItem; + } + } + + const SfxPoolItem* pFoundItem = nullptr; + // 2. search for an item with matching attributes. + if (rItem.IsSortable()) + { + pFoundItem = rItemArr.findByLessThan(&rItem); + if (pFoundItem) + assert(*pFoundItem == rItem); + } + else if(rItem.HasLookup()) + { + auto it = rItem.Lookup(rItemArr.begin(), rItemArr.end()); + if( it != rItemArr.end()) + pFoundItem = *it; + } + else + { + for (auto it = rItemArr.begin(); it != rItemArr.end(); ++it) + { + if (**it == rItem) + { + pFoundItem = *it; + break; + } + } + } + if (pFoundItem) + { + assert((!bPassingOwnership || (&rItem != pFoundItem)) && "can't be passing ownership and have the item already in the pool"); + AddRef(*pFoundItem); + if (bPassingOwnership) + delete &rItem; + return *pFoundItem; + } + } + + // 3. not found, so clone to insert into the pointer array. + SfxPoolItem* pNewItem; + if (bPassingOwnership) + { + assert(!dynamic_cast<const SfxItemSet*>(&rItem) && "can't pass ownership of SfxItem, they need to be cloned to the master pool"); + pNewItem = const_cast<SfxPoolItem*>(&rItem); + } + else + pNewItem = rItem.Clone(pImpl->mpMaster); + pNewItem->SetWhich(nWhich); + assert(typeid(rItem) == typeid(*pNewItem) && "SfxItemPool::Put(): unequal types, no Clone() override?"); +#ifndef NDEBUG + if (dynamic_cast<const SfxSetItem*>(&rItem) == nullptr) + { + assert((!IsItemPoolable(nWhich) || rItem == *pNewItem) + && "SfxItemPool::Put(): unequal items: no operator== override?"); + assert((!IsItemPoolable(*pNewItem) || *pNewItem == rItem) + && "SfxItemPool::Put(): unequal items: no operator== override?"); + } +#endif + AddRef( *pNewItem ); + + // 4. finally insert into the pointer array + rItemArr.insert( pNewItem ); + return *pNewItem; +} + +void SfxItemPool::Remove( const SfxPoolItem& rItem ) +{ + assert(!IsPoolDefaultItem(&rItem) && "cannot remove Pool Default"); + + // Find correct Secondary Pool + const sal_uInt16 nWhich = rItem.Which(); + bool bSID = IsSlot(nWhich); + if ( !bSID && !IsInRange(nWhich) ) + { + if ( pImpl->mpSecondary ) + { + pImpl->mpSecondary->Remove( rItem ); + return; + } + OSL_FAIL( "unknown WhichId - cannot remove item" ); + } + + // SID ? + if ( bSID ) + { + assert(!IsDefaultItem(&rItem) && "a non Pool Item is Default?!"); + if ( 0 == ReleaseRef(rItem) ) + { + delete &rItem; + } + return; + } + + assert(rItem.GetRefCount() && "RefCount == 0, Remove impossible"); + + const sal_uInt16 nIndex = GetIndex_Impl(nWhich); + // Static Defaults are just there + if ( IsStaticDefaultItem(&rItem) && + &rItem == (*pImpl->mpStaticDefaults)[nIndex]) + return; + + // Find Item in own Pool + SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[nIndex]; + + auto it = rItemArr.find(const_cast<SfxPoolItem *>(&rItem)); + if (it != rItemArr.end()) + { + if ( rItem.GetRefCount() ) //! + ReleaseRef( rItem ); + else + { + assert(false && "removing Item without ref"); + } + + // FIXME: Hack, for as long as we have problems with the Outliner + // See other MI-REF + if ( 0 == rItem.GetRefCount() && nWhich < 4000 ) + { + rItemArr.erase(it); + delete &rItem; + } + + return; + } + + // not found + assert(false && "removing Item not in Pool"); +} + + +const SfxPoolItem& SfxItemPool::GetDefaultItem( sal_uInt16 nWhich ) const +{ + if ( !IsInRange(nWhich) ) + { + if ( pImpl->mpSecondary ) + return pImpl->mpSecondary->GetDefaultItem( nWhich ); + assert(!"unknown which - don't ask me for defaults"); + } + + DBG_ASSERT( pImpl->mpStaticDefaults, "no defaults known - don't ask me for defaults" ); + sal_uInt16 nPos = GetIndex_Impl(nWhich); + SfxPoolItem* pDefault = pImpl->maPoolDefaults[nPos]; + if ( pDefault ) + return *pDefault; + return *(*pImpl->mpStaticDefaults)[nPos]; +} + +SfxItemPool* SfxItemPool::GetSecondaryPool() const +{ + return pImpl->mpSecondary.get(); +} + +/* get the last pool by following the GetSecondaryPool chain */ +SfxItemPool* SfxItemPool::GetLastPoolInChain() +{ + SfxItemPool* pLast = this; + while(pLast->GetSecondaryPool()) + pLast = pLast->GetSecondaryPool(); + return pLast; +} + +SfxItemPool* SfxItemPool::GetMasterPool() const +{ + return pImpl->mpMaster; +} + +/** + * This method should be called at the master pool, when all secondary + * pools are appended to it. + * + * It calculates the ranges of 'which-ids' for fast construction of + * item-sets, which contains all 'which-ids'. + */ +void SfxItemPool::FreezeIdRanges() +{ + assert(pImpl->mpPoolRanges.empty() && "pool already frozen, cannot freeze twice"); + FillItemIdRanges_Impl( pImpl->mpPoolRanges ); +} + + +void SfxItemPool::FillItemIdRanges_Impl( WhichRangesContainer& pWhichRanges ) const +{ + DBG_ASSERT( pImpl->mpPoolRanges.empty(), "GetFrozenRanges() would be faster!" ); + + pWhichRanges.reset(); + + // Merge all ranges, keeping them sorted + for (const SfxItemPool* pPool = this; pPool; pPool = pPool->pImpl->mpSecondary.get()) + pWhichRanges = pWhichRanges.MergeRange(pPool->pImpl->mnStart, pPool->pImpl->mnEnd); +} + +const WhichRangesContainer& SfxItemPool::GetFrozenIdRanges() const +{ + return pImpl->mpPoolRanges; +} + +const SfxPoolItem *SfxItemPool::GetItem2Default(sal_uInt16 nWhich) const +{ + if ( !IsInRange(nWhich) ) + { + if ( pImpl->mpSecondary ) + return pImpl->mpSecondary->GetItem2Default( nWhich ); + assert(false && "unknown WhichId - cannot resolve surrogate"); + return nullptr; + } + return (*pImpl->mpStaticDefaults)[ GetIndex_Impl(nWhich) ]; +} + +SfxItemPool::Item2Range SfxItemPool::GetItemSurrogates(sal_uInt16 nWhich) const +{ + static const o3tl::sorted_vector<SfxPoolItem*> EMPTY; + + if ( !IsInRange(nWhich) ) + { + if ( pImpl->mpSecondary ) + return pImpl->mpSecondary->GetItemSurrogates( nWhich ); + assert(false && "unknown WhichId - cannot resolve surrogate"); + return { EMPTY.end(), EMPTY.end() }; + } + + SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(nWhich)]; + return { rItemArr.begin(), rItemArr.end() }; +} + +/* This is only valid for SfxPoolItem that override IsSortable and operator< */ +std::vector<const SfxPoolItem*> SfxItemPool::FindItemSurrogate(sal_uInt16 nWhich, SfxPoolItem const & rSample) const +{ + if ( !IsInRange(nWhich) ) + { + if ( pImpl->mpSecondary ) + return pImpl->mpSecondary->FindItemSurrogate( nWhich, rSample ); + assert(false && "unknown WhichId - cannot resolve surrogate"); + return std::vector<const SfxPoolItem*>(); + } + + SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(nWhich)]; + return rItemArr.findSurrogateRange(&rSample); +} + +sal_uInt32 SfxItemPool::GetItemCount2(sal_uInt16 nWhich) const +{ + if ( !IsInRange(nWhich) ) + { + if ( pImpl->mpSecondary ) + return pImpl->mpSecondary->GetItemCount2( nWhich ); + assert(false && "unknown WhichId - cannot resolve surrogate"); + return 0; + } + + SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(nWhich)]; + return rItemArr.size(); +} + + +sal_uInt16 SfxItemPool::GetWhich( sal_uInt16 nSlotId, bool bDeep ) const +{ + if ( !IsSlot(nSlotId) ) + return nSlotId; + + sal_uInt16 nCount = pImpl->mnEnd - pImpl->mnStart + 1; + for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs ) + if ( pItemInfos[nOfs]._nSID == nSlotId ) + return nOfs + pImpl->mnStart; + if ( pImpl->mpSecondary && bDeep ) + return pImpl->mpSecondary->GetWhich(nSlotId); + return nSlotId; +} + + +sal_uInt16 SfxItemPool::GetSlotId( sal_uInt16 nWhich ) const +{ + if ( !IsWhich(nWhich) ) + return nWhich; + + if ( !IsInRange( nWhich ) ) + { + if ( pImpl->mpSecondary ) + return pImpl->mpSecondary->GetSlotId(nWhich); + assert(false && "unknown WhichId - cannot get slot-id"); + return 0; + } + + sal_uInt16 nSID = pItemInfos[nWhich - pImpl->mnStart]._nSID; + return nSID ? nSID : nWhich; +} + + +sal_uInt16 SfxItemPool::GetTrueWhich( sal_uInt16 nSlotId, bool bDeep ) const +{ + if ( !IsSlot(nSlotId) ) + return 0; + + sal_uInt16 nCount = pImpl->mnEnd - pImpl->mnStart + 1; + for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs ) + if ( pItemInfos[nOfs]._nSID == nSlotId ) + return nOfs + pImpl->mnStart; + if ( pImpl->mpSecondary && bDeep ) + return pImpl->mpSecondary->GetTrueWhich(nSlotId); + return 0; +} + + +sal_uInt16 SfxItemPool::GetTrueSlotId( sal_uInt16 nWhich ) const +{ + if ( !IsWhich(nWhich) ) + return 0; + + if ( !IsInRange( nWhich ) ) + { + if ( pImpl->mpSecondary ) + return pImpl->mpSecondary->GetTrueSlotId(nWhich); + assert(false && "unknown WhichId - cannot get slot-id"); + return 0; + } + return pItemInfos[nWhich - pImpl->mnStart]._nSID; +} + +void SfxItemPool::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SfxItemPool")); + for (auto const & rArray : pImpl->maPoolItemArrays) + for (auto const & rItem : rArray) + rItem->dumpAsXml(pWriter); + (void)xmlTextWriterEndElement(pWriter); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |