/* -*- 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 <tools/debug.hxx>
#include <cassert>
#include <vector>
// WhichIDs that need to set SFX_ITEMINFOFLAG_SUPPORT_SURROGATE 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
// 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
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);
}
const SlotIDToWhichIDMap& ItemInfoPackage::getSlotIDToWhichIDMap() const
{
if (maSlotIDToWhichIDMap.empty())
{
// will be filled only once per office runtime
for (size_t a(0); a < size(); a++)
{
const ItemInfoStatic& rCandidate(getItemInfoStatic(a));
if (0 != rCandidate.getSlotID())
{
#ifdef DBG_UTIL
if (maSlotIDToWhichIDMap.find(rCandidate.getSlotID()) != maSlotIDToWhichIDMap.end())
assert(false && "ITEM: SlotID used double in ItemInfoPackage (!)");
#endif
maSlotIDToWhichIDMap[rCandidate.getSlotID()] = rCandidate.getWhich();
}
}
}
return maSlotIDToWhichIDMap;
}
const ItemInfo& ItemInfoPackage::getExistingItemInfo(size_t /*nIndex*/)
{
static ItemInfoStatic EMPTY(0, nullptr, 0, 0);
return EMPTY;
}
void SfxItemPool::registerItemInfoPackage(
ItemInfoPackage& rPackage,
const std::function<SfxPoolItem*(sal_uInt16)>& rCallback)
{
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++)
{
// 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();
// set mapper for fast SlotIDToWhichID conversion
mpSlotIDToWhichIDMap = &rPackage.getSlotIDToWhichIDMap();
#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;
}
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)
{
registeredSfxItemSets& rTarget(GetMasterPool()->maRegisteredSfxItemSets);
#ifdef DBG_UTIL
const size_t nBefore(rTarget.size());
#endif
rTarget.insert(&rSet);
#ifdef DBG_UTIL
const size_t nAfter(rTarget.size());
if (nBefore + 1 != nAfter)
{
SAL_WARN("svl.items", "SfxItemPool::registerItemSet: ItemSet was already registered (!)");
}
#endif
}
void SfxItemPool::unregisterItemSet(SfxItemSet& rSet)
{
registeredSfxItemSets& rTarget(GetMasterPool()->maRegisteredSfxItemSets);
#ifdef DBG_UTIL
const size_t nBefore(rTarget.size());
#endif
rTarget.erase(&rSet);
#ifdef DBG_UTIL
const size_t nAfter(rTarget.size());
if (nBefore != nAfter + 1)
{
SAL_WARN("svl.items", "SfxItemPool::unregisterItemSet: ItemSet was not registered (!)");
}
#endif
}
void SfxItemPool::registerPoolItemHolder(SfxPoolItemHolder& rHolder)
{
registeredSfxPoolItemHolders& rTarget(GetMasterPool()->maRegisteredSfxPoolItemHolders);
#ifdef DBG_UTIL
const size_t nBefore(rTarget.size());
#endif
rTarget.insert(&rHolder);
#ifdef DBG_UTIL
const size_t nAfter(rTarget.size());
if (nBefore + 1 != nAfter)
{
SAL_WARN("svl.items", "SfxItemPool::registerPoolItemHolder: SfxPoolItemHolder was already registered (!)");
}
#endif
if (rHolder.is() && rHolder.getItem()->isNameOrIndex())
registerNameOrIndex(*rHolder.getItem());
}
void SfxItemPool::unregisterPoolItemHolder(SfxPoolItemHolder& rHolder)
{
registeredSfxPoolItemHolders& rTarget(GetMasterPool()->maRegisteredSfxPoolItemHolders);
#ifdef DBG_UTIL
const size_t nBefore(rTarget.size());
#endif
rTarget.erase(&rHolder);
#ifdef DBG_UTIL
const size_t nAfter(rTarget.size());
if (nBefore != nAfter + 1)
{
SAL_WARN("svl.items", "SfxItemPool::unregisterPoolItemHolder: SfxPoolItemHolder was not registered (!)");
}
#endif
if (rHolder.is() && rHolder.getItem()->isNameOrIndex())
unregisterNameOrIndex(*rHolder.getItem());
}
void SfxItemPool::registerNameOrIndex(const SfxPoolItem& rItem)
{
assert(rItem.isNameOrIndex() && "ITEM: only Items derived from NameOrIndex supported for this mechanism (!)");
NameOrIndexContent& rTarget(GetMasterPool()->maRegisteredNameOrIndex[rItem.ItemType()]);
NameOrIndexContent::iterator aHit(rTarget.find(&rItem));
if (aHit == rTarget.end())
rTarget.insert(std::pair<const SfxPoolItem*, sal_uInt32>(&rItem, 0));
else
aHit->second++;
}
void SfxItemPool::unregisterNameOrIndex(const SfxPoolItem& rItem)
{
assert(rItem.isNameOrIndex() && "ITEM: only Items derived from NameOrIndex supported for this mechanism (!)");
NameOrIndexContent& rTarget(GetMasterPool()->maRegisteredNameOrIndex[rItem.ItemType()]);
NameOrIndexContent::iterator aHit(rTarget.find(&rItem));
assert(aHit != rTarget.end() && "ITEM: malformed order of buffered NameOrIndex Items, entry *expected* (!)");
if (0 == aHit->second)
rTarget.erase(aHit);
else
aHit->second--;
}
SfxItemPool* SfxItemPool::getTargetPool(sal_uInt16 nWhich) const
{
if (IsInRange(nWhich))
return const_cast<SfxItemPool*>(this);
if (mpSecondary)
return mpSecondary->getTargetPool(nWhich);
return nullptr;
}
bool SfxItemPool::CheckItemInfoFlag(sal_uInt16 nWhich, sal_uInt16 nMask) const
{
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 pTarget->CheckItemInfoFlag_Impl(pTarget->GetIndex_Impl(nWhich), nMask);
}
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
* 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::SetPoolDefaults(std::vector<SfxPoolItem*>*).
*
* @see SfxItemPool::SetPoolDefaults(std::vector<SfxPoolItem*>*)
* @see SfxItemPool::ReleasePoolDefaults(std::vector<SfxPoolItem*>*,bool)
* @see SfxItemPool::ReleasePoolDefaults(bool)
*/
SfxItemPool::SfxItemPool(const OUString& rName) /* Pool name to identify in the file format */
: salhelper::SimpleReferenceObject()
, aBC()
, aName(rName)
, mpMaster(this)
, mpSecondary()
, mnStart(0)
, mnEnd(0)
, eDefMetric(MapUnit::MapCM)
, maRegisteredSfxItemSets()
, maRegisteredSfxPoolItemHolders()
, maRegisteredNameOrIndex()
, mbShutdownHintSent(false)
, maItemInfos()
, maUserItemInfos()
, mpSlotIDToWhichIDMap(nullptr)
{
eDefMetric = MapUnit::MapTwip;
}
/**
* Copy ctor
*
* @see SfxItemPool::Clone() const
*/
SfxItemPool::SfxItemPool(const SfxItemPool& rPool) // Copy from this instance
: salhelper::SimpleReferenceObject()
, aBC()
, aName(rPool.aName)
, mpMaster(this)
, mpSecondary()
, maPoolRanges()
, mnStart(rPool.mnStart)
, mnEnd(rPool.mnEnd)
, eDefMetric(MapUnit::MapCM)
, maRegisteredSfxItemSets()
, maRegisteredSfxPoolItemHolders()
, maRegisteredNameOrIndex()
, mbShutdownHintSent(false)
, maItemInfos(rPool.maItemInfos)
, maUserItemInfos(rPool.maUserItemInfos)
, mpSlotIDToWhichIDMap(rPool.mpSlotIDToWhichIDMap)
{
// DynamicDefaults and UserDefaults need to be cloned for the new Pool
for (itemInfoVector::iterator aInfo(maItemInfos.begin()); aInfo != maItemInfos.end(); aInfo++)
*aInfo = impCheckItemInfoForClone(*aInfo);
// DynamicDefaults need to be cloned for the new Pool (no UserDefaults in UserItemInfos)
for (auto& rUserItem : maUserItemInfos)
rUserItem.second = impCheckItemInfoForClone(rUserItem.second);
eDefMetric = rPool.eDefMetric;
// Repair linkage
if ( rPool.mpSecondary )
SetSecondaryPool( rPool.mpSecondary->Clone().get() );
}
SfxItemPool::~SfxItemPool()
{
// cleanup UserDefaults & delete owned DynamicDefaults
cleanupItemInfos();
// Need to send ShutdownHint?
sendShutdownHint();
if (mpMaster != nullptr && mpMaster != this)
{
// This condition indicates an error.
// A 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( mpMaster == this, "destroying active Secondary-Pool" );
if (mpMaster->mpSecondary == this)
mpMaster->mpSecondary = nullptr;
}
}
void SfxItemPool::SetSecondaryPool( SfxItemPool *pPool )
{
// Reset Master in attached Pools
if ( mpSecondary )
{
mpSecondary->mpMaster = mpSecondary.get();
for ( SfxItemPool *p = mpSecondary->mpSecondary.get(); p; p = p->mpSecondary.get() )
p->mpMaster = mpSecondary.get();
}
// Set Master of new Secondary Pools
DBG_ASSERT( !pPool || pPool->mpMaster == pPool, "Secondary is present in two Pools" );
SfxItemPool *pNewMaster = GetMasterPool() ? mpMaster : this;
for ( SfxItemPool *p = pPool; p; p = p->mpSecondary.get() )
p->mpMaster = pNewMaster;
// Remember new Secondary Pool
mpSecondary = pPool;
}
MapUnit SfxItemPool::GetMetric( sal_uInt16 ) const
{
return eDefMetric;
}
void SfxItemPool::SetDefaultMetric( MapUnit eNewMetric )
{
// assert((pImpl->eDefMetric == eNewMetric || !pImpl->maPoolRanges) && "pool already frozen, cannot change metric");
eDefMetric = eNewMetric;
}
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::sendShutdownHint()
{
// Already sent?
if (mbShutdownHintSent)
return;
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");
const sal_uInt16 nWhich(rItem.Which());
userItemInfos::iterator aHit(pTarget->maUserItemInfos.find(nWhich));
if (aHit == pTarget->maUserItemInfos.end())
{
// 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;
}
// 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;
}
const SfxPoolItem* SfxItemPool::GetUserDefaultItem( sal_uInt16 nWhich ) const
{
SfxItemPool* pTarget(getTargetPool(nWhich));
if (nullptr == pTarget)
{
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 nWhich )
{
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
{
SfxItemPool* pTarget(getTargetPool(nWhich));
if (nullptr == pTarget)
assert(!"unknown which - don't ask me for defaults");
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);
while(pLast->GetSecondaryPool())
pLast = pLast->GetSecondaryPool();
return pLast;
}
const WhichRangesContainer& SfxItemPool::GetMergedIdRanges() const
{
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);
}
return maPoolRanges;
}
const SfxPoolItem* SfxItemPool::GetPoolDefaultItem(sal_uInt16 nWhich) const
{
SfxItemPool* pTarget(getTargetPool(nWhich));
if (nullptr == pTarget)
assert(false && "unknown WhichId - cannot resolve surrogate");
const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
userItemInfos::iterator aHit(pTarget->maUserItemInfos.find(nWhich));
if (aHit != pTarget->maUserItemInfos.end())
{
// 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();
}
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
{
class SurrogateData_ItemSet : public SfxItemPool::SurrogateData
{
const SfxPoolItem* mpItem;
SfxItemSet* mpSet;
public:
SurrogateData_ItemSet(const SfxPoolItem& rItem, SfxItemSet& rSet)
: SfxItemPool::SurrogateData()
, mpItem(&rItem)
, mpSet(&rSet)
{
}
SurrogateData_ItemSet(const SurrogateData_ItemSet&) = default;
virtual const SfxPoolItem& getItem() const override
{
return *mpItem;
}
virtual const SfxPoolItem* setItem(std::unique_ptr<SfxPoolItem> aNew) override
{
return mpSet->Put(std::unique_ptr<SfxPoolItem>(aNew.release()));
}
};
class SurrogateData_ItemHolder : public SfxItemPool::SurrogateData
{
SfxPoolItemHolder* mpHolder;
public:
SurrogateData_ItemHolder(SfxPoolItemHolder& rHolder)
: SfxItemPool::SurrogateData()
, mpHolder(&rHolder)
{
}
SurrogateData_ItemHolder(const SurrogateData_ItemHolder&) = default;
virtual const SfxPoolItem& getItem() const override
{
return *mpHolder->getItem();
}
virtual const SfxPoolItem* setItem(std::unique_ptr<SfxPoolItem> aNew) override
{
*mpHolder = SfxPoolItemHolder(mpHolder->getPool(), aNew.release(), true);
return mpHolder->getItem();
}
};
}
void SfxItemPool::iterateItemSurrogates(
sal_uInt16 nWhich,
const std::function<bool(SurrogateData& rCand)>& rItemCallback) const
{
// 1st source for surrogates
const registeredSfxItemSets& rSets(GetMasterPool()->maRegisteredSfxItemSets);
if(!rSets.empty())
{
const SfxPoolItem* pItem(nullptr);
std::vector<SurrogateData_ItemSet> aEntries;
// NOTE: this collects the callback data in a preparing run. This
// is by purpose, else any write change may change the iterators
// used at registeredSfxItemSets. I tied with direct feed and
// that worked most of the time, but failed for ItemHolders due
// to these being changed and being re-registered. I have avoided
// this in SfxPoolItemHolder::operator=, but it's just a question
// that in some scenario someone replaces an Item even with a
// different type/WhichID that this will then break/crash
for (const auto& rCand : rSets)
if (SfxItemState::SET == rCand->GetItemState(nWhich, false, &pItem))
aEntries.emplace_back(*pItem, *rCand);
if (!aEntries.empty())
for (auto& rCand : aEntries)
if (!rItemCallback(rCand))
return;
}
// 2nd source for surrogates
const registeredSfxPoolItemHolders& rHolders(GetMasterPool()->maRegisteredSfxPoolItemHolders);
if (!rHolders.empty())
{
std::vector<SurrogateData_ItemHolder> aEntries;
// NOTE: same as above, look there
for (auto& rCand : rHolders)
if (rCand->Which() == nWhich && nullptr != rCand->getItem())
aEntries.emplace_back(*rCand);
if (!aEntries.empty())
for (auto& rCand : aEntries)
if (!rItemCallback(rCand))
return;
}
}
void SfxItemPool::GetItemSurrogatesForItem(ItemSurrogates& rTarget, SfxItemType eItemType) const
{
rTarget.clear();
const registeredNameOrIndex& rRegistered(GetMasterPool()->maRegisteredNameOrIndex);
registeredNameOrIndex::const_iterator aHit(rRegistered.find(eItemType));
if (aHit != rRegistered.end())
{
rTarget.reserve(aHit->second.size());
for (const auto& entry : aHit->second)
rTarget.push_back(entry.first);
}
}
void SfxItemPool::GetItemSurrogatesForItem(ItemSurrogates& rTarget, const SfxPoolItem& rItem) const
{
assert(rItem.isNameOrIndex() && "ITEM: only Items derived from NameOrIndex supported for this mechanism (!)");
GetItemSurrogatesForItem(rTarget, rItem.ItemType());
}
void SfxItemPool::GetItemSurrogates(ItemSurrogates& rTarget, sal_uInt16 nWhich) const
{
rTarget.clear();
if (0 == nWhich)
return;
// NOTE: This is pre-collected, in this case mainly to
// remove all double listings of SfxPoolItems which can
// of course be referenced multiple times in multiple
// ItemSets/ItemHolders. It comes handy that
// std::unordered_set does this by definition
std::unordered_set<const SfxPoolItem*> aNewSurrogates;
// 1st source for surrogates
const registeredSfxItemSets& rSets(GetMasterPool()->maRegisteredSfxItemSets);
const SfxPoolItem* pItem(nullptr);
for (const auto& rCand : rSets)
if (SfxItemState::SET == rCand->GetItemState(nWhich, false, &pItem))
aNewSurrogates.insert(pItem);
// 2nd source for surrogates
const registeredSfxPoolItemHolders& rHolders(GetMasterPool()->maRegisteredSfxPoolItemHolders);
for (const auto& rCand : rHolders)
if (rCand->Which() == nWhich && nullptr != rCand->getItem())
aNewSurrogates.insert(rCand->getItem());
rTarget = ItemSurrogates(aNewSurrogates.begin(), aNewSurrogates.end());
}
sal_uInt16 SfxItemPool::GetWhichIDFromSlotID(sal_uInt16 nSlotId, bool bDeep) const
{
if (!IsSlot(nSlotId))
return nSlotId;
if (nullptr != mpSlotIDToWhichIDMap)
{
// use the static global translation table -> near linear access time
SlotIDToWhichIDMap::const_iterator aHit(mpSlotIDToWhichIDMap->find(nSlotId));
if (aHit != mpSlotIDToWhichIDMap->end())
return aHit->second;
}
if (mpSecondary && bDeep)
return mpSecondary->GetWhichIDFromSlotID(nSlotId);
return nSlotId;
}
sal_uInt16 SfxItemPool::GetSlotId(sal_uInt16 nWhich) const
{
if (!IsWhich(nWhich))
return nWhich;
SfxItemPool* pTarget(getTargetPool(nWhich));
if (nullptr == pTarget)
assert(false && "unknown WhichId - cannot get slot-id");
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::GetTrueWhichIDFromSlotID( sal_uInt16 nSlotId, bool bDeep ) const
{
if (!IsSlot(nSlotId))
return 0;
if (nullptr != mpSlotIDToWhichIDMap)
{
// use the static global translation table -> near linear access time
SlotIDToWhichIDMap::const_iterator aHit(mpSlotIDToWhichIDMap->find(nSlotId));
if (aHit != mpSlotIDToWhichIDMap->end())
return aHit->second;
}
if (mpSecondary && bDeep)
return mpSecondary->GetTrueWhichIDFromSlotID(nSlotId);
return 0;
}
sal_uInt16 SfxItemPool::GetTrueSlotId( sal_uInt16 nWhich ) const
{
if (!IsWhich(nWhich))
return 0;
SfxItemPool* pTarget(getTargetPool(nWhich));
if (nullptr == pTarget)
assert(false && "unknown WhichId - cannot get slot-id");
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: */
↑ V547 Expression is always false.