Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/toolkit/source/controls/geometrycontrolmodel.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 <controls/geometrycontrolmodel.hxx>
21
#include <com/sun/star/beans/PropertyAttribute.hpp>
22
#include <com/sun/star/resource/XStringResourceResolver.hpp>
23
#include <osl/diagnose.h>
24
#include <comphelper/sequence.hxx>
25
#include <controls/eventcontainer.hxx>
26
#include <helper/property.hxx>
27
#include <algorithm>
28
#include <functional>
29
#include <utility>
30
31
namespace
32
{
33
    enum GcmPropertyId : sal_Int32
34
    {
35
        GCM_PROPERTY_ID_POS_X            = 1,
36
        GCM_PROPERTY_ID_POS_Y            = 2,
37
        GCM_PROPERTY_ID_WIDTH            = 3,
38
        GCM_PROPERTY_ID_HEIGHT           = 4,
39
        GCM_PROPERTY_ID_NAME             = 5,
40
        GCM_PROPERTY_ID_TABINDEX         = 6,
41
        GCM_PROPERTY_ID_STEP             = 7,
42
        GCM_PROPERTY_ID_TAG              = 8,
43
        GCM_PROPERTY_ID_RESOURCERESOLVER = 9
44
    };
45
}
46
47
constexpr OUStringLiteral GCM_PROPERTY_POS_X = u"PositionX";
48
constexpr OUStringLiteral GCM_PROPERTY_POS_Y = u"PositionY";
49
constexpr OUStringLiteral GCM_PROPERTY_WIDTH = u"Width";
50
constexpr OUStringLiteral GCM_PROPERTY_HEIGHT = u"Height";
51
constexpr OUStringLiteral GCM_PROPERTY_NAME = u"Name";
52
constexpr OUStringLiteral GCM_PROPERTY_TABINDEX = u"TabIndex";
53
constexpr OUStringLiteral GCM_PROPERTY_STEP = u"Step";
54
constexpr OUStringLiteral GCM_PROPERTY_TAG = u"Tag";
55
constexpr OUStringLiteral GCM_PROPERTY_RESOURCERESOLVER = u"ResourceResolver";
56
57
0
#define DEFAULT_ATTRIBS()       PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT
58
59
60
// namespace toolkit
61
// {
62
63
64
    using namespace ::com::sun::star;
65
    using namespace ::com::sun::star::uno;
66
    using namespace ::com::sun::star::lang;
67
    using namespace ::com::sun::star::beans;
68
    using namespace ::com::sun::star::util;
69
    using namespace ::com::sun::star::container;
70
    using namespace ::comphelper;
71
72
73
    //= OGeometryControlModel_Base
74
75
76
    OGeometryControlModel_Base::OGeometryControlModel_Base(css::uno::XAggregation* _pAggregateInstance)
77
0
        :OPropertySetAggregationHelper( m_aBHelper )
78
0
        ,OPropertyContainer( m_aBHelper )
79
0
        ,OGCM_Base( m_aMutex )
80
0
        ,m_nPosX(0)
81
0
        ,m_nPosY(0)
82
0
        ,m_nWidth(0)
83
0
        ,m_nHeight(0)
84
0
        ,m_nTabIndex(-1)
85
0
        ,m_nStep(0)
86
0
        ,m_bCloneable(false)
87
0
    {
88
0
        OSL_ENSURE(nullptr != _pAggregateInstance, "OGeometryControlModel_Base::OGeometryControlModel_Base: invalid aggregate!");
89
90
0
        osl_atomic_increment(&m_refCount);
91
0
        {
92
0
            m_xAggregate = _pAggregateInstance;
93
94
0
            {   // check if the aggregate is clonable
95
0
                Reference< XCloneable > xCloneAccess(m_xAggregate, UNO_QUERY);
96
0
                m_bCloneable = xCloneAccess.is();
97
0
            }
98
99
0
            setAggregation(m_xAggregate);
100
0
            m_xAggregate->setDelegator(getXWeak());
101
0
        }
102
0
        osl_atomic_decrement(&m_refCount);
103
104
0
        registerProperties();
105
0
    }
106
107
108
    OGeometryControlModel_Base::OGeometryControlModel_Base(Reference< XCloneable >& _rxAggregateInstance)
109
0
        :OPropertySetAggregationHelper( m_aBHelper )
110
0
        ,OPropertyContainer( m_aBHelper )
111
0
        ,OGCM_Base( m_aMutex )
112
0
        ,m_nPosX(0)
113
0
        ,m_nPosY(0)
114
0
        ,m_nWidth(0)
115
0
        ,m_nHeight(0)
116
0
        ,m_nTabIndex(-1)
117
0
        ,m_nStep(0)
118
0
        ,m_bCloneable(_rxAggregateInstance.is())
119
0
    {
120
0
        osl_atomic_increment(&m_refCount);
121
0
        {
122
0
            {
123
                // ensure that the temporary gets destructed NOW
124
0
                m_xAggregate.set(_rxAggregateInstance, UNO_QUERY);
125
0
            }
126
0
            OSL_ENSURE(m_xAggregate.is(), "OGeometryControlModel_Base::OGeometryControlModel_Base: invalid object given!");
127
128
            // now the aggregate has a ref count of 2, but before setting the delegator it must be 1
129
0
            _rxAggregateInstance.clear();
130
            // now it should be the 1 we need here ...
131
132
0
            setAggregation(m_xAggregate);
133
0
            m_xAggregate->setDelegator(getXWeak());
134
0
        }
135
0
        osl_atomic_decrement(&m_refCount);
136
137
0
        registerProperties();
138
0
    }
139
140
141
    Sequence< Type > SAL_CALL OGeometryControlModel_Base::getTypes(  )
142
0
    {
143
        // our own types
144
0
        Sequence< Type > aTypes = ::comphelper::concatSequences(
145
0
            OPropertySetAggregationHelper::getTypes(),
146
0
            getBaseTypes(),
147
0
            OGCM_Base::getTypes()
148
0
        );
149
150
0
        if ( m_xAggregate.is() )
151
0
        {
152
            // retrieve the types of the aggregate
153
0
            Reference< XTypeProvider > xAggregateTypeProv;
154
0
            m_xAggregate->queryAggregation( cppu::UnoType<decltype(xAggregateTypeProv)>::get() ) >>= xAggregateTypeProv;
155
0
            OSL_ENSURE( xAggregateTypeProv.is(), "OGeometryControlModel_Base::getTypes: aggregate should be a type provider!" );
156
0
            Sequence< Type > aAggTypes;
157
0
            if ( xAggregateTypeProv.is() )
158
0
                aAggTypes = xAggregateTypeProv->getTypes();
159
160
            // concat the sequences
161
0
            sal_Int32 nOldSize = aTypes.getLength();
162
0
            aTypes.realloc( nOldSize + aAggTypes.getLength() );
163
0
            ::std::copy(
164
0
                std::cbegin(aAggTypes),
165
0
                std::cend(aAggTypes),
166
0
                aTypes.getArray() + nOldSize
167
0
            );
168
0
        }
169
170
0
        return aTypes;
171
0
    }
172
173
174
    void OGeometryControlModel_Base::registerProperties()
175
0
    {
176
        // register our members for the property handling of the OPropertyContainer
177
0
        registerProperty(GCM_PROPERTY_POS_X,    GCM_PROPERTY_ID_POS_X,      DEFAULT_ATTRIBS(), &m_nPosX, cppu::UnoType<decltype(m_nPosX)>::get());
178
0
        registerProperty(GCM_PROPERTY_POS_Y,    GCM_PROPERTY_ID_POS_Y,      DEFAULT_ATTRIBS(), &m_nPosY, cppu::UnoType<decltype(m_nPosY)>::get());
179
0
        registerProperty(GCM_PROPERTY_WIDTH,    GCM_PROPERTY_ID_WIDTH,      DEFAULT_ATTRIBS(), &m_nWidth, cppu::UnoType<decltype(m_nWidth)>::get());
180
0
        registerProperty(GCM_PROPERTY_HEIGHT,   GCM_PROPERTY_ID_HEIGHT,     DEFAULT_ATTRIBS(), &m_nHeight, cppu::UnoType<decltype(m_nHeight)>::get());
181
0
        registerProperty(GCM_PROPERTY_NAME,     GCM_PROPERTY_ID_NAME,       DEFAULT_ATTRIBS(), &m_aName, cppu::UnoType<decltype(m_aName)>::get());
182
0
        registerProperty(GCM_PROPERTY_TABINDEX, GCM_PROPERTY_ID_TABINDEX,   DEFAULT_ATTRIBS(), &m_nTabIndex, cppu::UnoType<decltype(m_nTabIndex)>::get());
183
0
        registerProperty(GCM_PROPERTY_STEP,     GCM_PROPERTY_ID_STEP,       DEFAULT_ATTRIBS(), &m_nStep, cppu::UnoType<decltype(m_nStep)>::get());
184
0
        registerProperty(GCM_PROPERTY_TAG,      GCM_PROPERTY_ID_TAG,        DEFAULT_ATTRIBS(), &m_aTag, cppu::UnoType<decltype(m_aTag)>::get());
185
0
        registerProperty(GCM_PROPERTY_RESOURCERESOLVER, GCM_PROPERTY_ID_RESOURCERESOLVER, DEFAULT_ATTRIBS(), &m_xStrResolver, cppu::UnoType<decltype(m_xStrResolver)>::get());
186
0
    }
187
188
189
    css::uno::Any OGeometryControlModel_Base::ImplGetDefaultValueByHandle(sal_Int32 nHandle)
190
0
    {
191
0
        css::uno::Any aDefault;
192
193
0
        switch ( nHandle )
194
0
        {
195
0
            case GCM_PROPERTY_ID_POS_X:             aDefault <<= sal_Int32(0); break;
196
0
            case GCM_PROPERTY_ID_POS_Y:             aDefault <<= sal_Int32(0); break;
197
0
            case GCM_PROPERTY_ID_WIDTH:             aDefault <<= sal_Int32(0); break;
198
0
            case GCM_PROPERTY_ID_HEIGHT:            aDefault <<= sal_Int32(0); break;
199
0
            case GCM_PROPERTY_ID_NAME:              aDefault <<= OUString(); break;
200
0
            case GCM_PROPERTY_ID_TABINDEX:          aDefault <<= sal_Int16(-1); break;
201
0
            case GCM_PROPERTY_ID_STEP:              aDefault <<= sal_Int32(0); break;
202
0
            case GCM_PROPERTY_ID_TAG:               aDefault <<= OUString(); break;
203
0
            case GCM_PROPERTY_ID_RESOURCERESOLVER:  aDefault <<= Reference< resource::XStringResourceResolver >(); break;
204
0
            default:                            OSL_FAIL( "ImplGetDefaultValueByHandle - unknown Property" );
205
0
        }
206
207
0
        return aDefault;
208
0
    }
209
210
211
    css::uno::Any OGeometryControlModel_Base::ImplGetPropertyValueByHandle(sal_Int32 nHandle) const
212
0
    {
213
0
        css::uno::Any aValue;
214
215
0
        switch ( nHandle )
216
0
        {
217
0
            case GCM_PROPERTY_ID_POS_X:         aValue <<= m_nPosX; break;
218
0
            case GCM_PROPERTY_ID_POS_Y:         aValue <<= m_nPosY; break;
219
0
            case GCM_PROPERTY_ID_WIDTH:         aValue <<= m_nWidth; break;
220
0
            case GCM_PROPERTY_ID_HEIGHT:        aValue <<= m_nHeight; break;
221
0
            case GCM_PROPERTY_ID_NAME:          aValue <<= m_aName; break;
222
0
            case GCM_PROPERTY_ID_TABINDEX:      aValue <<= m_nTabIndex; break;
223
0
            case GCM_PROPERTY_ID_STEP:          aValue <<= m_nStep; break;
224
0
            case GCM_PROPERTY_ID_TAG:           aValue <<= m_aTag; break;
225
0
            case GCM_PROPERTY_ID_RESOURCERESOLVER: aValue <<= m_xStrResolver; break;
226
0
            default:                            OSL_FAIL( "ImplGetPropertyValueByHandle - unknown Property" );
227
0
        }
228
229
0
        return aValue;
230
0
    }
231
232
233
    void OGeometryControlModel_Base::ImplSetPropertyValueByHandle(sal_Int32 nHandle, const css::uno::Any& aValue)
234
0
    {
235
0
        switch ( nHandle )
236
0
        {
237
0
            case GCM_PROPERTY_ID_POS_X:         aValue >>= m_nPosX; break;
238
0
            case GCM_PROPERTY_ID_POS_Y:         aValue >>= m_nPosY; break;
239
0
            case GCM_PROPERTY_ID_WIDTH:         aValue >>= m_nWidth; break;
240
0
            case GCM_PROPERTY_ID_HEIGHT:        aValue >>= m_nHeight; break;
241
0
            case GCM_PROPERTY_ID_NAME:          aValue >>= m_aName; break;
242
0
            case GCM_PROPERTY_ID_TABINDEX:      aValue >>= m_nTabIndex; break;
243
0
            case GCM_PROPERTY_ID_STEP:          aValue >>= m_nStep; break;
244
0
            case GCM_PROPERTY_ID_TAG:           aValue >>= m_aTag; break;
245
0
            case GCM_PROPERTY_ID_RESOURCERESOLVER: aValue >>= m_xStrResolver; break;
246
0
            default:                            OSL_FAIL( "ImplSetPropertyValueByHandle - unknown Property" );
247
0
        }
248
0
    }
249
250
251
    Any SAL_CALL OGeometryControlModel_Base::queryAggregation( const Type& _rType )
252
0
    {
253
0
        Any aReturn;
254
0
        if (_rType.equals(cppu::UnoType<XCloneable>::get()) && !m_bCloneable)
255
            // somebody is asking for the XCloneable interface, but our aggregate does not support it
256
            // -> outta here
257
            // (need this extra check, cause OGCM_Base::queryAggregation would return this interface
258
            // in every case)
259
0
            return aReturn;
260
261
0
        aReturn = OGCM_Base::queryAggregation(_rType);
262
            // the basic interfaces (XInterface, XAggregation etc)
263
264
0
        if (!aReturn.hasValue())
265
0
            aReturn = OPropertySetAggregationHelper::queryInterface(_rType);
266
            // the property set related interfaces
267
268
0
        if (!aReturn.hasValue() && m_xAggregate.is())
269
0
            aReturn = m_xAggregate->queryAggregation(_rType);
270
            // the interfaces our aggregate can provide
271
272
0
        return aReturn;
273
0
    }
274
275
276
    Any SAL_CALL OGeometryControlModel_Base::queryInterface( const Type& _rType )
277
0
    {
278
0
        return OGCM_Base::queryInterface(_rType);
279
0
    }
280
281
282
    void SAL_CALL OGeometryControlModel_Base::acquire(  ) noexcept
283
0
    {
284
0
        OGCM_Base::acquire();
285
0
    }
286
287
288
    void SAL_CALL OGeometryControlModel_Base::release(  ) noexcept
289
0
    {
290
0
        OGCM_Base::release();
291
0
    }
292
293
294
    void OGeometryControlModel_Base::releaseAggregation()
295
0
    {
296
        // release the aggregate (_before_ clearing m_xAggregate)
297
0
        if (m_xAggregate.is())
298
0
            m_xAggregate->setDelegator(nullptr);
299
0
        setAggregation(nullptr);
300
0
    }
301
302
303
    OGeometryControlModel_Base::~OGeometryControlModel_Base()
304
0
    {
305
0
        releaseAggregation();
306
0
    }
307
308
309
    sal_Bool SAL_CALL OGeometryControlModel_Base::convertFastPropertyValue(Any& _rConvertedValue, Any& _rOldValue,
310
            sal_Int32 _nHandle, const Any& _rValue)
311
0
    {
312
0
        return OPropertyContainer::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
313
0
    }
314
315
316
    void SAL_CALL OGeometryControlModel_Base::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue)
317
0
    {
318
0
        OPropertyContainer::setFastPropertyValue_NoBroadcast(_nHandle, _rValue);
319
0
    }
320
321
322
    void SAL_CALL OGeometryControlModel_Base::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
323
0
    {
324
0
        OPropertyArrayAggregationHelper& rPH = static_cast<OPropertyArrayAggregationHelper&>(const_cast<OGeometryControlModel_Base*>(this)->getInfoHelper());
325
0
        OUString sPropName;
326
0
        sal_Int32   nOriginalHandle = -1;
327
328
0
        if (rPH.fillAggregatePropertyInfoByHandle(&sPropName, &nOriginalHandle, _nHandle))
329
0
            OPropertySetAggregationHelper::getFastPropertyValue(_rValue, _nHandle);
330
0
        else
331
0
            OPropertyContainer::getFastPropertyValue(_rValue, _nHandle);
332
0
    }
333
334
335
    css::beans::PropertyState OGeometryControlModel_Base::getPropertyStateByHandle(sal_Int32 nHandle)
336
0
    {
337
0
        css::uno::Any aValue = ImplGetPropertyValueByHandle( nHandle );
338
0
        css::uno::Any aDefault = ImplGetDefaultValueByHandle( nHandle );
339
340
0
        return CompareProperties( aValue, aDefault ) ? css::beans::PropertyState_DEFAULT_VALUE : css::beans::PropertyState_DIRECT_VALUE;
341
0
    }
342
343
344
    void OGeometryControlModel_Base::setPropertyToDefaultByHandle(sal_Int32 nHandle)
345
0
    {
346
0
        ImplSetPropertyValueByHandle( nHandle , ImplGetDefaultValueByHandle( nHandle ) );
347
0
    }
348
349
350
    css::uno::Any OGeometryControlModel_Base::getPropertyDefaultByHandle( sal_Int32 nHandle ) const
351
0
    {
352
0
        return ImplGetDefaultValueByHandle( nHandle );
353
0
    }
354
355
356
    Reference< XPropertySetInfo> SAL_CALL OGeometryControlModel_Base::getPropertySetInfo()
357
0
    {
358
0
        return OPropertySetAggregationHelper::createPropertySetInfo(getInfoHelper());
359
0
    }
360
361
362
    Reference< XCloneable > SAL_CALL OGeometryControlModel_Base::createClone(  )
363
0
    {
364
0
        OSL_ENSURE(m_bCloneable, "OGeometryControlModel_Base::createClone: invalid call!");
365
0
        if (!m_bCloneable)
366
0
            return Reference< XCloneable >();
367
368
        // let the aggregate create its own clone
369
        // the interface
370
0
        Reference< XCloneable > xCloneAccess;
371
0
        m_xAggregate->queryAggregation(cppu::UnoType<decltype(xCloneAccess)>::get()) >>= xCloneAccess;
372
0
        OSL_ENSURE(xCloneAccess.is(), "OGeometryControlModel_Base::createClone: suspicious aggregate!");
373
0
        if (!xCloneAccess.is())
374
0
            return Reference< XCloneable >();
375
        // the aggregate's clone
376
0
        Reference< XCloneable > xAggregateClone = xCloneAccess->createClone();
377
0
        OSL_ENSURE(xAggregateClone.is(), "OGeometryControlModel_Base::createClone: suspicious return of the aggregate!");
378
379
        // create a new wrapper aggregating this return value
380
0
        rtl::Reference<OGeometryControlModel_Base> pOwnClone = createClone_Impl(xAggregateClone);
381
0
        OSL_ENSURE(pOwnClone, "OGeometryControlModel_Base::createClone: invalid derivee behaviour!");
382
0
        OSL_ENSURE(!xAggregateClone.is(), "OGeometryControlModel_Base::createClone: invalid ctor behaviour!");
383
            // should have been reset
384
385
        // set properties
386
0
        pOwnClone->m_nPosX      = m_nPosX;
387
0
        pOwnClone->m_nPosY      = m_nPosY;
388
0
        pOwnClone->m_nWidth     = m_nWidth;
389
0
        pOwnClone->m_nHeight    = m_nHeight;
390
0
        pOwnClone->m_aName      = m_aName;
391
0
        pOwnClone->m_nTabIndex  = m_nTabIndex;
392
0
        pOwnClone->m_nStep      = m_nStep;
393
0
        pOwnClone->m_aTag       = m_aTag;
394
395
396
        // Clone event container
397
0
        Reference< css::script::XScriptEventsSupplier > xEventsSupplier =
398
0
            static_cast< css::script::XScriptEventsSupplier* >( this );
399
400
0
        if( xEventsSupplier.is() )
401
0
        {
402
0
            Reference< XNameContainer > xEventCont = xEventsSupplier->getEvents();
403
0
            Reference< XNameContainer > xCloneEventCont = pOwnClone->getEvents();
404
405
0
            const css::uno::Sequence< OUString > aNames =
406
0
                xEventCont->getElementNames();
407
408
0
            for( const OUString& aName : aNames )
409
0
            {
410
0
                css::uno::Any aElement = xEventCont->getByName( aName );
411
0
                xCloneEventCont->insertByName( aName, aElement );
412
0
            }
413
0
        }
414
415
0
        return pOwnClone;
416
0
    }
417
418
419
    Reference< XNameContainer > SAL_CALL OGeometryControlModel_Base::getEvents()
420
0
    {
421
0
        if( !mxEventContainer.is() )
422
0
            mxEventContainer = new toolkit::ScriptEventContainer();
423
0
        return mxEventContainer;
424
0
    }
425
426
427
    void SAL_CALL OGeometryControlModel_Base::disposing()
428
0
    {
429
0
        OGCM_Base::disposing();
430
0
        OPropertySetAggregationHelper::disposing();
431
432
0
        if (auto xComp = query_aggregation<XComponent>(m_xAggregate))
433
0
            xComp->dispose();
434
0
    }
435
436
437
    //= OCommonGeometryControlModel
438
439
440
    typedef std::unordered_map< OUString, sal_Int32 > HashMapString2Int;
441
    typedef std::vector< css::uno::Sequence< css::beans::Property > >   PropSeqArray;
442
    typedef std::vector< ::std::vector< sal_Int32 > > IntArrayArray;
443
444
    // for creating class-unique PropertySetInfo's, we need some info:
445
    namespace { HashMapString2Int gServiceSpecifierMap; }
446
    // this one maps from a String, which is the service specifier for our
447
    // aggregate, to a unique id
448
449
    namespace { PropSeqArray gAggregateProperties; }
450
    // this one contains the properties which belong to all the unique ids
451
    // in ServiceSpecifierMap
452
453
    namespace { IntArrayArray gAmbiguousPropertyIds; }
454
    // the ids of the properties which we as well as our aggregate supply
455
    // For such props, we let our base class handle them, and whenever such
456
    // a prop is set, we forward this to our aggregate.
457
458
    // With this, we can ensure that two instances of this class share the
459
    // same PropertySetInfo if and only if both aggregates have the same
460
    // service specifier.
461
462
463
    OCommonGeometryControlModel::OCommonGeometryControlModel( Reference< XCloneable >& _rxAgg, OUString _aServiceSpecifier )
464
0
        :OGeometryControlModel_Base( _rxAgg )
465
0
        ,m_sServiceSpecifier(std::move( _aServiceSpecifier ))
466
0
        ,m_nPropertyMapId( 0 )
467
0
    {
468
0
        Reference< XPropertySetInfo > xPI;
469
0
        if ( m_xAggregateSet.is() )
470
0
            xPI = m_xAggregateSet->getPropertySetInfo();
471
0
        if ( !xPI.is() )
472
0
        {
473
0
            releaseAggregation();
474
0
            throw IllegalArgumentException();
475
0
        }
476
477
0
        HashMapString2Int::iterator aPropMapIdPos = gServiceSpecifierMap.find( m_sServiceSpecifier );
478
0
        if ( gServiceSpecifierMap.end() == aPropMapIdPos )
479
0
        {
480
0
            m_nPropertyMapId = gAggregateProperties.size();
481
0
            gAggregateProperties.push_back( xPI->getProperties() );
482
0
            gAmbiguousPropertyIds.emplace_back( );
483
484
0
            gServiceSpecifierMap[ m_sServiceSpecifier ] = m_nPropertyMapId;
485
0
        }
486
0
        else
487
0
            m_nPropertyMapId = aPropMapIdPos->second;
488
0
    }
489
490
    namespace {
491
492
    struct PropertyNameLess
493
    {
494
        bool operator()( const Property& _rLHS, const Property& _rRHS )
495
0
        {
496
0
            return _rLHS.Name < _rRHS.Name;
497
0
        }
498
    };
499
500
501
    struct PropertyNameEqual
502
    {
503
        const OUString&  m_rCompare;
504
0
        explicit PropertyNameEqual( const OUString& _rCompare ) : m_rCompare( _rCompare ) { }
505
506
        bool operator()( const Property& _rLHS )
507
0
        {
508
0
            return _rLHS.Name == m_rCompare;
509
0
        }
510
    };
511
512
    }
513
514
    ::cppu::IPropertyArrayHelper* OCommonGeometryControlModel::createArrayHelper( sal_Int32 _nId ) const
515
0
    {
516
0
        OSL_ENSURE( _nId == m_nPropertyMapId, "OCommonGeometryControlModel::createArrayHelper: invalid argument!" );
517
0
        OSL_ENSURE( _nId < static_cast<sal_Int32>(gAggregateProperties.size()), "OCommonGeometryControlModel::createArrayHelper: invalid status info (1)!" );
518
0
        OSL_ENSURE( _nId < static_cast<sal_Int32>(gAmbiguousPropertyIds.size()), "OCommonGeometryControlModel::createArrayHelper: invalid status info (2)!" );
519
520
        // our own properties
521
0
        Sequence< Property > aProps;
522
0
        OPropertyContainer::describeProperties( aProps );
523
524
        // the aggregate properties
525
0
        Sequence< Property > aAggregateProps = gAggregateProperties[ _nId ];
526
527
        // look for duplicates, and remember them
528
0
        IntArrayArray::value_type& rDuplicateIds = gAmbiguousPropertyIds[ _nId ];
529
        // for this, sort the aggregate properties
530
0
        auto [begin, end] = asNonConstRange(aAggregateProps);
531
0
        ::std::sort(
532
0
            begin,
533
0
            end,
534
0
            PropertyNameLess()
535
0
        );
536
537
        // now loop through our own props
538
0
        for (const Property& rProp : aProps)
539
0
        {
540
            // look for the current property in the properties of our aggregate
541
0
            const Property* pAggPropPos = ::std::find_if( std::cbegin(aAggregateProps), std::cend(aAggregateProps), PropertyNameEqual( rProp.Name ) );
542
0
            if ( pAggPropPos != std::cend(aAggregateProps) )
543
0
            {   // found a duplicate
544
                // -> remove from the aggregate property sequence
545
0
                ::comphelper::removeElementAt( aAggregateProps, pAggPropPos - std::cbegin(aAggregateProps) );
546
547
                // and additionally, remember the id of this property
548
0
                rDuplicateIds.push_back( rProp.Handle );
549
0
            }
550
0
        }
551
552
        // now, finally, sort the duplicates
553
0
        ::std::sort( rDuplicateIds.begin(), rDuplicateIds.end(), ::std::less< sal_Int32 >() );
554
555
0
        return new OPropertyArrayAggregationHelper(aProps, aAggregateProps);
556
0
    }
557
558
559
    ::cppu::IPropertyArrayHelper& SAL_CALL OCommonGeometryControlModel::getInfoHelper()
560
0
    {
561
0
        return *getArrayHelper( m_nPropertyMapId );
562
0
    }
563
564
565
    rtl::Reference<OGeometryControlModel_Base> OCommonGeometryControlModel::createClone_Impl( Reference< XCloneable >& _rxAggregateInstance )
566
0
    {
567
0
        return new OCommonGeometryControlModel( _rxAggregateInstance, m_sServiceSpecifier );
568
0
    }
569
570
    Sequence< sal_Int8 > SAL_CALL OCommonGeometryControlModel::getImplementationId(  )
571
0
    {
572
0
        return css::uno::Sequence<sal_Int8>();
573
0
    }
574
575
    namespace {
576
577
    struct Int32Equal
578
    {
579
        sal_Int32   m_nCompare;
580
0
        explicit Int32Equal( sal_Int32 _nCompare ) : m_nCompare( _nCompare ) { }
581
582
        bool operator()( sal_Int32 _nLHS )
583
0
        {
584
0
            return _nLHS == m_nCompare;
585
0
        }
586
    };
587
588
    }
589
590
    void SAL_CALL OCommonGeometryControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue )
591
0
    {
592
0
        OGeometryControlModel_Base::setFastPropertyValue_NoBroadcast( _nHandle, _rValue );
593
594
        // look if this id is one we recognized as duplicate
595
0
        IntArrayArray::value_type& rDuplicateIds = gAmbiguousPropertyIds[ m_nPropertyMapId ];
596
597
0
        if ( std::any_of(rDuplicateIds.begin(), rDuplicateIds.end(), Int32Equal( _nHandle )) )
598
0
        {
599
            // yes, it is such a property
600
0
            OUString sPropName;
601
0
            sal_Int16 nAttributes(0);
602
0
            static_cast< OPropertyArrayAggregationHelper* >( getArrayHelper( m_nPropertyMapId ) )->fillPropertyMembersByHandle( &sPropName, &nAttributes, _nHandle );
603
604
0
            if ( m_xAggregateSet.is() && !sPropName.isEmpty() )
605
0
                m_xAggregateSet->setPropertyValue( sPropName, _rValue );
606
0
        }
607
0
    }
608
609
610
// }    // namespace toolkit
611
612
613
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */