summaryrefslogtreecommitdiffstats
path: root/svl/source/items/itempool.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svl/source/items/itempool.cxx')
-rw-r--r--svl/source/items/itempool.cxx1253
1 files changed, 1253 insertions, 0 deletions
diff --git a/svl/source/items/itempool.cxx b/svl/source/items/itempool.cxx
new file mode 100644
index 0000000000..faedbd516a
--- /dev/null
+++ b/svl/source/items/itempool.cxx
@@ -0,0 +1,1253 @@
+/* -*- 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>
+
+#ifdef DBG_UTIL
+static size_t nAllDirectlyPooledSfxPoolItemCount(0);
+static size_t nRemainingDirectlyPooledSfxPoolItemCount(0);
+size_t getAllDirectlyPooledSfxPoolItemCount() { return nAllDirectlyPooledSfxPoolItemCount; }
+size_t getRemainingDirectlyPooledSfxPoolItemCount() { return nRemainingDirectlyPooledSfxPoolItemCount; }
+#endif
+
+// WhichIDs that need to set _bNeedsPoolRegistration in SfxItemInfo
+// to true to allow a register of all items of that type/with that WhichID
+// to be accessible using SfxItemPool::GetItemSurrogates. Created by
+// grepping for 'GetItemSurrogates' usages & interpreting. Some
+// are double, more may be necessary. There is a SAL_INFO("svl.items", ...)
+// in SfxItemPool::GetItemSurrogates that will give hints on missing flags.
+//
+// due to SwTable::UpdateFields
+// due to SwCursorShell::GotoNxtPrvTableFormula
+// due to DocumentFieldsManager::UpdateTableFields
+// due to SwTable::GatherFormulas
+// RES_BOXATR_FORMULA ok
+// due to SwContentTree::EditEntry
+// due to SwDoc::FindINetAttr
+// due to SwUndoResetAttr::RedoImpl
+// due to SwContentTree::EditEntry
+// due to SwContentTree::BringEntryToAttention
+// RES_TXTATR_REFMARK ok
+// due to ImpEditEngine::WriteRTF
+// due to ScDocument::UpdateFontCharSet()
+// due to ScXMLFontAutoStylePool_Impl
+// due to SdXImpressDocument::getPropertyValue
+// due to Writer::AddFontItems_
+// EE_CHAR_FONTINFO ok
+// due to ImpEditEngine::WriteRTF
+// due to ScXMLFontAutoStylePool_Impl
+// due to SdXImpressDocument::getPropertyValue
+// due to Writer::AddFontItems_
+// EE_CHAR_FONTINFO_CJK ok
+// due to ImpEditEngine::WriteRTF
+// due to ScXMLFontAutoStylePool_Impl
+// due to SdXImpressDocument::getPropertyValue
+// due to Writer::AddFontItems_
+// EE_CHAR_FONTINFO_CTL ok
+// due to ImpEditEngine::WriteRTF
+// EE_CHAR_COLOR ok
+// due to ScDocumentPool::StyleDeleted
+// ATTR_PATTERN ok
+// due to ScDocument::UpdateFontCharSet()
+// due to ScXMLFontAutoStylePool_Impl
+// ATTR_FONT ok
+// due to OptimizeHasAttrib
+// ATTR_ROTATE_VALUE ok
+// due to ScDocument::GetDocColors()
+// ATTR_BACKGROUND ok
+// ATTR_FONT_COLOR ok
+// due to ScXMLExport::CollectUserDefinedNamespaces
+// ATTR_USERDEF ok
+// due to ScXMLExport::CollectUserDefinedNamespaces
+// due to SwXMLExport::exportDoc
+// EE_PARA_XMLATTRIBS ok
+// due to ScXMLExport::CollectUserDefinedNamespaces
+// due to SwXMLExport::exportDoc
+// EE_CHAR_XMLATTRIBS ok
+// due to ScXMLExport::CollectUserDefinedNamespaces
+// due to SwXMLExport::exportDoc
+// SDRATTR_XMLATTRIBUTES ok
+// due to ScXMLFontAutoStylePool_Impl
+// ATTR_CJK_FONT ok
+// ATTR_CTL_FONT ok
+// ATTR_PAGE_HEADERLEFT ok
+// ATTR_PAGE_FOOTERLEFT ok
+// ATTR_PAGE_HEADERRIGHT ok
+// ATTR_PAGE_FOOTERRIGHT ok
+// ATTR_PAGE_HEADERFIRST ok
+// ATTR_PAGE_FOOTERFIRST ok
+// due to ScCellShell::ExecuteEdit
+// due to ScTabViewShell::CreateRefDialogController
+// SCITEM_CONDFORMATDLGDATA ok
+// due to SdDrawDocument::UpdatePageRelativeURLs
+// EE_FEATURE_FIELD ok
+// due to SvxUnoMarkerTable::replaceByName
+// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
+// due to XLineStartItem::checkForUniqueItem
+// XATTR_LINESTART ok
+// due to SvxUnoMarkerTable::replaceByName
+// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
+// due to XLineStartItem::checkForUniqueItem
+// XATTR_LINEEND ok
+// due to SvxUnoNameItemTable
+// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
+// due to NameOrIndex::CheckNamedItem all derived from NameOrIndex
+// XATTR_FILLBITMAP ok
+// due to SvxUnoNameItemTable
+// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
+// XATTR_LINEDASH ok
+// due to SvxUnoNameItemTable
+// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
+// due to NameOrIndex::CheckNamedItem all derived from NameOrIndex
+// XATTR_FILLGRADIENT ok
+// due to SvxUnoNameItemTable
+// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
+// XATTR_FILLHATCH ok
+// due to SvxUnoNameItemTable
+// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
+// XATTR_FILLFLOATTRANSPARENCE ok
+// due to NamespaceIteratorImpl
+// -> needs to be evaluated
+// due to SwCursorShell::GotoNxtPrvTOXMark
+// due to SwDoc::GetTOIKeys
+// RES_TXTATR_TOXMARK ok
+// due to SwDoc::GetRefMark
+// due to SwDoc::CallEvent
+// due to SwURLStateChanged::Notify
+// due to SwHTMLWriter::CollectLinkTargets
+// due to MSWordExportBase::CollectOutlineBookmarks
+// RES_TXTATR_INETFMT ok
+// due to SwDoc::GetAllUsedDB
+// due to lcl_FindInputField
+// due to SwViewShell::IsAnyFieldInDoc
+// RES_TXTATR_FIELD ok
+// due to SwDoc::GetAllUsedDB
+// due to lcl_FindInputField
+// due to SwViewShell::IsAnyFieldInDoc
+// RES_TXTATR_INPUTFIELD ok
+// due to SwDoc::SetDefault
+// RES_PARATR_TABSTOP ok
+// due to SwDoc::GetDocColors()
+// due to RtfExport::OutColorTable
+// RES_CHRATR_COLOR ok
+// due to SwDoc::GetDocColors()
+// RES_CHRATR_HIGHLIGHT ok
+// due to SwDoc::GetDocColors()
+// RES_BACKGROUND ok
+// due to SwNode::FindPageDesc
+// due to SwPageNumberFieldType::ChangeExpansion
+// due to SwFrame::GetVirtPageNum
+// RES_PAGEDESC ok
+// due to SwAutoStylesEnumImpl::
+// RES_TXTATR_CJK_RUBY ok
+// due to SwHTMLWriter::CollectLinkTargets
+// due to MSWordExportBase::CollectOutlineBookmarks
+// RES_URL
+// due to RtfExport::OutColorTable
+// RES_CHRATR_UNDERLINE ok
+// RES_CHRATR_OVERLINE ok
+// RES_CHRATR_BACKGROUND ok
+// RES_SHADOW ok
+// RES_BOX ok
+// RES_CHRATR_BOX ok
+// XATTR_FILLCOLOR ok
+// due to wwFontHelper::InitFontTable
+// due to SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl
+// RES_CHRATR_FONT ok
+// due to wwFontHelper::InitFontTable
+// due to SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl
+// RES_CHRATR_CJK_FONT ok
+// due to wwFontHelper::InitFontTable
+// due to SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl
+// RES_CHRATR_CTL_FONT
+// due to SwXMLExport::exportDoc
+// RES_UNKNOWNATR_CONTAINER ok
+// RES_TXTATR_UNKNOWN_CONTAINER ok
+
+
+
+#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
+
+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;
+}
+
+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::NeedsPoolRegistration(sal_uInt16 nWhich) const
+{
+ if (!IsInRange(nWhich))
+ {
+ // get to correct pool
+ if (pImpl->mpSecondary)
+ return pImpl->mpSecondary->NeedsPoolRegistration(nWhich);
+ return false;
+ }
+
+ return NeedsPoolRegistration_Impl(nWhich - pImpl->mnStart);
+}
+
+bool SfxItemPool::Shareable(sal_uInt16 nWhich) const
+{
+ if (!IsInRange(nWhich))
+ {
+ // get to correct pool
+ if (pImpl->mpSecondary)
+ return pImpl->mpSecondary->Shareable(nWhich);
+ return false;
+ }
+
+ return Shareable_Impl(nWhich - pImpl->mnStart);
+}
+
+
+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 ) ),
+ ppRegisteredSfxPoolItems(nullptr)
+{
+ 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 ) ),
+ ppRegisteredSfxPoolItems(nullptr)
+{
+ 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]->setStaticDefault();
+ }
+
+ 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]->setPoolDefault();
+ }
+
+ // 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)
+ && "items ids in pool-ranges and in static-defaults do not match" );
+ (*pImpl->mpStaticDefaults)[n]->setStaticDefault();
+ DBG_ASSERT(nullptr == ppRegisteredSfxPoolItems || nullptr == ppRegisteredSfxPoolItems[n]
+ || ppRegisteredSfxPoolItems[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()
+{
+ // Need to be deleted?
+ // Caution: ppRegisteredSfxPoolItems is on-demand created and can be nullptr
+ if ( nullptr != ppRegisteredSfxPoolItems || !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 (nullptr != pImpl->mpStaticDefaults
+ && nullptr != ppRegisteredSfxPoolItems
+ && nullptr != pImpl->mpSecondary->ppRegisteredSfxPoolItems)
+ // 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)
+ {
+ const SfxPoolItem* pStaticDefaultItem((*pImpl->mpStaticDefaults)[i]);
+ bHasSetItems = pStaticDefaultItem->isSetItem();
+ }
+
+ if (bHasSetItems)
+ {
+ // Detached Pools must be empty
+ registeredSfxPoolItems** ppSet(pImpl->mpSecondary->ppRegisteredSfxPoolItems);
+
+ for (sal_uInt16 a(0); a < pImpl->mpSecondary->GetSize_Impl(); a++, ppSet++)
+ {
+ if (nullptr != *ppSet && (*ppSet)->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?
+ // Caution: ppRegisteredSfxPoolItems is on-demand created and can be nullptr
+ if (nullptr == ppRegisteredSfxPoolItems && pImpl->maPoolDefaults.empty())
+ return;
+
+ // Inform e.g. running Requests
+ pImpl->aBC.Broadcast( SfxHint( SfxHintId::Dying ) );
+
+ // Iterate through twice: first for the SetItems.
+ if (nullptr != pImpl->mpStaticDefaults && nullptr != ppRegisteredSfxPoolItems)
+ {
+ 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 (pStaticDefaultItem->isSetItem() && nullptr != ppRegisteredSfxPoolItems[n])
+ {
+ // SfxSetItem found, remove PoolItems (and defaults) with same ID
+ auto& rArray(*(ppRegisteredSfxPoolItems[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;
+ }
+ }
+ }
+ }
+
+ if (nullptr != ppRegisteredSfxPoolItems)
+ {
+ registeredSfxPoolItems** ppSet(ppRegisteredSfxPoolItems);
+
+ for (sal_uInt16 a(0); a < GetSize_Impl(); a++, ppSet++)
+ {
+ if (nullptr != *ppSet)
+ {
+ for (auto& rCandidate : **ppSet)
+ {
+ if (nullptr != rCandidate && !IsDefaultItem(rCandidate))
+ {
+ ReleaseRef(*rCandidate, rCandidate->GetRefCount()); // for RefCount check in dtor
+ delete rCandidate;
+ }
+ }
+
+ delete *ppSet;
+ *ppSet = nullptr;
+ }
+ }
+
+ delete[] ppRegisteredSfxPoolItems;
+ ppRegisteredSfxPoolItems = nullptr;
+ }
+
+ // 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->setPoolDefault();
+ 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::DirectPutItemInPoolImpl(const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership)
+{
+ // CAUTION: Do not register the problematic pool default
+ if (rItem.isExceptionalSCItem() && GetMasterPool()->newItem_UseDirect(rItem))
+ return rItem;
+
+#ifdef DBG_UTIL
+ nAllDirectlyPooledSfxPoolItemCount++;
+ nRemainingDirectlyPooledSfxPoolItemCount++;
+#endif
+
+ // make sure to use 'master'-pool, that's the one used by SfxItemSets
+ const SfxPoolItem* pRetval(implCreateItemEntry(*GetMasterPool(), &rItem, nWhich, bPassingOwnership));
+
+ // For the moment, as long as DirectPutItemInPoolImpl is used, make sure that
+ // the changes in implCreateItemEntry do not change anything, that would
+ // risc memory leaks by not (ab)using the garbage collector aspect of the pool.
+ registerSfxPoolItem(*pRetval);
+
+ return *pRetval;
+}
+
+void SfxItemPool::DirectRemoveItemFromPool(const SfxPoolItem& rItem)
+{
+ // CAUTION: Do not remove the problematic pool default
+ if (rItem.isExceptionalSCItem() && GetMasterPool()->newItem_UseDirect(rItem))
+ return;
+
+#ifdef DBG_UTIL
+ nRemainingDirectlyPooledSfxPoolItemCount--;
+#endif
+
+ // make sure to use 'master'-pool, that's the one used by SfxItemSets
+ implCleanupItemEntry(*GetMasterPool(), &rItem);
+}
+
+void SfxItemPool::newItem_Callback(const SfxPoolItem& rItem) const
+{
+ if (!IsInRange(rItem.Which()) && pImpl->mpSecondary)
+ pImpl->mpSecondary->newItem_Callback(rItem);
+}
+
+bool SfxItemPool::newItem_UseDirect(const SfxPoolItem& rItem) const
+{
+ if (!IsInRange(rItem.Which()) && pImpl->mpSecondary)
+ return pImpl->mpSecondary->newItem_UseDirect(rItem);
+ return false;
+}
+
+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) ];
+}
+
+#ifdef DBG_UTIL
+static void warnForMissingPoolRegistration(const SfxItemPool& rPool, sal_uInt16 nWhich)
+{
+ if (!rPool.NeedsPoolRegistration(nWhich))
+ SAL_INFO("svl.items", "ITEM: ItemSurrogate requested for WhichID " << nWhich <<
+ " class " << typeid(rPool.GetDefaultItem(nWhich)).name() <<
+ ": needs _bNeedsPoolRegistration==true in SfxItemInfo for that slot");
+}
+#endif
+
+const registeredSfxPoolItems& SfxItemPool::GetItemSurrogates(sal_uInt16 nWhich) const
+{
+ static const registeredSfxPoolItems EMPTY;
+
+ if (!IsInRange(nWhich))
+ {
+ if (pImpl->mpSecondary)
+ return pImpl->mpSecondary->GetItemSurrogates(nWhich);
+ return EMPTY;
+ }
+
+ if (nullptr == ppRegisteredSfxPoolItems)
+ {
+#ifdef DBG_UTIL
+ warnForMissingPoolRegistration(*this, nWhich);
+#endif
+ return EMPTY;
+ }
+
+ registeredSfxPoolItems* pSet(ppRegisteredSfxPoolItems[nWhich - pImpl->mnStart]);
+
+ if (nullptr == pSet)
+ {
+#ifdef DBG_UTIL
+ warnForMissingPoolRegistration(*this, nWhich);
+#endif
+ return EMPTY;
+ }
+
+ return *pSet;
+}
+
+std::vector<const SfxPoolItem*> SfxItemPool::FindItemSurrogate(sal_uInt16 nWhich, SfxPoolItem const & rSample) const
+{
+ static const std::vector<const SfxPoolItem*> EMPTY;
+
+ if (nullptr == ppRegisteredSfxPoolItems)
+ return EMPTY;
+
+ if ( !IsInRange(nWhich) )
+ {
+ if ( pImpl->mpSecondary )
+ return pImpl->mpSecondary->FindItemSurrogate( nWhich, rSample );
+ assert(false && "unknown WhichId - cannot resolve surrogate");
+ return EMPTY;
+ }
+
+ // get index (must exist due to checks above)
+ const sal_uInt16 nIndex(rSample.Which() - pImpl->mnStart);
+
+ if (nullptr == ppRegisteredSfxPoolItems)
+ {
+#ifdef DBG_UTIL
+ warnForMissingPoolRegistration(*this, nWhich);
+#endif
+ return EMPTY;
+ }
+
+ // get registeredSfxPoolItems container
+ registeredSfxPoolItems* pSet(ppRegisteredSfxPoolItems[nIndex]);
+
+ if (nullptr == pSet)
+ {
+#ifdef DBG_UTIL
+ warnForMissingPoolRegistration(*this, nWhich);
+#endif
+ return EMPTY;
+ }
+
+ std::vector<const SfxPoolItem*> rv;
+
+ for (const SfxPoolItem* p : *pSet)
+ if (rSample == *p)
+ rv.push_back(p);
+
+ return rv;
+}
+
+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::registerSfxPoolItem(const SfxPoolItem& rItem)
+{
+ assert(rItem.Which() != 0);
+
+ if (IsSlot(rItem.Which()))
+ // do not register SlotItems
+ return;
+
+ if (rItem.isRegisteredAtPool())
+ // already registered, done
+ return;
+
+ if (!IsInRange(rItem.Which()))
+ {
+ // get to the right pool
+ if (pImpl->mpSecondary)
+ {
+ pImpl->mpSecondary->registerSfxPoolItem(rItem);
+ return;
+ }
+
+ return;
+ }
+
+ if (nullptr == ppRegisteredSfxPoolItems)
+ // on-demand allocate array of registeredSfxPoolItems and init to nullptr
+ ppRegisteredSfxPoolItems = new registeredSfxPoolItems*[GetSize_Impl()]{};
+
+ // get correct registeredSfxPoolItems
+ const sal_uInt16 nIndex(rItem.Which() - pImpl->mnStart);
+ registeredSfxPoolItems* pSet(ppRegisteredSfxPoolItems[nIndex]);
+
+ if (nullptr == pSet)
+ // on-demand allocate
+ ppRegisteredSfxPoolItems[nIndex] = pSet = new registeredSfxPoolItems;
+
+ // insert to registeredSfxPoolItems and set flag at Item
+ pSet->insert(&rItem);
+ const_cast<SfxPoolItem&>(rItem).setRegisteredAtPool(true);
+}
+
+void SfxItemPool::unregisterSfxPoolItem(const SfxPoolItem& rItem)
+{
+ if (!rItem.isRegisteredAtPool())
+ // Item is not registered, done
+ return;
+
+ if (!IsInRange(rItem.Which()))
+ {
+ // get to the right pool
+ if (pImpl->mpSecondary)
+ {
+ pImpl->mpSecondary->unregisterSfxPoolItem(rItem);
+ return;
+ }
+
+ assert(false && "unknown WhichId - cannot execute unregisterSfxPoolItem");
+ return;
+ }
+
+ // we need a valid WhichID and the array of containers has to exist
+ assert(rItem.Which() != 0);
+ assert(nullptr != ppRegisteredSfxPoolItems);
+
+ // get index (must exist due to checks above)
+ const sal_uInt16 nIndex(rItem.Which() - pImpl->mnStart);
+
+ // a valid registeredSfxPoolItems container has to exist
+ registeredSfxPoolItems* pSet(ppRegisteredSfxPoolItems[nIndex]);
+ assert(nullptr != pSet);
+
+ // remove registered Item and reset flag at Item
+ pSet->erase(&rItem);
+ const_cast<SfxPoolItem&>(rItem).setRegisteredAtPool(false);
+}
+
+bool SfxItemPool::isSfxPoolItemRegisteredAtThisPool(const SfxPoolItem& rItem) const
+{
+ if (!rItem.isRegisteredAtPool())
+ // Item is not registered at all, so also not at this Pool
+ return false;
+
+ if (IsSlot(rItem.Which()))
+ // do not check being registered for SlotItems
+ return false;
+
+ if (!IsInRange(rItem.Which()))
+ {
+ // get to the right pool
+ if (pImpl->mpSecondary)
+ return pImpl->mpSecondary->isSfxPoolItemRegisteredAtThisPool(rItem);
+ return false;
+ }
+
+ // we need a valid WhichID
+ assert(rItem.Which() != 0);
+
+ if (nullptr == ppRegisteredSfxPoolItems)
+ // when no array of containers exists the Item is not registered
+ return false;
+
+ // get index (must exist due to checks above)
+ const sal_uInt16 nIndex(rItem.Which() - pImpl->mnStart);
+
+ // get registeredSfxPoolItems container
+ registeredSfxPoolItems* pSet(ppRegisteredSfxPoolItems[nIndex]);
+
+ if (nullptr == pSet)
+ // when no registeredSfxPoolItems container exists the Item is not registered
+ return false;
+
+ // test if Item is registered
+ return pSet->find(&rItem) != pSet->end();
+}
+
+const SfxPoolItem* SfxItemPool::tryToGetEqualItem(const SfxPoolItem& rItem, sal_uInt16 nWhich) const
+{
+ if (IsSlot(nWhich))
+ // SlotItems are not registered @pool and not in any range
+ return nullptr;
+
+ if (!IsInRange(nWhich))
+ {
+ // get to the right pool
+ if (pImpl->mpSecondary)
+ return pImpl->mpSecondary->tryToGetEqualItem(rItem, nWhich);
+ return nullptr;
+ }
+
+ if (nullptr == ppRegisteredSfxPoolItems)
+ // no Items at all
+ return nullptr;
+
+ // get index (must exist due to checks above)
+ const sal_uInt16 nIndex(nWhich - pImpl->mnStart);
+
+ if (!Shareable_Impl(nIndex))
+ // not shareable
+ return nullptr;
+
+ // get registeredSfxPoolItems container
+ registeredSfxPoolItems* pSet(ppRegisteredSfxPoolItems[nIndex]);
+
+ if (nullptr == pSet)
+ // no registeredSfxPoolItems for this WhichID
+ return nullptr;
+
+ for (const auto& rCandidate : *pSet)
+ if (*rCandidate == rItem)
+ return rCandidate;
+
+ return nullptr;
+}
+
+void SfxItemPool::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SfxItemPool"));
+
+ if (nullptr != ppRegisteredSfxPoolItems)
+ {
+ registeredSfxPoolItems** ppSet(ppRegisteredSfxPoolItems);
+
+ for (sal_uInt16 a(0); a < GetSize_Impl(); a++, ppSet++)
+ {
+ if (nullptr != *ppSet)
+ {
+ for (auto& rCandidate : **ppSet)
+ {
+ if (nullptr != rCandidate)
+ {
+ rCandidate->dumpAsXml(pWriter);
+ }
+ }
+ }
+ }
+ }
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */