Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/unodraw/UnoNameItemTable.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
21
#include <set>
22
23
#include <svl/itempool.hxx>
24
#include <svl/itemset.hxx>
25
#include <comphelper/profilezone.hxx>
26
#include <comphelper/sequence.hxx>
27
#include <cppuhelper/supportsservice.hxx>
28
29
#include <svx/svdmodel.hxx>
30
#include "UnoNameItemTable.hxx"
31
#include <vcl/svapp.hxx>
32
33
#include <svx/unoapi.hxx>
34
#include <memory>
35
36
using namespace ::com::sun::star;
37
using namespace ::cppu;
38
39
namespace
40
{
41
    // We need to override operator== here and specifically bypass the assert
42
    // in SfxPoolItem::operator== in order to make the GetItemSurrogates call
43
    // and comparing it's results in SvxUnoNameItemTable::hasByName safe.
44
    class SampleItem : public NameOrIndex
45
    {
46
    public:
47
        DECLARE_ITEM_TYPE_FUNCTION(SampleItem)
48
1.46k
        SampleItem(sal_uInt16 nWhich, const OUString& rName) : NameOrIndex(TypedWhichId<NameOrIndex>(nWhich), rName) {}
49
50
        bool operator==(const SfxPoolItem& rCmp) const override
51
2.36k
        {
52
2.36k
            assert(dynamic_cast<const NameOrIndex*>(&rCmp) && "comparing different pool item subclasses");
53
2.36k
            auto const & rOther = static_cast<const NameOrIndex&>(rCmp);
54
2.36k
            return GetName() == rOther.GetName() && GetPalIndex() == rOther.GetPalIndex();
55
2.36k
        }
56
    };
57
58
}
59
60
61
SvxUnoNameItemTable::SvxUnoNameItemTable( SdrModel* pModel, sal_uInt16 nWhich, sal_uInt8 nMemberId ) noexcept
62
737
: mpModel( pModel ),
63
737
  mpModelPool( pModel ? &pModel->GetItemPool() : nullptr ),
64
737
  mnWhich( nWhich ), mnMemberId( nMemberId )
65
737
{
66
737
    if( pModel )
67
737
        StartListening( *pModel );
68
737
}
69
70
SvxUnoNameItemTable::~SvxUnoNameItemTable() noexcept
71
737
{
72
737
    SolarMutexGuard aGuard;
73
74
737
    if( mpModel )
75
737
        EndListening( *mpModel );
76
737
    dispose();
77
737
}
78
79
bool SvxUnoNameItemTable::isValid( const NameOrIndex* pItem ) const
80
895
{
81
895
    return pItem && !pItem->GetName().isEmpty();
82
895
}
83
84
void SvxUnoNameItemTable::dispose()
85
1.26k
{
86
1.26k
    maItemSetVector.clear();
87
1.26k
}
88
89
void SvxUnoNameItemTable::Notify( SfxBroadcaster&, const SfxHint& rHint ) noexcept
90
3.26k
{
91
3.26k
    if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
92
262
        return;
93
3.00k
    const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
94
3.00k
    if( SdrHintKind::ModelCleared == pSdrHint->GetKind() )
95
524
        dispose();
96
3.00k
}
97
98
sal_Bool SAL_CALL SvxUnoNameItemTable::supportsService( const  OUString& ServiceName )
99
0
{
100
0
    return cppu::supportsService(this, ServiceName);
101
0
}
102
103
void SvxUnoNameItemTable::ImplInsertByName( const OUString& aName, const uno::Any& aElement )
104
540
{
105
540
    maItemSetVector.push_back( std::make_unique< SfxItemSet >( *mpModelPool, mnWhich, mnWhich ) );
106
107
540
    std::unique_ptr<NameOrIndex> xNewItem(createItem());
108
540
    xNewItem->SetName(aName);
109
540
    xNewItem->PutValue(aElement, mnMemberId);
110
540
    xNewItem->SetWhich(mnWhich);
111
540
    maItemSetVector.back()->Put(std::move(xNewItem));
112
540
}
113
114
// XNameContainer
115
void SAL_CALL SvxUnoNameItemTable::insertByName( const OUString& aApiName, const uno::Any& aElement )
116
540
{
117
540
    SolarMutexGuard aGuard;
118
540
    comphelper::ProfileZone aZone("SvxUnoNameItemTable::insertByName");
119
120
540
    if( hasByName( aApiName ) )
121
0
        throw container::ElementExistException();
122
123
540
    OUString aName = SvxUnogetInternalNameForItem(mnWhich, aApiName);
124
125
540
    ImplInsertByName( aName, aElement );
126
540
}
127
128
void SAL_CALL SvxUnoNameItemTable::cancel()
129
0
{
130
0
    SolarMutexGuard aGuard;
131
    // drop all items that are owned by this service and not the document
132
    // (i.e. they are unused)
133
0
    dispose();
134
0
}
135
136
void SAL_CALL SvxUnoNameItemTable::removeByName( const OUString& aApiName )
137
0
{
138
0
    SolarMutexGuard aGuard;
139
0
    comphelper::ProfileZone aZone("SvxUnoNameItemTable::removeByName");
140
141
0
    OUString sName = SvxUnogetInternalNameForItem(mnWhich, aApiName);
142
143
0
    auto aIter = std::find_if(maItemSetVector.begin(), maItemSetVector.end(),
144
0
        [&](const std::unique_ptr<SfxItemSet>& rpItem) {
145
0
            const NameOrIndex *pItem = static_cast<const NameOrIndex *>(&(rpItem->Get( mnWhich ) ));
146
0
            return sName == pItem->GetName();
147
0
        });
148
0
    if (aIter != maItemSetVector.end())
149
0
    {
150
0
        maItemSetVector.erase( aIter );
151
0
        return;
152
0
    }
153
154
0
    if (!hasByName(sName))
155
0
        throw container::NoSuchElementException();
156
0
}
157
158
// XNameReplace
159
void SAL_CALL SvxUnoNameItemTable::replaceByName( const OUString& aApiName, const uno::Any& aElement )
160
18
{
161
18
    SolarMutexGuard aGuard;
162
163
18
    OUString aName = SvxUnogetInternalNameForItem(mnWhich, aApiName);
164
165
18
    auto aIter = std::find_if(maItemSetVector.begin(), maItemSetVector.end(),
166
19
        [&](const std::unique_ptr<SfxItemSet>& rpItem) {
167
19
            const NameOrIndex *pItem = static_cast<const NameOrIndex *>(&(rpItem->Get( mnWhich ) ));
168
19
            return aName == pItem->GetName();
169
19
        });
170
18
    if (aIter != maItemSetVector.end())
171
18
    {
172
18
        std::unique_ptr<NameOrIndex> xNewItem(createItem());
173
18
        xNewItem->SetName(aName);
174
18
        if (!xNewItem->PutValue(aElement, mnMemberId) || !isValid(xNewItem.get()))
175
0
            throw lang::IllegalArgumentException();
176
18
        (*aIter)->Put(std::move(xNewItem));
177
18
        return;
178
18
    }
179
180
    // if it is not in our own sets, modify the pool!
181
0
    bool bFound = false;
182
183
0
    if (mpModelPool)
184
0
    {
185
0
        SampleItem aSample(mnWhich, aName);
186
187
0
        for (const SfxPoolItem* pNameOrIndex : mpModelPool->GetItemSurrogates(mnWhich))
188
0
            if (aSample == *pNameOrIndex)
189
0
                if (isValid(static_cast<const NameOrIndex*>(pNameOrIndex)))
190
0
                {
191
0
                    const_cast<SfxPoolItem*>(pNameOrIndex)->PutValue( aElement, mnMemberId );
192
0
                    bFound = true;
193
0
                }
194
0
    }
195
196
0
    if( !bFound )
197
0
        throw container::NoSuchElementException();
198
199
0
    ImplInsertByName( aName, aElement );
200
201
0
    if( !hasByName( aName ) )
202
0
        throw container::NoSuchElementException();
203
0
}
204
205
// XNameAccess
206
uno::Any SAL_CALL SvxUnoNameItemTable::getByName( const OUString& aApiName )
207
294
{
208
294
    SolarMutexGuard aGuard;
209
294
    comphelper::ProfileZone aZone("SvxUnoNameItemTable::getByName");
210
211
294
    OUString aName = SvxUnogetInternalNameForItem(mnWhich, aApiName);
212
213
294
    if (mpModelPool && !aName.isEmpty())
214
294
    {
215
294
        SampleItem aSample(mnWhich, aName);
216
217
294
        for (const SfxPoolItem* pFindItem : mpModelPool->GetItemSurrogates(mnWhich))
218
1.24k
            if (aSample == *pFindItem)
219
294
                if (isValid(static_cast<const NameOrIndex*>(pFindItem)))
220
294
                {
221
294
                    uno::Any aAny;
222
294
                    pFindItem->QueryValue( aAny, mnMemberId );
223
294
                    return aAny;
224
294
                }
225
294
    }
226
227
0
    throw container::NoSuchElementException();
228
294
}
229
230
uno::Sequence< OUString > SAL_CALL SvxUnoNameItemTable::getElementNames(  )
231
49
{
232
49
    SolarMutexGuard aGuard;
233
234
49
    std::set< OUString > aNameSet;
235
236
237
49
    if (mpModelPool)
238
49
    {
239
49
        for (const SfxPoolItem* pItem : mpModelPool->GetItemSurrogates(mnWhich))
240
343
        {
241
343
            const NameOrIndex *pNameOrIndex = static_cast<const NameOrIndex*>(pItem);
242
243
343
            if( !isValid( pNameOrIndex ) )
244
49
                continue;
245
246
294
            OUString aApiName = SvxUnogetApiNameForItem(mnWhich, pNameOrIndex->GetName());
247
294
            aNameSet.insert(aApiName);
248
294
        }
249
49
    }
250
251
49
    return comphelper::containerToSequence(aNameSet);
252
49
}
253
254
sal_Bool SAL_CALL SvxUnoNameItemTable::hasByName( const OUString& aApiName )
255
1.17k
{
256
1.17k
    SolarMutexGuard aGuard;
257
258
1.17k
    OUString aName = SvxUnogetInternalNameForItem(mnWhich, aApiName);
259
260
1.17k
    if (aName.isEmpty())
261
0
        return false;
262
263
1.17k
    if (!mpModelPool)
264
0
        return false;
265
266
1.17k
    SampleItem aSample(mnWhich, aName);
267
268
1.17k
    for (const SfxPoolItem* pFindItem : mpModelPool->GetItemSurrogates(mnWhich))
269
1.12k
        if (aSample == *pFindItem)
270
18
            if (isValid(static_cast<const NameOrIndex*>(pFindItem)))
271
18
                return true;
272
1.15k
    return false;
273
1.17k
}
274
275
sal_Bool SAL_CALL SvxUnoNameItemTable::hasElements(  )
276
245
{
277
245
    SolarMutexGuard aGuard;
278
279
245
    if (mpModelPool)
280
245
    {
281
245
        for (const SfxPoolItem* pItem : mpModelPool->GetItemSurrogates(mnWhich))
282
222
        {
283
222
            const NameOrIndex *pNameOrIndex = static_cast<const NameOrIndex*>(pItem);
284
285
222
            if( isValid( pNameOrIndex ) )
286
49
                return true;
287
222
        }
288
245
    }
289
290
196
    return false;
291
245
}
292
293
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */