Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svl/source/items/itempool.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
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 .
18
 */
19
20
#include <svl/itempool.hxx>
21
#include <svl/setitem.hxx>
22
23
#include <string.h>
24
#include <libxml/xmlwriter.h>
25
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>
32
#include <tools/mapunit.hxx>
33
34
#include <cassert>
35
#include <vector>
36
37
// WhichIDs that need to set SFX_ITEMINFOFLAG_SUPPORT_SURROGATE in SfxItemInfo
38
// to true to allow a register of all items of that type/with that WhichID
39
// to be accessible using SfxItemPool::GetItemSurrogates. Created by
40
// grepping for 'GetItemSurrogates' usages & interpreting. Some
41
// are double, more may be necessary. There is a SAL_INFO("svl.items", ...)
42
// in SfxItemPool::GetItemSurrogates that will give hints on missing flags.
43
//
44
// due to SwTable::UpdateFields
45
// due to SwCursorShell::GotoNxtPrvTableFormula
46
// due to DocumentFieldsManager::UpdateTableFields
47
// due to SwTable::GatherFormulas
48
//  RES_BOXATR_FORMULA ok
49
// due to SwContentTree::EditEntry
50
// due to SwDoc::FindINetAttr
51
// due to SwUndoResetAttr::RedoImpl
52
// due to SwContentTree::EditEntry
53
// due to SwContentTree::BringEntryToAttention
54
//  RES_TXTATR_REFMARK ok
55
// due to ImpEditEngine::WriteRTF
56
// due to ScDocument::UpdateFontCharSet()
57
// due to ScXMLFontAutoStylePool_Impl
58
// due to SdXImpressDocument::getPropertyValue
59
// due to Writer::AddFontItems_
60
//  EE_CHAR_FONTINFO ok
61
// due to ImpEditEngine::WriteRTF
62
// due to ScXMLFontAutoStylePool_Impl
63
// due to SdXImpressDocument::getPropertyValue
64
// due to Writer::AddFontItems_
65
//  EE_CHAR_FONTINFO_CJK ok
66
// due to ImpEditEngine::WriteRTF
67
// due to ScXMLFontAutoStylePool_Impl
68
// due to SdXImpressDocument::getPropertyValue
69
// due to Writer::AddFontItems_
70
//  EE_CHAR_FONTINFO_CTL ok
71
// due to ImpEditEngine::WriteRTF
72
//  EE_CHAR_COLOR ok
73
// due to ScDocumentPool::StyleDeleted
74
// due to ScDocument::UpdateFontCharSet()
75
// due to ScXMLFontAutoStylePool_Impl
76
//  ATTR_FONT ok
77
// due to OptimizeHasAttrib
78
//  ATTR_ROTATE_VALUE ok
79
// due to ScDocument::GetDocColors()
80
//  ATTR_BACKGROUND ok
81
//  ATTR_FONT_COLOR ok
82
// due to ScXMLExport::CollectUserDefinedNamespaces
83
//  ATTR_USERDEF ok
84
// due to ScXMLExport::CollectUserDefinedNamespaces
85
// due to SwXMLExport::exportDoc
86
//  EE_PARA_XMLATTRIBS ok
87
// due to ScXMLExport::CollectUserDefinedNamespaces
88
// due to SwXMLExport::exportDoc
89
//  EE_CHAR_XMLATTRIBS ok
90
// due to ScXMLExport::CollectUserDefinedNamespaces
91
// due to SwXMLExport::exportDoc
92
//  SDRATTR_XMLATTRIBUTES ok
93
// due to ScXMLFontAutoStylePool_Impl
94
//  ATTR_CJK_FONT ok
95
//  ATTR_CTL_FONT ok
96
//  ATTR_PAGE_HEADERLEFT ok
97
//  ATTR_PAGE_FOOTERLEFT ok
98
//  ATTR_PAGE_HEADERRIGHT ok
99
//  ATTR_PAGE_FOOTERRIGHT ok
100
//  ATTR_PAGE_HEADERFIRST ok
101
//  ATTR_PAGE_FOOTERFIRST ok
102
// due to ScCellShell::ExecuteEdit
103
// due to ScTabViewShell::CreateRefDialogController
104
//  SCITEM_CONDFORMATDLGDATA ok
105
// due to SdDrawDocument::UpdatePageRelativeURLs
106
//  EE_FEATURE_FIELD ok
107
// due to SvxUnoMarkerTable::replaceByName
108
// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
109
// due to XLineStartItem::checkForUniqueItem
110
//  XATTR_LINESTART ok
111
// due to SvxUnoMarkerTable::replaceByName
112
// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
113
// due to XLineStartItem::checkForUniqueItem
114
//  XATTR_LINEEND ok
115
// due to SvxUnoNameItemTable
116
// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
117
// due to NameOrIndex::CheckNamedItem all derived from NameOrIndex
118
//  XATTR_FILLBITMAP ok
119
// due to SvxUnoNameItemTable
120
// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
121
//  XATTR_LINEDASH ok
122
// due to SvxUnoNameItemTable
123
// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
124
// due to NameOrIndex::CheckNamedItem all derived from NameOrIndex
125
//  XATTR_FILLGRADIENT ok
126
// due to SvxUnoNameItemTable
127
// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
128
//  XATTR_FILLHATCH ok
129
// due to SvxUnoNameItemTable
130
// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
131
//  XATTR_FILLFLOATTRANSPARENCE ok
132
// due to NamespaceIteratorImpl
133
//      -> needs to be evaluated
134
// due to SwCursorShell::GotoNxtPrvTOXMark
135
// due to SwDoc::GetTOIKeys
136
//  RES_TXTATR_TOXMARK ok
137
// due to SwDoc::GetRefMark
138
// due to SwDoc::CallEvent
139
// due to SwURLStateChanged::Notify
140
// due to SwHTMLWriter::CollectLinkTargets
141
// due to MSWordExportBase::CollectOutlineBookmarks
142
//  RES_TXTATR_INETFMT ok
143
// due to SwDoc::GetAllUsedDB
144
// due to lcl_FindInputField
145
// due to SwViewShell::IsAnyFieldInDoc
146
//  RES_TXTATR_FIELD ok
147
// due to SwDoc::GetAllUsedDB
148
// due to lcl_FindInputField
149
// due to SwViewShell::IsAnyFieldInDoc
150
//  RES_TXTATR_INPUTFIELD ok
151
// due to SwDoc::SetDefault
152
//  RES_PARATR_TABSTOP ok
153
// due to SwDoc::GetDocColors()
154
// due to RtfExport::OutColorTable
155
//  RES_CHRATR_COLOR ok
156
// due to SwDoc::GetDocColors()
157
//  RES_CHRATR_HIGHLIGHT ok
158
// due to SwDoc::GetDocColors()
159
//  RES_BACKGROUND ok
160
// due to SwNode::FindPageDesc
161
// due to SwPageNumberFieldType::ChangeExpansion
162
// due to SwFrame::GetVirtPageNum
163
//  RES_PAGEDESC ok
164
// due to SwAutoStylesEnumImpl::
165
//  RES_TXTATR_CJK_RUBY ok
166
// due to SwHTMLWriter::CollectLinkTargets
167
// due to MSWordExportBase::CollectOutlineBookmarks
168
//  RES_URL
169
// due to RtfExport::OutColorTable
170
//  RES_CHRATR_UNDERLINE ok
171
//  RES_CHRATR_OVERLINE ok
172
//  RES_CHRATR_BACKGROUND ok
173
//  RES_SHADOW ok
174
//  RES_BOX ok
175
//  RES_CHRATR_BOX ok
176
//  XATTR_FILLCOLOR ok
177
// due to wwFontHelper::InitFontTable
178
// due to SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl
179
//  RES_CHRATR_FONT ok
180
// due to wwFontHelper::InitFontTable
181
// due to SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl
182
//  RES_CHRATR_CJK_FONT ok
183
// due to wwFontHelper::InitFontTable
184
// due to SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl
185
//  RES_CHRATR_CTL_FONT
186
// due to SwXMLExport::exportDoc
187
//  RES_UNKNOWNATR_CONTAINER ok
188
//  RES_TXTATR_UNKNOWN_CONTAINER ok
189
190
ItemInfoUser::ItemInfoUser(const ItemInfo& rItemInfo, const SfxItemPool& rItemPool, const SfxPoolItem& rItem, bool bPassingOwnership)
191
4.94M
: ItemInfo(rItemInfo)
192
4.94M
, m_pItem(implCreateItemEntry(rItemPool, &rItem, bPassingOwnership))
193
4.94M
{
194
4.94M
}
195
196
ItemInfoUser::~ItemInfoUser()
197
4.94M
{
198
4.94M
    implCleanupItemEntry(m_pItem);
199
4.94M
}
200
201
const SlotIDToWhichIDMap& ItemInfoPackage::getSlotIDToWhichIDMap() const
202
982k
{
203
982k
    if (maSlotIDToWhichIDMap.empty())
204
102
    {
205
        // will be filled only once per office runtime
206
9.01k
        for (size_t a(0); a < size(); a++)
207
8.91k
        {
208
8.91k
            const ItemInfoStatic& rCandidate(getItemInfoStatic(a));
209
8.91k
            if (0 != rCandidate.getSlotID())
210
3.80k
            {
211
#ifdef DBG_UTIL
212
                if (maSlotIDToWhichIDMap.contains(rCandidate.getSlotID()))
213
                    assert(false && "ITEM: SlotID used double in ItemInfoPackage (!)");
214
#endif
215
3.80k
                maSlotIDToWhichIDMap[rCandidate.getSlotID()] = rCandidate.getWhich();
216
3.80k
            }
217
8.91k
        }
218
102
    }
219
220
982k
    return maSlotIDToWhichIDMap;
221
982k
}
222
223
const ItemInfo& ItemInfoPackage::getExistingItemInfo(size_t /*nIndex*/)
224
0
{
225
0
    static ItemInfoStatic EMPTY(0, nullptr, 0, 0);
226
0
    return EMPTY;
227
0
}
228
229
void SfxItemPool::registerItemInfoPackage(
230
    ItemInfoPackage& rPackage,
231
    const std::function<SfxPoolItem*(sal_uInt16)>& rCallback)
232
982k
{
233
982k
    assert(maItemInfos.empty() && "ITEM: registering more than one ItemInfoPackage per Pool is not allowed (!)");
234
235
    // we know the size :-)
236
982k
    maItemInfos.reserve(rPackage.size());
237
238
    // loop over ItemInfoPackage and add ptrs to provided ItemInfos
239
100M
    for(size_t a(0); a < rPackage.size(); a++)
240
99.6M
    {
241
        // get ItemInfo entry, maybe StaticDefault or DynamicDefault
242
99.6M
        const ItemInfo& rItemInfo(rPackage.getItemInfo(a, *this));
243
244
99.6M
        if (nullptr != rItemInfo.getItem())
245
99.6M
        {
246
            // if it has an item, use it, done
247
99.6M
            maItemInfos.push_back(&rItemInfo);
248
99.6M
            continue;
249
99.6M
        }
250
251
        // if not, use the callback to create a DynamicDefault. This
252
        // *has* to be supported then by the caller
253
0
        SfxPoolItem* pDynamicItem(rCallback(rItemInfo.getWhich()));
254
0
        assert(nullptr != pDynamicItem);
255
0
        maItemInfos.push_back(new ItemInfoDynamic(rItemInfo, pDynamicItem));
256
0
    }
257
258
    // use infos to fill local variables
259
982k
    mnStart = maItemInfos.front()->getWhich();
260
982k
    mnEnd = maItemInfos.back()->getWhich();
261
262
    // set mapper for fast SlotIDToWhichID conversion
263
982k
    mpSlotIDToWhichIDMap = &rPackage.getSlotIDToWhichIDMap();
264
265
#ifdef DBG_UTIL
266
    for (size_t a(1); a < maItemInfos.size(); a++)
267
        if (maItemInfos[a-1]->getWhich() + 1 != maItemInfos[a]->getWhich())
268
            assert(false && "ITEM: Order is wrong (!)");
269
#endif
270
982k
}
271
272
const ItemInfo* SfxItemPool::impCheckItemInfoForClone(const ItemInfo* pInfo)
273
0
{
274
0
    const SfxPoolItem* pItem(pInfo->getItem());
275
0
    assert(nullptr != pItem && "ITEM: Missing Item in ItemInfo (!)");
276
277
0
    if (pItem->isStaticDefault())
278
        // noting to do, not ref-counted
279
0
        return pInfo;
280
281
0
    if (pItem->isDynamicDefault())
282
0
    {
283
        // need to clone to new Pool as DynamicDefault, owned by the Pool
284
        // and not shared. Mainly SfxSetItems. Not RefCounted
285
0
        return new ItemInfoDynamic(*pInfo, pItem->Clone(this));
286
0
    }
287
288
    // all Items else that can be in the Pool are UserDefaults. These
289
    // are RefCounted, so use implCreateItemEntry to increase reference
290
0
    return new ItemInfoUser(*pInfo, *this, *pItem);
291
0
}
292
293
void SfxItemPool::impClearUserDefault(const userItemInfos::iterator& rHit)
294
4.49M
{
295
4.49M
    if (rHit == maUserItemInfos.end())
296
        // does not exist
297
0
        return;
298
299
    // get ItemInfo and Item, HAS to be a UserDefault
300
4.49M
    const sal_uInt16 nIndex(GetIndex_Impl(rHit->first));
301
4.49M
    const ItemInfo* pInfo(maItemInfos[nIndex]);
302
4.49M
    assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
303
304
    // restore original entry using the remembered one
305
4.49M
    maItemInfos[nIndex] = rHit->second;
306
307
    // free Item, delete ItemInfo
308
4.49M
    delete pInfo;
309
4.49M
}
310
311
void SfxItemPool::impCreateUserDefault(const SfxPoolItem& rItem)
312
4.49M
{
313
4.49M
    const sal_uInt16 nWhich(rItem.Which());
314
315
    // make sure by an assert check that none exists
316
4.49M
    assert(maUserItemInfos.end() == maUserItemInfos.find(nWhich));
317
318
4.49M
    const sal_uInt16 nIndex(GetIndex_Impl(nWhich));
319
4.49M
    const ItemInfo* pInfo(maItemInfos[nIndex]);
320
4.49M
    assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
321
322
    // safe original ItemInfo in UserItemInfos
323
4.49M
    maUserItemInfos.insert({nWhich, pInfo});
324
325
    // create new Item by using implCreateItemEntry and new ItemInfo
326
4.49M
    maItemInfos[nIndex] = new ItemInfoUser(*pInfo, *this, rItem);
327
4.49M
}
328
329
void SfxItemPool::cleanupItemInfos()
330
981k
{
331
    // reset all UserDefaultItems & restore original maItemInfos
332
5.47M
    while (!maUserItemInfos.empty())
333
4.49M
    {
334
        // get next candidate, cleanup UseDefault and remove data
335
4.49M
        userItemInfos::iterator aHit(maUserItemInfos.begin());
336
4.49M
        impClearUserDefault(aHit);
337
4.49M
        maUserItemInfos.erase(aHit);
338
4.49M
    }
339
340
    // delete DynamicDefaults in maItemInfos, these only exist
341
    // for Pool lifetime since they are Pool-dependent. There should
342
    // be NO MORE UserDefaults after cleanup above
343
981k
    for (auto& rInfo : maItemInfos)
344
99.6M
    {
345
99.6M
        if (rInfo->getItem()->isDynamicDefault())
346
1.37M
        {
347
            // the whole ItemInfo is owned by the pool, so
348
            // delete the Item and the ItemInfo (in that order :-)
349
1.37M
            delete rInfo;
350
1.37M
        }
351
#ifdef DBG_UTIL
352
        // since there should be NO MORE UserDefaults the item
353
        // then *has* to be StaticDefault - check that
354
        else if (!rInfo->getItem()->isStaticDefault())
355
            assert(false && "ITEM: Error in UserDefault handling (!)");
356
#endif
357
99.6M
    }
358
981k
}
359
360
void SfxItemPool::registerItemSet(SfxItemSet& rSet)
361
17.9M
{
362
17.9M
    registeredSfxItemSets& rTarget(GetMasterPool()->maRegisteredSfxItemSets);
363
#ifdef DBG_UTIL
364
    const size_t nBefore(rTarget.size());
365
#endif
366
17.9M
    rTarget.insert(&rSet);
367
#ifdef DBG_UTIL
368
    const size_t nAfter(rTarget.size());
369
    if (nBefore + 1 != nAfter)
370
    {
371
        SAL_WARN("svl.items", "SfxItemPool::registerItemSet: ItemSet was already registered (!)");
372
    }
373
#endif
374
17.9M
}
375
376
void SfxItemPool::unregisterItemSet(SfxItemSet& rSet)
377
17.9M
{
378
17.9M
    registeredSfxItemSets& rTarget(GetMasterPool()->maRegisteredSfxItemSets);
379
#ifdef DBG_UTIL
380
    const size_t nBefore(rTarget.size());
381
#endif
382
17.9M
    rTarget.erase(&rSet);
383
#ifdef DBG_UTIL
384
    const size_t nAfter(rTarget.size());
385
    if (nBefore != nAfter + 1)
386
    {
387
        SAL_WARN("svl.items", "SfxItemPool::unregisterItemSet: ItemSet was not registered (!)");
388
    }
389
#endif
390
17.9M
}
391
392
void SfxItemPool::registerPoolItemHolder(SfxPoolItemHolder& rHolder)
393
7.09M
{
394
7.09M
    registeredSfxPoolItemHolders& rTarget(GetMasterPool()->maRegisteredSfxPoolItemHolders);
395
#ifdef DBG_UTIL
396
    const size_t nBefore(rTarget.size());
397
#endif
398
7.09M
    rTarget.insert(&rHolder);
399
#ifdef DBG_UTIL
400
    const size_t nAfter(rTarget.size());
401
    if (nBefore + 1 != nAfter)
402
    {
403
        SAL_WARN("svl.items", "SfxItemPool::registerPoolItemHolder: SfxPoolItemHolder was already registered (!)");
404
    }
405
#endif
406
7.09M
    if (rHolder.is() && rHolder.getItem()->isNameOrIndex())
407
0
        registerNameOrIndex(*rHolder.getItem());
408
7.09M
}
409
410
void SfxItemPool::unregisterPoolItemHolder(SfxPoolItemHolder& rHolder)
411
7.09M
{
412
7.09M
    registeredSfxPoolItemHolders& rTarget(GetMasterPool()->maRegisteredSfxPoolItemHolders);
413
#ifdef DBG_UTIL
414
    const size_t nBefore(rTarget.size());
415
#endif
416
7.09M
    rTarget.erase(&rHolder);
417
#ifdef DBG_UTIL
418
    const size_t nAfter(rTarget.size());
419
    if (nBefore != nAfter + 1)
420
    {
421
        SAL_WARN("svl.items", "SfxItemPool::unregisterPoolItemHolder: SfxPoolItemHolder was not registered (!)");
422
    }
423
#endif
424
7.09M
    if (rHolder.is() && rHolder.getItem()->isNameOrIndex())
425
0
        unregisterNameOrIndex(*rHolder.getItem());
426
7.09M
}
427
428
void SfxItemPool::registerNameOrIndex(const SfxPoolItem& rItem)
429
4.02M
{
430
4.02M
    assert(rItem.isNameOrIndex() && "ITEM: only Items derived from NameOrIndex supported for this mechanism (!)");
431
4.02M
    NameOrIndexContent& rTarget(GetMasterPool()->maRegisteredNameOrIndex[rItem.ItemType()]);
432
4.02M
    NameOrIndexContent::iterator aHit(rTarget.find(&rItem));
433
4.02M
    if (aHit == rTarget.end())
434
989k
        rTarget.insert(std::pair<const SfxPoolItem*, sal_uInt32>(&rItem, 0));
435
3.03M
    else
436
3.03M
        aHit->second++;
437
4.02M
}
438
439
void SfxItemPool::unregisterNameOrIndex(const SfxPoolItem& rItem)
440
4.02M
{
441
4.02M
    assert(rItem.isNameOrIndex() && "ITEM: only Items derived from NameOrIndex supported for this mechanism (!)");
442
4.02M
    NameOrIndexContent& rTarget(GetMasterPool()->maRegisteredNameOrIndex[rItem.ItemType()]);
443
4.02M
    NameOrIndexContent::iterator aHit(rTarget.find(&rItem));
444
4.02M
    assert(aHit != rTarget.end() && "ITEM: malformed order of buffered NameOrIndex Items, entry *expected* (!)");
445
4.02M
    if (0 == aHit->second)
446
989k
        rTarget.erase(aHit);
447
3.03M
    else
448
3.03M
        aHit->second--;
449
4.02M
}
450
451
SfxItemPool* SfxItemPool::getTargetPool(sal_uInt16 nWhich) const
452
3.43G
{
453
3.43G
    if (IsInRange(nWhich))
454
2.56G
        return const_cast<SfxItemPool*>(this);
455
867M
    if (mpSecondary)
456
867M
        return mpSecondary->getTargetPool(nWhich);
457
15.7k
    return nullptr;
458
867M
}
459
460
bool SfxItemPool::CheckItemInfoFlag(sal_uInt16 nWhich, sal_uInt16 nMask) const
461
1.63G
{
462
1.63G
    SfxItemPool* pTarget(getTargetPool(nWhich));
463
1.63G
    if (nullptr == pTarget)
464
15.7k
        return false;
465
466
1.63G
    if (!pTarget->maItemInfos.empty())
467
1.63G
    {
468
1.63G
        const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
469
1.63G
        const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
470
1.63G
        assert(nullptr != pInfo);
471
1.63G
        return pInfo->getItemInfoFlags() & nMask;
472
1.63G
    }
473
474
0
    return pTarget->CheckItemInfoFlag_Impl(pTarget->GetIndex_Impl(nWhich), nMask);
475
1.63G
}
476
477
SfxBroadcaster& SfxItemPool::BC()
478
0
{
479
0
    return aBC;
480
0
}
481
482
/**
483
 * This is the regular ctor to be used for this class.
484
 * An SfxItemPool instance is initialized, which can manage Items in the
485
 * range from 'nStartWhich' to 'nEndWhich'.
486
 *
487
 * For every one of these WhichIds a static Default must be present in the
488
 * 'pDefaults' array. They start with an SfxPoolItem (with the WhichId
489
 * 'nStartWhich'), are sorted by WhichId and consecutively stored.
490
 *
491
 * 'pItemInfos' is a USHORT array arranged in the same way, which holds
492
 *  SlotIds and Flags. These SlotIds can be 0, if the affected Items are
493
 *  exclusively used in the Core.
494
 *  The flags allow for e.g. enabling value sharing (poolable).
495
 *
496
 *  If the Pool is supposed to hold SfxSetItems, the ctor cannot yet contain
497
 *  static Defaults. This needs to be done afterwards, using
498
 *  @see SfxItemPool::SetPoolDefaults(std::vector<SfxPoolItem*>*).
499
 *
500
 *  @see SfxItemPool::SetPoolDefaults(std::vector<SfxPoolItem*>*)
501
 *  @see SfxItemPool::ReleasePoolDefaults(std::vector<SfxPoolItem*>*,bool)
502
 *  @see SfxItemPool::ReleasePoolDefaults(bool)
503
 */
504
SfxItemPool::SfxItemPool(const OUString& rName) /* Pool name to identify in the file format */
505
982k
: salhelper::SimpleReferenceObject()
506
982k
, aBC()
507
982k
, aName(rName)
508
982k
, mpMaster(this)
509
982k
, mpSecondary()
510
982k
, mnStart(0)
511
982k
, mnEnd(0)
512
982k
, eDefMetric(MapUnit::MapCM)
513
982k
, maRegisteredSfxItemSets()
514
982k
, maRegisteredSfxPoolItemHolders()
515
982k
, maRegisteredNameOrIndex()
516
982k
, mbShutdownHintSent(false)
517
982k
, maItemInfos()
518
982k
, maUserItemInfos()
519
982k
, mpSlotIDToWhichIDMap(nullptr)
520
982k
{
521
982k
    eDefMetric = MapUnit::MapTwip;
522
982k
}
523
524
/**
525
 * Copy ctor
526
 *
527
 * @see SfxItemPool::Clone() const
528
*/
529
SfxItemPool::SfxItemPool(const SfxItemPool& rPool) //  Copy from this instance
530
0
: salhelper::SimpleReferenceObject()
531
0
, aBC()
532
0
, aName(rPool.aName)
533
0
, mpMaster(this)
534
0
, mpSecondary()
535
0
, maPoolRanges()
536
0
, mnStart(rPool.mnStart)
537
0
, mnEnd(rPool.mnEnd)
538
0
, eDefMetric(MapUnit::MapCM)
539
0
, maRegisteredSfxItemSets()
540
0
, maRegisteredSfxPoolItemHolders()
541
0
, maRegisteredNameOrIndex()
542
0
, mbShutdownHintSent(false)
543
0
, maItemInfos(rPool.maItemInfos)
544
0
, maUserItemInfos(rPool.maUserItemInfos)
545
0
, mpSlotIDToWhichIDMap(rPool.mpSlotIDToWhichIDMap)
546
0
{
547
    // DynamicDefaults and UserDefaults need to be cloned for the new Pool
548
0
    for (itemInfoVector::iterator aInfo(maItemInfos.begin()); aInfo != maItemInfos.end(); aInfo++)
549
0
        *aInfo = impCheckItemInfoForClone(*aInfo);
550
551
    // DynamicDefaults need to be cloned for the new Pool (no UserDefaults in UserItemInfos)
552
0
    for (auto& rUserItem : maUserItemInfos)
553
0
        rUserItem.second = impCheckItemInfoForClone(rUserItem.second);
554
555
0
    eDefMetric = rPool.eDefMetric;
556
557
    // Repair linkage
558
0
    if ( rPool.mpSecondary )
559
0
        SetSecondaryPool( rPool.mpSecondary->Clone().get() );
560
0
}
561
562
SfxItemPool::~SfxItemPool()
563
981k
{
564
    // cleanup UserDefaults & delete owned DynamicDefaults
565
981k
    cleanupItemInfos();
566
567
    // Need to send ShutdownHint?
568
981k
    sendShutdownHint();
569
570
981k
    if (mpMaster != nullptr && mpMaster != this)
571
0
    {
572
        // This condition indicates an error.
573
        // A mpMaster->SetSecondaryPool(...) call should have been made
574
        // earlier to prevent this. At this point we can only try to
575
        // prevent a crash later on.
576
0
        DBG_ASSERT( mpMaster == this, "destroying active Secondary-Pool" );
577
0
        if (mpMaster->mpSecondary == this)
578
0
            mpMaster->mpSecondary = nullptr;
579
0
    }
580
981k
}
581
582
void SfxItemPool::SetSecondaryPool( SfxItemPool *pPool )
583
1.28M
{
584
    // Reset Master in attached Pools
585
1.28M
    if ( mpSecondary )
586
268k
    {
587
268k
        mpSecondary->mpMaster = mpSecondary.get();
588
365k
        for ( SfxItemPool *p = mpSecondary->mpSecondary.get(); p; p = p->mpSecondary.get() )
589
96.6k
            p->mpMaster = mpSecondary.get();
590
268k
    }
591
592
    // Set Master of new Secondary Pools
593
1.28M
    DBG_ASSERT( !pPool || pPool->mpMaster == pPool, "Secondary is present in two Pools" );
594
1.28M
    SfxItemPool *pNewMaster = GetMasterPool() ? mpMaster : this;
595
1.57M
    for ( SfxItemPool *p = pPool; p; p = p->mpSecondary.get() )
596
288k
        p->mpMaster = pNewMaster;
597
598
    // Remember new Secondary Pool
599
1.28M
    mpSecondary = pPool;
600
1.28M
}
601
602
MapUnit SfxItemPool::GetMetric( sal_uInt16 ) const
603
26.8M
{
604
26.8M
    return eDefMetric;
605
26.8M
}
606
607
void SfxItemPool::SetDefaultMetric( MapUnit eNewMetric )
608
383k
{
609
//    assert((pImpl->eDefMetric == eNewMetric || !pImpl->maPoolRanges) && "pool already frozen, cannot change metric");
610
383k
    eDefMetric = eNewMetric;
611
383k
}
612
613
bool SfxItemPool::GetPresentation
614
(
615
    const SfxPoolItem&  rItem,
616
    MapUnit             eMetric,
617
    OUString&           rText,
618
    const IntlWrapper&  rIntlWrapper
619
)   const
620
0
{
621
0
    return rItem.GetPresentation(
622
0
        SfxItemPresentation::Complete, GetMetric(rItem.Which()), eMetric, rText, rIntlWrapper );
623
0
}
624
625
rtl::Reference<SfxItemPool> SfxItemPool::Clone() const
626
0
{
627
0
    return new SfxItemPool( *this );
628
0
}
629
630
void SfxItemPool::sendShutdownHint()
631
1.39M
{
632
    // Already sent?
633
1.39M
    if (mbShutdownHintSent)
634
415k
        return;
635
636
981k
    mbShutdownHintSent = true;
637
638
    // Inform e.g. running Requests
639
981k
    aBC.Broadcast( SfxHint( SfxHintId::Dying ) );
640
981k
    maPoolRanges.reset();
641
981k
}
642
643
void SfxItemPool::SetUserDefaultItem(const SfxPoolItem& rItem)
644
6.45M
{
645
6.45M
    SfxItemPool* pTarget(getTargetPool(rItem.Which()));
646
6.45M
    if (nullptr == pTarget)
647
6.45M
        assert(false && "unknown WhichId - cannot set pool default");
648
649
6.45M
    const sal_uInt16 nWhich(rItem.Which());
650
6.45M
    userItemInfos::iterator aHit(pTarget->maUserItemInfos.find(nWhich));
651
652
6.45M
    if (aHit == pTarget->maUserItemInfos.end())
653
4.49M
    {
654
        // UserDefault does not exist, create needed entries to safe
655
        // original ItemInfo in UserItemInfos and set new, owned
656
        // ItemInfo containing an owned clone of the Item in ItemInfos
657
4.49M
        pTarget->impCreateUserDefault(rItem);
658
4.49M
        return;
659
4.49M
    }
660
661
    // UserDefault does exist, check and evtl. replace
662
1.95M
    const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
663
1.95M
    const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
664
1.95M
    assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
665
1.95M
    const SfxPoolItem* pItem(pInfo->getItem());
666
1.95M
    assert(nullptr != pItem && "ITEM: access error to Defaults in Pool (!)");
667
668
    // nothing to do if equal, so check
669
1.95M
    if (SfxPoolItem::areSame(pItem, &rItem))
670
1.50M
        return;
671
672
    // need to exchange existing instance and free current one
673
447k
    pTarget->maItemInfos[nIndex] = new ItemInfoUser(*pInfo, *pTarget, rItem);
674
447k
    delete pInfo;
675
447k
}
676
677
const SfxPoolItem* SfxItemPool::GetUserDefaultItem( sal_uInt16 nWhich ) const
678
5.50M
{
679
5.50M
    SfxItemPool* pTarget(getTargetPool(nWhich));
680
5.50M
    if (nullptr == pTarget)
681
0
    {
682
0
        assert(false && "unknown WhichId - cannot get pool default");
683
0
        return nullptr;
684
0
    }
685
686
5.50M
    userItemInfos::iterator aHit(pTarget->maUserItemInfos.find(nWhich));
687
688
5.50M
    if (aHit == pTarget->maUserItemInfos.end())
689
        // no default item
690
5.34M
        return nullptr;
691
692
166k
    const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
693
166k
    const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
694
166k
    assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
695
166k
    const SfxPoolItem* pItem(pInfo->getItem());
696
166k
    assert(nullptr != pItem && "ITEM: access error to Defaults in Pool (!)");
697
166k
    return pItem;
698
5.50M
}
699
700
/**
701
 * Resets the default of the given WhichId back to the static Default.
702
 * If a pool default exists, it is removed.
703
 */
704
void SfxItemPool::ResetUserDefaultItem( sal_uInt16 nWhich )
705
0
{
706
0
    SfxItemPool* pTarget(getTargetPool(nWhich));
707
0
    if (nullptr == pTarget)
708
0
        assert(false && "unknown WhichId - cannot reset pool default");
709
710
0
    userItemInfos::iterator aHit(pTarget->maUserItemInfos.find(nWhich));
711
712
0
    if (aHit != pTarget->maUserItemInfos.end())
713
0
    {
714
        // clear entry, cleanup, restore previous data
715
0
        pTarget->impClearUserDefault(aHit);
716
717
        // remove remembered data
718
0
        pTarget->maUserItemInfos.erase(aHit);
719
0
    }
720
0
}
721
722
const SfxPoolItem& SfxItemPool::GetUserOrPoolDefaultItem( sal_uInt16 nWhich ) const
723
917M
{
724
917M
    SfxItemPool* pTarget(getTargetPool(nWhich));
725
917M
    if (nullptr == pTarget)
726
917M
        assert(!"unknown which - don't ask me for defaults");
727
728
917M
    const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
729
917M
    const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
730
917M
    assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
731
917M
    const SfxPoolItem* pItem(pInfo->getItem());
732
917M
    assert(nullptr != pItem && "ITEM: access error to Defaults in Pool (!)");
733
917M
    return *pItem;
734
917M
}
735
736
/* get the last pool by following the GetSecondaryPool chain */
737
SfxItemPool* SfxItemPool::GetLastPoolInChain()
738
77.0k
{
739
77.0k
    SfxItemPool* pLast(this);
740
741
77.0k
    while(pLast->GetSecondaryPool())
742
0
        pLast = pLast->GetSecondaryPool();
743
744
77.0k
    return pLast;
745
77.0k
}
746
747
const WhichRangesContainer& SfxItemPool::GetMergedIdRanges() const
748
3.73M
{
749
3.73M
    if (maPoolRanges.empty())
750
169k
    {
751
        // Merge all ranges, keeping them sorted
752
585k
        for (const SfxItemPool* pPool = this; pPool; pPool = pPool->mpSecondary.get())
753
415k
            maPoolRanges = maPoolRanges.MergeRange(pPool->mnStart, pPool->mnEnd);
754
169k
    }
755
756
3.73M
    return maPoolRanges;
757
3.73M
}
758
759
const SfxPoolItem* SfxItemPool::GetPoolDefaultItem(sal_uInt16 nWhich) const
760
4.11M
{
761
4.11M
    SfxItemPool* pTarget(getTargetPool(nWhich));
762
4.11M
    if (nullptr == pTarget)
763
4.11M
        assert(false && "unknown WhichId - cannot resolve surrogate");
764
765
4.11M
    const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
766
4.11M
    userItemInfos::iterator aHit(pTarget->maUserItemInfos.find(nWhich));
767
768
4.11M
    if (aHit != pTarget->maUserItemInfos.end())
769
0
    {
770
        // If it is a UserDefault Item, check saved ItemInfo and use
771
        // Item from there
772
0
        assert(aHit != pTarget->maUserItemInfos.end() && "ITEM: Error in UserDefault handling (!)");
773
0
        return aHit->second->getItem();
774
0
    }
775
776
4.11M
    const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
777
4.11M
    assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
778
4.11M
    const SfxPoolItem* pItem(pInfo->getItem());
779
4.11M
    assert(nullptr != pItem && "ITEM: access error to Defaults in Pool (!)");
780
4.11M
    return pItem;
781
4.11M
}
782
783
namespace
784
{
785
    class SurrogateData_ItemSet : public SfxItemPool::SurrogateData
786
    {
787
        const SfxPoolItem*  mpItem;
788
        SfxItemSet*         mpSet;
789
790
    public:
791
        SurrogateData_ItemSet(const SfxPoolItem& rItem, SfxItemSet& rSet)
792
3.50k
        : SfxItemPool::SurrogateData()
793
3.50k
        , mpItem(&rItem)
794
3.50k
        , mpSet(&rSet)
795
3.50k
        {
796
3.50k
        }
797
798
2.12k
        SurrogateData_ItemSet(const SurrogateData_ItemSet&) = default;
799
800
        virtual const SfxPoolItem& getItem() const override
801
2.14k
        {
802
2.14k
            return *mpItem;
803
2.14k
        }
804
805
        virtual const SfxPoolItem* setItem(std::unique_ptr<SfxPoolItem> aNew) override
806
1.56k
        {
807
1.56k
            return mpSet->Put(std::unique_ptr<SfxPoolItem>(aNew.release()));
808
1.56k
        }
809
    };
810
811
    class SurrogateData_ItemHolder : public SfxItemPool::SurrogateData
812
    {
813
        SfxPoolItemHolder*  mpHolder;
814
815
    public:
816
        SurrogateData_ItemHolder(SfxPoolItemHolder& rHolder)
817
0
        : SfxItemPool::SurrogateData()
818
0
        , mpHolder(&rHolder)
819
0
        {
820
0
        }
821
822
0
        SurrogateData_ItemHolder(const SurrogateData_ItemHolder&) = default;
823
824
        virtual const SfxPoolItem& getItem() const override
825
0
        {
826
0
            return *mpHolder->getItem();
827
0
        }
828
829
        virtual const SfxPoolItem* setItem(std::unique_ptr<SfxPoolItem> aNew) override
830
0
        {
831
0
            *mpHolder = SfxPoolItemHolder(mpHolder->getPool(), aNew.release(), true);
832
0
            return mpHolder->getItem();
833
0
        }
834
    };
835
}
836
837
void SfxItemPool::iterateItemSurrogates(
838
    sal_uInt16 nWhich,
839
    const std::function<bool(SurrogateData& rCand)>& rItemCallback) const
840
1.56k
{
841
    // 1st source for surrogates
842
1.56k
    const registeredSfxItemSets& rSets(GetMasterPool()->maRegisteredSfxItemSets);
843
844
1.56k
    if(!rSets.empty())
845
1.56k
    {
846
1.56k
        const SfxPoolItem* pItem(nullptr);
847
1.56k
        std::vector<SurrogateData_ItemSet> aEntries;
848
849
        // NOTE: this collects the callback data in a preparing run. This
850
        //   is by purpose, else any write change may change the iterators
851
        //   used at registeredSfxItemSets. I tied with direct feed and
852
        //   that worked most of the time, but failed for ItemHolders due
853
        //   to these being changed and being re-registered. I have avoided
854
        //   this in SfxPoolItemHolder::operator=, but it's just a question
855
        //   that in some scenario someone replaces an Item even with a
856
        //   different type/WhichID that this will then break/crash
857
1.56k
        for (const auto& rCand : rSets)
858
50.7k
            if (SfxItemState::SET == rCand->GetItemState(nWhich, false, &pItem))
859
3.50k
                aEntries.emplace_back(*pItem, *rCand);
860
861
1.56k
        if (!aEntries.empty())
862
1.56k
            for (auto& rCand : aEntries)
863
2.14k
                if (!rItemCallback(rCand))
864
1.56k
                    return;
865
1.56k
    }
866
867
    // 2nd source for surrogates
868
0
    const registeredSfxPoolItemHolders& rHolders(GetMasterPool()->maRegisteredSfxPoolItemHolders);
869
870
0
    if (!rHolders.empty())
871
0
    {
872
0
        std::vector<SurrogateData_ItemHolder> aEntries;
873
874
        // NOTE: same as above, look there
875
0
        for (auto& rCand : rHolders)
876
0
            if (rCand->Which() == nWhich && nullptr != rCand->getItem())
877
0
                aEntries.emplace_back(*rCand);
878
879
0
        if (!aEntries.empty())
880
0
            for (auto& rCand : aEntries)
881
0
                if (!rItemCallback(rCand))
882
0
                    return;
883
0
    }
884
0
}
885
886
ItemSurrogates SfxItemPool::GetItemSurrogatesForItem(SfxItemType eItemType) const
887
264k
{
888
264k
    ItemSurrogates aTarget;
889
264k
    const registeredNameOrIndex& rRegistered(GetMasterPool()->maRegisteredNameOrIndex);
890
264k
    registeredNameOrIndex::const_iterator aHit(rRegistered.find(eItemType));
891
264k
    if (aHit != rRegistered.end())
892
215k
    {
893
215k
        aTarget.reserve(aHit->second.size());
894
215k
        for (const auto& entry : aHit->second)
895
897k
            aTarget.push_back(entry.first);
896
215k
    }
897
264k
    return aTarget;
898
264k
}
899
900
ItemSurrogates SfxItemPool::GetItemSurrogatesForItem(const SfxPoolItem& rItem) const
901
128k
{
902
128k
    assert(rItem.isNameOrIndex() && "ITEM: only Items derived from NameOrIndex supported for this mechanism (!)");
903
128k
    return GetItemSurrogatesForItem(rItem.ItemType());
904
128k
}
905
906
ItemSurrogates SfxItemPool::GetItemSurrogates(sal_uInt16 nWhich) const
907
1.94k
{
908
1.94k
    if (0 == nWhich)
909
0
        return {};
910
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
1.94k
    std::unordered_set<const SfxPoolItem*> aNewSurrogates;
917
918
    // 1st source for surrogates
919
1.94k
    const registeredSfxItemSets& rSets(GetMasterPool()->maRegisteredSfxItemSets);
920
1.94k
    const SfxPoolItem* pItem(nullptr);
921
1.94k
    for (const auto& rCand : rSets)
922
48.9k
        if (SfxItemState::SET == rCand->GetItemState(nWhich, false, &pItem))
923
8.12k
            aNewSurrogates.insert(pItem);
924
925
    // 2nd source for surrogates
926
1.94k
    const registeredSfxPoolItemHolders& rHolders(GetMasterPool()->maRegisteredSfxPoolItemHolders);
927
1.94k
    for (const auto& rCand : rHolders)
928
21.9k
        if (rCand->Which() == nWhich && nullptr != rCand->getItem())
929
0
            aNewSurrogates.insert(rCand->getItem());
930
931
1.94k
    return ItemSurrogates(aNewSurrogates.begin(), aNewSurrogates.end());
932
1.94k
}
933
934
sal_uInt16 SfxItemPool::GetWhichIDFromSlotID(sal_uInt16 nSlotId, bool bDeep) const
935
351M
{
936
351M
    if (!IsSlot(nSlotId))
937
147M
        return nSlotId;
938
939
204M
    if (nullptr != mpSlotIDToWhichIDMap)
940
204M
    {
941
        // use the static global translation table -> near linear access time
942
204M
        SlotIDToWhichIDMap::const_iterator aHit(mpSlotIDToWhichIDMap->find(nSlotId));
943
204M
        if (aHit != mpSlotIDToWhichIDMap->end())
944
1.14M
            return aHit->second;
945
204M
    }
946
947
202M
    if (mpSecondary && bDeep)
948
12.3M
        return mpSecondary->GetWhichIDFromSlotID(nSlotId);
949
950
190M
    return nSlotId;
951
202M
}
952
953
954
sal_uInt16 SfxItemPool::GetSlotId(sal_uInt16 nWhich) const
955
1.98M
{
956
1.98M
    if (!IsWhich(nWhich))
957
0
        return nWhich;
958
959
1.98M
    SfxItemPool* pTarget(getTargetPool(nWhich));
960
1.98M
    if (nullptr == pTarget)
961
1.98M
        assert(false && "unknown WhichId - cannot get slot-id");
962
963
1.98M
    const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
964
1.98M
    const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
965
1.98M
    assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
966
1.98M
    const sal_uInt16 nSID(pInfo->getSlotID());
967
1.98M
    return (0 != nSID) ? nSID : nWhich;
968
1.98M
}
969
970
971
sal_uInt16 SfxItemPool::GetTrueWhichIDFromSlotID( sal_uInt16 nSlotId, bool bDeep ) const
972
2.20M
{
973
2.20M
    if (!IsSlot(nSlotId))
974
0
        return 0;
975
976
2.20M
    if (nullptr != mpSlotIDToWhichIDMap)
977
2.20M
    {
978
        // use the static global translation table -> near linear access time
979
2.20M
        SlotIDToWhichIDMap::const_iterator aHit(mpSlotIDToWhichIDMap->find(nSlotId));
980
2.20M
        if (aHit != mpSlotIDToWhichIDMap->end())
981
1.98M
            return aHit->second;
982
2.20M
    }
983
984
229k
    if (mpSecondary && bDeep)
985
0
        return mpSecondary->GetTrueWhichIDFromSlotID(nSlotId);
986
987
229k
    return 0;
988
229k
}
989
990
991
sal_uInt16 SfxItemPool::GetTrueSlotId( sal_uInt16 nWhich ) const
992
986k
{
993
986k
    if (!IsWhich(nWhich))
994
0
        return 0;
995
996
986k
    SfxItemPool* pTarget(getTargetPool(nWhich));
997
986k
    if (nullptr == pTarget)
998
986k
        assert(false && "unknown WhichId - cannot get slot-id");
999
1000
986k
    const sal_uInt16 nIndex(pTarget->GetIndex_Impl(nWhich));
1001
986k
    const ItemInfo* pInfo(pTarget->maItemInfos[nIndex]);
1002
    assert(nullptr != pInfo && "ITEM: access error to Defaults in Pool (!)");
1003
986k
    return pInfo->getSlotID();
1004
986k
}
1005
1006
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */