Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/svx/source/unodraw/unomtabl.cxx
Line
Count
Source (jump to first uncovered line)
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 <sal/config.h>
21
22
#include <memory>
23
#include <set>
24
#include <com/sun/star/lang/XServiceInfo.hpp>
25
#include <com/sun/star/container/XNameContainer.hpp>
26
#include <com/sun/star/drawing/PointSequence.hpp>
27
#include <com/sun/star/util/XCancellable.hpp>
28
29
#include <comphelper/sequence.hxx>
30
#include <cppuhelper/implbase.hxx>
31
#include <cppuhelper/supportsservice.hxx>
32
#include <svl/itempool.hxx>
33
#include <svl/itemset.hxx>
34
#include <svl/lstner.hxx>
35
#include <svx/xlnedit.hxx>
36
#include <svx/xlnstit.hxx>
37
#include <svx/svdmodel.hxx>
38
#include <svx/xdef.hxx>
39
40
#include <vector>
41
#include <vcl/svapp.hxx>
42
43
44
#include <svx/unofill.hxx>
45
46
#include <svx/unoapi.hxx>
47
48
using namespace ::com::sun::star;
49
using namespace ::cppu;
50
51
typedef std::vector<std::unique_ptr<SfxItemSet>> ItemPoolVector;
52
53
namespace {
54
55
class SvxUnoMarkerTable
56
    : public WeakImplHelper<
57
        util::XCancellable,
58
        container::XNameContainer,
59
        lang::XServiceInfo>
60
    , public SfxListener
61
{
62
private:
63
    SdrModel*       mpModel;
64
    SfxItemPool*    mpModelPool;
65
66
    ItemPoolVector maItemSetVector;
67
68
public:
69
    explicit SvxUnoMarkerTable( SdrModel* pModel ) noexcept;
70
    virtual ~SvxUnoMarkerTable() noexcept override;
71
72
    void dispose();
73
74
    // SfxListener
75
    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) noexcept override;
76
77
    void ImplInsertByName( const OUString& aName, const uno::Any& aElement );
78
79
    // XServiceInfo
80
    virtual OUString SAL_CALL getImplementationName(  ) override;
81
    virtual sal_Bool SAL_CALL supportsService( const  OUString& ServiceName ) override;
82
    virtual uno::Sequence<  OUString > SAL_CALL getSupportedServiceNames(  ) override;
83
84
    // XCancellable
85
    virtual void SAL_CALL cancel() override;
86
87
    // XNameContainer
88
    virtual void SAL_CALL insertByName( const  OUString& aName, const  uno::Any& aElement ) override;
89
    virtual void SAL_CALL removeByName( const  OUString& Name ) override;
90
91
    // XNameReplace
92
    virtual void SAL_CALL replaceByName( const  OUString& aName, const  uno::Any& aElement ) override;
93
94
    // XNameAccess
95
    virtual uno::Any SAL_CALL getByName( const  OUString& aName ) override;
96
    virtual uno::Sequence<  OUString > SAL_CALL getElementNames(  ) override;
97
    virtual sal_Bool SAL_CALL hasByName( const  OUString& aName ) override;
98
99
    // XElementAccess
100
    virtual uno::Type SAL_CALL getElementType(  ) override;
101
    virtual sal_Bool SAL_CALL hasElements(  ) override;
102
};
103
104
}
105
106
SvxUnoMarkerTable::SvxUnoMarkerTable( SdrModel* pModel ) noexcept
107
1.81k
: mpModel( pModel ),
108
1.81k
  mpModelPool( pModel ? &pModel->GetItemPool() : nullptr )
109
1.81k
{
110
1.81k
    if( pModel )
111
1.81k
        StartListening( *pModel );
112
1.81k
}
113
114
SvxUnoMarkerTable::~SvxUnoMarkerTable() noexcept
115
1.81k
{
116
1.81k
    SolarMutexGuard aGuard;
117
118
1.81k
    if( mpModel )
119
1.81k
        EndListening( *mpModel );
120
1.81k
    dispose();
121
1.81k
}
122
123
void SvxUnoMarkerTable::dispose()
124
2.01k
{
125
2.01k
    maItemSetVector.clear();
126
2.01k
}
127
128
// SfxListener
129
void SvxUnoMarkerTable::Notify( SfxBroadcaster&, const SfxHint& rHint ) noexcept
130
12.7k
{
131
12.7k
    if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
132
12.6k
    {
133
12.6k
        const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
134
12.6k
        if( SdrHintKind::ModelCleared == pSdrHint->GetKind() )
135
198
            dispose();
136
12.6k
    }
137
12.7k
}
138
139
sal_Bool SAL_CALL SvxUnoMarkerTable::supportsService( const  OUString& ServiceName )
140
0
{
141
0
    return cppu::supportsService(this, ServiceName);
142
0
}
143
144
OUString SAL_CALL SvxUnoMarkerTable::getImplementationName()
145
0
{
146
0
    return u"SvxUnoMarkerTable"_ustr;
147
0
}
148
149
uno::Sequence< OUString > SAL_CALL SvxUnoMarkerTable::getSupportedServiceNames(  )
150
0
{
151
0
    uno::Sequence<OUString> aSNS { u"com.sun.star.drawing.MarkerTable"_ustr };
152
0
    return aSNS;
153
0
}
154
155
void SvxUnoMarkerTable::ImplInsertByName( const OUString& aName, const uno::Any& aElement )
156
11.5k
{
157
11.5k
    maItemSetVector.push_back(
158
11.5k
        std::make_unique<SfxItemSetFixed<XATTR_LINESTART, XATTR_LINEEND>>( *mpModelPool ));
159
11.5k
    auto pInSet = maItemSetVector.back().get();
160
161
11.5k
    XLineEndItem aEndMarker(XATTR_LINEEND);
162
11.5k
    aEndMarker.SetName( aName );
163
11.5k
    aEndMarker.PutValue( aElement, 0 );
164
165
11.5k
    pInSet->Put( aEndMarker );
166
167
11.5k
    XLineStartItem aStartMarker(XATTR_LINESTART);
168
11.5k
    aStartMarker.SetName( aName );
169
11.5k
    aStartMarker.PutValue( aElement, 0 );
170
171
11.5k
    pInSet->Put( aStartMarker );
172
11.5k
}
173
174
// XNameContainer
175
void SAL_CALL SvxUnoMarkerTable::insertByName( const OUString& aApiName, const uno::Any& aElement )
176
10.0k
{
177
10.0k
    SolarMutexGuard aGuard;
178
179
10.0k
    if( hasByName( aApiName ) )
180
0
        throw container::ElementExistException();
181
182
10.0k
    OUString aName = SvxUnogetInternalNameForItem(XATTR_LINEEND, aApiName);
183
184
10.0k
    ImplInsertByName( aName, aElement );
185
10.0k
}
186
187
void SAL_CALL SvxUnoMarkerTable::cancel()
188
0
{
189
0
    SolarMutexGuard aGuard;
190
    // drop all items that are owned by this service and not the document
191
    // (i.e. they are unused)
192
0
    dispose();
193
0
}
194
195
void SAL_CALL SvxUnoMarkerTable::removeByName( const OUString& aApiName )
196
0
{
197
0
    SolarMutexGuard aGuard;
198
199
0
    OUString aName = SvxUnogetInternalNameForItem(XATTR_LINEEND, aApiName);
200
201
0
    auto aIter = std::find_if(maItemSetVector.begin(), maItemSetVector.end(),
202
0
        [&aName](const std::unique_ptr<SfxItemSet>& rpItem) {
203
0
            const NameOrIndex *pItem = &(rpItem->Get( XATTR_LINEEND ) );
204
0
            return pItem->GetName() == aName;
205
0
        });
206
0
    if (aIter != maItemSetVector.end())
207
0
    {
208
0
        maItemSetVector.erase( aIter );
209
0
        return;
210
0
    }
211
212
0
    if( !hasByName( aName ) )
213
0
        throw container::NoSuchElementException();
214
0
}
215
216
// XNameReplace
217
void SAL_CALL SvxUnoMarkerTable::replaceByName( const OUString& aApiName, const uno::Any& aElement )
218
21.3k
{
219
21.3k
    SolarMutexGuard aGuard;
220
221
21.3k
    const OUString aName = SvxUnogetInternalNameForItem(XATTR_LINEEND, aApiName);
222
223
21.3k
    auto aIter = std::find_if(maItemSetVector.begin(), maItemSetVector.end(),
224
25.3k
        [&aName](const std::unique_ptr<SfxItemSet>& rpItem) {
225
25.3k
            const NameOrIndex *pItem = &(rpItem->Get( XATTR_LINEEND ) );
226
25.3k
            return pItem->GetName() == aName;
227
25.3k
        });
228
21.3k
    if (aIter != maItemSetVector.end())
229
19.9k
    {
230
19.9k
        XLineEndItem aEndMarker(XATTR_LINEEND);
231
19.9k
        aEndMarker.SetName( aName );
232
19.9k
        if( !aEndMarker.PutValue( aElement, 0 ) )
233
0
            throw lang::IllegalArgumentException();
234
235
19.9k
        (*aIter)->Put( aEndMarker );
236
237
19.9k
        XLineStartItem aStartMarker(XATTR_LINESTART);
238
19.9k
        aStartMarker.SetName( aName );
239
19.9k
        aStartMarker.PutValue( aElement, 0 );
240
241
19.9k
        (*aIter)->Put( aStartMarker );
242
19.9k
        return;
243
19.9k
    }
244
245
    // if it is not in our own sets, modify the pool!
246
1.43k
    bool bFound = false;
247
248
1.43k
    if (mpModelPool)
249
1.43k
    {
250
1.43k
        mpModelPool->iterateItemSurrogates(XATTR_LINESTART, [&](SfxItemPool::SurrogateData& rData)
251
1.94k
        {
252
1.94k
            const NameOrIndex* pItem(static_cast<const NameOrIndex*>(&rData.getItem()));
253
1.94k
            if( pItem && pItem->GetName() == aName )
254
1.43k
            {
255
1.43k
                NameOrIndex* pNew(pItem->Clone(mpModelPool));
256
1.43k
                pNew->PutValue(aElement, 0);
257
1.43k
                rData.setItem(std::unique_ptr<SfxPoolItem>(pNew));
258
1.43k
                bFound = true;
259
1.43k
                return false; // interrupt callbacks
260
1.43k
            }
261
513
            return true; // continue callbacks
262
1.94k
        });
263
1.43k
    }
264
265
1.43k
    if (mpModelPool)
266
1.43k
    {
267
1.43k
        mpModelPool->iterateItemSurrogates(XATTR_LINEEND, [&](SfxItemPool::SurrogateData& rData)
268
1.94k
        {
269
1.94k
            const NameOrIndex* pItem(static_cast<const NameOrIndex*>(&rData.getItem()));
270
1.94k
            if( pItem && pItem->GetName() == aName )
271
1.43k
            {
272
1.43k
                NameOrIndex* pNew(pItem->Clone(mpModelPool));
273
1.43k
                pNew->PutValue(aElement, 0);
274
1.43k
                rData.setItem(std::unique_ptr<SfxPoolItem>(pNew));
275
1.43k
                bFound = true;
276
1.43k
                return false; // interrupt callbacks
277
1.43k
            }
278
513
            return true; // continue callbacks
279
1.94k
        });
280
1.43k
    }
281
282
1.43k
    if( !bFound )
283
0
        throw container::NoSuchElementException();
284
285
1.43k
    ImplInsertByName( aName, aElement );
286
1.43k
}
287
288
static bool getByNameFromPool( std::u16string_view rSearchName, SfxItemPool const * pPool, SfxItemType eItemType, uno::Any& rAny )
289
0
{
290
0
    if (pPool)
291
0
    {
292
0
        for (const SfxPoolItem* p : pPool->GetItemSurrogatesForItem(eItemType))
293
0
        {
294
0
            const NameOrIndex *pItem = static_cast<const NameOrIndex*>(p);
295
296
0
            if( pItem->GetName() == rSearchName )
297
0
            {
298
0
                pItem->QueryValue( rAny );
299
0
                return true;
300
0
            }
301
0
        }
302
0
    }
303
304
0
    return false;
305
0
}
306
307
// XNameAccess
308
uno::Any SAL_CALL SvxUnoMarkerTable::getByName( const OUString& aApiName )
309
0
{
310
0
    SolarMutexGuard aGuard;
311
312
0
    OUString aName = SvxUnogetInternalNameForItem(XATTR_LINEEND, aApiName);
313
314
0
    uno::Any aAny;
315
316
0
    if (mpModelPool && !aName.isEmpty())
317
0
    {
318
0
        do
319
0
        {
320
0
            if (getByNameFromPool(aName, mpModelPool, SfxItemType::XLineStartItemType, aAny)) // XATTR_LINESTART
321
0
                break;
322
323
0
            if (getByNameFromPool(aName, mpModelPool, SfxItemType::XLineEndItemType, aAny)) // XATTR_LINEEND
324
0
                break;
325
326
0
            throw container::NoSuchElementException();
327
0
        }
328
0
        while(false);
329
0
    }
330
331
0
    return aAny;
332
0
}
333
334
static void createNamesForPool( SfxItemPool const * pPool, SfxItemType eItemType, std::set< OUString >& rNameSet )
335
0
{
336
0
    for (const SfxPoolItem* p : pPool->GetItemSurrogatesForItem(eItemType))
337
0
    {
338
0
        const NameOrIndex* pItem = static_cast<const NameOrIndex*>(p);
339
340
0
        if( pItem->GetName().isEmpty() )
341
0
            continue;
342
343
0
        OUString aName = SvxUnogetApiNameForItem(XATTR_LINEEND, pItem->GetName());
344
0
        rNameSet.insert( aName );
345
0
    }
346
0
}
347
348
uno::Sequence< OUString > SAL_CALL SvxUnoMarkerTable::getElementNames()
349
0
{
350
0
    SolarMutexGuard aGuard;
351
352
0
    std::set< OUString > aNameSet;
353
354
    // search model pool for line starts
355
0
    createNamesForPool( mpModelPool, SfxItemType::XLineStartItemType, aNameSet ); // XATTR_LINESTART
356
357
    // search model pool for line ends
358
0
    createNamesForPool( mpModelPool, SfxItemType::XLineEndItemType, aNameSet ); // XATTR_LINEEND
359
360
0
    return comphelper::containerToSequence(aNameSet);
361
0
}
362
363
sal_Bool SAL_CALL SvxUnoMarkerTable::hasByName( const OUString& aName )
364
42.5k
{
365
42.5k
    SolarMutexGuard aGuard;
366
367
42.5k
    if( aName.isEmpty() )
368
17.7k
        return false;
369
370
24.7k
    OUString aSearchName;
371
372
24.7k
    const NameOrIndex *pItem;
373
374
24.7k
    aSearchName = SvxUnogetInternalNameForItem(XATTR_LINESTART, aName);
375
24.7k
    if (mpModelPool)
376
24.7k
    {
377
        // XATTR_LINESTART
378
24.7k
        for (const SfxPoolItem* p :
379
24.7k
             mpModelPool->GetItemSurrogatesForItem(SfxItemType::XLineStartItemType))
380
51.6k
        {
381
51.6k
            pItem = static_cast<const NameOrIndex*>(p);
382
51.6k
            if( pItem && pItem->GetName() == aSearchName )
383
22.0k
                return true;
384
51.6k
        }
385
24.7k
    }
386
387
2.67k
    aSearchName = SvxUnogetInternalNameForItem(XATTR_LINEEND, aName);
388
2.67k
    if (mpModelPool)
389
2.67k
    {
390
        // XATTR_LINEEND
391
2.67k
        for (const SfxPoolItem* p :
392
2.67k
             mpModelPool->GetItemSurrogatesForItem(SfxItemType::XLineEndItemType))
393
9.06k
        {
394
9.06k
            pItem = static_cast<const NameOrIndex*>(p);
395
9.06k
            if( pItem && pItem->GetName() == aSearchName )
396
0
                return true;
397
9.06k
        }
398
2.67k
    }
399
400
2.67k
    return false;
401
2.67k
}
402
403
// XElementAccess
404
uno::Type SAL_CALL SvxUnoMarkerTable::getElementType(  )
405
0
{
406
0
    return cppu::UnoType<drawing::PointSequence>::get();
407
0
}
408
409
sal_Bool SAL_CALL SvxUnoMarkerTable::hasElements(  )
410
0
{
411
0
    SolarMutexGuard aGuard;
412
413
0
    const NameOrIndex *pItem;
414
415
0
    if (mpModelPool)
416
0
    {
417
        // XATTR_LINESTART
418
0
        for (const SfxPoolItem* p :
419
0
             mpModelPool->GetItemSurrogatesForItem(SfxItemType::XLineStartItemType))
420
0
        {
421
0
            pItem = static_cast<const NameOrIndex*>(p);
422
0
            if( pItem && !pItem->GetName().isEmpty() )
423
0
                return true;
424
0
        }
425
0
    }
426
427
0
    if (mpModelPool)
428
0
    {
429
        // XATTR_LINEEND
430
0
        for (const SfxPoolItem* p :
431
0
             mpModelPool->GetItemSurrogatesForItem(SfxItemType::XLineEndItemType))
432
0
        {
433
0
            pItem = static_cast<const NameOrIndex*>(p);
434
0
            if( pItem && !pItem->GetName().isEmpty() )
435
0
                return true;
436
0
        }
437
0
    }
438
439
0
    return false;
440
0
}
441
442
/**
443
 * Create a hatchtable
444
 */
445
uno::Reference< uno::XInterface > SvxUnoMarkerTable_createInstance( SdrModel* pModel )
446
1.81k
{
447
1.81k
    return *new SvxUnoMarkerTable(pModel);
448
1.81k
}
449
450
451
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */