1006 lines
33 KiB
C++
1006 lines
33 KiB
C++
/* -*- 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: */
|