/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include // 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& 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(&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(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*). * * @see SfxItemPool::SetPoolDefaults(std::vector*) * @see SfxItemPool::ReleasePoolDefaults(std::vector*,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::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 aNew) override { return mpSet->Put(std::unique_ptr(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 aNew) override { *mpHolder = SfxPoolItemHolder(mpHolder->getPool(), aNew.release(), true); return mpHolder->getItem(); } }; } void SfxItemPool::iterateItemSurrogates( sal_uInt16 nWhich, const std::function& rItemCallback) const { // 1st source for surrogates const registeredSfxItemSets& rSets(GetMasterPool()->maRegisteredSfxItemSets); if(!rSets.empty()) { const SfxPoolItem* pItem(nullptr); std::vector 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 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 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: */