a11y: Simplify OCommonAccessibleComponent::getAccessibleIndexInParent
[LibreOffice.git] / svl / source / items / itempool.cxx
blobea9166c376189332a341f6e0d6d0588a3cd1f828
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svl/itempool.hxx>
21 #include <svl/setitem.hxx>
23 #include <string.h>
24 #include <libxml/xmlwriter.h>
26 #include <osl/diagnose.h>
27 #include <sal/log.hxx>
28 #include <svl/SfxBroadcaster.hxx>
29 #include <svl/hint.hxx>
30 #include <svl/itemset.hxx>
31 #include <tools/debug.hxx>
33 #include <cassert>
34 #include <vector>
36 // WhichIDs that need to set SFX_ITEMINFOFLAG_SUPPORT_SURROGATE in SfxItemInfo
37 // to true to allow a register of all items of that type/with that WhichID
38 // to be accessible using SfxItemPool::GetItemSurrogates. Created by
39 // grepping for 'GetItemSurrogates' usages & interpreting. Some
40 // are double, more may be necessary. There is a SAL_INFO("svl.items", ...)
41 // in SfxItemPool::GetItemSurrogates that will give hints on missing flags.
43 // due to SwTable::UpdateFields
44 // due to SwCursorShell::GotoNxtPrvTableFormula
45 // due to DocumentFieldsManager::UpdateTableFields
46 // due to SwTable::GatherFormulas
47 // RES_BOXATR_FORMULA ok
48 // due to SwContentTree::EditEntry
49 // due to SwDoc::FindINetAttr
50 // due to SwUndoResetAttr::RedoImpl
51 // due to SwContentTree::EditEntry
52 // due to SwContentTree::BringEntryToAttention
53 // RES_TXTATR_REFMARK ok
54 // due to ImpEditEngine::WriteRTF
55 // due to ScDocument::UpdateFontCharSet()
56 // due to ScXMLFontAutoStylePool_Impl
57 // due to SdXImpressDocument::getPropertyValue
58 // due to Writer::AddFontItems_
59 // EE_CHAR_FONTINFO ok
60 // due to ImpEditEngine::WriteRTF
61 // due to ScXMLFontAutoStylePool_Impl
62 // due to SdXImpressDocument::getPropertyValue
63 // due to Writer::AddFontItems_
64 // EE_CHAR_FONTINFO_CJK ok
65 // due to ImpEditEngine::WriteRTF
66 // due to ScXMLFontAutoStylePool_Impl
67 // due to SdXImpressDocument::getPropertyValue
68 // due to Writer::AddFontItems_
69 // EE_CHAR_FONTINFO_CTL ok
70 // due to ImpEditEngine::WriteRTF
71 // EE_CHAR_COLOR ok
72 // due to ScDocumentPool::StyleDeleted
73 // due to ScDocument::UpdateFontCharSet()
74 // due to ScXMLFontAutoStylePool_Impl
75 // ATTR_FONT ok
76 // due to OptimizeHasAttrib
77 // ATTR_ROTATE_VALUE ok
78 // due to ScDocument::GetDocColors()
79 // ATTR_BACKGROUND ok
80 // ATTR_FONT_COLOR ok
81 // due to ScXMLExport::CollectUserDefinedNamespaces
82 // ATTR_USERDEF ok
83 // due to ScXMLExport::CollectUserDefinedNamespaces
84 // due to SwXMLExport::exportDoc
85 // EE_PARA_XMLATTRIBS ok
86 // due to ScXMLExport::CollectUserDefinedNamespaces
87 // due to SwXMLExport::exportDoc
88 // EE_CHAR_XMLATTRIBS ok
89 // due to ScXMLExport::CollectUserDefinedNamespaces
90 // due to SwXMLExport::exportDoc
91 // SDRATTR_XMLATTRIBUTES ok
92 // due to ScXMLFontAutoStylePool_Impl
93 // ATTR_CJK_FONT ok
94 // ATTR_CTL_FONT ok
95 // ATTR_PAGE_HEADERLEFT ok
96 // ATTR_PAGE_FOOTERLEFT ok
97 // ATTR_PAGE_HEADERRIGHT ok
98 // ATTR_PAGE_FOOTERRIGHT ok
99 // ATTR_PAGE_HEADERFIRST ok
100 // ATTR_PAGE_FOOTERFIRST ok
101 // due to ScCellShell::ExecuteEdit
102 // due to ScTabViewShell::CreateRefDialogController
103 // SCITEM_CONDFORMATDLGDATA ok
104 // due to SdDrawDocument::UpdatePageRelativeURLs
105 // EE_FEATURE_FIELD ok
106 // due to SvxUnoMarkerTable::replaceByName
107 // due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
108 // due to XLineStartItem::checkForUniqueItem
109 // XATTR_LINESTART ok
110 // due to SvxUnoMarkerTable::replaceByName
111 // due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
112 // due to XLineStartItem::checkForUniqueItem
113 // XATTR_LINEEND ok
114 // due to SvxUnoNameItemTable
115 // due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
116 // due to NameOrIndex::CheckNamedItem all derived from NameOrIndex
117 // XATTR_FILLBITMAP ok
118 // due to SvxUnoNameItemTable
119 // due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
120 // XATTR_LINEDASH ok
121 // due to SvxUnoNameItemTable
122 // due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
123 // due to NameOrIndex::CheckNamedItem all derived from NameOrIndex
124 // XATTR_FILLGRADIENT ok
125 // due to SvxUnoNameItemTable
126 // due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
127 // XATTR_FILLHATCH ok
128 // due to SvxUnoNameItemTable
129 // due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
130 // XATTR_FILLFLOATTRANSPARENCE ok
131 // due to NamespaceIteratorImpl
132 // -> needs to be evaluated
133 // due to SwCursorShell::GotoNxtPrvTOXMark
134 // due to SwDoc::GetTOIKeys
135 // RES_TXTATR_TOXMARK ok
136 // due to SwDoc::GetRefMark
137 // due to SwDoc::CallEvent
138 // due to SwURLStateChanged::Notify
139 // due to SwHTMLWriter::CollectLinkTargets
140 // due to MSWordExportBase::CollectOutlineBookmarks
141 // RES_TXTATR_INETFMT ok
142 // due to SwDoc::GetAllUsedDB
143 // due to lcl_FindInputField
144 // due to SwViewShell::IsAnyFieldInDoc
145 // RES_TXTATR_FIELD ok
146 // due to SwDoc::GetAllUsedDB
147 // due to lcl_FindInputField
148 // due to SwViewShell::IsAnyFieldInDoc
149 // RES_TXTATR_INPUTFIELD ok
150 // due to SwDoc::SetDefault
151 // RES_PARATR_TABSTOP ok
152 // due to SwDoc::GetDocColors()
153 // due to RtfExport::OutColorTable
154 // RES_CHRATR_COLOR ok
155 // due to SwDoc::GetDocColors()
156 // RES_CHRATR_HIGHLIGHT ok
157 // due to SwDoc::GetDocColors()
158 // RES_BACKGROUND ok
159 // due to SwNode::FindPageDesc
160 // due to SwPageNumberFieldType::ChangeExpansion
161 // due to SwFrame::GetVirtPageNum
162 // RES_PAGEDESC ok
163 // due to SwAutoStylesEnumImpl::
164 // RES_TXTATR_CJK_RUBY ok
165 // due to SwHTMLWriter::CollectLinkTargets
166 // due to MSWordExportBase::CollectOutlineBookmarks
167 // RES_URL
168 // due to RtfExport::OutColorTable
169 // RES_CHRATR_UNDERLINE ok
170 // RES_CHRATR_OVERLINE ok
171 // RES_CHRATR_BACKGROUND ok
172 // RES_SHADOW ok
173 // RES_BOX ok
174 // RES_CHRATR_BOX ok
175 // XATTR_FILLCOLOR ok
176 // due to wwFontHelper::InitFontTable
177 // due to SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl
178 // RES_CHRATR_FONT ok
179 // due to wwFontHelper::InitFontTable
180 // due to SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl
181 // RES_CHRATR_CJK_FONT ok
182 // due to wwFontHelper::InitFontTable
183 // due to SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl
184 // RES_CHRATR_CTL_FONT
185 // due to SwXMLExport::exportDoc
186 // RES_UNKNOWNATR_CONTAINER ok
187 // RES_TXTATR_UNKNOWN_CONTAINER ok
189 ItemInfoUser::ItemInfoUser(const ItemInfo& rItemInfo, SfxItemPool& rItemPool, const SfxPoolItem& rItem, bool bPassingOwnership)
190 : ItemInfo(rItemInfo)
191 , m_pItem(implCreateItemEntry(rItemPool, &rItem, bPassingOwnership))
195 ItemInfoUser::~ItemInfoUser()
197 implCleanupItemEntry(m_pItem);
200 const SlotIDToWhichIDMap& ItemInfoPackage::getSlotIDToWhichIDMap() const
202 if (maSlotIDToWhichIDMap.empty())
204 // will be filled only once per office runtime
205 for (size_t a(0); a < size(); a++)
207 const ItemInfoStatic& rCandidate(getItemInfoStatic(a));
208 if (0 != rCandidate.getSlotID())
210 #ifdef DBG_UTIL
211 if (maSlotIDToWhichIDMap.find(rCandidate.getSlotID()) != maSlotIDToWhichIDMap.end())
212 assert(false && "ITEM: SlotID used double in ItemInfoPackage (!)");
213 #endif
214 maSlotIDToWhichIDMap[rCandidate.getSlotID()] = rCandidate.getWhich();
219 return maSlotIDToWhichIDMap;
222 const ItemInfo& ItemInfoPackage::getExistingItemInfo(size_t /*nIndex*/)
224 static ItemInfoStatic EMPTY(0, nullptr, 0, 0);
225 return EMPTY;
228 void SfxItemPool::registerItemInfoPackage(
229 ItemInfoPackage& rPackage,
230 const std::function<SfxPoolItem*(sal_uInt16)>& rCallback)
232 assert(maItemInfos.empty() && "ITEM: registering more than one ItemInfoPackage per Pool is not allowed (!)");
234 // we know the size :-)
235 maItemInfos.reserve(rPackage.size());
237 // loop over ItemInfoPackage and add ptrs to provided ItemInfos
238 for(size_t a(0); a < rPackage.size(); a++)
240 // get ItemInfo entry, maybe StaticDefault or DynamicDefault
241 const ItemInfo& rItemInfo(rPackage.getItemInfo(a, *this));
243 if (nullptr != rItemInfo.getItem())
245 // if it has an item, use it, done
246 maItemInfos.push_back(&rItemInfo);
247 continue;
250 // if not, use the callback to create a DynamicDefault. This
251 // *has* to be supported then by the caller
252 SfxPoolItem* pDynamicItem(rCallback(rItemInfo.getWhich()));
253 assert(nullptr != pDynamicItem);
254 maItemInfos.push_back(new ItemInfoDynamic(rItemInfo, pDynamicItem));
257 // use infos to fill local variables
258 mnStart = maItemInfos.front()->getWhich();
259 mnEnd = maItemInfos.back()->getWhich();
261 // set mapper for fast SlotIDToWhichID conversion
262 mpSlotIDToWhichIDMap = &rPackage.getSlotIDToWhichIDMap();
264 #ifdef DBG_UTIL
265 for (size_t a(1); a < maItemInfos.size(); a++)
266 if (maItemInfos[a-1]->getWhich() + 1 != maItemInfos[a]->getWhich())
267 assert(false && "ITEM: Order is wrong (!)");
268 #endif
271 const ItemInfo* SfxItemPool::impCheckItemInfoForClone(const ItemInfo* pInfo)
273 const SfxPoolItem* pItem(pInfo->getItem());
274 assert(nullptr != pItem && "ITEM: Missing Item in ItemInfo (!)");
276 if (pItem->isStaticDefault())
277 // noting to do, not ref-counted
278 return pInfo;
280 if (pItem->isDynamicDefault())
282 // need to clone to new Pool as DynamicDefault, owned by the Pool
283 // and not shared. Mainly SfxSetItems. Not RefCounted
284 return new ItemInfoDynamic(*pInfo, pItem->Clone(this));
287 // all Items else that can be in the Pool are UserDefaults. These
288 // are RefCounted, so use implCreateItemEntry to increase reference
289 return new ItemInfoUser(*pInfo, *this, *pItem);
292 void SfxItemPool::impClearUserDefault(userItemInfos::iterator& rHit)
294 if (rHit == maUserItemInfos.end())
295 // does not exist
296 return;
298 // get ItemInfo and Item, HAS to be a UserDefault
299 const sal_uInt16 nIndex(GetIndex_Impl(rHit->first));
300 const ItemInfo* pInfo(maItemInfos[nIndex]);
301 assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
303 // restore original entry using the remembered one
304 maItemInfos[nIndex] = rHit->second;
306 // free Item, delete ItemInfo
307 delete pInfo;
310 void SfxItemPool::impCreateUserDefault(const SfxPoolItem& rItem)
312 const sal_uInt16 nWhich(rItem.Which());
314 // make sure by an assert check that none exists
315 assert(maUserItemInfos.end() == maUserItemInfos.find(nWhich));
317 const sal_uInt16 nIndex(GetIndex_Impl(nWhich));
318 const ItemInfo* pInfo(maItemInfos[nIndex]);
319 assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
321 // safe original ItemInfo in UserItemInfos
322 maUserItemInfos.insert({nWhich, pInfo});
324 // create new Item by using implCreateItemEntry and new ItemInfo
325 maItemInfos[nIndex] = new ItemInfoUser(*pInfo, *this, rItem);
328 void SfxItemPool::cleanupItemInfos()
330 // reset all UserDefaultItems & restore original maItemInfos
331 while (!maUserItemInfos.empty())
333 // get next candidate, cleanup UseDefault and remove data
334 userItemInfos::iterator aHit(maUserItemInfos.begin());
335 impClearUserDefault(aHit);
336 maUserItemInfos.erase(aHit);
339 // delete DynamicDefaults in maItemInfos, these only exist
340 // for Pool lifetime since they are Pool-dependent. There should
341 // be NO MORE UserDefaults after cleanup above
342 for (auto& rInfo : maItemInfos)
344 if (rInfo->getItem()->isDynamicDefault())
346 // the whole ItemInfo is owned by the pool, so
347 // delete the Item and the ItemInfo (in that order :-)
348 delete rInfo;
350 #ifdef DBG_UTIL
351 // since there should be NO MORE UserDefaults the item
352 // then *has* to be StaticDefault - check that
353 else if (!rInfo->getItem()->isStaticDefault())
354 assert(false && "ITEM: Error in UserDefault handling (!)");
355 #endif
359 void SfxItemPool::registerItemSet(SfxItemSet& rSet)
361 registeredSfxItemSets& rTarget(GetMasterPool()->maRegisteredSfxItemSets);
362 #ifdef DBG_UTIL
363 const size_t nBefore(rTarget.size());
364 #endif
365 rTarget.insert(&rSet);
366 #ifdef DBG_UTIL
367 const size_t nAfter(rTarget.size());
368 if (nBefore + 1 != nAfter)
370 SAL_WARN("svl.items", "SfxItemPool::registerItemSet: ItemSet was already registered (!)");
372 #endif
375 void SfxItemPool::unregisterItemSet(SfxItemSet& rSet)
377 registeredSfxItemSets& rTarget(GetMasterPool()->maRegisteredSfxItemSets);
378 #ifdef DBG_UTIL
379 const size_t nBefore(rTarget.size());
380 #endif
381 rTarget.erase(&rSet);
382 #ifdef DBG_UTIL
383 const size_t nAfter(rTarget.size());
384 if (nBefore != nAfter + 1)
386 SAL_WARN("svl.items", "SfxItemPool::unregisterItemSet: ItemSet was not registered (!)");
388 #endif
391 void SfxItemPool::registerPoolItemHolder(SfxPoolItemHolder& rHolder)
393 registeredSfxPoolItemHolders& rTarget(GetMasterPool()->maRegisteredSfxPoolItemHolders);
394 #ifdef DBG_UTIL
395 const size_t nBefore(rTarget.size());
396 #endif
397 rTarget.insert(&rHolder);
398 #ifdef DBG_UTIL
399 const size_t nAfter(rTarget.size());
400 if (nBefore + 1 != nAfter)
402 SAL_WARN("svl.items", "SfxItemPool::registerPoolItemHolder: SfxPoolItemHolder was already registered (!)");
404 #endif
405 if (rHolder.is() && rHolder.getItem()->isNameOrIndex())
406 registerNameOrIndex(*rHolder.getItem());
409 void SfxItemPool::unregisterPoolItemHolder(SfxPoolItemHolder& rHolder)
411 registeredSfxPoolItemHolders& rTarget(GetMasterPool()->maRegisteredSfxPoolItemHolders);
412 #ifdef DBG_UTIL
413 const size_t nBefore(rTarget.size());
414 #endif
415 rTarget.erase(&rHolder);
416 #ifdef DBG_UTIL
417 const size_t nAfter(rTarget.size());
418 if (nBefore != nAfter + 1)
420 SAL_WARN("svl.items", "SfxItemPool::unregisterPoolItemHolder: SfxPoolItemHolder was not registered (!)");
422 #endif
423 if (rHolder.is() && rHolder.getItem()->isNameOrIndex())
424 unregisterNameOrIndex(*rHolder.getItem());
427 void SfxItemPool::registerNameOrIndex(const SfxPoolItem& rItem)
429 assert(rItem.isNameOrIndex() && "ITEM: only Items derived from NameOrIndex supported for this mechanism (!)");
430 NameOrIndexContent& rTarget(GetMasterPool()->maRegisteredNameOrIndex[rItem.ItemType()]);
431 NameOrIndexContent::iterator aHit(rTarget.find(&rItem));
432 if (aHit == rTarget.end())
433 rTarget.insert(std::pair<const SfxPoolItem*, sal_uInt32>(&rItem, 0));
434 else
435 aHit->second++;
438 void SfxItemPool::unregisterNameOrIndex(const SfxPoolItem& rItem)
440 assert(rItem.isNameOrIndex() && "ITEM: only Items derived from NameOrIndex supported for this mechanism (!)");
441 NameOrIndexContent& rTarget(GetMasterPool()->maRegisteredNameOrIndex[rItem.ItemType()]);
442 NameOrIndexContent::iterator aHit(rTarget.find(&rItem));
443 assert(aHit != rTarget.end() && "ITEM: malformed order of buffered NameOrIndex Items, entry *expected* (!)");
444 if (0 == aHit->second)
445 rTarget.erase(aHit);
446 else
447 aHit->second--;
450 SfxItemPool* SfxItemPool::getTargetPool(sal_uInt16 nWhich) const
452 if (IsInRange(nWhich))
453 return const_cast<SfxItemPool*>(this);
454 if (mpSecondary)
455 return mpSecondary->getTargetPool(nWhich);
456 return nullptr;
459 bool SfxItemPool::CheckItemInfoFlag(sal_uInt16 nWhich, sal_uInt16 nMask) const
461 SfxItemPool* pTarget(getTargetPool(nWhich));
462 if (nullptr == pTarget)
463 return false;
465 if (!pTarget->maItemInfos.empty())
467 const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
468 const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
469 assert(nullptr != pInfo);
470 return pInfo->getItemInfoFlags() & nMask;
473 return pTarget->CheckItemInfoFlag_Impl(pTarget->GetIndex_Impl(nWhich), nMask);
476 SfxBroadcaster& SfxItemPool::BC()
478 return aBC;
482 * This is the regular ctor to be used for this class.
483 * An SfxItemPool instance is initialized, which can manage Items in the
484 * range from 'nStartWhich' to 'nEndWhich'.
486 * For every one of these WhichIds a static Default must be present in the
487 * 'pDefaults' array. They start with an SfxPoolItem (with the WhichId
488 * 'nStartWhich'), are sorted by WhichId and consecutively stored.
490 * 'pItemInfos' is a USHORT array arranged in the same way, which holds
491 * SlotIds and Flags. These SlotIds can be 0, if the affected Items are
492 * exclusively used in the Core.
493 * The flags allow for e.g. enabling value sharing (poolable).
495 * If the Pool is supposed to hold SfxSetItems, the ctor cannot yet contain
496 * static Defaults. This needs to be done afterwards, using
497 * @see SfxItemPool::SetPoolDefaults(std::vector<SfxPoolItem*>*).
499 * @see SfxItemPool::SetPoolDefaults(std::vector<SfxPoolItem*>*)
500 * @see SfxItemPool::ReleasePoolDefaults(std::vector<SfxPoolItem*>*,bool)
501 * @see SfxItemPool::ReleasePoolDefaults(bool)
503 SfxItemPool::SfxItemPool(const OUString& rName) /* Pool name to identify in the file format */
504 : salhelper::SimpleReferenceObject()
505 , aBC()
506 , aName(rName)
507 , mpMaster(this)
508 , mpSecondary()
509 , mnStart(0)
510 , mnEnd(0)
511 , eDefMetric(MapUnit::MapCM)
512 , maRegisteredSfxItemSets()
513 , maRegisteredSfxPoolItemHolders()
514 , maRegisteredNameOrIndex()
515 , mbShutdownHintSent(false)
516 , maItemInfos()
517 , maUserItemInfos()
518 , mpSlotIDToWhichIDMap(nullptr)
520 eDefMetric = MapUnit::MapTwip;
524 * Copy ctor
526 * @see SfxItemPool::Clone() const
528 SfxItemPool::SfxItemPool(const SfxItemPool& rPool) // Copy from this instance
529 : salhelper::SimpleReferenceObject()
530 , aBC()
531 , aName(rPool.aName)
532 , mpMaster(this)
533 , mpSecondary()
534 , maPoolRanges()
535 , mnStart(rPool.mnStart)
536 , mnEnd(rPool.mnEnd)
537 , eDefMetric(MapUnit::MapCM)
538 , maRegisteredSfxItemSets()
539 , maRegisteredSfxPoolItemHolders()
540 , maRegisteredNameOrIndex()
541 , mbShutdownHintSent(false)
542 , maItemInfos(rPool.maItemInfos)
543 , maUserItemInfos(rPool.maUserItemInfos)
544 , mpSlotIDToWhichIDMap(rPool.mpSlotIDToWhichIDMap)
546 // DynamicDefaults and UserDefaults need to be cloned for the new Pool
547 for (itemInfoVector::iterator aInfo(maItemInfos.begin()); aInfo != maItemInfos.end(); aInfo++)
548 *aInfo = impCheckItemInfoForClone(*aInfo);
550 // DynamicDefaults need to be cloned for the new Pool (no UserDefaults in UserItemInfos)
551 for (auto& rUserItem : maUserItemInfos)
552 rUserItem.second = impCheckItemInfoForClone(rUserItem.second);
554 eDefMetric = rPool.eDefMetric;
556 // Repair linkage
557 if ( rPool.mpSecondary )
558 SetSecondaryPool( rPool.mpSecondary->Clone().get() );
561 SfxItemPool::~SfxItemPool()
563 // cleanup UserDefaults & delete owned DynamicDefaults
564 cleanupItemInfos();
566 // Need to send ShutdownHint?
567 sendShutdownHint();
569 if (mpMaster != nullptr && mpMaster != this)
571 // This condition indicates an error.
572 // A mpMaster->SetSecondaryPool(...) call should have been made
573 // earlier to prevent this. At this point we can only try to
574 // prevent a crash later on.
575 DBG_ASSERT( mpMaster == this, "destroying active Secondary-Pool" );
576 if (mpMaster->mpSecondary == this)
577 mpMaster->mpSecondary = nullptr;
581 void SfxItemPool::SetSecondaryPool( SfxItemPool *pPool )
583 // Reset Master in attached Pools
584 if ( mpSecondary )
586 mpSecondary->mpMaster = mpSecondary.get();
587 for ( SfxItemPool *p = mpSecondary->mpSecondary.get(); p; p = p->mpSecondary.get() )
588 p->mpMaster = mpSecondary.get();
591 // Set Master of new Secondary Pools
592 DBG_ASSERT( !pPool || pPool->mpMaster == pPool, "Secondary is present in two Pools" );
593 SfxItemPool *pNewMaster = GetMasterPool() ? mpMaster : this;
594 for ( SfxItemPool *p = pPool; p; p = p->mpSecondary.get() )
595 p->mpMaster = pNewMaster;
597 // Remember new Secondary Pool
598 mpSecondary = pPool;
601 MapUnit SfxItemPool::GetMetric( sal_uInt16 ) const
603 return eDefMetric;
606 void SfxItemPool::SetDefaultMetric( MapUnit eNewMetric )
608 // assert((pImpl->eDefMetric == eNewMetric || !pImpl->maPoolRanges) && "pool already frozen, cannot change metric");
609 eDefMetric = eNewMetric;
612 bool SfxItemPool::GetPresentation
614 const SfxPoolItem& rItem,
615 MapUnit eMetric,
616 OUString& rText,
617 const IntlWrapper& rIntlWrapper
618 ) const
620 return rItem.GetPresentation(
621 SfxItemPresentation::Complete, GetMetric(rItem.Which()), eMetric, rText, rIntlWrapper );
624 rtl::Reference<SfxItemPool> SfxItemPool::Clone() const
626 return new SfxItemPool( *this );
629 void SfxItemPool::sendShutdownHint()
631 // Already sent?
632 if (mbShutdownHintSent)
633 return;
635 mbShutdownHintSent = true;
637 // Inform e.g. running Requests
638 aBC.Broadcast( SfxHint( SfxHintId::Dying ) );
639 maPoolRanges.reset();
642 void SfxItemPool::SetUserDefaultItem(const SfxPoolItem& rItem)
644 SfxItemPool* pTarget(getTargetPool(rItem.Which()));
645 if (nullptr == pTarget)
646 assert(false && "unknown WhichId - cannot set pool default");
648 const sal_uInt16 nWhich(rItem.Which());
649 userItemInfos::iterator aHit(pTarget->maUserItemInfos.find(nWhich));
651 if (aHit == pTarget->maUserItemInfos.end())
653 // UserDefault does not exist, create needed entries to safe
654 // original ItemInfo in UserItemInfos and set new, owned
655 // ItemInfo containing an owned clone of the Item in ItemInfos
656 pTarget->impCreateUserDefault(rItem);
657 return;
660 // UserDefault does exist, check and evtl. replace
661 const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
662 const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
663 assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
664 const SfxPoolItem* pItem(pInfo->getItem());
665 assert(nullptr != pItem && "ITEM: access error to Defaults in Pool (!)");
667 // nothing to do if equal, so check
668 if (SfxPoolItem::areSame(pItem, &rItem))
669 return;
671 // need to exchange existing instance and free current one
672 pTarget->maItemInfos[nIndex] = new ItemInfoUser(*pInfo, *pTarget, rItem);
673 delete pInfo;
676 const SfxPoolItem* SfxItemPool::GetUserDefaultItem( sal_uInt16 nWhich ) const
678 SfxItemPool* pTarget(getTargetPool(nWhich));
679 if (nullptr == pTarget)
681 assert(false && "unknown WhichId - cannot get pool default");
682 return nullptr;
685 userItemInfos::iterator aHit(pTarget->maUserItemInfos.find(nWhich));
687 if (aHit == pTarget->maUserItemInfos.end())
688 // no default item
689 return nullptr;
691 const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
692 const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
693 assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
694 const SfxPoolItem* pItem(pInfo->getItem());
695 assert(nullptr != pItem && "ITEM: access error to Defaults in Pool (!)");
696 return pItem;
700 * Resets the default of the given WhichId back to the static Default.
701 * If a pool default exists, it is removed.
703 void SfxItemPool::ResetUserDefaultItem( sal_uInt16 nWhich )
705 SfxItemPool* pTarget(getTargetPool(nWhich));
706 if (nullptr == pTarget)
707 assert(false && "unknown WhichId - cannot reset pool default");
709 userItemInfos::iterator aHit(pTarget->maUserItemInfos.find(nWhich));
711 if (aHit != pTarget->maUserItemInfos.end())
713 // clear entry, cleanup, restore previous data
714 pTarget->impClearUserDefault(aHit);
716 // remove remembered data
717 pTarget->maUserItemInfos.erase(aHit);
721 const SfxPoolItem& SfxItemPool::GetUserOrPoolDefaultItem( sal_uInt16 nWhich ) const
723 SfxItemPool* pTarget(getTargetPool(nWhich));
724 if (nullptr == pTarget)
725 assert(!"unknown which - don't ask me for defaults");
727 const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
728 const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
729 assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
730 const SfxPoolItem* pItem(pInfo->getItem());
731 assert(nullptr != pItem && "ITEM: access error to Defaults in Pool (!)");
732 return *pItem;
735 /* get the last pool by following the GetSecondaryPool chain */
736 SfxItemPool* SfxItemPool::GetLastPoolInChain()
738 SfxItemPool* pLast(this);
740 while(pLast->GetSecondaryPool())
741 pLast = pLast->GetSecondaryPool();
743 return pLast;
746 const WhichRangesContainer& SfxItemPool::GetMergedIdRanges() const
748 if (maPoolRanges.empty())
750 // Merge all ranges, keeping them sorted
751 for (const SfxItemPool* pPool = this; pPool; pPool = pPool->mpSecondary.get())
752 maPoolRanges = maPoolRanges.MergeRange(pPool->mnStart, pPool->mnEnd);
755 return maPoolRanges;
758 const SfxPoolItem* SfxItemPool::GetPoolDefaultItem(sal_uInt16 nWhich) const
760 SfxItemPool* pTarget(getTargetPool(nWhich));
761 if (nullptr == pTarget)
762 assert(false && "unknown WhichId - cannot resolve surrogate");
764 const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
765 userItemInfos::iterator aHit(pTarget->maUserItemInfos.find(nWhich));
767 if (aHit != pTarget->maUserItemInfos.end())
769 // If it is a UserDefault Item, check saved ItemInfo and use
770 // Item from there
771 assert(aHit != pTarget->maUserItemInfos.end() && "ITEM: Error in UserDefault handling (!)");
772 return aHit->second->getItem();
775 const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
776 assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
777 const SfxPoolItem* pItem(pInfo->getItem());
778 assert(nullptr != pItem && "ITEM: access error to Defaults in Pool (!)");
779 return pItem;
782 namespace
784 class SurrogateData_ItemSet : public SfxItemPool::SurrogateData
786 const SfxPoolItem* mpItem;
787 SfxItemSet* mpSet;
789 public:
790 SurrogateData_ItemSet(const SfxPoolItem& rItem, SfxItemSet& rSet)
791 : SfxItemPool::SurrogateData()
792 , mpItem(&rItem)
793 , mpSet(&rSet)
797 SurrogateData_ItemSet(const SurrogateData_ItemSet&) = default;
799 virtual const SfxPoolItem& getItem() const override
801 return *mpItem;
804 virtual const SfxPoolItem* setItem(std::unique_ptr<SfxPoolItem> aNew) override
806 return mpSet->Put(std::unique_ptr<SfxPoolItem>(aNew.release()));
810 class SurrogateData_ItemHolder : public SfxItemPool::SurrogateData
812 SfxPoolItemHolder* mpHolder;
814 public:
815 SurrogateData_ItemHolder(SfxPoolItemHolder& rHolder)
816 : SfxItemPool::SurrogateData()
817 , mpHolder(&rHolder)
821 SurrogateData_ItemHolder(const SurrogateData_ItemHolder&) = default;
823 virtual const SfxPoolItem& getItem() const override
825 return *mpHolder->getItem();
828 virtual const SfxPoolItem* setItem(std::unique_ptr<SfxPoolItem> aNew) override
830 *mpHolder = SfxPoolItemHolder(mpHolder->getPool(), aNew.release(), true);
831 return mpHolder->getItem();
836 void SfxItemPool::iterateItemSurrogates(
837 sal_uInt16 nWhich,
838 const std::function<bool(SurrogateData& rCand)>& rItemCallback) const
840 // 1st source for surrogates
841 const registeredSfxItemSets& rSets(GetMasterPool()->maRegisteredSfxItemSets);
843 if(!rSets.empty())
845 const SfxPoolItem* pItem(nullptr);
846 std::vector<SurrogateData_ItemSet> aEntries;
848 // NOTE: this collects the callback data in a preparing run. This
849 // is by purpose, else any write change may change the iterators
850 // used at registeredSfxItemSets. I tied with direct feed and
851 // that worked most of the time, but failed for ItemHolders due
852 // to these being changed and being re-registered. I have avoided
853 // this in SfxPoolItemHolder::operator=, but it's just a question
854 // that in some scenario someone replaces an Item even with a
855 // different type/WhichID that this will then break/crash
856 for (const auto& rCand : rSets)
857 if (SfxItemState::SET == rCand->GetItemState(nWhich, false, &pItem))
858 aEntries.emplace_back(*pItem, *rCand);
860 if (!aEntries.empty())
861 for (auto& rCand : aEntries)
862 if (!rItemCallback(rCand))
863 return;
866 // 2nd source for surrogates
867 const registeredSfxPoolItemHolders& rHolders(GetMasterPool()->maRegisteredSfxPoolItemHolders);
869 if (!rHolders.empty())
871 std::vector<SurrogateData_ItemHolder> aEntries;
873 // NOTE: same as above, look there
874 for (auto& rCand : rHolders)
875 if (rCand->Which() == nWhich && nullptr != rCand->getItem())
876 aEntries.emplace_back(*rCand);
878 if (!aEntries.empty())
879 for (auto& rCand : aEntries)
880 if (!rItemCallback(rCand))
881 return;
885 void SfxItemPool::GetItemSurrogatesForItem(ItemSurrogates& rTarget, SfxItemType eItemType) const
887 rTarget.clear();
888 const registeredNameOrIndex& rRegistered(GetMasterPool()->maRegisteredNameOrIndex);
889 registeredNameOrIndex::const_iterator aHit(rRegistered.find(eItemType));
890 if (aHit != rRegistered.end())
892 rTarget.reserve(aHit->second.size());
893 for (const auto& entry : aHit->second)
894 rTarget.push_back(entry.first);
898 void SfxItemPool::GetItemSurrogatesForItem(ItemSurrogates& rTarget, const SfxPoolItem& rItem) const
900 assert(rItem.isNameOrIndex() && "ITEM: only Items derived from NameOrIndex supported for this mechanism (!)");
901 GetItemSurrogatesForItem(rTarget, rItem.ItemType());
904 void SfxItemPool::GetItemSurrogates(ItemSurrogates& rTarget, sal_uInt16 nWhich) const
906 rTarget.clear();
908 if (0 == nWhich)
909 return;
911 // NOTE: This is pre-collected, in this case mainly to
912 // remove all double listings of SfxPoolItems which can
913 // of course be referenced multiple times in multiple
914 // ItemSets/ItemHolders. It comes handy that
915 // std::unordered_set does this by definition
916 std::unordered_set<const SfxPoolItem*> aNewSurrogates;
918 // 1st source for surrogates
919 const registeredSfxItemSets& rSets(GetMasterPool()->maRegisteredSfxItemSets);
920 const SfxPoolItem* pItem(nullptr);
921 for (const auto& rCand : rSets)
922 if (SfxItemState::SET == rCand->GetItemState(nWhich, false, &pItem))
923 aNewSurrogates.insert(pItem);
925 // 2nd source for surrogates
926 const registeredSfxPoolItemHolders& rHolders(GetMasterPool()->maRegisteredSfxPoolItemHolders);
927 for (const auto& rCand : rHolders)
928 if (rCand->Which() == nWhich && nullptr != rCand->getItem())
929 aNewSurrogates.insert(rCand->getItem());
931 rTarget = ItemSurrogates(aNewSurrogates.begin(), aNewSurrogates.end());
934 sal_uInt16 SfxItemPool::GetWhichIDFromSlotID(sal_uInt16 nSlotId, bool bDeep) const
936 if (!IsSlot(nSlotId))
937 return nSlotId;
939 if (nullptr != mpSlotIDToWhichIDMap)
941 // use the static global translation table -> near linear access time
942 SlotIDToWhichIDMap::const_iterator aHit(mpSlotIDToWhichIDMap->find(nSlotId));
943 if (aHit != mpSlotIDToWhichIDMap->end())
944 return aHit->second;
947 if (mpSecondary && bDeep)
948 return mpSecondary->GetWhichIDFromSlotID(nSlotId);
950 return nSlotId;
954 sal_uInt16 SfxItemPool::GetSlotId(sal_uInt16 nWhich) const
956 if (!IsWhich(nWhich))
957 return nWhich;
959 SfxItemPool* pTarget(getTargetPool(nWhich));
960 if (nullptr == pTarget)
961 assert(false && "unknown WhichId - cannot get slot-id");
963 const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
964 const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
965 assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
966 const sal_uInt16 nSID(pInfo->getSlotID());
967 return (0 != nSID) ? nSID : nWhich;
971 sal_uInt16 SfxItemPool::GetTrueWhichIDFromSlotID( sal_uInt16 nSlotId, bool bDeep ) const
973 if (!IsSlot(nSlotId))
974 return 0;
976 if (nullptr != mpSlotIDToWhichIDMap)
978 // use the static global translation table -> near linear access time
979 SlotIDToWhichIDMap::const_iterator aHit(mpSlotIDToWhichIDMap->find(nSlotId));
980 if (aHit != mpSlotIDToWhichIDMap->end())
981 return aHit->second;
984 if (mpSecondary && bDeep)
985 return mpSecondary->GetTrueWhichIDFromSlotID(nSlotId);
987 return 0;
991 sal_uInt16 SfxItemPool::GetTrueSlotId( sal_uInt16 nWhich ) const
993 if (!IsWhich(nWhich))
994 return 0;
996 SfxItemPool* pTarget(getTargetPool(nWhich));
997 if (nullptr == pTarget)
998 assert(false && "unknown WhichId - cannot get slot-id");
1000 const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
1001 const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
1002 assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
1003 return pInfo->getSlotID();
1006 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */