Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/comphelper/source/property/propagg.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 <comphelper/propagg.hxx>
21
#include <comphelper/property.hxx>
22
#include <comphelper/sequence.hxx>
23
#include <cppuhelper/queryinterface.hxx>
24
#include <osl/diagnose.h>
25
#include <sal/log.hxx>
26
#include <com/sun/star/beans/PropertyAttribute.hpp>
27
#include <o3tl/sorted_vector.hxx>
28
#include <typeinfo>
29
#include <algorithm>
30
#include <cstddef>
31
#include <unordered_set>
32
#include <memory>
33
34
35
namespace comphelper
36
{
37
38
39
    using namespace ::com::sun::star::uno;
40
    using namespace ::com::sun::star::lang;
41
    using namespace ::com::sun::star::beans;
42
43
    using namespace internal;
44
45
46
    namespace
47
    {
48
        const Property* lcl_findPropertyByName( const std::vector< Property >& _rProps, const OUString& _rName )
49
0
        {
50
0
            Property aNameProp(_rName, 0, Type(), 0);
51
0
            auto pResult = std::lower_bound(_rProps.begin(), _rProps.end(), aNameProp, PropertyCompareByName());
52
0
            if ( pResult == _rProps.end() || pResult->Name != _rName )
53
0
                return nullptr;
54
55
0
            return &*pResult;
56
0
        }
57
    }
58
59
OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper(
60
        const  Sequence< Property >& _rProperties, const  Sequence< Property >& _rAggProperties,
61
        IPropertyInfoService* _pInfoService, sal_Int32 _nFirstAggregateId )
62
0
{
63
    // if properties are present both at the delegatee and the aggregate, then the former are supposed to win
64
    // merge and sort properties by name, delete duplicates (stable sort ensures delegator properties win)
65
0
    m_aProperties.insert( m_aProperties.end(), _rProperties.begin(), _rProperties.end() );
66
0
    m_aProperties.insert( m_aProperties.end(), _rAggProperties.begin(), _rAggProperties.end() );
67
0
    std::stable_sort( m_aProperties.begin(), m_aProperties.end(), PropertyCompareByName() );
68
0
    m_aProperties.erase( std::unique(m_aProperties.begin(), m_aProperties.end(),
69
0
        []( const css::beans::Property& x, const css::beans::Property& y ) -> bool { return x.Name == y.Name; } ),
70
0
        m_aProperties.end() );
71
0
    m_aProperties.shrink_to_fit();
72
73
    // fill aDelegatorProps with names from _rProperties for a fast existence check
74
    // different kinds of properties are processed differently
75
0
    std::unordered_set< OUString > aDelegatorProps;
76
0
    aDelegatorProps.reserve( _rProperties.getLength() );
77
0
    for( auto &delegateProp: _rProperties )
78
0
    {
79
0
        const auto inserted = aDelegatorProps.insert( delegateProp.Name );
80
0
        OSL_ENSURE( inserted.second,
81
0
            "OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper: duplicate delegatee property!" );
82
0
    }
83
84
0
    std::unordered_set< sal_Int32 > existingHandles;
85
0
    existingHandles.reserve( m_aProperties.size() );
86
0
    sal_Int32 nAggregateHandle = _nFirstAggregateId;
87
0
    for ( std::size_t nMPLoop = 0; nMPLoop < m_aProperties.size(); ++nMPLoop )
88
0
    {
89
0
        auto &prop = m_aProperties[ nMPLoop ];
90
0
        if ( aDelegatorProps.find( prop.Name ) != aDelegatorProps.end() )
91
0
        {
92
0
            m_aPropertyAccessors.insert_or_assign(
93
0
                prop.Handle, OPropertyAccessor( -1, nMPLoop, false ));
94
0
            existingHandles.insert( prop.Handle );
95
0
        }
96
0
        else
97
0
        {
98
            // determine the handle for the property which we will expose to the outside world
99
0
            sal_Int32 nHandle = -1;
100
            // ask the info service first
101
0
            if ( _pInfoService )
102
0
                nHandle = _pInfoService->getPreferredPropertyId( prop.Name );
103
104
0
            if ( ( -1 == nHandle ) || ( existingHandles.find( nHandle ) != existingHandles.end() ) )
105
0
            {
106
                // 1. no handle from the info service -> default
107
                // 2. conflicts -> use another one (which we don't check anymore, assuming _nFirstAggregateId was large enough)
108
0
                nHandle = nAggregateHandle++;
109
0
            }
110
0
            else
111
0
            {
112
0
                existingHandles.insert( nHandle );
113
0
            }
114
115
            // remember the accessor for this property
116
0
            m_aPropertyAccessors.insert_or_assign(
117
0
                nHandle, OPropertyAccessor( prop.Handle, nMPLoop, true ));
118
0
            prop.Handle = nHandle;
119
0
        }
120
0
    }
121
0
}
122
123
124
OPropertyArrayAggregationHelper::PropertyOrigin OPropertyArrayAggregationHelper::classifyProperty( const OUString& _rName )
125
0
{
126
0
    PropertyOrigin eOrigin = PropertyOrigin::Unknown;
127
    // look up the name
128
0
    const Property* pPropertyDescriptor = lcl_findPropertyByName( m_aProperties, _rName );
129
0
    if ( pPropertyDescriptor )
130
0
    {
131
        // look up the handle for this name
132
0
        auto aPos = m_aPropertyAccessors.find( pPropertyDescriptor->Handle );
133
0
        OSL_ENSURE( m_aPropertyAccessors.end() != aPos, "OPropertyArrayAggregationHelper::classifyProperty: should have this handle in my map!" );
134
0
        if ( m_aPropertyAccessors.end() != aPos )
135
0
        {
136
0
            eOrigin = aPos->second.bAggregate ? PropertyOrigin::Aggregate : PropertyOrigin::Delegator;
137
0
        }
138
0
    }
139
0
    return eOrigin;
140
0
}
141
142
143
Property OPropertyArrayAggregationHelper::getPropertyByName( const OUString& _rPropertyName )
144
0
{
145
0
    const Property* pProperty = findPropertyByName( _rPropertyName );
146
147
0
    if ( !pProperty )
148
0
        throw  UnknownPropertyException(_rPropertyName);
149
150
0
    return *pProperty;
151
0
}
152
153
154
sal_Bool OPropertyArrayAggregationHelper::hasPropertyByName(const OUString& _rPropertyName)
155
0
{
156
0
    return nullptr != findPropertyByName( _rPropertyName );
157
0
}
158
159
160
const Property* OPropertyArrayAggregationHelper::findPropertyByName(const OUString& _rName ) const
161
0
{
162
0
    return lcl_findPropertyByName( m_aProperties, _rName );
163
0
}
164
165
166
sal_Int32 OPropertyArrayAggregationHelper::getHandleByName(const OUString& _rPropertyName)
167
0
{
168
0
    const Property* pProperty = findPropertyByName( _rPropertyName );
169
0
    return pProperty ? pProperty->Handle : -1;
170
0
}
171
172
173
sal_Bool OPropertyArrayAggregationHelper::fillPropertyMembersByHandle(
174
            OUString* _pPropName, sal_Int16* _pAttributes, sal_Int32 _nHandle)
175
0
{
176
0
    auto i = m_aPropertyAccessors.find(_nHandle);
177
0
    bool bRet = i != m_aPropertyAccessors.end();
178
0
    if (bRet)
179
0
    {
180
0
        const css::beans::Property& rProperty = m_aProperties[(*i).second.nPos];
181
0
        if (_pPropName)
182
0
            *_pPropName = rProperty.Name;
183
0
        if (_pAttributes)
184
0
            *_pAttributes = rProperty.Attributes;
185
0
    }
186
0
    return bRet;
187
0
}
188
189
190
bool OPropertyArrayAggregationHelper::getPropertyByHandle( sal_Int32 _nHandle, Property& _rProperty ) const
191
0
{
192
0
    auto pos = m_aPropertyAccessors.find(_nHandle);
193
0
    if ( pos != m_aPropertyAccessors.end() )
194
0
    {
195
0
        _rProperty = m_aProperties[ pos->second.nPos ];
196
0
        return true;
197
0
    }
198
0
    return false;
199
0
}
200
201
202
bool OPropertyArrayAggregationHelper::fillAggregatePropertyInfoByHandle(
203
            OUString* _pPropName, sal_Int32* _pOriginalHandle, sal_Int32 _nHandle) const
204
0
{
205
0
    auto i = m_aPropertyAccessors.find(_nHandle);
206
0
    bool bRet = i != m_aPropertyAccessors.end() && (*i).second.bAggregate;
207
0
    if (bRet)
208
0
    {
209
0
        if (_pOriginalHandle)
210
0
            *_pOriginalHandle = (*i).second.nOriginalHandle;
211
0
        if (_pPropName)
212
0
        {
213
0
            OSL_ENSURE((*i).second.nPos < m_aProperties.size(),"Invalid index for sequence!");
214
0
            const css::beans::Property& rProperty = m_aProperties[(*i).second.nPos];
215
0
            *_pPropName = rProperty.Name;
216
0
        }
217
0
    }
218
0
    return bRet;
219
0
}
220
221
222
css::uno::Sequence< css::beans::Property> OPropertyArrayAggregationHelper::getProperties()
223
0
{
224
0
    return comphelper::containerToSequence(m_aProperties);
225
0
}
226
227
228
sal_Int32 OPropertyArrayAggregationHelper::fillHandles(
229
        sal_Int32* _pHandles, const css::uno::Sequence< OUString >& _rPropNames )
230
0
{
231
0
    sal_Int32 nHitCount = 0;
232
233
0
    Property aNameProp;
234
0
    for (sal_Int32 i = 0; i < _rPropNames.getLength(); ++i)
235
0
    {
236
0
        aNameProp.Name = _rPropNames[i];
237
0
        auto findIter = std::lower_bound(m_aProperties.begin(), m_aProperties.end(), aNameProp, PropertyCompareByName());
238
0
        if (findIter != m_aProperties.end() && findIter->Name == _rPropNames[i])
239
0
        {
240
0
            _pHandles[i] = findIter->Handle;
241
0
            nHitCount++;
242
0
        }
243
0
    }
244
0
    return nHitCount;
245
0
}
246
247
namespace internal
248
{
249
    class PropertyForwarder
250
    {
251
    private:
252
        OPropertySetAggregationHelper&  m_rAggregationHelper;
253
        o3tl::sorted_vector< sal_Int32 > m_aProperties;
254
        sal_Int32                       m_nCurrentlyForwarding;
255
256
    public:
257
        explicit PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper );
258
259
        /** declares that the forwarder should be responsible for the given property
260
261
        @param _nHandle
262
            the public handle (<em>not</em> the original handle!) of the property
263
        */
264
        void    takeResponsibilityFor( sal_Int32 _nHandle );
265
266
        /** checks whether the forwarder is responsible for the given property
267
        */
268
        bool    isResponsibleFor( sal_Int32 _nHandle ) const;
269
270
        /// actually forwards a property value to the aggregate
271
        ///
272
        /// @throws Exception
273
        void    doForward( sal_Int32 _nHandle, const Any& _rValue );
274
275
0
        sal_Int32 getCurrentlyForwardedProperty( ) const { return m_nCurrentlyForwarding; }
276
    };
277
278
279
    PropertyForwarder::PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper )
280
0
        :m_rAggregationHelper( _rAggregationHelper )
281
0
        ,m_nCurrentlyForwarding( -1 )
282
0
    {
283
0
    }
284
285
286
    void PropertyForwarder::takeResponsibilityFor( sal_Int32 _nHandle )
287
0
    {
288
0
        m_aProperties.insert( _nHandle );
289
0
    }
290
291
292
    bool PropertyForwarder::isResponsibleFor( sal_Int32 _nHandle ) const
293
0
    {
294
0
        return m_aProperties.find( _nHandle ) != m_aProperties.end();
295
0
    }
296
297
298
    void PropertyForwarder::doForward( sal_Int32 _nHandle, const Any& _rValue )
299
0
    {
300
0
        OSL_ENSURE( m_rAggregationHelper.m_xAggregateSet.is(), "PropertyForwarder::doForward: no property set!" );
301
0
        if ( !m_rAggregationHelper.m_xAggregateSet.is() )
302
0
            return;
303
304
0
        m_rAggregationHelper.forwardingPropertyValue( _nHandle );
305
306
0
        OSL_ENSURE( m_nCurrentlyForwarding == -1, "PropertyForwarder::doForward: reentrance?" );
307
0
        m_nCurrentlyForwarding = _nHandle;
308
309
0
        try
310
0
        {
311
0
            m_rAggregationHelper.m_xAggregateSet->setPropertyValue( m_rAggregationHelper.getPropertyName( _nHandle ), _rValue );
312
                // TODO: cache the property name? (it's a O(log n) search)
313
0
        }
314
0
        catch( const Exception& )
315
0
        {
316
0
            m_rAggregationHelper.forwardedPropertyValue( _nHandle );
317
0
            throw;
318
0
        }
319
320
0
        m_nCurrentlyForwarding = -1;
321
322
0
        m_rAggregationHelper.forwardedPropertyValue( _nHandle );
323
0
    }
324
}
325
326
OPropertySetAggregationHelper::OPropertySetAggregationHelper( ::cppu::OBroadcastHelper& rBHlp )
327
0
    :OPropertyStateHelper( rBHlp )
328
0
    ,m_bListening( false )
329
0
{
330
0
    m_pForwarder.reset( new PropertyForwarder( *this ) );
331
0
}
332
333
334
OPropertySetAggregationHelper::~OPropertySetAggregationHelper()
335
0
{
336
0
}
337
338
339
css::uno::Any SAL_CALL OPropertySetAggregationHelper::queryInterface(const  css::uno::Type& _rType)
340
0
{
341
0
    css::uno::Any aReturn = OPropertyStateHelper::queryInterface(_rType);
342
343
0
    if ( !aReturn.hasValue() )
344
0
        aReturn = cppu::queryInterface(_rType
345
0
        ,static_cast< css::beans::XPropertiesChangeListener*>(this)
346
0
        ,static_cast< css::beans::XVetoableChangeListener*>(this)
347
0
        ,static_cast< css::lang::XEventListener*>(static_cast< css::beans::XPropertiesChangeListener*>(this))
348
0
        );
349
350
0
    return aReturn;
351
0
}
352
353
354
void OPropertySetAggregationHelper::disposing()
355
0
{
356
0
    osl::MutexGuard aGuard(rBHelper.rMutex);
357
358
0
    if ( m_xAggregateSet.is() && m_bListening )
359
0
    {
360
        // register as a single listener
361
0
        m_xAggregateMultiSet->removePropertiesChangeListener(this);
362
0
        m_xAggregateSet->removeVetoableChangeListener(OUString(), this);
363
0
        m_bListening = false;
364
0
    }
365
366
0
    OPropertyStateHelper::disposing();
367
0
}
368
369
370
void SAL_CALL OPropertySetAggregationHelper::disposing(const css::lang::EventObject& _rSource)
371
0
{
372
0
    OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::disposing : don't have an aggregate anymore !");
373
0
    if (_rSource.Source == m_xAggregateSet)
374
0
        m_bListening = false;
375
0
}
376
377
378
void SAL_CALL OPropertySetAggregationHelper::propertiesChange(const css::uno::Sequence< css::beans::PropertyChangeEvent>& _rEvents)
379
0
{
380
0
    OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::propertiesChange : have no aggregate !");
381
382
0
    sal_Int32 nLen = _rEvents.getLength();
383
0
    cppu::IPropertyArrayHelper& rPH = getInfoHelper();
384
385
0
    if (1 == nLen)
386
0
    {
387
0
        const css::beans::PropertyChangeEvent& evt = _rEvents[0];
388
0
        OSL_ENSURE(!evt.PropertyName.isEmpty(), "OPropertySetAggregationHelper::propertiesChange : invalid event !");
389
            // we had a bug where this assertion would have us saved a whole day :) (72514)
390
0
        sal_Int32 nHandle = rPH.getHandleByName( evt.PropertyName );
391
392
        // If nHandle is -1 the event marks a (aggregate) property which we hide to callers
393
        // If isCurrentlyForwardingProperty( nHandle ) is <TRUE/>, then we ourself triggered
394
        // setting this property. In this case, it will be notified later (by the OPropertySetHelper
395
        // implementation)
396
397
0
        if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
398
0
            fire(&nHandle, &evt.NewValue, &evt.OldValue, 1, false);
399
0
    }
400
0
    else
401
0
    {
402
0
        std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nLen]);
403
0
        std::unique_ptr< css::uno::Any[]> pNewValues(new css::uno::Any[nLen]);
404
0
        std::unique_ptr< css::uno::Any[]> pOldValues(new css::uno::Any[nLen]);
405
406
0
        sal_Int32 nDest = 0;
407
0
        for (const css::beans::PropertyChangeEvent& rEvent : _rEvents)
408
0
        {
409
0
            sal_Int32 nHandle = rPH.getHandleByName(rEvent.PropertyName);
410
0
            if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
411
0
            {   // same as above : -1 is valid (73247) ...
412
0
                pHandles[nDest] = nHandle;
413
0
                pNewValues[nDest] = rEvent.NewValue;
414
0
                pOldValues[nDest] = rEvent.OldValue;
415
0
                ++nDest;
416
0
            }
417
0
        }
418
419
0
        if (nDest)
420
0
            fire(pHandles.get(), pNewValues.get(), pOldValues.get(), nDest, false);
421
0
    }
422
0
}
423
424
425
void SAL_CALL OPropertySetAggregationHelper::vetoableChange(const css::beans::PropertyChangeEvent& _rEvent)
426
0
{
427
0
    OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::vetoableChange : have no aggregate !");
428
429
0
    cppu::IPropertyArrayHelper& rPH = getInfoHelper();
430
431
0
    sal_Int32 nHandle = rPH.getHandleByName(_rEvent.PropertyName);
432
0
    fire(&nHandle, &_rEvent.NewValue, &_rEvent.OldValue, 1, true);
433
0
}
434
435
436
void OPropertySetAggregationHelper::setAggregation(const css::uno::Reference<  css::uno::XInterface >& _rxDelegate)
437
0
{
438
0
    osl::MutexGuard aGuard(rBHelper.rMutex);
439
440
0
    if (m_bListening && m_xAggregateSet.is())
441
0
    {
442
0
        m_xAggregateMultiSet->removePropertiesChangeListener(this);
443
0
        m_xAggregateSet->removeVetoableChangeListener(OUString(), this);
444
0
        m_bListening = false;
445
0
    }
446
447
0
    m_xAggregateState.set(_rxDelegate, css::uno::UNO_QUERY);
448
0
    m_xAggregateSet.set(_rxDelegate, css::uno::UNO_QUERY);
449
0
    m_xAggregateMultiSet.set(_rxDelegate, css::uno::UNO_QUERY);
450
0
    m_xAggregateFastSet.set(_rxDelegate, css::uno::UNO_QUERY);
451
452
    // must support XPropertySet and XMultiPropertySet
453
0
    if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() )
454
0
        throw  css::lang::IllegalArgumentException();
455
0
}
456
457
458
void OPropertySetAggregationHelper::startListening()
459
0
{
460
0
    osl::MutexGuard aGuard(rBHelper.rMutex);
461
462
0
    if (!m_bListening && m_xAggregateSet.is())
463
0
    {
464
        // register as a single listener
465
0
        css::uno::Sequence< OUString > aPropertyNames;
466
0
        m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this);
467
0
        m_xAggregateSet->addVetoableChangeListener(OUString(), this);
468
469
0
        m_bListening = true;
470
0
    }
471
0
}
472
473
474
void SAL_CALL OPropertySetAggregationHelper::addVetoableChangeListener(const OUString& _rPropertyName,
475
                                                                       const  css::uno::Reference< css::beans::XVetoableChangeListener>& _rxListener)
476
0
{
477
0
    OPropertySetHelper::addVetoableChangeListener(_rPropertyName, _rxListener);
478
0
    if (!m_bListening)
479
0
        startListening();
480
0
}
481
482
483
void SAL_CALL OPropertySetAggregationHelper::addPropertyChangeListener(const OUString& _rPropertyName,
484
                                                                       const css::uno::Reference< css::beans::XPropertyChangeListener>& _rxListener)
485
0
{
486
0
    OPropertySetHelper::addPropertyChangeListener(_rPropertyName, _rxListener);
487
0
    if (!m_bListening)
488
0
        startListening();
489
0
}
490
491
492
void SAL_CALL OPropertySetAggregationHelper::addPropertiesChangeListener(const css::uno::Sequence< OUString >& _rPropertyNames,
493
                                                                         const css::uno::Reference< css::beans::XPropertiesChangeListener>& _rxListener)
494
0
{
495
0
    OPropertySetHelper::addPropertiesChangeListener(_rPropertyNames, _rxListener);
496
0
    if (!m_bListening)
497
0
        startListening();
498
0
}
499
500
501
sal_Int32 OPropertySetAggregationHelper::getOriginalHandle(sal_Int32 nHandle) const
502
0
{
503
0
    OPropertyArrayAggregationHelper& rPH = static_cast<OPropertyArrayAggregationHelper&>( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
504
0
    sal_Int32 nOriginalHandle = -1;
505
0
    (void)rPH.fillAggregatePropertyInfoByHandle(nullptr, &nOriginalHandle, nHandle);
506
0
    return nOriginalHandle;
507
0
}
508
509
510
OUString OPropertySetAggregationHelper::getPropertyName( sal_Int32 _nHandle ) const
511
0
{
512
0
    OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
513
0
    Property aProperty;
514
0
    OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
515
0
    return aProperty.Name;
516
0
}
517
518
519
void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue(sal_Int32 _nHandle, const  css::uno::Any& _rValue)
520
0
{
521
0
    OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
522
0
    OUString aPropName;
523
0
    sal_Int32   nOriginalHandle = -1;
524
525
    // does the handle belong to the aggregation ?
526
0
    if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, _nHandle))
527
0
        if (m_xAggregateFastSet.is())
528
0
            m_xAggregateFastSet->setFastPropertyValue(nOriginalHandle, _rValue);
529
0
        else
530
0
            m_xAggregateSet->setPropertyValue(aPropName, _rValue);
531
0
    else
532
0
        OPropertySetHelper::setFastPropertyValue(_nHandle, _rValue);
533
0
}
534
535
536
void OPropertySetAggregationHelper::getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle) const
537
0
{
538
0
    OPropertyArrayAggregationHelper& rPH = static_cast<OPropertyArrayAggregationHelper&>( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
539
0
    OUString aPropName;
540
0
    sal_Int32   nOriginalHandle = -1;
541
542
0
    if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
543
0
    {
544
0
        if (m_xAggregateFastSet.is())
545
0
            rValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
546
0
        else
547
0
            rValue = m_xAggregateSet->getPropertyValue(aPropName);
548
0
    }
549
0
    else if ( m_pForwarder->isResponsibleFor( nHandle ) )
550
0
    {
551
        // this is a property which has been "overwritten" in our instance (thus
552
        // fillAggregatePropertyInfoByHandle didn't find it)
553
0
        rValue = m_xAggregateSet->getPropertyValue( getPropertyName( nHandle ) );
554
0
    }
555
0
}
556
557
558
css::uno::Any SAL_CALL OPropertySetAggregationHelper::getFastPropertyValue(sal_Int32 nHandle)
559
0
{
560
0
    OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
561
0
    OUString aPropName;
562
0
    sal_Int32   nOriginalHandle = -1;
563
0
    css::uno::Any  aValue;
564
565
0
    if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
566
0
    {
567
0
        if (m_xAggregateFastSet.is())
568
0
            aValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
569
0
        else
570
0
            aValue = m_xAggregateSet->getPropertyValue(aPropName);
571
0
    }
572
0
    else
573
0
        aValue = OPropertySetHelper::getFastPropertyValue(nHandle);
574
575
0
    return aValue;
576
0
}
577
578
579
void SAL_CALL OPropertySetAggregationHelper::setPropertyValues(
580
        const Sequence< OUString >& _rPropertyNames, const Sequence< Any >& _rValues )
581
0
{
582
0
    OSL_ENSURE( !rBHelper.bInDispose, "OPropertySetAggregationHelper::setPropertyValues : do not use within the dispose call !");
583
0
    OSL_ENSURE( !rBHelper.bDisposed, "OPropertySetAggregationHelper::setPropertyValues : object is disposed" );
584
585
    // check where the properties come from
586
0
    if (!m_xAggregateSet.is())
587
0
        OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
588
0
    else if (_rPropertyNames.getLength() == 1) // use the more efficient way
589
0
    {
590
0
        if (_rValues.getLength() != 1)
591
0
            throw IllegalArgumentException(u"lengths do not match"_ustr, static_cast<XPropertySet*>(this),
592
0
                                           -1);
593
0
        try
594
0
        {
595
0
            setPropertyValue( _rPropertyNames[0], _rValues[0] );
596
0
        }
597
0
        catch( const UnknownPropertyException& )
598
0
        {
599
            // by definition of XMultiPropertySet::setPropertyValues, unknown properties are to be ignored
600
0
            SAL_WARN( "comphelper", "OPropertySetAggregationHelper::setPropertyValues: unknown property: '"
601
0
                    << _rPropertyNames[0] << "', implementation: " << typeid( *this ).name() );
602
0
        }
603
0
    }
604
0
    else
605
0
    {
606
0
        OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
607
608
        // determine which properties belong to the aggregate, and which ones to the delegator
609
0
        sal_Int32 nAggCount(0);
610
0
        sal_Int32 nLen(_rPropertyNames.getLength());
611
612
0
        for ( const OUString& rName : _rPropertyNames )
613
0
        {
614
0
            OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( rName );
615
0
            if ( OPropertyArrayAggregationHelper::PropertyOrigin::Unknown == ePropOrg )
616
0
                throw WrappedTargetException( OUString(), static_cast< XMultiPropertySet* >( this ), Any( UnknownPropertyException( ) ) );
617
                // due to a flaw in the API design, this method is not allowed to throw an UnknownPropertyException
618
                // so we wrap it into a WrappedTargetException
619
620
0
            if ( OPropertyArrayAggregationHelper::PropertyOrigin::Aggregate == ePropOrg )
621
0
                ++nAggCount;
622
0
        }
623
624
        // all properties belong to the aggregate
625
0
        if (nAggCount == nLen)
626
0
            m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues);
627
628
        // all properties belong to the aggregating object
629
0
        else if (nAggCount == 0)
630
0
            OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
631
632
        // mixed
633
0
        else
634
0
        {
635
0
            if (_rValues.getLength() != nLen)
636
0
                throw IllegalArgumentException(u"lengths do not match"_ustr,
637
0
                                               static_cast<XPropertySet*>(this), -1);
638
639
            // aggregate's names
640
0
            Sequence< OUString > AggPropertyNames( nAggCount );
641
0
            OUString* pAggNames = AggPropertyNames.getArray();
642
            // aggregate's values
643
0
            Sequence< Any >  AggValues( nAggCount );
644
0
            Any* pAggValues = AggValues.getArray();
645
646
            // delegator names
647
0
            Sequence< OUString > DelPropertyNames( nLen - nAggCount );
648
0
            OUString* pDelNames = DelPropertyNames.getArray();
649
650
            // delegator values
651
0
            Sequence< Any > DelValues( nLen - nAggCount );
652
0
            Any* pDelValues = DelValues.getArray();
653
654
0
            for (sal_Int32 i = 0; i < nLen; ++i)
655
0
            {
656
0
                if ( OPropertyArrayAggregationHelper::PropertyOrigin::Aggregate == rPH.classifyProperty( _rPropertyNames[i] ) )
657
0
                {
658
0
                    *pAggNames++ = _rPropertyNames[i];
659
0
                    *pAggValues++ = _rValues[i];
660
0
                }
661
0
                else
662
0
                {
663
0
                    *pDelNames++ = _rPropertyNames[i];
664
0
                    *pDelValues++ = _rValues[i];
665
0
                }
666
0
            }
667
668
0
            std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[ nLen - nAggCount ]);
669
670
            // get the map table
671
0
            cppu::IPropertyArrayHelper& rPH2 = getInfoHelper();
672
673
            // fill the handle array
674
0
            sal_Int32 nHitCount = rPH2.fillHandles( pHandles.get(), DelPropertyNames );
675
0
            if (nHitCount != 0)
676
0
            {
677
0
                std::unique_ptr< css::uno::Any[]> pConvertedValues(new  css::uno::Any[ nHitCount ]);
678
0
                std::unique_ptr< css::uno::Any[]> pOldValues(new  css::uno::Any[ nHitCount ]);
679
0
                nHitCount = 0;
680
0
                sal_Int32 i;
681
682
0
                {
683
                // must lock the mutex outside the loop. So all values are consistent.
684
0
                    osl::MutexGuard aGuard( rBHelper.rMutex );
685
0
                    for( i = 0; i < (nLen - nAggCount); ++i )
686
0
                    {
687
0
                        if( pHandles[i] != -1 )
688
0
                        {
689
0
                            sal_Int16 nAttributes;
690
0
                            rPH2.fillPropertyMembersByHandle( nullptr, &nAttributes, pHandles[i] );
691
0
                            if( nAttributes & css::beans::PropertyAttribute::READONLY )
692
0
                                throw css::beans::PropertyVetoException();
693
                            // Will the property change?
694
0
                            if( convertFastPropertyValue( pConvertedValues[ nHitCount ], pOldValues[nHitCount],
695
0
                                                        pHandles[i], DelValues[i] ) )
696
0
                            {
697
                                // only increment if the property really change
698
0
                                pHandles[nHitCount]         = pHandles[i];
699
0
                                nHitCount++;
700
0
                            }
701
0
                        }
702
0
                    }
703
                // release guard to fire events
704
0
                }
705
706
                // fire vetoable events
707
0
                fire( pHandles.get(), pConvertedValues.get(), pOldValues.get(), nHitCount, true );
708
709
                // setting the agg Properties
710
0
                m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
711
712
0
                {
713
                // must lock the mutex outside the loop.
714
0
                    osl::MutexGuard aGuard( rBHelper.rMutex );
715
                    // Loop over all changed properties
716
0
                    for( i = 0; i < nHitCount; i++ )
717
0
                    {
718
                        // Will the property change?
719
0
                        setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
720
0
                    }
721
                // release guard to fire events
722
0
                }
723
724
                // fire change events
725
0
                fire( pHandles.get(), pConvertedValues.get(), pOldValues.get(), nHitCount, false );
726
0
            }
727
0
            else
728
0
                m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
729
0
        }
730
0
    }
731
0
}
732
733
// XPropertyState
734
735
css::beans::PropertyState SAL_CALL OPropertySetAggregationHelper::getPropertyState(const OUString& _rPropertyName)
736
0
{
737
0
    OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
738
0
    sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName );
739
740
0
    if (nHandle == -1)
741
0
    {
742
0
        throw css::beans::UnknownPropertyException(_rPropertyName);
743
0
    }
744
745
0
    OUString aPropName;
746
0
    sal_Int32   nOriginalHandle = -1;
747
0
    if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
748
0
    {
749
0
        if (m_xAggregateState.is())
750
0
            return m_xAggregateState->getPropertyState(_rPropertyName);
751
0
        else
752
0
            return css::beans::PropertyState_DIRECT_VALUE;
753
0
    }
754
0
    else
755
0
        return getPropertyStateByHandle(nHandle);
756
0
}
757
758
759
void SAL_CALL OPropertySetAggregationHelper::setPropertyToDefault(const OUString& _rPropertyName)
760
0
{
761
0
    OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
762
0
    sal_Int32 nHandle = rPH.getHandleByName(_rPropertyName);
763
0
    if (nHandle == -1)
764
0
    {
765
0
        throw css::beans::UnknownPropertyException(_rPropertyName);
766
0
    }
767
768
0
    OUString aPropName;
769
0
    sal_Int32   nOriginalHandle = -1;
770
0
    if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
771
0
    {
772
0
        if (m_xAggregateState.is())
773
0
            m_xAggregateState->setPropertyToDefault(_rPropertyName);
774
0
    }
775
0
    else
776
0
    {
777
0
        try
778
0
        {
779
0
            setPropertyToDefaultByHandle( nHandle );
780
0
        }
781
0
        catch( const UnknownPropertyException& ) { throw; }
782
0
        catch( const RuntimeException& ) { throw; }
783
0
        catch( const Exception& )
784
0
        {
785
0
            OSL_FAIL( "OPropertySetAggregationHelper::setPropertyToDefault: caught an exception which is not allowed to leave here!" );
786
0
        }
787
0
    }
788
0
}
789
790
791
css::uno::Any SAL_CALL OPropertySetAggregationHelper::getPropertyDefault(const OUString& aPropertyName)
792
0
{
793
0
    OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
794
0
    sal_Int32 nHandle = rPH.getHandleByName( aPropertyName );
795
796
0
    if ( nHandle == -1 )
797
0
        throw css::beans::UnknownPropertyException(aPropertyName);
798
799
0
    OUString aPropName;
800
0
    sal_Int32   nOriginalHandle = -1;
801
0
    if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
802
0
    {
803
0
        if (m_xAggregateState.is())
804
0
            return m_xAggregateState->getPropertyDefault(aPropertyName);
805
0
        else
806
0
            return css::uno::Any();
807
0
    }
808
0
    else
809
0
        return getPropertyDefaultByHandle(nHandle);
810
0
}
811
812
sal_Bool SAL_CALL OPropertySetAggregationHelper::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue )
813
0
{
814
0
    bool bModified = false;
815
816
0
    OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::convertFastPropertyValue: this is no forwarded property - did you use declareForwardedProperty for it?" );
817
0
    if ( m_pForwarder->isResponsibleFor( _nHandle ) )
818
0
    {
819
        // need to determine the type of the property for conversion
820
0
        OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
821
0
        Property aProperty;
822
0
        OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
823
824
0
        Any aCurrentValue;
825
0
        getFastPropertyValue( aCurrentValue, _nHandle );
826
0
        bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, aCurrentValue, aProperty.Type );
827
0
    }
828
829
0
    return bModified;
830
0
}
831
832
void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue )
833
0
{
834
0
    OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast: this is no forwarded property - did you use declareForwardedProperty for it?" );
835
0
    if ( m_pForwarder->isResponsibleFor( _nHandle ) )
836
0
        m_pForwarder->doForward( _nHandle, _rValue );
837
0
}
838
839
840
void OPropertySetAggregationHelper::declareForwardedProperty( sal_Int32 _nHandle )
841
0
{
842
0
    OSL_ENSURE( !m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::declareForwardedProperty: already declared!" );
843
0
    m_pForwarder->takeResponsibilityFor( _nHandle );
844
0
}
845
846
847
void OPropertySetAggregationHelper::forwardingPropertyValue( sal_Int32 )
848
0
{
849
    // not interested in
850
0
}
851
852
853
void OPropertySetAggregationHelper::forwardedPropertyValue( sal_Int32 )
854
0
{
855
    // not interested in
856
0
}
857
858
859
bool OPropertySetAggregationHelper::isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const
860
0
{
861
0
    return m_pForwarder->getCurrentlyForwardedProperty() == _nHandle;
862
0
}
863
864
865
}   // namespace comphelper
866
867
868
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */