Simplify a bit
[LibreOffice.git] / comphelper / source / property / propagg.cxx
blob5acf8a1dc2d5d1be728de551913f53d0a829e414
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
35 namespace comphelper
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::lang;
41 using namespace ::com::sun::star::beans;
43 using namespace internal;
46 namespace
48 const Property* lcl_findPropertyByName( const std::vector< Property >& _rProps, const OUString& _rName )
50 Property aNameProp(_rName, 0, Type(), 0);
51 auto pResult = std::lower_bound(_rProps.begin(), _rProps.end(), aNameProp, PropertyCompareByName());
52 if ( pResult == _rProps.end() || pResult->Name != _rName )
53 return nullptr;
55 return &*pResult;
59 OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper(
60 const Sequence< Property >& _rProperties, const Sequence< Property >& _rAggProperties,
61 IPropertyInfoService* _pInfoService, sal_Int32 _nFirstAggregateId )
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 m_aProperties.insert( m_aProperties.end(), _rProperties.begin(), _rProperties.end() );
66 m_aProperties.insert( m_aProperties.end(), _rAggProperties.begin(), _rAggProperties.end() );
67 std::stable_sort( m_aProperties.begin(), m_aProperties.end(), PropertyCompareByName() );
68 m_aProperties.erase( std::unique(m_aProperties.begin(), m_aProperties.end(),
69 []( const css::beans::Property& x, const css::beans::Property& y ) -> bool { return x.Name == y.Name; } ),
70 m_aProperties.end() );
71 m_aProperties.shrink_to_fit();
73 // fill aDelegatorProps with names from _rProperties for a fast existence check
74 // different kinds of properties are processed differently
75 std::unordered_set< OUString > aDelegatorProps;
76 aDelegatorProps.reserve( _rProperties.getLength() );
77 for( auto &delegateProp: _rProperties )
79 const auto inserted = aDelegatorProps.insert( delegateProp.Name );
80 OSL_ENSURE( inserted.second,
81 "OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper: duplicate delegatee property!" );
84 std::unordered_set< sal_Int32 > existingHandles;
85 existingHandles.reserve( m_aProperties.size() );
86 sal_Int32 nAggregateHandle = _nFirstAggregateId;
87 for ( std::size_t nMPLoop = 0; nMPLoop < m_aProperties.size(); ++nMPLoop )
89 auto &prop = m_aProperties[ nMPLoop ];
90 if ( aDelegatorProps.find( prop.Name ) != aDelegatorProps.end() )
92 m_aPropertyAccessors.insert_or_assign(
93 prop.Handle, OPropertyAccessor( -1, nMPLoop, false ));
94 existingHandles.insert( prop.Handle );
96 else
98 // determine the handle for the property which we will expose to the outside world
99 sal_Int32 nHandle = -1;
100 // ask the info service first
101 if ( _pInfoService )
102 nHandle = _pInfoService->getPreferredPropertyId( prop.Name );
104 if ( ( -1 == nHandle ) || ( existingHandles.find( nHandle ) != existingHandles.end() ) )
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 nHandle = nAggregateHandle++;
110 else
112 existingHandles.insert( nHandle );
115 // remember the accessor for this property
116 m_aPropertyAccessors.insert_or_assign(
117 nHandle, OPropertyAccessor( prop.Handle, nMPLoop, true ));
118 prop.Handle = nHandle;
124 OPropertyArrayAggregationHelper::PropertyOrigin OPropertyArrayAggregationHelper::classifyProperty( const OUString& _rName )
126 PropertyOrigin eOrigin = PropertyOrigin::Unknown;
127 // look up the name
128 const Property* pPropertyDescriptor = lcl_findPropertyByName( m_aProperties, _rName );
129 if ( pPropertyDescriptor )
131 // look up the handle for this name
132 auto aPos = m_aPropertyAccessors.find( pPropertyDescriptor->Handle );
133 OSL_ENSURE( m_aPropertyAccessors.end() != aPos, "OPropertyArrayAggregationHelper::classifyProperty: should have this handle in my map!" );
134 if ( m_aPropertyAccessors.end() != aPos )
136 eOrigin = aPos->second.bAggregate ? PropertyOrigin::Aggregate : PropertyOrigin::Delegator;
139 return eOrigin;
143 Property OPropertyArrayAggregationHelper::getPropertyByName( const OUString& _rPropertyName )
145 const Property* pProperty = findPropertyByName( _rPropertyName );
147 if ( !pProperty )
148 throw UnknownPropertyException(_rPropertyName);
150 return *pProperty;
154 sal_Bool OPropertyArrayAggregationHelper::hasPropertyByName(const OUString& _rPropertyName)
156 return nullptr != findPropertyByName( _rPropertyName );
160 const Property* OPropertyArrayAggregationHelper::findPropertyByName(const OUString& _rName ) const
162 return lcl_findPropertyByName( m_aProperties, _rName );
166 sal_Int32 OPropertyArrayAggregationHelper::getHandleByName(const OUString& _rPropertyName)
168 const Property* pProperty = findPropertyByName( _rPropertyName );
169 return pProperty ? pProperty->Handle : -1;
173 sal_Bool OPropertyArrayAggregationHelper::fillPropertyMembersByHandle(
174 OUString* _pPropName, sal_Int16* _pAttributes, sal_Int32 _nHandle)
176 auto i = m_aPropertyAccessors.find(_nHandle);
177 bool bRet = i != m_aPropertyAccessors.end();
178 if (bRet)
180 const css::beans::Property& rProperty = m_aProperties[(*i).second.nPos];
181 if (_pPropName)
182 *_pPropName = rProperty.Name;
183 if (_pAttributes)
184 *_pAttributes = rProperty.Attributes;
186 return bRet;
190 bool OPropertyArrayAggregationHelper::getPropertyByHandle( sal_Int32 _nHandle, Property& _rProperty ) const
192 auto pos = m_aPropertyAccessors.find(_nHandle);
193 if ( pos != m_aPropertyAccessors.end() )
195 _rProperty = m_aProperties[ pos->second.nPos ];
196 return true;
198 return false;
202 bool OPropertyArrayAggregationHelper::fillAggregatePropertyInfoByHandle(
203 OUString* _pPropName, sal_Int32* _pOriginalHandle, sal_Int32 _nHandle) const
205 auto i = m_aPropertyAccessors.find(_nHandle);
206 bool bRet = i != m_aPropertyAccessors.end() && (*i).second.bAggregate;
207 if (bRet)
209 if (_pOriginalHandle)
210 *_pOriginalHandle = (*i).second.nOriginalHandle;
211 if (_pPropName)
213 OSL_ENSURE((*i).second.nPos < m_aProperties.size(),"Invalid index for sequence!");
214 const css::beans::Property& rProperty = m_aProperties[(*i).second.nPos];
215 *_pPropName = rProperty.Name;
218 return bRet;
222 css::uno::Sequence< css::beans::Property> OPropertyArrayAggregationHelper::getProperties()
224 return comphelper::containerToSequence(m_aProperties);
228 sal_Int32 OPropertyArrayAggregationHelper::fillHandles(
229 sal_Int32* _pHandles, const css::uno::Sequence< OUString >& _rPropNames )
231 sal_Int32 nHitCount = 0;
233 Property aNameProp;
234 for (sal_Int32 i = 0; i < _rPropNames.getLength(); ++i)
236 aNameProp.Name = _rPropNames[i];
237 auto findIter = std::lower_bound(m_aProperties.begin(), m_aProperties.end(), aNameProp, PropertyCompareByName());
238 if (findIter != m_aProperties.end() && findIter->Name == _rPropNames[i])
240 _pHandles[i] = findIter->Handle;
241 nHitCount++;
244 return nHitCount;
247 namespace internal
249 class PropertyForwarder
251 private:
252 OPropertySetAggregationHelper& m_rAggregationHelper;
253 o3tl::sorted_vector< sal_Int32 > m_aProperties;
254 sal_Int32 m_nCurrentlyForwarding;
256 public:
257 explicit PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper );
259 /** declares that the forwarder should be responsible for the given property
261 @param _nHandle
262 the public handle (<em>not</em> the original handle!) of the property
264 void takeResponsibilityFor( sal_Int32 _nHandle );
266 /** checks whether the forwarder is responsible for the given property
268 bool isResponsibleFor( sal_Int32 _nHandle ) const;
270 /// actually forwards a property value to the aggregate
272 /// @throws Exception
273 void doForward( sal_Int32 _nHandle, const Any& _rValue );
275 sal_Int32 getCurrentlyForwardedProperty( ) const { return m_nCurrentlyForwarding; }
279 PropertyForwarder::PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper )
280 :m_rAggregationHelper( _rAggregationHelper )
281 ,m_nCurrentlyForwarding( -1 )
286 void PropertyForwarder::takeResponsibilityFor( sal_Int32 _nHandle )
288 m_aProperties.insert( _nHandle );
292 bool PropertyForwarder::isResponsibleFor( sal_Int32 _nHandle ) const
294 return m_aProperties.find( _nHandle ) != m_aProperties.end();
298 void PropertyForwarder::doForward( sal_Int32 _nHandle, const Any& _rValue )
300 OSL_ENSURE( m_rAggregationHelper.m_xAggregateSet.is(), "PropertyForwarder::doForward: no property set!" );
301 if ( !m_rAggregationHelper.m_xAggregateSet.is() )
302 return;
304 m_rAggregationHelper.forwardingPropertyValue( _nHandle );
306 OSL_ENSURE( m_nCurrentlyForwarding == -1, "PropertyForwarder::doForward: reentrance?" );
307 m_nCurrentlyForwarding = _nHandle;
311 m_rAggregationHelper.m_xAggregateSet->setPropertyValue( m_rAggregationHelper.getPropertyName( _nHandle ), _rValue );
312 // TODO: cache the property name? (it's a O(log n) search)
314 catch( const Exception& )
316 m_rAggregationHelper.forwardedPropertyValue( _nHandle );
317 throw;
320 m_nCurrentlyForwarding = -1;
322 m_rAggregationHelper.forwardedPropertyValue( _nHandle );
326 OPropertySetAggregationHelper::OPropertySetAggregationHelper( ::cppu::OBroadcastHelper& rBHlp )
327 :OPropertyStateHelper( rBHlp )
328 ,m_bListening( false )
330 m_pForwarder.reset( new PropertyForwarder( *this ) );
334 OPropertySetAggregationHelper::~OPropertySetAggregationHelper()
339 css::uno::Any SAL_CALL OPropertySetAggregationHelper::queryInterface(const css::uno::Type& _rType)
341 css::uno::Any aReturn = OPropertyStateHelper::queryInterface(_rType);
343 if ( !aReturn.hasValue() )
344 aReturn = cppu::queryInterface(_rType
345 ,static_cast< css::beans::XPropertiesChangeListener*>(this)
346 ,static_cast< css::beans::XVetoableChangeListener*>(this)
347 ,static_cast< css::lang::XEventListener*>(static_cast< css::beans::XPropertiesChangeListener*>(this))
350 return aReturn;
354 void OPropertySetAggregationHelper::disposing()
356 osl::MutexGuard aGuard(rBHelper.rMutex);
358 if ( m_xAggregateSet.is() && m_bListening )
360 // register as a single listener
361 m_xAggregateMultiSet->removePropertiesChangeListener(this);
362 m_xAggregateSet->removeVetoableChangeListener(OUString(), this);
363 m_bListening = false;
366 OPropertyStateHelper::disposing();
370 void SAL_CALL OPropertySetAggregationHelper::disposing(const css::lang::EventObject& _rSource)
372 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::disposing : don't have an aggregate anymore !");
373 if (_rSource.Source == m_xAggregateSet)
374 m_bListening = false;
378 void SAL_CALL OPropertySetAggregationHelper::propertiesChange(const css::uno::Sequence< css::beans::PropertyChangeEvent>& _rEvents)
380 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::propertiesChange : have no aggregate !");
382 sal_Int32 nLen = _rEvents.getLength();
383 cppu::IPropertyArrayHelper& rPH = getInfoHelper();
385 if (1 == nLen)
387 const css::beans::PropertyChangeEvent& evt = _rEvents[0];
388 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 sal_Int32 nHandle = rPH.getHandleByName( evt.PropertyName );
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)
397 if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
398 fire(&nHandle, &evt.NewValue, &evt.OldValue, 1, false);
400 else
402 std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nLen]);
403 std::unique_ptr< css::uno::Any[]> pNewValues(new css::uno::Any[nLen]);
404 std::unique_ptr< css::uno::Any[]> pOldValues(new css::uno::Any[nLen]);
406 sal_Int32 nDest = 0;
407 for (const css::beans::PropertyChangeEvent& rEvent : _rEvents)
409 sal_Int32 nHandle = rPH.getHandleByName(rEvent.PropertyName);
410 if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
411 { // same as above : -1 is valid (73247) ...
412 pHandles[nDest] = nHandle;
413 pNewValues[nDest] = rEvent.NewValue;
414 pOldValues[nDest] = rEvent.OldValue;
415 ++nDest;
419 if (nDest)
420 fire(pHandles.get(), pNewValues.get(), pOldValues.get(), nDest, false);
425 void SAL_CALL OPropertySetAggregationHelper::vetoableChange(const css::beans::PropertyChangeEvent& _rEvent)
427 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::vetoableChange : have no aggregate !");
429 cppu::IPropertyArrayHelper& rPH = getInfoHelper();
431 sal_Int32 nHandle = rPH.getHandleByName(_rEvent.PropertyName);
432 fire(&nHandle, &_rEvent.NewValue, &_rEvent.OldValue, 1, true);
436 void OPropertySetAggregationHelper::setAggregation(const css::uno::Reference< css::uno::XInterface >& _rxDelegate)
438 osl::MutexGuard aGuard(rBHelper.rMutex);
440 if (m_bListening && m_xAggregateSet.is())
442 m_xAggregateMultiSet->removePropertiesChangeListener(this);
443 m_xAggregateSet->removeVetoableChangeListener(OUString(), this);
444 m_bListening = false;
447 m_xAggregateState.set(_rxDelegate, css::uno::UNO_QUERY);
448 m_xAggregateSet.set(_rxDelegate, css::uno::UNO_QUERY);
449 m_xAggregateMultiSet.set(_rxDelegate, css::uno::UNO_QUERY);
450 m_xAggregateFastSet.set(_rxDelegate, css::uno::UNO_QUERY);
452 // must support XPropertySet and XMultiPropertySet
453 if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() )
454 throw css::lang::IllegalArgumentException();
458 void OPropertySetAggregationHelper::startListening()
460 osl::MutexGuard aGuard(rBHelper.rMutex);
462 if (!m_bListening && m_xAggregateSet.is())
464 // register as a single listener
465 css::uno::Sequence< OUString > aPropertyNames;
466 m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this);
467 m_xAggregateSet->addVetoableChangeListener(OUString(), this);
469 m_bListening = true;
474 void SAL_CALL OPropertySetAggregationHelper::addVetoableChangeListener(const OUString& _rPropertyName,
475 const css::uno::Reference< css::beans::XVetoableChangeListener>& _rxListener)
477 OPropertySetHelper::addVetoableChangeListener(_rPropertyName, _rxListener);
478 if (!m_bListening)
479 startListening();
483 void SAL_CALL OPropertySetAggregationHelper::addPropertyChangeListener(const OUString& _rPropertyName,
484 const css::uno::Reference< css::beans::XPropertyChangeListener>& _rxListener)
486 OPropertySetHelper::addPropertyChangeListener(_rPropertyName, _rxListener);
487 if (!m_bListening)
488 startListening();
492 void SAL_CALL OPropertySetAggregationHelper::addPropertiesChangeListener(const css::uno::Sequence< OUString >& _rPropertyNames,
493 const css::uno::Reference< css::beans::XPropertiesChangeListener>& _rxListener)
495 OPropertySetHelper::addPropertiesChangeListener(_rPropertyNames, _rxListener);
496 if (!m_bListening)
497 startListening();
501 sal_Int32 OPropertySetAggregationHelper::getOriginalHandle(sal_Int32 nHandle) const
503 OPropertyArrayAggregationHelper& rPH = static_cast<OPropertyArrayAggregationHelper&>( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
504 sal_Int32 nOriginalHandle = -1;
505 (void)rPH.fillAggregatePropertyInfoByHandle(nullptr, &nOriginalHandle, nHandle);
506 return nOriginalHandle;
510 OUString OPropertySetAggregationHelper::getPropertyName( sal_Int32 _nHandle ) const
512 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
513 Property aProperty;
514 OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
515 return aProperty.Name;
519 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue(sal_Int32 _nHandle, const css::uno::Any& _rValue)
521 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
522 OUString aPropName;
523 sal_Int32 nOriginalHandle = -1;
525 // does the handle belong to the aggregation ?
526 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, _nHandle))
527 if (m_xAggregateFastSet.is())
528 m_xAggregateFastSet->setFastPropertyValue(nOriginalHandle, _rValue);
529 else
530 m_xAggregateSet->setPropertyValue(aPropName, _rValue);
531 else
532 OPropertySetHelper::setFastPropertyValue(_nHandle, _rValue);
536 void OPropertySetAggregationHelper::getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle) const
538 OPropertyArrayAggregationHelper& rPH = static_cast<OPropertyArrayAggregationHelper&>( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
539 OUString aPropName;
540 sal_Int32 nOriginalHandle = -1;
542 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
544 if (m_xAggregateFastSet.is())
545 rValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
546 else
547 rValue = m_xAggregateSet->getPropertyValue(aPropName);
549 else if ( m_pForwarder->isResponsibleFor( nHandle ) )
551 // this is a property which has been "overwritten" in our instance (thus
552 // fillAggregatePropertyInfoByHandle didn't find it)
553 rValue = m_xAggregateSet->getPropertyValue( getPropertyName( nHandle ) );
558 css::uno::Any SAL_CALL OPropertySetAggregationHelper::getFastPropertyValue(sal_Int32 nHandle)
560 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
561 OUString aPropName;
562 sal_Int32 nOriginalHandle = -1;
563 css::uno::Any aValue;
565 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
567 if (m_xAggregateFastSet.is())
568 aValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
569 else
570 aValue = m_xAggregateSet->getPropertyValue(aPropName);
572 else
573 aValue = OPropertySetHelper::getFastPropertyValue(nHandle);
575 return aValue;
579 void SAL_CALL OPropertySetAggregationHelper::setPropertyValues(
580 const Sequence< OUString >& _rPropertyNames, const Sequence< Any >& _rValues )
582 OSL_ENSURE( !rBHelper.bInDispose, "OPropertySetAggregationHelper::setPropertyValues : do not use within the dispose call !");
583 OSL_ENSURE( !rBHelper.bDisposed, "OPropertySetAggregationHelper::setPropertyValues : object is disposed" );
585 // check where the properties come from
586 if (!m_xAggregateSet.is())
587 OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
588 else if (_rPropertyNames.getLength() == 1) // use the more efficient way
590 if (_rValues.getLength() != 1)
591 throw IllegalArgumentException("lengths do not match", static_cast<XPropertySet*>(this),
592 -1);
595 setPropertyValue( _rPropertyNames[0], _rValues[0] );
597 catch( const UnknownPropertyException& )
599 // by definition of XMultiPropertySet::setPropertyValues, unknown properties are to be ignored
600 SAL_WARN( "comphelper", "OPropertySetAggregationHelper::setPropertyValues: unknown property: '"
601 << _rPropertyNames[0] << "', implementation: " << typeid( *this ).name() );
604 else
606 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
608 // determine which properties belong to the aggregate, and which ones to the delegator
609 sal_Int32 nAggCount(0);
610 sal_Int32 nLen(_rPropertyNames.getLength());
612 for ( const OUString& rName : _rPropertyNames )
614 OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( rName );
615 if ( OPropertyArrayAggregationHelper::PropertyOrigin::Unknown == ePropOrg )
616 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
620 if ( OPropertyArrayAggregationHelper::PropertyOrigin::Aggregate == ePropOrg )
621 ++nAggCount;
624 // all properties belong to the aggregate
625 if (nAggCount == nLen)
626 m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues);
628 // all properties belong to the aggregating object
629 else if (nAggCount == 0)
630 OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
632 // mixed
633 else
635 if (_rValues.getLength() != nLen)
636 throw IllegalArgumentException("lengths do not match",
637 static_cast<XPropertySet*>(this), -1);
639 // aggregate's names
640 Sequence< OUString > AggPropertyNames( nAggCount );
641 OUString* pAggNames = AggPropertyNames.getArray();
642 // aggregate's values
643 Sequence< Any > AggValues( nAggCount );
644 Any* pAggValues = AggValues.getArray();
646 // delegator names
647 Sequence< OUString > DelPropertyNames( nLen - nAggCount );
648 OUString* pDelNames = DelPropertyNames.getArray();
650 // delegator values
651 Sequence< Any > DelValues( nLen - nAggCount );
652 Any* pDelValues = DelValues.getArray();
654 for (sal_Int32 i = 0; i < nLen; ++i)
656 if ( OPropertyArrayAggregationHelper::PropertyOrigin::Aggregate == rPH.classifyProperty( _rPropertyNames[i] ) )
658 *pAggNames++ = _rPropertyNames[i];
659 *pAggValues++ = _rValues[i];
661 else
663 *pDelNames++ = _rPropertyNames[i];
664 *pDelValues++ = _rValues[i];
668 std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[ nLen - nAggCount ]);
670 // get the map table
671 cppu::IPropertyArrayHelper& rPH2 = getInfoHelper();
673 // fill the handle array
674 sal_Int32 nHitCount = rPH2.fillHandles( pHandles.get(), DelPropertyNames );
675 if (nHitCount != 0)
677 std::unique_ptr< css::uno::Any[]> pConvertedValues(new css::uno::Any[ nHitCount ]);
678 std::unique_ptr< css::uno::Any[]> pOldValues(new css::uno::Any[ nHitCount ]);
679 nHitCount = 0;
680 sal_Int32 i;
683 // must lock the mutex outside the loop. So all values are consistent.
684 osl::MutexGuard aGuard( rBHelper.rMutex );
685 for( i = 0; i < (nLen - nAggCount); ++i )
687 if( pHandles[i] != -1 )
689 sal_Int16 nAttributes;
690 rPH2.fillPropertyMembersByHandle( nullptr, &nAttributes, pHandles[i] );
691 if( nAttributes & css::beans::PropertyAttribute::READONLY )
692 throw css::beans::PropertyVetoException();
693 // Will the property change?
694 if( convertFastPropertyValue( pConvertedValues[ nHitCount ], pOldValues[nHitCount],
695 pHandles[i], DelValues[i] ) )
697 // only increment if the property really change
698 pHandles[nHitCount] = pHandles[i];
699 nHitCount++;
703 // release guard to fire events
706 // fire vetoable events
707 fire( pHandles.get(), pConvertedValues.get(), pOldValues.get(), nHitCount, true );
709 // setting the agg Properties
710 m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
713 // must lock the mutex outside the loop.
714 osl::MutexGuard aGuard( rBHelper.rMutex );
715 // Loop over all changed properties
716 for( i = 0; i < nHitCount; i++ )
718 // Will the property change?
719 setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
721 // release guard to fire events
724 // fire change events
725 fire( pHandles.get(), pConvertedValues.get(), pOldValues.get(), nHitCount, false );
727 else
728 m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
733 // XPropertyState
735 css::beans::PropertyState SAL_CALL OPropertySetAggregationHelper::getPropertyState(const OUString& _rPropertyName)
737 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
738 sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName );
740 if (nHandle == -1)
742 throw css::beans::UnknownPropertyException(_rPropertyName);
745 OUString aPropName;
746 sal_Int32 nOriginalHandle = -1;
747 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
749 if (m_xAggregateState.is())
750 return m_xAggregateState->getPropertyState(_rPropertyName);
751 else
752 return css::beans::PropertyState_DIRECT_VALUE;
754 else
755 return getPropertyStateByHandle(nHandle);
759 void SAL_CALL OPropertySetAggregationHelper::setPropertyToDefault(const OUString& _rPropertyName)
761 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
762 sal_Int32 nHandle = rPH.getHandleByName(_rPropertyName);
763 if (nHandle == -1)
765 throw css::beans::UnknownPropertyException(_rPropertyName);
768 OUString aPropName;
769 sal_Int32 nOriginalHandle = -1;
770 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
772 if (m_xAggregateState.is())
773 m_xAggregateState->setPropertyToDefault(_rPropertyName);
775 else
779 setPropertyToDefaultByHandle( nHandle );
781 catch( const UnknownPropertyException& ) { throw; }
782 catch( const RuntimeException& ) { throw; }
783 catch( const Exception& )
785 OSL_FAIL( "OPropertySetAggregationHelper::setPropertyToDefault: caught an exception which is not allowed to leave here!" );
791 css::uno::Any SAL_CALL OPropertySetAggregationHelper::getPropertyDefault(const OUString& aPropertyName)
793 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
794 sal_Int32 nHandle = rPH.getHandleByName( aPropertyName );
796 if ( nHandle == -1 )
797 throw css::beans::UnknownPropertyException(aPropertyName);
799 OUString aPropName;
800 sal_Int32 nOriginalHandle = -1;
801 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
803 if (m_xAggregateState.is())
804 return m_xAggregateState->getPropertyDefault(aPropertyName);
805 else
806 return css::uno::Any();
808 else
809 return getPropertyDefaultByHandle(nHandle);
812 sal_Bool SAL_CALL OPropertySetAggregationHelper::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue )
814 bool bModified = false;
816 OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::convertFastPropertyValue: this is no forwarded property - did you use declareForwardedProperty for it?" );
817 if ( m_pForwarder->isResponsibleFor( _nHandle ) )
819 // need to determine the type of the property for conversion
820 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
821 Property aProperty;
822 OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
824 Any aCurrentValue;
825 getFastPropertyValue( aCurrentValue, _nHandle );
826 bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, aCurrentValue, aProperty.Type );
829 return bModified;
832 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue )
834 OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast: this is no forwarded property - did you use declareForwardedProperty for it?" );
835 if ( m_pForwarder->isResponsibleFor( _nHandle ) )
836 m_pForwarder->doForward( _nHandle, _rValue );
840 void OPropertySetAggregationHelper::declareForwardedProperty( sal_Int32 _nHandle )
842 OSL_ENSURE( !m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::declareForwardedProperty: already declared!" );
843 m_pForwarder->takeResponsibilityFor( _nHandle );
847 void OPropertySetAggregationHelper::forwardingPropertyValue( sal_Int32 )
849 // not interested in
853 void OPropertySetAggregationHelper::forwardedPropertyValue( sal_Int32 )
855 // not interested in
859 bool OPropertySetAggregationHelper::isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const
861 return m_pForwarder->getCurrentlyForwardedProperty() == _nHandle;
865 } // namespace comphelper
868 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */