LibreOffice Module svl (master) 1
itempool.cxx
Go to the documentation of this file.
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>
29#include <svl/hint.hxx>
30#include <svl/itemset.hxx>
31
32#include <poolio.hxx>
33
34#include <cassert>
35#include <vector>
36
37
38#if OSL_DEBUG_LEVEL > 0
39#include <map>
40
41static void
42lcl_CheckSlots2(std::map<sal_uInt16, sal_uInt16> & rSlotMap,
43 SfxItemPool const& rPool, SfxItemInfo const* pInfo)
44{
45 if (!pInfo)
46 return; // may not be initialized yet
47 if (rPool.GetName() == "EditEngineItemPool")
48 return; // HACK: this one has loads of duplicates already, ignore it :(
49 sal_uInt16 const nFirst(rPool.GetFirstWhich());
50 sal_uInt16 const nCount(rPool.GetLastWhich() - rPool.GetFirstWhich() + 1);
51 for (sal_uInt16 n = 0; n < nCount; ++n)
52 {
53 sal_uInt16 const nSlotId(pInfo[n]._nSID);
54 if (nSlotId != 0
55 && nSlotId != 10883 // preexisting duplicate SID_ATTR_GRAF_CROP
56 && nSlotId != 10023 // preexisting duplicate SID_ATTR_BORDER_INNER
57 && nSlotId != 10024 // preexisting duplicate SID_ATTR_BORDER_OUTER
58 && nSlotId != 11013 // preexisting duplicate SID_ATTR_BORDER_DIAG_TLBR
59 && nSlotId != 11014) // preexisting duplicate SID_ATTR_BORDER_DIAG_BLTR
60 { // check for duplicate slot-id mapping
61 std::map<sal_uInt16, sal_uInt16>::const_iterator const iter(
62 rSlotMap.find(nSlotId));
63 sal_uInt16 const nWhich(nFirst + n);
64 if (iter != rSlotMap.end())
65 {
66 SAL_WARN("svl", "SfxItemPool: duplicate SlotId " << nSlotId
67 << " mapped to " << iter->second << " and " << nWhich);
68 assert(false);
69 }
70 rSlotMap.insert(std::make_pair(nSlotId, nWhich));
71 }
72 }
73}
74
75#define CHECK_SLOTS() \
76do { \
77 std::map<sal_uInt16, sal_uInt16> slotmap; \
78 for (SfxItemPool * p = pImpl->mpMaster; p; p = p->pImpl->mpSecondary.get()) \
79 { \
80 lcl_CheckSlots2(slotmap, *p, p->pItemInfos); \
81 } \
82} while (false)
83
84#else
85#define CHECK_SLOTS() do {} while (false)
86#endif
87
92{
94 maSortablePoolItems.clear();
95}
96
98{
99 return pImpl->mnStart;
100}
101
103{
104 return pImpl->mnEnd;
105}
106
107bool SfxItemPool::IsInRange( sal_uInt16 nWhich ) const
108{
109 return nWhich >= pImpl->mnStart && nWhich <= pImpl->mnEnd;
110}
111
112sal_uInt16 SfxItemPool::GetIndex_Impl(sal_uInt16 nWhich) const
113{
114 if (nWhich < pImpl->mnStart || nWhich > pImpl->mnEnd)
115 {
116 assert(false && "missing bounds check before use");
117 return 0;
118 }
119 return nWhich - pImpl->mnStart;
120}
121
123{
124 return pImpl->mnEnd - pImpl->mnStart + 1;
125}
126
127
129{
130 DBG_ASSERT( pItem, "no 0-Pointer Surrogate" );
131 DBG_ASSERT( !IsInvalidItem(pItem), "no Invalid-Item Surrogate" );
132 DBG_ASSERT( !IsPoolDefaultItem(pItem), "no Pool-Default-Item Surrogate" );
133
134 if ( !IsInRange(pItem->Which()) )
135 {
136 if ( pImpl->mpSecondary )
137 return pImpl->mpSecondary->CheckItemInPool( pItem );
138 SAL_WARN( "svl.items", "unknown Which-Id - don't ask me for surrogates, with ID/pos " << pItem->Which());
139 }
140
141 // Pointer on static or pool-default attribute?
142 if( IsStaticDefaultItem(pItem) || IsPoolDefaultItem(pItem) )
143 return true;
144
145 SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(pItem->Which())];
146
147 for ( auto p : rItemArr )
148 {
149 if ( p == pItem )
150 return true;
151 }
152 SAL_WARN( "svl.items", "Item not in the pool, with ID/pos " << pItem->Which());
153 return false;
154}
155
156const SfxPoolItem* SfxItemPool::GetPoolDefaultItem( sal_uInt16 nWhich ) const
157{
158 const SfxPoolItem* pRet;
159 if( IsInRange( nWhich ) )
160 pRet = pImpl->maPoolDefaults[GetIndex_Impl(nWhich)];
161 else if( pImpl->mpSecondary )
162 pRet = pImpl->mpSecondary->GetPoolDefaultItem( nWhich );
163 else
164 {
165 assert(false && "unknown WhichId - cannot get pool default");
166 pRet = nullptr;
167 }
168 return pRet;
169}
170
171
172bool SfxItemPool::IsItemPoolable_Impl( sal_uInt16 nPos ) const
173{
174 return pItemInfos[nPos]._bPoolable;
175}
176
177
178bool SfxItemPool::IsItemPoolable( sal_uInt16 nWhich ) const
179{
180 for ( const SfxItemPool *pPool = this; pPool; pPool = pPool->pImpl->mpSecondary.get() )
181 {
182 if ( pPool->IsInRange(nWhich) )
183 return pPool->IsItemPoolable_Impl( pPool->GetIndex_Impl(nWhich));
184 }
185 DBG_ASSERT( !IsWhich(nWhich), "unknown which-id" );
186 return false;
187}
188
189
191{
192 return pImpl->aBC;
193}
194
195
219(
220 const OUString& rName, /* Pool name to identify in the file format */
221 sal_uInt16 nStartWhich, /* First WhichId of the Pool (must be > 0) */
222 sal_uInt16 nEndWhich, /* Last WhichId of the Pool */
223 const SfxItemInfo* pInfo, /* SID Map and Item flags */
224 std::vector<SfxPoolItem*>*
225 pDefaults /* Pointer to static Defaults;
226 is directly referenced by the Pool,
227 but no transfer of ownership */
228) :
229 pItemInfos(pInfo),
230 pImpl( new SfxItemPool_Impl( this, rName, nStartWhich, nEndWhich ) )
231{
232 pImpl->eDefMetric = MapUnit::MapTwip;
233
234 if ( pDefaults )
235 SetDefaults(pDefaults);
236
237#ifdef DBG_UTIL
238 if (pItemInfos)
239 {
240 auto p = pItemInfos;
241 auto nWhich = nStartWhich;
242 while (nWhich <= nEndWhich)
243 {
244 if (p->_nSID == nWhich)
245 {
246 SAL_WARN("svl.items", "No point mapping a SID to itself, just put a 0 here in the SfxItemInfo array, at index " << (p - pItemInfos));
247 assert(false);
248 }
249 ++p;
250 ++nWhich;
251 }
252 }
253#endif
254}
255
256
263(
264 const SfxItemPool& rPool, // Copy from this instance
265 bool bCloneStaticDefaults /* true
266 Copy static Defaults
267
268 false
269 Take over static Defaults */
270) :
271 salhelper::SimpleReferenceObject(),
272 pItemInfos(rPool.pItemInfos),
273 pImpl( new SfxItemPool_Impl( this, rPool.pImpl->aName, rPool.pImpl->mnStart, rPool.pImpl->mnEnd ) )
274{
275 pImpl->eDefMetric = rPool.pImpl->eDefMetric;
276
277 // Take over static Defaults
278 if ( bCloneStaticDefaults )
279 {
280 std::vector<SfxPoolItem *>* ppDefaults = new std::vector<SfxPoolItem*>(pImpl->mnEnd-pImpl->mnStart+1);
281 for ( sal_uInt16 n = 0; n <= pImpl->mnEnd - pImpl->mnStart; ++n )
282 {
283 (*ppDefaults)[n] = (*rPool.pImpl->mpStaticDefaults)[n]->Clone(this);
284 (*ppDefaults)[n]->SetKind(SfxItemKind::StaticDefault);
285 }
286
287 SetDefaults( ppDefaults );
288 }
289 else
290 SetDefaults( rPool.pImpl->mpStaticDefaults );
291
292 // Copy Pool Defaults
293 for (size_t n = 0; n < pImpl->maPoolDefaults.size(); ++n )
294 if (rPool.pImpl->maPoolDefaults[n])
295 {
296 pImpl->maPoolDefaults[n] = rPool.pImpl->maPoolDefaults[n]->Clone(this); //resets kind
297 pImpl->maPoolDefaults[n]->SetKind(SfxItemKind::PoolDefault);
298 }
299
300 // Repair linkage
301 if ( rPool.pImpl->mpSecondary )
302 SetSecondaryPool( rPool.pImpl->mpSecondary->Clone().get() );
303}
304
305void SfxItemPool::SetDefaults( std::vector<SfxPoolItem*>* pDefaults )
306{
307 DBG_ASSERT( pDefaults, "first we ask for it, and then we don't give back..." );
308 DBG_ASSERT( !pImpl->mpStaticDefaults, "already have Defaults" );
309
310 pImpl->mpStaticDefaults = pDefaults;
313 {
314 DBG_ASSERT( (*pImpl->mpStaticDefaults)[0]->GetRefCount() == 0 ||
315 IsDefaultItem( (*pImpl->mpStaticDefaults)[0] ),
316 "these are not static" );
317 for ( sal_uInt16 n = 0; n <= pImpl->mnEnd - pImpl->mnStart; ++n )
318 {
319 assert( ((*pImpl->mpStaticDefaults)[n]->Which() == n + pImpl->mnStart)
320 && "items ids in pool-ranges and in static-defaults do not match" );
321 (*pImpl->mpStaticDefaults)[n]->SetKind(SfxItemKind::StaticDefault);
322 DBG_ASSERT( pImpl->maPoolItemArrays[n].empty(), "defaults with setitems with items?!" );
323 }
324 }
325}
326
328{
329 pImpl->mpStaticDefaults = nullptr;
330}
331
340(
341 bool bDelete /* true
342 Deletes the array as well as the single static Defaults
343
344 false
345 Neither deletes the array not the single static Defaults */
346)
347
348
349{
350 DBG_ASSERT( pImpl->mpStaticDefaults, "requirements not met" );
351 ReleaseDefaults( pImpl->mpStaticDefaults, bDelete );
352
353 // mpStaticDefaults points to deleted memory if bDelete == true.
354 if ( bDelete )
355 pImpl->mpStaticDefaults = nullptr;
356}
357
358
367(
368 std::vector<SfxPoolItem*>*
369 pDefaults, /* Static Defaults that are to be freed */
370
371 bool bDelete /* true
372 Deletes the array as well as the specified
373 static Defaults
374
375 false
376 Neither deletes the array nor the single
377 static Defaults */
378)
379{
380 DBG_ASSERT( pDefaults, "we first ask for it and the return nothing ..." );
381
382 for ( auto & rpItem : *pDefaults )
383 {
384 assert(IsStaticDefaultItem(rpItem));
385 rpItem->SetRefCount(0);
386 if ( bDelete )
387 {
388 delete rpItem;
389 rpItem = nullptr;
390 }
391 }
392
393 if ( bDelete )
394 {
395 delete pDefaults;
396 pDefaults = nullptr;
397 }
398}
399
400
402{
403 if ( !pImpl->maPoolItemArrays.empty() && !pImpl->maPoolDefaults.empty() )
404 Delete();
405
406 if (pImpl->mpMaster != nullptr && pImpl->mpMaster != this)
407 {
408 // This condition indicates an error.
409 // A pImpl->mpMaster->SetSecondaryPool(...) call should have been made
410 // earlier to prevent this. At this point we can only try to
411 // prevent a crash later on.
412 DBG_ASSERT( pImpl->mpMaster == this, "destroying active Secondary-Pool" );
413 if (pImpl->mpMaster->pImpl->mpSecondary == this)
414 pImpl->mpMaster->pImpl->mpSecondary = nullptr;
415 }
416}
417
419{
420 // Reset Master in attached Pools
421 if ( pImpl->mpSecondary )
422 {
423#ifdef DBG_UTIL
424 if (pImpl->mpStaticDefaults != nullptr && !pImpl->maPoolItemArrays.empty()
425 && !pImpl->mpSecondary->pImpl->maPoolItemArrays.empty())
426 // Delete() did not yet run?
427 {
428 // Does the Master have SetItems?
429 bool bHasSetItems = false;
430 for ( sal_uInt16 i = 0; !bHasSetItems && i < pImpl->mnEnd - pImpl->mnStart; ++i )
431 bHasSetItems = dynamic_cast<const SfxSetItem *>((*pImpl->mpStaticDefaults)[i]) != nullptr;
432
433 // Detached Pools must be empty
434 bool bOK = bHasSetItems;
435 for (auto const& rSecArray : pImpl->mpSecondary->pImpl->maPoolItemArrays)
436 {
437 if (!bOK)
438 break;
439 if (rSecArray.size()>0)
440 {
441 SAL_WARN("svl.items", "old secondary pool: " << pImpl->mpSecondary->pImpl->aName
442 << " of pool: " << pImpl->aName << " must be empty.");
443 break;
444 }
445 }
446 }
447#endif
448
449 pImpl->mpSecondary->pImpl->mpMaster = pImpl->mpSecondary.get();
450 for ( SfxItemPool *p = pImpl->mpSecondary->pImpl->mpSecondary.get(); p; p = p->pImpl->mpSecondary.get() )
451 p->pImpl->mpMaster = pImpl->mpSecondary.get();
452 }
453
454 // Set Master of new Secondary Pools
455 DBG_ASSERT( !pPool || pPool->pImpl->mpMaster == pPool, "Secondary is present in two Pools" );
456 SfxItemPool *pNewMaster = GetMasterPool() ? pImpl->mpMaster : this;
457 for ( SfxItemPool *p = pPool; p; p = p->pImpl->mpSecondary.get() )
458 p->pImpl->mpMaster = pNewMaster;
459
460 // Remember new Secondary Pool
461 pImpl->mpSecondary = pPool;
462
463 CHECK_SLOTS();
464}
465
467{
468 pItemInfos = pInfo;
469 CHECK_SLOTS();
470}
471
472
474{
475 return pImpl->eDefMetric;
476}
477
478
480{
481// assert((pImpl->eDefMetric == eNewMetric || !pImpl->mpPoolRanges) && "pool already frozen, cannot change metric");
482 pImpl->eDefMetric = eNewMetric;
483}
484
486{
487 return pImpl->eDefMetric;
488}
489
490const OUString& SfxItemPool::GetName() const
491{
492 return pImpl->aName;
493}
494
495
497(
498 const SfxPoolItem& rItem,
499 MapUnit eMetric,
500 OUString& rText,
501 const IntlWrapper& rIntlWrapper
502) const
503{
504 return rItem.GetPresentation(
505 SfxItemPresentation::Complete, GetMetric(rItem.Which()), eMetric, rText, rIntlWrapper );
506}
507
508
510{
511 return new SfxItemPool( *this );
512}
513
514
516{
517 // Already deleted?
518 if (pImpl->maPoolItemArrays.empty() || pImpl->maPoolDefaults.empty())
519 return;
520
521 // Inform e.g. running Requests
522 pImpl->aBC.Broadcast( SfxHint( SfxHintId::Dying ) );
523
524 // Iterate through twice: first for the SetItems.
525 if (pImpl->mpStaticDefaults != nullptr) {
526 for (size_t n = 0; n < GetSize_Impl(); ++n)
527 {
528 // *mpStaticDefaultItem could've already been deleted in a class derived
529 // from SfxItemPool
530 // This causes chaos in Itempool!
531 const SfxPoolItem* pStaticDefaultItem = (*pImpl->mpStaticDefaults)[n];
532 if (dynamic_cast<const SfxSetItem*>(pStaticDefaultItem))
533 {
534 // SfxSetItem found, remove PoolItems (and defaults) with same ID
535 auto& rArray = pImpl->maPoolItemArrays[n];
536 for (auto& rItemPtr : rArray)
537 {
538 ReleaseRef(*rItemPtr, rItemPtr->GetRefCount()); // for RefCount check in dtor
539 delete rItemPtr;
540 }
541 rArray.clear();
542 // let pImpl->DeleteItems() delete item arrays in maPoolItems
543 auto& rItemPtr = pImpl->maPoolDefaults[n];
544 if (rItemPtr)
545 {
546#ifdef DBG_UTIL
547 ClearRefCount(*rItemPtr);
548#endif
549 delete rItemPtr;
550 rItemPtr = nullptr;
551 }
552 }
553 }
554 }
555
556 // now remove remaining PoolItems (and defaults) who didn't have SetItems
557 for (auto& rArray : pImpl->maPoolItemArrays)
558 {
559 for (auto& rItemPtr : rArray)
560 {
561 ReleaseRef(*rItemPtr, rItemPtr->GetRefCount()); // for RefCount check in dtor
562 delete rItemPtr;
563 }
564 rArray.clear();
565 // let pImpl->DeleteItems() delete item arrays in maPoolItems
566 }
567 pImpl->maPoolItemArrays.clear();
568 // default items
569 for (auto rItemPtr : pImpl->maPoolDefaults)
570 {
571 if (rItemPtr)
572 {
573#ifdef DBG_UTIL
574 ClearRefCount(*rItemPtr);
575#endif
576 delete rItemPtr;
577 rItemPtr = nullptr;
578 }
579 }
580
581 pImpl->DeleteItems();
582}
583
584
586{
587 if ( IsInRange(rItem.Which()) )
588 {
589 auto& rOldDefault =
590 pImpl->maPoolDefaults[GetIndex_Impl(rItem.Which())];
591 SfxPoolItem *pNewDefault = rItem.Clone(this);
592 pNewDefault->SetKind(SfxItemKind::PoolDefault);
593 if (rOldDefault)
594 {
595 rOldDefault->SetRefCount(0);
596 delete rOldDefault;
597 rOldDefault = nullptr;
598 }
599 rOldDefault = pNewDefault;
600 }
601 else if ( pImpl->mpSecondary )
602 pImpl->mpSecondary->SetPoolDefaultItem(rItem);
603 else
604 {
605 assert(false && "unknown WhichId - cannot set pool default");
606 }
607}
608
613void SfxItemPool::ResetPoolDefaultItem( sal_uInt16 nWhichId )
614{
615 if ( IsInRange(nWhichId) )
616 {
617 auto& rOldDefault =
618 pImpl->maPoolDefaults[GetIndex_Impl(nWhichId)];
619 if (rOldDefault)
620 {
621 rOldDefault->SetRefCount(0);
622 delete rOldDefault;
623 rOldDefault = nullptr;
624 }
625 }
626 else if ( pImpl->mpSecondary )
627 pImpl->mpSecondary->ResetPoolDefaultItem(nWhichId);
628 else
629 {
630 assert(false && "unknown WhichId - cannot reset pool default");
631 }
632}
633
634
635const SfxPoolItem& SfxItemPool::PutImpl( const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership )
636{
637 if ( 0 == nWhich )
638 nWhich = rItem.Which();
639
640 // Find correct Secondary Pool
641 bool bSID = IsSlot(nWhich);
642 if ( !bSID && !IsInRange(nWhich) )
643 {
644 if ( pImpl->mpSecondary )
645 return pImpl->mpSecondary->PutImpl( rItem, nWhich, bPassingOwnership );
646 OSL_FAIL( "unknown WhichId - cannot put item" );
647 }
648
649 // SID ?
650 if (bSID)
651 {
652 assert((rItem.Which() != nWhich ||
653 !IsDefaultItem(&rItem) || rItem.GetKind() == SfxItemKind::DeleteOnIdle)
654 && "a non Pool Item is Default?!");
655 SfxPoolItem *pPoolItem = rItem.Clone(pImpl->mpMaster);
656 pPoolItem->SetWhich(nWhich);
657 AddRef( *pPoolItem );
658 if (bPassingOwnership)
659 delete &rItem;
660 return *pPoolItem;
661 }
662
663 assert(!pImpl->mpStaticDefaults ||
664 typeid(rItem) == typeid(GetDefaultItem(nWhich)));
665
666 const sal_uInt16 nIndex = GetIndex_Impl(nWhich);
667 SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[nIndex];
668
669 // Is this a 'poolable' item - ie. should we re-use and return
670 // the same underlying item for equivalent (==) SfxPoolItems?
672 {
673 // if is already in a pool, then it is worth checking if it is in this one.
674 if ( IsPooledItem(&rItem) )
675 {
676 // 1. search for an identical pointer in the pool
677 auto it = rItemArr.find(const_cast<SfxPoolItem *>(&rItem));
678 if (it != rItemArr.end())
679 {
680 AddRef(rItem);
681 assert(!bPassingOwnership && "can't be passing ownership and have the item already in the pool");
682 return rItem;
683 }
684 }
685
686 const SfxPoolItem* pFoundItem = nullptr;
687 // 2. search for an item with matching attributes.
688 if (rItem.IsSortable())
689 {
690 pFoundItem = rItemArr.findByLessThan(&rItem);
691 if (pFoundItem)
692 assert(*pFoundItem == rItem);
693 }
694 else if(rItem.HasLookup())
695 {
696 auto it = rItem.Lookup(rItemArr.begin(), rItemArr.end());
697 if( it != rItemArr.end())
698 pFoundItem = *it;
699 }
700 else
701 {
702 for (auto it = rItemArr.begin(); it != rItemArr.end(); ++it)
703 {
704 if (**it == rItem)
705 {
706 pFoundItem = *it;
707 break;
708 }
709 }
710 }
711 if (pFoundItem)
712 {
713 assert((!bPassingOwnership || (&rItem != pFoundItem)) && "can't be passing ownership and have the item already in the pool");
714 AddRef(*pFoundItem);
715 if (bPassingOwnership)
716 delete &rItem;
717 return *pFoundItem;
718 }
719 }
720
721 // 3. not found, so clone to insert into the pointer array.
722 SfxPoolItem* pNewItem;
723 if (bPassingOwnership)
724 {
725#ifndef NDEBUG
726 if (auto pSetItem = dynamic_cast<const SfxSetItem*>(&rItem))
727 assert(pSetItem->GetItemSet().GetPool() == pImpl->mpMaster && "can't pass ownership of SfxSetItem, unless they have been cloned to the master pool");
728#endif
729 pNewItem = const_cast<SfxPoolItem*>(&rItem);
730 }
731 else
732 pNewItem = rItem.Clone(pImpl->mpMaster);
733 pNewItem->SetWhich(nWhich);
734 assert(typeid(rItem) == typeid(*pNewItem) && "SfxItemPool::Put(): unequal types, no Clone() override?");
735#ifndef NDEBUG
736 if (dynamic_cast<const SfxSetItem*>(&rItem) == nullptr)
737 {
738 assert((!IsItemPoolable(nWhich) || rItem == *pNewItem)
739 && "SfxItemPool::Put(): unequal items: no operator== override?");
740 assert((!IsItemPoolable(*pNewItem) || *pNewItem == rItem)
741 && "SfxItemPool::Put(): unequal items: no operator== override?");
742 }
743#endif
744 AddRef( *pNewItem );
745
746 // 4. finally insert into the pointer array
747 rItemArr.insert( pNewItem );
748 return *pNewItem;
749}
750
752{
753 assert(!IsPoolDefaultItem(&rItem) && "cannot remove Pool Default");
754
755 // Find correct Secondary Pool
756 const sal_uInt16 nWhich = rItem.Which();
757 bool bSID = IsSlot(nWhich);
758 if ( !bSID && !IsInRange(nWhich) )
759 {
760 if ( pImpl->mpSecondary )
761 {
762 pImpl->mpSecondary->Remove( rItem );
763 return;
764 }
765 OSL_FAIL( "unknown WhichId - cannot remove item" );
766 }
767
768 // SID ?
769 if ( bSID )
770 {
771 assert(!IsDefaultItem(&rItem) && "a non Pool Item is Default?!");
772 if ( 0 == ReleaseRef(rItem) )
773 {
774 delete &rItem;
775 }
776 return;
777 }
778
779 assert(rItem.GetRefCount() && "RefCount == 0, Remove impossible");
780
781 const sal_uInt16 nIndex = GetIndex_Impl(nWhich);
782 // Static Defaults are just there
783 if ( IsStaticDefaultItem(&rItem) &&
784 &rItem == (*pImpl->mpStaticDefaults)[nIndex])
785 return;
786
787 // Find Item in own Pool
788 SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[nIndex];
789
790 auto it = rItemArr.find(const_cast<SfxPoolItem *>(&rItem));
791 if (it != rItemArr.end())
792 {
793 if ( rItem.GetRefCount() )
794 ReleaseRef( rItem );
795 else
796 {
797 assert(false && "removing Item without ref");
798 }
799
800 // FIXME: Hack, for as long as we have problems with the Outliner
801 // See other MI-REF
802 if ( 0 == rItem.GetRefCount() && nWhich < 4000 )
803 {
804 rItemArr.erase(it);
805 delete &rItem;
806 }
807
808 return;
809 }
810
811 // not found
812 assert(false && "removing Item not in Pool");
813}
814
815
816const SfxPoolItem& SfxItemPool::GetDefaultItem( sal_uInt16 nWhich ) const
817{
818 if ( !IsInRange(nWhich) )
819 {
820 if ( pImpl->mpSecondary )
821 return pImpl->mpSecondary->GetDefaultItem( nWhich );
822 assert(!"unknown which - don't ask me for defaults");
823 }
824
825 DBG_ASSERT( pImpl->mpStaticDefaults, "no defaults known - don't ask me for defaults" );
826 sal_uInt16 nPos = GetIndex_Impl(nWhich);
827 SfxPoolItem* pDefault = pImpl->maPoolDefaults[nPos];
828 if ( pDefault )
829 return *pDefault;
830 return *(*pImpl->mpStaticDefaults)[nPos];
831}
832
834{
835 return pImpl->mpSecondary.get();
836}
837
838/* get the last pool by following the GetSecondaryPool chain */
840{
841 SfxItemPool* pLast = this;
842 while(pLast->GetSecondaryPool())
843 pLast = pLast->GetSecondaryPool();
844 return pLast;
845}
846
848{
849 return pImpl->mpMaster;
850}
851
860{
861 assert(pImpl->mpPoolRanges.empty() && "pool already frozen, cannot freeze twice");
862 FillItemIdRanges_Impl( pImpl->mpPoolRanges );
863}
864
865
867{
868 DBG_ASSERT( pImpl->mpPoolRanges.empty(), "GetFrozenRanges() would be faster!" );
869
870 pWhichRanges.reset();
871
872 // Merge all ranges, keeping them sorted
873 for (const SfxItemPool* pPool = this; pPool; pPool = pPool->pImpl->mpSecondary.get())
874 pWhichRanges = pWhichRanges.MergeRange(pPool->pImpl->mnStart, pPool->pImpl->mnEnd);
875}
876
878{
879 return pImpl->mpPoolRanges;
880}
881
882const SfxPoolItem *SfxItemPool::GetItem2Default(sal_uInt16 nWhich) const
883{
884 if ( !IsInRange(nWhich) )
885 {
886 if ( pImpl->mpSecondary )
887 return pImpl->mpSecondary->GetItem2Default( nWhich );
888 assert(false && "unknown WhichId - cannot resolve surrogate");
889 return nullptr;
890 }
891 return (*pImpl->mpStaticDefaults)[ GetIndex_Impl(nWhich) ];
892}
893
895{
897
898 if ( !IsInRange(nWhich) )
899 {
900 if ( pImpl->mpSecondary )
901 return pImpl->mpSecondary->GetItemSurrogates( nWhich );
902 assert(false && "unknown WhichId - cannot resolve surrogate");
903 return { EMPTY.end(), EMPTY.end() };
904 }
905
906 SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(nWhich)];
907 return { rItemArr.begin(), rItemArr.end() };
908}
909
910/* This is only valid for SfxPoolItem that override IsSortable and operator< */
911std::vector<const SfxPoolItem*> SfxItemPool::FindItemSurrogate(sal_uInt16 nWhich, SfxPoolItem const & rSample) const
912{
913 if ( !IsInRange(nWhich) )
914 {
915 if ( pImpl->mpSecondary )
916 return pImpl->mpSecondary->FindItemSurrogate( nWhich, rSample );
917 assert(false && "unknown WhichId - cannot resolve surrogate");
918 return std::vector<const SfxPoolItem*>();
919 }
920
921 SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(nWhich)];
922 return rItemArr.findSurrogateRange(&rSample);
923}
924
925sal_uInt32 SfxItemPool::GetItemCount2(sal_uInt16 nWhich) const
926{
927 if ( !IsInRange(nWhich) )
928 {
929 if ( pImpl->mpSecondary )
930 return pImpl->mpSecondary->GetItemCount2( nWhich );
931 assert(false && "unknown WhichId - cannot resolve surrogate");
932 return 0;
933 }
934
935 SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(nWhich)];
936 return rItemArr.size();
937}
938
939
940sal_uInt16 SfxItemPool::GetWhich( sal_uInt16 nSlotId, bool bDeep ) const
941{
942 if ( !IsSlot(nSlotId) )
943 return nSlotId;
944
945 sal_uInt16 nCount = pImpl->mnEnd - pImpl->mnStart + 1;
946 for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs )
947 if ( pItemInfos[nOfs]._nSID == nSlotId )
948 return nOfs + pImpl->mnStart;
949 if ( pImpl->mpSecondary && bDeep )
950 return pImpl->mpSecondary->GetWhich(nSlotId);
951 return nSlotId;
952}
953
954
955sal_uInt16 SfxItemPool::GetSlotId( sal_uInt16 nWhich ) const
956{
957 if ( !IsWhich(nWhich) )
958 return nWhich;
959
960 if ( !IsInRange( nWhich ) )
961 {
962 if ( pImpl->mpSecondary )
963 return pImpl->mpSecondary->GetSlotId(nWhich);
964 assert(false && "unknown WhichId - cannot get slot-id");
965 return 0;
966 }
967
968 sal_uInt16 nSID = pItemInfos[nWhich - pImpl->mnStart]._nSID;
969 return nSID ? nSID : nWhich;
970}
971
972
973sal_uInt16 SfxItemPool::GetTrueWhich( sal_uInt16 nSlotId, bool bDeep ) const
974{
975 if ( !IsSlot(nSlotId) )
976 return 0;
977
978 sal_uInt16 nCount = pImpl->mnEnd - pImpl->mnStart + 1;
979 for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs )
980 if ( pItemInfos[nOfs]._nSID == nSlotId )
981 return nOfs + pImpl->mnStart;
982 if ( pImpl->mpSecondary && bDeep )
983 return pImpl->mpSecondary->GetTrueWhich(nSlotId);
984 return 0;
985}
986
987
988sal_uInt16 SfxItemPool::GetTrueSlotId( sal_uInt16 nWhich ) const
989{
990 if ( !IsWhich(nWhich) )
991 return 0;
992
993 if ( !IsInRange( nWhich ) )
994 {
995 if ( pImpl->mpSecondary )
996 return pImpl->mpSecondary->GetTrueSlotId(nWhich);
997 assert(false && "unknown WhichId - cannot get slot-id");
998 return 0;
999 }
1000 return pItemInfos[nWhich - pImpl->mnStart]._nSID;
1001}
1002
1004{
1005 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SfxItemPool"));
1006 for (auto const & rArray : pImpl->maPoolItemArrays)
1007 for (auto const & rItem : rArray)
1008 rItem->dumpAsXml(pWriter);
1009 (void)xmlTextWriterEndElement(pWriter);
1010}
1011
1012/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
size_t mnEnd
Base class for providers of defaults of SfxPoolItems.
Definition: itempool.hxx:51
void ClearDefaults()
Definition: itempool.cxx:327
Item2Range GetItemSurrogates(sal_uInt16 nWhich) const
Definition: itempool.cxx:894
sal_uInt16 GetWhich(sal_uInt16 nSlot, bool bDeep=true) const
Definition: itempool.cxx:940
const WhichRangesContainer & GetFrozenIdRanges() const
Definition: itempool.cxx:877
SfxItemPool * GetSecondaryPool() const
Definition: itempool.cxx:833
const SfxPoolItem & GetDefaultItem(sal_uInt16 nWhich) const
Definition: itempool.cxx:816
const SfxItemInfo * pItemInfos
Definition: itempool.hxx:56
void ResetPoolDefaultItem(sal_uInt16 nWhich)
Resets the default of the given WhichId back to the static Default.
Definition: itempool.cxx:613
bool IsItemPoolable(sal_uInt16 nWhich) const
Definition: itempool.cxx:178
void Delete()
Definition: itempool.cxx:515
void dumpAsXml(xmlTextWriterPtr pWriter) const
Definition: itempool.cxx:1003
void FreezeIdRanges()
This method should be called at the master pool, when all secondary pools are appended to it.
Definition: itempool.cxx:859
const OUString & GetName() const
Definition: itempool.cxx:490
static void ClearRefCount(SfxPoolItem &rItem)
Definition: itempool.hxx:211
bool CheckItemInPool(const SfxPoolItem *) const
Definition: itempool.cxx:128
const SfxPoolItem * GetPoolDefaultItem(sal_uInt16 nWhich) const
Definition: itempool.cxx:156
sal_uInt16 GetSlotId(sal_uInt16 nWhich) const
Definition: itempool.cxx:955
sal_uInt16 GetTrueSlotId(sal_uInt16 nWhich) const
Definition: itempool.cxx:988
void SetDefaults(std::vector< SfxPoolItem * > *pDefaults)
Definition: itempool.cxx:305
SfxItemPool(const SfxItemPool &rPool, bool bCloneStaticDefaults=false)
Copy ctor.
Definition: itempool.cxx:263
static void AddRef(const SfxPoolItem &rItem)
Definition: itempool.hxx:217
sal_uInt16 GetTrueWhich(sal_uInt16 nSlot, bool bDeep=true) const
Definition: itempool.cxx:973
static bool IsWhich(sal_uInt16 nId)
Definition: itempool.hxx:194
std::unique_ptr< SfxItemPool_Impl > pImpl
Definition: itempool.hxx:57
void SetPoolDefaultItem(const SfxPoolItem &)
Definition: itempool.cxx:585
SfxItemPool * GetLastPoolInChain()
Definition: itempool.cxx:839
SVL_DLLPRIVATE bool IsItemPoolable_Impl(sal_uInt16 nWhich) const
Definition: itempool.cxx:172
void SetItemInfos(const SfxItemInfo *pInfos)
Definition: itempool.cxx:466
bool IsInRange(sal_uInt16 nWhich) const
Definition: itempool.cxx:107
void Remove(const SfxPoolItem &)
Definition: itempool.cxx:751
sal_uInt16 GetLastWhich() const
Definition: itempool.cxx:102
static bool IsSlot(sal_uInt16 nId)
Definition: itempool.hxx:196
sal_uInt16 GetSize_Impl() const
Definition: itempool.cxx:122
virtual const SfxPoolItem & PutImpl(const SfxPoolItem &, sal_uInt16 nWhich=0, bool bPassingOwnership=false)
Definition: itempool.cxx:635
virtual bool GetPresentation(const SfxPoolItem &rItem, MapUnit ePresentationMetric, OUString &rText, const IntlWrapper &rIntlWrapper) const
Request string representation of pool items.
Definition: itempool.cxx:497
SfxBroadcaster & BC()
Definition: itempool.cxx:190
virtual ~SfxItemPool()
Definition: itempool.cxx:401
std::vector< const SfxPoolItem * > FindItemSurrogate(sal_uInt16 nWhich, SfxPoolItem const &rNeedle) const
Definition: itempool.cxx:911
void ReleaseDefaults(bool bDelete=false)
Frees the static Defaults of the corresponding SfxItemPool instance and deletes them if specified.
Definition: itempool.cxx:340
sal_uInt16 GetFirstWhich() const
Definition: itempool.cxx:97
const SfxPoolItem * GetItem2Default(sal_uInt16 nWhich) const
Definition: itempool.cxx:882
void SetDefaultMetric(MapUnit eNewMetric)
Definition: itempool.cxx:479
void SetSecondaryPool(SfxItemPool *pPool)
Definition: itempool.cxx:418
virtual MapUnit GetMetric(sal_uInt16 nWhich) const
Definition: itempool.cxx:473
MapUnit GetDefaultMetric() const
Definition: itempool.cxx:485
virtual rtl::Reference< SfxItemPool > Clone() const
Definition: itempool.cxx:509
sal_uInt16 GetIndex_Impl(sal_uInt16 nWhich) const
Definition: itempool.cxx:112
static sal_uInt32 ReleaseRef(const SfxPoolItem &rItem, sal_uInt32 n=1)
Definition: itempool.hxx:223
void FillItemIdRanges_Impl(WhichRangesContainer &pWhichRanges) const
Definition: itempool.cxx:866
SfxItemPool * GetMasterPool() const
Definition: itempool.cxx:847
sal_uInt32 GetItemCount2(sal_uInt16 nWhich) const
Definition: itempool.cxx:925
void SetKind(SfxItemKind n)
Definition: poolitem.hxx:248
virtual bool GetPresentation(SfxItemPresentation ePresentation, MapUnit eCoreMetric, MapUnit ePresentationMetric, OUString &rText, const IntlWrapper &rIntlWrapper) const
This virtual method allows to get a textual representation of the value for the SfxPoolItem subclasse...
Definition: poolitem.cxx:524
sal_uInt32 GetRefCount() const
Definition: poolitem.hxx:226
virtual bool HasLookup() const
Definition: poolitem.hxx:200
virtual lookup_iterator Lookup(lookup_iterator, lookup_iterator end) const
Definition: poolitem.hxx:202
sal_uInt16 Which() const
Definition: poolitem.hxx:149
virtual bool IsSortable() const
Definition: poolitem.hxx:190
void SetWhich(sal_uInt16 nId)
Definition: poolitem.hxx:143
SfxItemKind GetKind() const
Definition: poolitem.hxx:227
virtual SfxPoolItem * Clone(SfxItemPool *pPool=nullptr) const =0
int nCount
#define DBG_ASSERT(sCon, aError)
struct _xmlTextWriter * xmlTextWriterPtr
sal_Int32 nIndex
OUString aName
#define CHECK_SLOTS()
Definition: itempool.cxx:75
static void lcl_CheckSlots2(std::map< sal_uInt16, sal_uInt16 > &rSlotMap, SfxItemPool const &rPool, SfxItemInfo const *pInfo)
Definition: itempool.cxx:42
void * p
sal_Int64 n
sal_uInt16 nPos
#define SAL_WARN(area, stream)
MapUnit
int i
constexpr OUStringLiteral EMPTY
bool IsPoolDefaultItem(const SfxPoolItem *pItem)
Definition: poolitem.hxx:269
bool IsDefaultItem(const SfxPoolItem *pItem)
Definition: poolitem.hxx:279
bool IsInvalidItem(const SfxPoolItem *pItem)
Definition: poolitem.hxx:289
bool IsPooledItem(const SfxPoolItem *pItem)
Definition: poolitem.hxx:284
bool IsStaticDefaultItem(const SfxPoolItem *pItem)
Definition: poolitem.hxx:274
bool _bPoolable
Definition: itempool.hxx:38
sal_uInt16 _nSID
Definition: itempool.hxx:37
This array contains a set of SfxPoolItems, if those items are poolable then each item has a unique se...
Definition: poolio.hxx:47
std::vector< SfxPoolItem * > maSortablePoolItems
Definition: poolio.hxx:54
size_t size() const
Definition: poolio.hxx:61
o3tl::sorted_vector< SfxPoolItem * > maPoolItemSet
Definition: poolio.hxx:49
o3tl::sorted_vector< SfxPoolItem * >::const_iterator find(SfxPoolItem *pItem) const
Definition: poolio.hxx:63
void insert(SfxPoolItem *pItem)
Definition: poolio.hxx:64
o3tl::sorted_vector< SfxPoolItem * >::const_iterator begin() const
Definition: poolio.hxx:56
const SfxPoolItem * findByLessThan(const SfxPoolItem *pNeedle) const
Definition: poolio.hxx:79
o3tl::sorted_vector< SfxPoolItem * >::const_iterator end() const
Definition: poolio.hxx:57
std::vector< const SfxPoolItem * > findSurrogateRange(const SfxPoolItem *pNeedle) const
Definition: poolio.hxx:97
void clear()
clear array of PoolItem variants after all PoolItems are deleted or all ref counts are decreased
Definition: itempool.cxx:91
void erase(o3tl::sorted_vector< SfxPoolItem * >::const_iterator it)
Definition: poolio.hxx:118
Most of the time, the which ranges we point at are a compile-time literal.
Definition: whichranges.hxx:79
SAL_WARN_UNUSED_RESULT WhichRangesContainer MergeRange(sal_uInt16 nFrom, sal_uInt16 nTo) const
Definition: itemset.cxx:1517
sal_Int32 mnStart