1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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>
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
72 // due to ScDocumentPool::StyleDeleted
73 // due to ScDocument::UpdateFontCharSet()
74 // due to ScXMLFontAutoStylePool_Impl
76 // due to OptimizeHasAttrib
77 // ATTR_ROTATE_VALUE ok
78 // due to ScDocument::GetDocColors()
81 // due to ScXMLExport::CollectUserDefinedNamespaces
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
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
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
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()
159 // due to SwNode::FindPageDesc
160 // due to SwPageNumberFieldType::ChangeExpansion
161 // due to SwFrame::GetVirtPageNum
163 // due to SwAutoStylesEnumImpl::
164 // RES_TXTATR_CJK_RUBY ok
165 // due to SwHTMLWriter::CollectLinkTargets
166 // due to MSWordExportBase::CollectOutlineBookmarks
168 // due to RtfExport::OutColorTable
169 // RES_CHRATR_UNDERLINE ok
170 // RES_CHRATR_OVERLINE ok
171 // RES_CHRATR_BACKGROUND 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())
211 if (maSlotIDToWhichIDMap
.find(rCandidate
.getSlotID()) != maSlotIDToWhichIDMap
.end())
212 assert(false && "ITEM: SlotID used double in ItemInfoPackage (!)");
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);
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
);
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();
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 (!)");
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
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())
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
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 :-)
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 (!)");
359 void SfxItemPool::registerItemSet(SfxItemSet
& rSet
)
361 registeredSfxItemSets
& rTarget(GetMasterPool()->maRegisteredSfxItemSets
);
363 const size_t nBefore(rTarget
.size());
365 rTarget
.insert(&rSet
);
367 const size_t nAfter(rTarget
.size());
368 if (nBefore
+ 1 != nAfter
)
370 SAL_WARN("svl.items", "SfxItemPool::registerItemSet: ItemSet was already registered (!)");
375 void SfxItemPool::unregisterItemSet(SfxItemSet
& rSet
)
377 registeredSfxItemSets
& rTarget(GetMasterPool()->maRegisteredSfxItemSets
);
379 const size_t nBefore(rTarget
.size());
381 rTarget
.erase(&rSet
);
383 const size_t nAfter(rTarget
.size());
384 if (nBefore
!= nAfter
+ 1)
386 SAL_WARN("svl.items", "SfxItemPool::unregisterItemSet: ItemSet was not registered (!)");
391 void SfxItemPool::registerPoolItemHolder(SfxPoolItemHolder
& rHolder
)
393 registeredSfxPoolItemHolders
& rTarget(GetMasterPool()->maRegisteredSfxPoolItemHolders
);
395 const size_t nBefore(rTarget
.size());
397 rTarget
.insert(&rHolder
);
399 const size_t nAfter(rTarget
.size());
400 if (nBefore
+ 1 != nAfter
)
402 SAL_WARN("svl.items", "SfxItemPool::registerPoolItemHolder: SfxPoolItemHolder was already registered (!)");
405 if (rHolder
.is() && rHolder
.getItem()->isNameOrIndex())
406 registerNameOrIndex(*rHolder
.getItem());
409 void SfxItemPool::unregisterPoolItemHolder(SfxPoolItemHolder
& rHolder
)
411 registeredSfxPoolItemHolders
& rTarget(GetMasterPool()->maRegisteredSfxPoolItemHolders
);
413 const size_t nBefore(rTarget
.size());
415 rTarget
.erase(&rHolder
);
417 const size_t nAfter(rTarget
.size());
418 if (nBefore
!= nAfter
+ 1)
420 SAL_WARN("svl.items", "SfxItemPool::unregisterPoolItemHolder: SfxPoolItemHolder was not registered (!)");
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));
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
)
450 SfxItemPool
* SfxItemPool::getTargetPool(sal_uInt16 nWhich
) const
452 if (IsInRange(nWhich
))
453 return const_cast<SfxItemPool
*>(this);
455 return mpSecondary
->getTargetPool(nWhich
);
459 bool SfxItemPool::CheckItemInfoFlag(sal_uInt16 nWhich
, sal_uInt16 nMask
) const
461 SfxItemPool
* pTarget(getTargetPool(nWhich
));
462 if (nullptr == pTarget
)
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()
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()
511 , eDefMetric(MapUnit::MapCM
)
512 , maRegisteredSfxItemSets()
513 , maRegisteredSfxPoolItemHolders()
514 , maRegisteredNameOrIndex()
515 , mbShutdownHintSent(false)
518 , mpSlotIDToWhichIDMap(nullptr)
520 eDefMetric
= MapUnit::MapTwip
;
526 * @see SfxItemPool::Clone() const
528 SfxItemPool::SfxItemPool(const SfxItemPool
& rPool
) // Copy from this instance
529 : salhelper::SimpleReferenceObject()
535 , mnStart(rPool
.mnStart
)
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
;
557 if ( rPool
.mpSecondary
)
558 SetSecondaryPool( rPool
.mpSecondary
->Clone().get() );
561 SfxItemPool::~SfxItemPool()
563 // cleanup UserDefaults & delete owned DynamicDefaults
566 // Need to send ShutdownHint?
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
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
601 MapUnit
SfxItemPool::GetMetric( sal_uInt16
) const
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
,
617 const IntlWrapper
& rIntlWrapper
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()
632 if (mbShutdownHintSent
)
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
);
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
))
671 // need to exchange existing instance and free current one
672 pTarget
->maItemInfos
[nIndex
] = new ItemInfoUser(*pInfo
, *pTarget
, rItem
);
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");
685 userItemInfos::iterator
aHit(pTarget
->maUserItemInfos
.find(nWhich
));
687 if (aHit
== pTarget
->maUserItemInfos
.end())
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 (!)");
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 (!)");
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();
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
);
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
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 (!)");
784 class SurrogateData_ItemSet
: public SfxItemPool::SurrogateData
786 const SfxPoolItem
* mpItem
;
790 SurrogateData_ItemSet(const SfxPoolItem
& rItem
, SfxItemSet
& rSet
)
791 : SfxItemPool::SurrogateData()
797 SurrogateData_ItemSet(const SurrogateData_ItemSet
&) = default;
799 virtual const SfxPoolItem
& getItem() const override
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
;
815 SurrogateData_ItemHolder(SfxPoolItemHolder
& rHolder
)
816 : SfxItemPool::SurrogateData()
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(
838 const std::function
<bool(SurrogateData
& rCand
)>& rItemCallback
) const
840 // 1st source for surrogates
841 const registeredSfxItemSets
& rSets(GetMasterPool()->maRegisteredSfxItemSets
);
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
))
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
))
885 void SfxItemPool::GetItemSurrogatesForItem(ItemSurrogates
& rTarget
, SfxItemType eItemType
) const
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
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
))
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())
947 if (mpSecondary
&& bDeep
)
948 return mpSecondary
->GetWhichIDFromSlotID(nSlotId
);
954 sal_uInt16
SfxItemPool::GetSlotId(sal_uInt16 nWhich
) const
956 if (!IsWhich(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
))
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())
984 if (mpSecondary
&& bDeep
)
985 return mpSecondary
->GetTrueWhichIDFromSlotID(nSlotId
);
991 sal_uInt16
SfxItemPool::GetTrueSlotId( sal_uInt16 nWhich
) const
993 if (!IsWhich(nWhich
))
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: */