summaryrefslogtreecommitdiff
path: root/svl/source/items
diff options
context:
space:
mode:
authorArmin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de>2024-02-09 11:13:58 +0100
committerArmin Le Grand <Armin.Le.Grand@me.com>2024-02-12 10:35:33 +0100
commitca3c6d468f68af1506bf4e56b47655e5d56306a8 (patch)
tree27da565a170606c4ea54ea07aa0dbb21eba3fe60 /svl/source/items
parent207501b8385818a5d413b9f4001e0d24aaa4f2a9 (diff)
ITEM: ItemPool Rework (I)
Driving forward the Item reworks I now take the ItemPool in focus: It now does not hold any items anymore and should be renamed to something like ItemInfoProvider/ItemHelper, since it's main purpose is to provide the Defaults for the Item functionality. There is that SfxItemInfo, only a struct and bundling SlotID and ItemFlags. There are also the DefaultItems, just handled as ptrs in an array. It is/was always error-prone to keep these in sync. Remember that it's also necessary for the order to not only being sorted but being increments of one with no gaps allowed in the WhichIDs to which the Items are bound. I now bundled that to a new class ItemInfo that joins WhichID, SlotID, ItemFlags and the default Item. This is a pure virtual base class, it comes in three derivations: (1) ItemInfoStatic: This is supposed to be global static and hosts the Item in a std::unique_ptr to ensure cleanup. It is designed to be constructed once during runtime and being shared globally. It allows the ItemPtr to be nullptr to mark as non-static (if initial static is not possible for some reason) but still offers the needed data. Most cases (95%+) are of that case. The contained Item is owned by that instance. The flag isStaticDefault() is set at the Item. (2) ItemInfoDynamic: This is supposed to be used for cases where the Item cannot be static: Mainly for SfxSetItem (that needs a Pool itself in the contained SfxItemSet, so lifetime is bound to that Pool), but other cases showed up in the transition. These instances live while the Pool lives and get destructed when the Pool goes down. Also uses std::unique_ptr for the Item instance for as much automated cleanup as possible, the contained Item is owned by that instance, the instance by the Pool. The flag isDynamicDefault() is set at the Item. (3) ItemInfoUser: This is used for UserDefaults that can be set for every ItemInfo entry to 'overshadow' the default from the 'outside'. It uses a regular Item and the central access methods implCreateItemEntry/ implCleanupItemEntry to manage the Item instance, thus works like a SfxPoolItemHolder. The Item instance can be globally shared and re-used even when the Pool goes down. Instances belong to the Pool and are cleaned up when the Pool goes down. This Item does not need any further flag to be set. The ItemInfos are organized using a class called ItemInfoPackage: This bundles groups of ItemInfoStatic to functional instances. There are derivations/ implementations of this e.g. for Writer ItemPool bundling all the needed defaults for Writer, similar for draw/impress, Calc and other usages. These ItemInfoPackage can be 'registered' at an ItemPool using it's method registerItemInfoPackage. This does all the needed stuff to setup that group of ItemInfos at the Pool (It even sets internal vars First/LastWhich, that info can just be derived from the buildup ItemInfo Ptrs). The ItemInfoPackage has methods 'size()' and 'getItemInfo(index) to allow looping over it and deliver the infos the Pool needs. The (forced, pure virtual) overloads of getItemInfo in the specific implementations check for the ItemPtr being nullptr and create a exclusive incarnation of ItemInfoDynamic for the Pool if needed, returning that. The Pool owns the ItemInfoDynamic incarnations and uses the ItemInfoStatic directly. On shutdown it cleans up the ItemInfoDynamic as needed. The ItemInfoUser is used by the Pool when a UserDefault is set/used: for SetUserDefaultItem, GetUserDefaultItem, ResetUserDefaultItem. It is not held in a 2nd list, but directly in the list of ItemInfo'ptrs: To keep track of this an unordered_map is used that helds the original ItemInfo associated with the WhichID. That way no two lookups (as before) are needed to get the current Pool's default for any WhichID. The derivations of ItemInfoPackage are encapsulated and just allow access to an ItemInfoPackage& with a single method as return value. All use a static local instance of a std::array<ItemInfoStatic, FIXED_SIZE> which constructs all ItemInfoStatic and the static Item instances - if already possible. Sometimes it is necessary to overload the constructor to set some static instances for Items later than the lib init. These are also just marked with nullptr as Item instance. Some need to overload getItemInfo to complete instances of ItemInfoStatic, if needed, or create and deliver instances of ItemInfoDynamic. The registerItemInfoPackage also offers a optional lambda callback: there were two cases where local data from the Pool was needed to incarnate the item - just add that to the call to registerItemInfoPackage if needed, see examples in the adapted code. For the re-use of Items this means that now in SfxItemSet/SfxPoolItemHolder *true* static Items can and will be used without RefCount directly and globally. This is also the case for dynamic Items, with the exception of differing Pools for SfxSetItems which cannot be done. Future: That design is already prepared to allow solving that Pool-chaining problem: currently there are master/sub-pools and all accesses have to traverse that structure before even doing anything. For the future the idea is more to 'compose' a Pool by registering ItemInfoPackages, e.g. for Writer pool you may start with SfxItemPool, register the writer-specific ItemInfoPackage, then the one for DrawingLayer (if needed) and the one for EditEngine. It should also be possible to get to smaller granularities of that packages. Ideas for new ones will emerge. We might also think about composing Pools which can e.g. run Writer and Chart, so allowing to use Chart *without* OLE stuff in Writer - just ideas... More changes: - Adapted all stuff, cleaned up old stuff/ definitions - Removed FreezeIdRanges, that can be done once per Pool on-demand (and cannot be forgotten to be called) - Merged XOutdevItemPool with SdrItemPool and offered a ItemInfoPackage which joins both needed sets of Items - All the cleanup hassle with Pools and defaults cleaned up - Adapted all access methods of the pool to use that new stuff. Pool chaining currently stays, but I use a central method 'getTargetPool' instead of recursive calling to get the correct Pool for the action Change-Id: I2b8d3d4c3cc80b1d0d0b3c0f4bd90d7656b4bab7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163157 Tested-by: Jenkins Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Diffstat (limited to 'svl/source/items')
-rw-r--r--svl/source/items/itempool.cxx746
-rw-r--r--svl/source/items/itemset.cxx42
-rw-r--r--svl/source/items/poolitem.cxx1
3 files changed, 347 insertions, 442 deletions
diff --git a/svl/source/items/itempool.cxx b/svl/source/items/itempool.cxx
index 0b5fd21b2fe8..8108a72b31c4 100644
--- a/svl/source/items/itempool.cxx
+++ b/svl/source/items/itempool.cxx
@@ -186,57 +186,150 @@
// RES_UNKNOWNATR_CONTAINER ok
// RES_TXTATR_UNKNOWN_CONTAINER ok
+ItemInfoUser::ItemInfoUser(const ItemInfo& rItemInfo, SfxItemPool& rItemPool, const SfxPoolItem& rItem, bool bPassingOwnership)
+: ItemInfo(rItemInfo)
+, m_pItem(implCreateItemEntry(rItemPool, &rItem, bPassingOwnership))
+{
+}
+ItemInfoUser::~ItemInfoUser()
+{
+ implCleanupItemEntry(m_pItem);
+}
-#if OSL_DEBUG_LEVEL > 0
-#include <map>
+const ItemInfo& ItemInfoPackage::getExistingItemInfo(size_t /*nIndex*/)
+{
+ static ItemInfoStatic EMPTY(0, nullptr, 0, 0);
+ return EMPTY;
+}
-static void
-lcl_CheckSlots2(std::map<sal_uInt16, sal_uInt16> & rSlotMap,
- SfxItemPool const& rPool, SfxItemInfo const* pInfo)
+void SfxItemPool::registerItemInfoPackage(
+ ItemInfoPackage& rPackage,
+ const std::function<SfxPoolItem*(sal_uInt16)>& rCallback)
{
- 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)
+ assert(maItemInfos.empty() && "ITEM: registering more than one ItemInfoPackage per Pool is not allowed (!)");
+
+ // we know the size :-)
+ maItemInfos.reserve(rPackage.size());
+
+ // loop over ItemInfoPackage and add ptrs to provided ItemInfos
+ for(size_t a(0); a < rPackage.size(); a++)
{
- sal_uInt16 const nSlotId(pInfo[n]._nItemInfoSlotID);
- 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));
+ // get ItemInfo entry, maybe StaticDefault or DynamicDefault
+ const ItemInfo& rItemInfo(rPackage.getItemInfo(a, *this));
+
+ if (nullptr != rItemInfo.getItem())
+ {
+ // if it has an item, use it, done
+ maItemInfos.push_back(&rItemInfo);
+ continue;
}
+
+ // if not, use the callback to create a DynamicDefault. This
+ // *has* to be supported then by the caller
+ SfxPoolItem* pDynamicItem(rCallback(rItemInfo.getWhich()));
+ assert(nullptr != pDynamicItem);
+ maItemInfos.push_back(new ItemInfoDynamic(rItemInfo, pDynamicItem));
+ }
+
+ // use infos to fill local variables
+ mnStart = maItemInfos.front()->getWhich();
+ mnEnd = maItemInfos.back()->getWhich();
+
+#ifdef DBG_UTIL
+ for (size_t a(1); a < maItemInfos.size(); a++)
+ if (maItemInfos[a-1]->getWhich() + 1 != maItemInfos[a]->getWhich())
+ assert(false && "ITEM: Order is wrong (!)");
+#endif
+}
+
+const ItemInfo* SfxItemPool::impCheckItemInfoForClone(const ItemInfo* pInfo)
+{
+ const SfxPoolItem* pItem(pInfo->getItem());
+ assert(nullptr != pItem && "ITEM: Missing Item in ItemInfo (!)");
+
+ if (pItem->isStaticDefault())
+ // noting to do, not ref-counted
+ return pInfo;
+
+ if (pItem->isDynamicDefault())
+ {
+ // need to clone to new Pool as DynamicDefault, owned by the Pool
+ // and not shared. Mainly SfxSetItems. Not RefCounted
+ return new ItemInfoDynamic(*pInfo, pItem->Clone(this));
}
+
+ // all Items else that can be in the Pool are UserDefaults. These
+ // are RefCounted, so use implCreateItemEntry to increase reference
+ return new ItemInfoUser(*pInfo, *this, *pItem);
+}
+
+void SfxItemPool::impClearUserDefault(userItemInfos::iterator& rHit)
+{
+ if (rHit == maUserItemInfos.end())
+ // does not exist
+ return;
+
+ // get ItemInfo and Item, HAS to be a UserDefault
+ const sal_uInt16 nIndex(GetIndex_Impl(rHit->first));
+ const ItemInfo* pInfo(maItemInfos[nIndex]);
+ assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
+
+ // restore original entry using the remembered one
+ maItemInfos[nIndex] = rHit->second;
+
+ // free Item, delete ItemInfo
+ delete pInfo;
}
-#define CHECK_SLOTS() \
-do { \
- std::map<sal_uInt16, sal_uInt16> slotmap; \
- for (SfxItemPool * p = mpMaster; p; p = p->mpSecondary.get()) \
- { \
- lcl_CheckSlots2(slotmap, *p, p->pItemInfos); \
- } \
-} while (false)
-
-#else
-#define CHECK_SLOTS() do {} while (false)
+void SfxItemPool::impCreateUserDefault(const SfxPoolItem& rItem)
+{
+ const sal_uInt16 nWhich(rItem.Which());
+
+ // make sure by an assert check that none exists
+ assert(maUserItemInfos.end() == maUserItemInfos.find(nWhich));
+
+ const sal_uInt16 nIndex(GetIndex_Impl(nWhich));
+ const ItemInfo* pInfo(maItemInfos[nIndex]);
+ assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
+
+ // safe original ItemInfo in UserItemInfos
+ maUserItemInfos.insert({nWhich, pInfo});
+
+ // create new Item by using implCreateItemEntry and new ItemInfo
+ maItemInfos[nIndex] = new ItemInfoUser(*pInfo, *this, rItem);
+}
+
+void SfxItemPool::cleanupItemInfos()
+{
+ // reset all UserDefaultItems & restore original maItemInfos
+ while (!maUserItemInfos.empty())
+ {
+ // get next candidate, cleanup UseDefault and remove data
+ userItemInfos::iterator aHit(maUserItemInfos.begin());
+ impClearUserDefault(aHit);
+ maUserItemInfos.erase(aHit);
+ }
+
+ // delete DynamicDefaults in maItemInfos, these only exist
+ // for Pool lifetime since they are Pool-dependent. There should
+ // be NO MORE UserDefaults after cleanup above
+ for (auto& rInfo : maItemInfos)
+ {
+ if (rInfo->getItem()->isDynamicDefault())
+ {
+ // the whole ItemInfo is owned by the pool, so
+ // delete the Item and the ItemInfo (in that order :-)
+ delete rInfo;
+ }
+#ifdef DBG_UTIL
+ // since there should be NO MORE UserDefaults the item
+ // then *has* to be StaticDefault - check that
+ else if (!rInfo->getItem()->isStaticDefault())
+ assert(false && "ITEM: Error in UserDefault handling (!)");
#endif
+ }
+}
void SfxItemPool::registerItemSet(SfxItemSet& rSet)
{
@@ -302,63 +395,30 @@ void SfxItemPool::unregisterPoolItemHolder(SfxPoolItemHolder& rHolder)
#endif
}
-sal_uInt16 SfxItemPool::GetFirstWhich() const
-{
- return mnStart;
-}
-
-sal_uInt16 SfxItemPool::GetLastWhich() const
-{
- return mnEnd;
-}
-
-bool SfxItemPool::IsInRange( sal_uInt16 nWhich ) const
-{
- return nWhich >= mnStart && nWhich <= mnEnd;
-}
-
-sal_uInt16 SfxItemPool::GetIndex_Impl(sal_uInt16 nWhich) const
+SfxItemPool* SfxItemPool::getTargetPool(sal_uInt16 nWhich) const
{
- if (nWhich < mnStart || nWhich > mnEnd)
- {
- assert(false && "missing bounds check before use");
- return 0;
- }
- return nWhich - mnStart;
+ if (IsInRange(nWhich))
+ return const_cast<SfxItemPool*>(this);
+ if (mpSecondary)
+ return mpSecondary->getTargetPool(nWhich);
+ return nullptr;
}
-sal_uInt16 SfxItemPool::GetSize_Impl() const
-{
- return mnEnd - mnStart + 1;
-}
-
-const SfxPoolItem* SfxItemPool::GetUserDefaultItem( sal_uInt16 nWhich ) const
-{
- const SfxPoolItem* pRet;
- if( IsInRange( nWhich ) )
- pRet = maUserDefaults[GetIndex_Impl(nWhich)];
- else if( mpSecondary )
- pRet = mpSecondary->GetUserDefaultItem( nWhich );
- else
- {
- assert(false && "unknown WhichId - cannot get pool default");
- pRet = nullptr;
- }
- return pRet;
-}
-
-
bool SfxItemPool::CheckItemInfoFlag(sal_uInt16 nWhich, sal_uInt16 nMask) const
{
- if (!IsInRange(nWhich))
- {
- // get to correct pool
- if (mpSecondary)
- return mpSecondary->CheckItemInfoFlag(nWhich, nMask);
+ SfxItemPool* pTarget(getTargetPool(nWhich));
+ if (nullptr == pTarget)
return false;
+
+ if (!pTarget->maItemInfos.empty())
+ {
+ const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
+ const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
+ assert(nullptr != pInfo);
+ return pInfo->getItemInfoFlags() & nMask;
}
- return CheckItemInfoFlag_Impl(nWhich - mnStart, nMask);
+ return pTarget->CheckItemInfoFlag_Impl(pTarget->GetIndex_Impl(nWhich), nMask);
}
SfxBroadcaster& SfxItemPool::BC()
@@ -366,7 +426,6 @@ SfxBroadcaster& SfxItemPool::BC()
return aBC;
}
-
/**
* This is the regular ctor to be used for this class.
* An SfxItemPool instance is initialized, which can manage Items in the
@@ -389,212 +448,67 @@ SfxBroadcaster& SfxItemPool::BC()
* @see SfxItemPool::ReleasePoolDefaults(std::vector<SfxPoolItem*>*,bool)
* @see SfxItemPool::ReleasePoolDefaults(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 */
-)
+SfxItemPool::SfxItemPool(const OUString& rName) /* Pool name to identify in the file format */
: salhelper::SimpleReferenceObject()
-,pItemInfos(pInfo)
+, aBC()
, aName(rName)
-, maUserDefaults(nEndWhich - nStartWhich + 1)
-, mpPoolDefaults(nullptr)
, mpMaster(this)
-, mnStart(nStartWhich)
-, mnEnd(nEndWhich)
+, mpSecondary()
+, mnStart(0)
+, mnEnd(0)
, eDefMetric(MapUnit::MapCM)
, maRegisteredSfxItemSets()
, maRegisteredSfxPoolItemHolders()
-, mbPreDeleteDone(false)
+, mbShutdownHintSent(false)
+, maItemInfos()
+, maUserItemInfos()
{
eDefMetric = MapUnit::MapTwip;
-
- if ( pDefaults )
- SetPoolDefaults(pDefaults);
-
-#ifdef DBG_UTIL
- if (pItemInfos)
- {
- auto p = pItemInfos;
- auto nWhich = nStartWhich;
- while (nWhich <= nEndWhich)
- {
- if (p->_nItemInfoSlotID == 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 */
-)
+SfxItemPool::SfxItemPool(const SfxItemPool& rPool) // Copy from this instance
: salhelper::SimpleReferenceObject()
-, pItemInfos(rPool.pItemInfos)
+, aBC()
, aName(rPool.aName)
-, maUserDefaults(rPool.mnEnd - rPool.mnStart + 1)
-, mpPoolDefaults(nullptr)
, mpMaster(this)
+, mpSecondary()
+, maPoolRanges()
, mnStart(rPool.mnStart)
, mnEnd(rPool.mnEnd)
, eDefMetric(MapUnit::MapCM)
, maRegisteredSfxItemSets()
, maRegisteredSfxPoolItemHolders()
-, mbPreDeleteDone(false)
+, mbShutdownHintSent(false)
+, maItemInfos(rPool.maItemInfos)
+, maUserItemInfos(rPool.maUserItemInfos)
{
- eDefMetric = rPool.eDefMetric;
-
- // Take over static Defaults
- if ( bCloneStaticDefaults )
- {
- std::vector<SfxPoolItem *>* ppDefaults = new std::vector<SfxPoolItem*>(mnEnd-mnStart+1);
- for ( sal_uInt16 n = 0; n <= mnEnd - mnStart; ++n )
- {
- (*ppDefaults)[n] = (*rPool.mpPoolDefaults)[n]->Clone(this);
- (*ppDefaults)[n]->setStaticDefault();
- }
+ // DynamicDefaults and UserDefaults need to be cloned for the new Pool
+ for (itemInfoVector::iterator aInfo(maItemInfos.begin()); aInfo != maItemInfos.end(); aInfo++)
+ *aInfo = impCheckItemInfoForClone(*aInfo);
- SetPoolDefaults( ppDefaults );
- }
- else
- SetPoolDefaults( rPool.mpPoolDefaults );
+ // DynamicDefaults need to be cloned for the new Pool (no UserDefaults in UserItemInfos)
+ for (auto& rUserItem : maUserItemInfos)
+ rUserItem.second = impCheckItemInfoForClone(rUserItem.second);
- // Copy Pool Defaults
- for (size_t n = 0; n < maUserDefaults.size(); ++n )
- if (rPool.maUserDefaults[n])
- {
- maUserDefaults[n] = rPool.maUserDefaults[n]->Clone(this); //resets kind
- maUserDefaults[n]->setUserDefault();
- }
+ eDefMetric = rPool.eDefMetric;
// Repair linkage
if ( rPool.mpSecondary )
SetSecondaryPool( rPool.mpSecondary->Clone().get() );
}
-void SfxItemPool::SetPoolDefaults( std::vector<SfxPoolItem*>* pDefaults )
-{
- DBG_ASSERT( pDefaults, "first we ask for it, and then we don't give back..." );
- DBG_ASSERT( !mpPoolDefaults, "already have Defaults" );
-
- mpPoolDefaults = pDefaults;
- //! if ((*mpPoolDefaults)->GetKind() != SfxItemKind::StaticDefault)
- //! FIXME: Probably doesn't work with SetItems at the end
- {
- DBG_ASSERT( (*mpPoolDefaults)[0]->GetRefCount() == 0 ||
- IsDefaultItem( (*mpPoolDefaults)[0] ),
- "these are not static" );
- for ( sal_uInt16 n = 0; n <= mnEnd - mnStart; ++n )
- {
- assert( ((*mpPoolDefaults)[n]->Which() == n + mnStart)
- && "items ids in pool-ranges and in static-defaults do not match" );
- (*mpPoolDefaults)[n]->setStaticDefault();
- }
- }
-}
-
-void SfxItemPool::ClearPoolDefaults()
-{
- mpPoolDefaults = 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::ReleasePoolDefaults
-(
- 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( mpPoolDefaults, "requirements not met" );
- ReleasePoolDefaults( mpPoolDefaults, bDelete );
-
- // mpPoolDefaults points to deleted memory if bDelete == true.
- if ( bDelete )
- mpPoolDefaults = 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::ReleasePoolDefaults
-(
- 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()
{
- // Need to be deleted?
- if (!mbPreDeleteDone)//maUserDefaults.empty())
- Delete();
+ // cleanup UserDefaults & delete owned DynamicDefaults
+ cleanupItemInfos();
+
+ // Need to send ShutdownHint?
+ sendShutdownHint();
if (mpMaster != nullptr && mpMaster != this)
{
@@ -626,40 +540,19 @@ void SfxItemPool::SetSecondaryPool( SfxItemPool *pPool )
// Remember new Secondary Pool
mpSecondary = pPool;
-
- CHECK_SLOTS();
-}
-
-void SfxItemPool::SetItemInfos(SfxItemInfo const*const pInfo)
-{
- pItemInfos = pInfo;
- CHECK_SLOTS();
}
-
MapUnit SfxItemPool::GetMetric( sal_uInt16 ) const
{
return eDefMetric;
}
-
void SfxItemPool::SetDefaultMetric( MapUnit eNewMetric )
{
-// assert((pImpl->eDefMetric == eNewMetric || !pImpl->mpPoolRanges) && "pool already frozen, cannot change metric");
+// assert((pImpl->eDefMetric == eNewMetric || !pImpl->maPoolRanges) && "pool already frozen, cannot change metric");
eDefMetric = eNewMetric;
}
-MapUnit SfxItemPool::GetDefaultMetric() const
-{
- return eDefMetric;
-}
-
-const OUString& SfxItemPool::GetName() const
-{
- return aName;
-}
-
-
bool SfxItemPool::GetPresentation
(
const SfxPoolItem& rItem,
@@ -672,166 +565,162 @@ bool SfxItemPool::GetPresentation
SfxItemPresentation::Complete, GetMetric(rItem.Which()), eMetric, rText, rIntlWrapper );
}
-
rtl::Reference<SfxItemPool> SfxItemPool::Clone() const
{
return new SfxItemPool( *this );
}
-
-void SfxItemPool::Delete()
+void SfxItemPool::sendShutdownHint()
{
- // Already deleted?
- if (mbPreDeleteDone)//maUserDefaults.empty())
+ // Already sent?
+ if (mbShutdownHintSent)
return;
- mbPreDeleteDone = true;
+
+ mbShutdownHintSent = true;
// Inform e.g. running Requests
aBC.Broadcast( SfxHint( SfxHintId::Dying ) );
+ maPoolRanges.reset();
+}
+
+void SfxItemPool::SetUserDefaultItem(const SfxPoolItem& rItem)
+{
+ SfxItemPool* pTarget(getTargetPool(rItem.Which()));
+ if (nullptr == pTarget)
+ assert(false && "unknown WhichId - cannot set pool default");
- // default items
- for (auto rItemPtr : maUserDefaults)
+ const sal_uInt16 nWhich(rItem.Which());
+ userItemInfos::iterator aHit(pTarget->maUserItemInfos.find(nWhich));
+
+ if (aHit == pTarget->maUserItemInfos.end())
{
- if (rItemPtr)
- {
-#ifdef DBG_UTIL
- ClearRefCount(*rItemPtr);
-#endif
- delete rItemPtr;
- rItemPtr = nullptr;
- }
+ // UserDefault does not exist, create needed entries to safe
+ // original ItemInfo in UserItemInfos and set new, owned
+ // ItemInfo containing an owned clone of the Item in ItemInfos
+ pTarget->impCreateUserDefault(rItem);
+ return;
}
- maUserDefaults.clear();
- mpPoolRanges.reset();
-}
+ // UserDefault does exist, check and evtl. replace
+ const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
+ const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
+ assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
+ const SfxPoolItem* pItem(pInfo->getItem());
+ assert(nullptr != pItem && "ITEM: access error to Defaults in Pool (!)");
+ // nothing to do if equal, so check
+ if (SfxPoolItem::areSame(pItem, &rItem))
+ return;
+
+ // need to exchange existing instance and free current one
+ pTarget->maItemInfos[nIndex] = new ItemInfoUser(*pInfo, *pTarget, rItem);
+ delete pInfo;
+}
-void SfxItemPool::SetUserDefaultItem(const SfxPoolItem &rItem)
+const SfxPoolItem* SfxItemPool::GetUserDefaultItem( sal_uInt16 nWhich ) const
{
- if ( IsInRange(rItem.Which()) )
+ SfxItemPool* pTarget(getTargetPool(nWhich));
+ if (nullptr == pTarget)
{
- auto& rOldDefault =
- maUserDefaults[GetIndex_Impl(rItem.Which())];
- SfxPoolItem *pNewDefault = rItem.Clone(this);
- pNewDefault->setUserDefault();
- if (rOldDefault)
- {
- rOldDefault->SetRefCount(0);
- delete rOldDefault;
- rOldDefault = nullptr;
- }
- rOldDefault = pNewDefault;
- }
- else if ( mpSecondary )
- mpSecondary->SetUserDefaultItem(rItem);
- else
- {
- assert(false && "unknown WhichId - cannot set pool default");
+ assert(false && "unknown WhichId - cannot get pool default");
+ return nullptr;
}
+
+ userItemInfos::iterator aHit(pTarget->maUserItemInfos.find(nWhich));
+
+ if (aHit == pTarget->maUserItemInfos.end())
+ // no default item
+ return nullptr;
+
+ const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
+ const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
+ assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
+ const SfxPoolItem* pItem(pInfo->getItem());
+ assert(nullptr != pItem && "ITEM: access error to Defaults in Pool (!)");
+ return pItem;
}
/**
* Resets the default of the given WhichId back to the static Default.
* If a pool default exists, it is removed.
*/
-void SfxItemPool::ResetUserDefaultItem( sal_uInt16 nWhichId )
+void SfxItemPool::ResetUserDefaultItem( sal_uInt16 nWhich )
{
- if ( IsInRange(nWhichId) )
- {
- auto& rOldDefault =
- maUserDefaults[GetIndex_Impl(nWhichId)];
- if (rOldDefault)
- {
- rOldDefault->SetRefCount(0);
- delete rOldDefault;
- rOldDefault = nullptr;
- }
- }
- else if ( mpSecondary )
- mpSecondary->ResetUserDefaultItem(nWhichId);
- else
- {
+ SfxItemPool* pTarget(getTargetPool(nWhich));
+ if (nullptr == pTarget)
assert(false && "unknown WhichId - cannot reset pool default");
+
+ userItemInfos::iterator aHit(pTarget->maUserItemInfos.find(nWhich));
+
+ if (aHit != pTarget->maUserItemInfos.end())
+ {
+ // clear entry, cleanup, restore previous data
+ pTarget->impClearUserDefault(aHit);
+
+ // remove remembered data
+ pTarget->maUserItemInfos.erase(aHit);
}
}
const SfxPoolItem& SfxItemPool::GetUserOrPoolDefaultItem( sal_uInt16 nWhich ) const
{
- if ( !IsInRange(nWhich) )
- {
- if ( mpSecondary )
- return mpSecondary->GetUserOrPoolDefaultItem( nWhich );
+ SfxItemPool* pTarget(getTargetPool(nWhich));
+ if (nullptr == pTarget)
assert(!"unknown which - don't ask me for defaults");
- }
-
- DBG_ASSERT( mpPoolDefaults, "no defaults known - don't ask me for defaults" );
- sal_uInt16 nPos = GetIndex_Impl(nWhich);
- SfxPoolItem* pDefault = maUserDefaults[nPos];
- if ( pDefault )
- return *pDefault;
- return *(*mpPoolDefaults)[nPos];
-}
-SfxItemPool* SfxItemPool::GetSecondaryPool() const
-{
- return mpSecondary.get();
+ const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
+ const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
+ assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
+ const SfxPoolItem* pItem(pInfo->getItem());
+ assert(nullptr != pItem && "ITEM: access error to Defaults in Pool (!)");
+ return *pItem;
}
/* get the last pool by following the GetSecondaryPool chain */
SfxItemPool* SfxItemPool::GetLastPoolInChain()
{
- SfxItemPool* pLast = this;
+ SfxItemPool* pLast(this);
+
while(pLast->GetSecondaryPool())
pLast = pLast->GetSecondaryPool();
+
return pLast;
}
-SfxItemPool* SfxItemPool::GetMasterPool() const
+const WhichRangesContainer& SfxItemPool::GetMergedIdRanges() const
{
- return mpMaster;
-}
+ if (maPoolRanges.empty())
+ {
+ // Merge all ranges, keeping them sorted
+ for (const SfxItemPool* pPool = this; pPool; pPool = pPool->mpSecondary.get())
+ maPoolRanges = maPoolRanges.MergeRange(pPool->mnStart, pPool->mnEnd);
+ }
-/**
- * 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(mpPoolRanges.empty() && "pool already frozen, cannot freeze twice");
- FillItemIdRanges_Impl( mpPoolRanges );
+ return maPoolRanges;
}
-
-void SfxItemPool::FillItemIdRanges_Impl( WhichRangesContainer& pWhichRanges ) const
+const SfxPoolItem* SfxItemPool::GetPoolDefaultItem(sal_uInt16 nWhich) const
{
- DBG_ASSERT( mpPoolRanges.empty(), "GetFrozenRanges() would be faster!" );
-
- pWhichRanges.reset();
-
- // Merge all ranges, keeping them sorted
- for (const SfxItemPool* pPool = this; pPool; pPool = pPool->mpSecondary.get())
- pWhichRanges = pWhichRanges.MergeRange(pPool->mnStart, pPool->mnEnd);
-}
+ SfxItemPool* pTarget(getTargetPool(nWhich));
+ if (nullptr == pTarget)
+ assert(false && "unknown WhichId - cannot resolve surrogate");
-const WhichRangesContainer& SfxItemPool::GetFrozenIdRanges() const
-{
- return mpPoolRanges;
-}
+ const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
+ userItemInfos::iterator aHit(pTarget->maUserItemInfos.find(nWhich));
-const SfxPoolItem *SfxItemPool::GetPoolDefaultItem(sal_uInt16 nWhich) const
-{
- if ( !IsInRange(nWhich) )
+ if (aHit != pTarget->maUserItemInfos.end())
{
- if ( mpSecondary )
- return mpSecondary->GetPoolDefaultItem( nWhich );
- assert(false && "unknown WhichId - cannot resolve surrogate");
- return nullptr;
+ // If it is a UserDefault Item, check saved ItemInfo and use
+ // Item from there
+ assert(aHit != pTarget->maUserItemInfos.end() && "ITEM: Error in UserDefault handling (!)");
+ return aHit->second->getItem();
}
- return (*mpPoolDefaults)[ GetIndex_Impl(nWhich) ];
+
+ const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
+ assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
+ const SfxPoolItem* pItem(pInfo->getItem());
+ assert(nullptr != pItem && "ITEM: access error to Defaults in Pool (!)");
+ return pItem;
}
namespace
@@ -967,67 +856,78 @@ void SfxItemPool::GetItemSurrogates(ItemSurrogates& rTarget, sal_uInt16 nWhich)
rTarget = ItemSurrogates(aNewSurrogates.begin(), aNewSurrogates.end());
}
-sal_uInt16 SfxItemPool::GetWhich( sal_uInt16 nSlotId, bool bDeep ) const
+sal_uInt16 SfxItemPool::GetWhich(sal_uInt16 nSlotId, bool bDeep) const
{
- if ( !IsSlot(nSlotId) )
+ if (!IsSlot(nSlotId))
return nSlotId;
- sal_uInt16 nCount = mnEnd - mnStart + 1;
- for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs )
- if ( pItemInfos[nOfs]._nItemInfoSlotID == nSlotId )
- return nOfs + mnStart;
- if ( mpSecondary && bDeep )
+ for (auto& rInfo : maItemInfos)
+ {
+ assert(nullptr != rInfo && "ITEM: access error to Defaults in Pool (!)");
+ if (nSlotId == rInfo->getSlotID())
+ {
+ return rInfo->getWhich();
+ }
+ }
+
+ if (mpSecondary && bDeep)
return mpSecondary->GetWhich(nSlotId);
+
return nSlotId;
}
-sal_uInt16 SfxItemPool::GetSlotId( sal_uInt16 nWhich ) const
+sal_uInt16 SfxItemPool::GetSlotId(sal_uInt16 nWhich) const
{
- if ( !IsWhich(nWhich) )
+ if (!IsWhich(nWhich))
return nWhich;
- if ( !IsInRange( nWhich ) )
- {
- if ( mpSecondary )
- return mpSecondary->GetSlotId(nWhich);
+ SfxItemPool* pTarget(getTargetPool(nWhich));
+ if (nullptr == pTarget)
assert(false && "unknown WhichId - cannot get slot-id");
- return 0;
- }
- sal_uInt16 nSID = pItemInfos[nWhich - mnStart]._nItemInfoSlotID;
- return nSID ? nSID : nWhich;
+ const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
+ const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
+ assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
+ const sal_uInt16 nSID(pInfo->getSlotID());
+ return (0 != nSID) ? nSID : nWhich;
}
sal_uInt16 SfxItemPool::GetTrueWhich( sal_uInt16 nSlotId, bool bDeep ) const
{
- if ( !IsSlot(nSlotId) )
+ if (!IsSlot(nSlotId))
return 0;
- sal_uInt16 nCount = mnEnd - mnStart + 1;
- for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs )
- if ( pItemInfos[nOfs]._nItemInfoSlotID == nSlotId )
- return nOfs + mnStart;
- if ( mpSecondary && bDeep )
+ for (auto& rInfo : maItemInfos)
+ {
+ assert(nullptr != rInfo && "ITEM: access error to Defaults in Pool (!)");
+ if (nSlotId == rInfo->getSlotID())
+ {
+ return rInfo->getWhich();
+ }
+ }
+
+ if (mpSecondary && bDeep)
return mpSecondary->GetTrueWhich(nSlotId);
+
return 0;
}
sal_uInt16 SfxItemPool::GetTrueSlotId( sal_uInt16 nWhich ) const
{
- if ( !IsWhich(nWhich) )
+ if (!IsWhich(nWhich))
return 0;
- if ( !IsInRange( nWhich ) )
- {
- if ( mpSecondary )
- return mpSecondary->GetTrueSlotId(nWhich);
+ SfxItemPool* pTarget(getTargetPool(nWhich));
+ if (nullptr == pTarget)
assert(false && "unknown WhichId - cannot get slot-id");
- return 0;
- }
- return pItemInfos[nWhich - mnStart]._nItemInfoSlotID;
+
+ const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
+ const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
+ assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
+ return pInfo->getSlotID();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svl/source/items/itemset.cxx b/svl/source/items/itemset.cxx
index 9271ab13f3c1..b01b0d54519e 100644
--- a/svl/source/items/itemset.cxx
+++ b/svl/source/items/itemset.cxx
@@ -209,18 +209,16 @@ bool SfxPoolItemHolder::operator==(const SfxPoolItemHolder &rHolder) const
*
* For Sfx programmers: an SfxItemSet constructed in this way cannot
* contain any Items with SlotIds as Which values.
- *
- * Don't create ItemSets with full range before FreezeIdRanges()!
*/
SfxItemSet::SfxItemSet(SfxItemPool& rPool)
: m_pPool(&rPool)
, m_pParent(nullptr)
, m_nCount(0)
, m_nRegister(0)
- , m_nTotalCount(svl::detail::CountRanges(rPool.GetFrozenIdRanges()))
+ , m_nTotalCount(svl::detail::CountRanges(rPool.GetMergedIdRanges()))
, m_bItemsFixed(false)
, m_ppItems(new SfxPoolItem const *[m_nTotalCount]{})
- , m_pWhichRanges(rPool.GetFrozenIdRanges())
+ , m_pWhichRanges(rPool.GetMergedIdRanges())
, m_aCallback()
{
#ifdef DBG_UTIL
@@ -497,16 +495,17 @@ SfxPoolItem const* implCreateItemEntry(SfxItemPool& rPool, SfxPoolItem const* pS
// just use pSource which equals DISABLED_POOL_ITEM
return pSource;
- // CAUTION: static default items are not *that* static as it seems
- // (or: should be). If they are freed with the Pool (see
- // ::ReleaseDefaults) they will be deleted. Same is true for
- // dynamic defaults. Thus currently no default can be shared
- // at all since these may be deleted with the pool owning them.
- // That these are not shared but cloned is ensured by those
- // having a default RefCount of zero, so these are used merely as
- // templates.
- // if (IsStaticDefaultItem(pSource))
- // return pSource;
+ if (pSource->isStaticDefault())
+ // static default Items can just be used without RefCounting
+ return pSource;
+
+ if (pSource->isDynamicDefault() && !pSource->isSetItem())
+ {
+ // dynamic default Items can only be used without RefCounting
+ // when same pool, else it has to be cloned (below)
+ if (static_cast<const SfxSetItem*>(pSource)->GetItemSet().GetPool() == &rPool)
+ return pSource;
+ }
if (0 == pSource->Which())
{
@@ -690,6 +689,17 @@ void implCleanupItemEntry(SfxPoolItem const* pSource)
// nothing to do for disabled item entries
return;
+ if (pSource->isStaticDefault())
+ // static default Items can just be used without RefCounting
+ return;
+
+ if (pSource->isDynamicDefault())
+ // dynamic default Items can only be used without RefCounting
+ // when same pool. this is already checked at implCreateItemEntry,
+ // so it would have been cloned (and would no longer have this
+ // flag). So we can just return here
+ return;
+
if (0 == pSource->Which())
{
// There should be no Items with 0 == WhichID, but there are some
@@ -713,10 +723,6 @@ void implCleanupItemEntry(SfxPoolItem const* pSource)
return;
}
- if (IsDefaultItem(pSource))
- // default items (static and dynamic) are owned by the pool, do not delete
- return;
-
// try to get an ItemInstanceManager for global Item instance sharing
ItemInstanceManager* pManager(aInstanceManagerHelper.getExistingItemInstanceManager(*pSource));
diff --git a/svl/source/items/poolitem.cxx b/svl/source/items/poolitem.cxx
index 31f6cd27990d..4ec0a5a2cd25 100644
--- a/svl/source/items/poolitem.cxx
+++ b/svl/source/items/poolitem.cxx
@@ -511,7 +511,6 @@ SfxPoolItem::SfxPoolItem(sal_uInt16 const nWhich)
#endif
, m_bStaticDefault(false)
, m_bDynamicDefault(false)
- , m_bUserDefault(false)
, m_bIsSetItem(false)
, m_bShareable(true)
#ifdef DBG_UTIL