Bump version to 4.3-4
[LibreOffice.git] / comphelper / source / property / propagg.cxx
blobbee4e70126cc78401a3bd7861e3e7928cb53c173
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 <cppuhelper/queryinterface.hxx>
23 #include <osl/diagnose.h>
24 #include <com/sun/star/beans/PropertyAttribute.hpp>
26 #if OSL_DEBUG_LEVEL > 0
27 #include <typeinfo>
28 #include <rtl/strbuf.hxx>
29 #endif
31 #include <algorithm>
32 #include <set>
33 #include <boost/scoped_array.hpp>
36 namespace comphelper
40 using namespace ::com::sun::star::uno;
41 using namespace ::com::sun::star::lang;
42 using namespace ::com::sun::star::beans;
44 using namespace internal;
47 namespace
49 const Property* lcl_findPropertyByName( const Sequence< Property >& _rProps, const OUString& _rName )
51 sal_Int32 nLen = _rProps.getLength();
52 const Property* pProperties = _rProps.getConstArray();
53 Property aNameProp(_rName, 0, Type(), 0);
54 const Property* pResult = ::std::lower_bound(pProperties, pProperties + nLen, aNameProp, PropertyCompareByName());
55 if ( pResult && ( pResult == pProperties + nLen || pResult->Name != _rName) )
56 pResult = NULL;
58 return pResult;
62 //= OPropertyArrayAggregationHelper
66 OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper(
67 const Sequence< Property >& _rProperties, const Sequence< Property >& _rAggProperties,
68 IPropertyInfoService* _pInfoService, sal_Int32 _nFirstAggregateId )
69 :m_aProperties( _rProperties )
71 sal_Int32 nDelegatorProps = _rProperties.getLength();
72 sal_Int32 nAggregateProps = _rAggProperties.getLength();
74 // make room for all properties
75 sal_Int32 nMergedProps = nDelegatorProps + nAggregateProps;
76 m_aProperties.realloc( nMergedProps );
78 const Property* pAggregateProps = _rAggProperties.getConstArray();
79 const Property* pDelegateProps = _rProperties.getConstArray();
80 Property* pMergedProps = m_aProperties.getArray();
82 // if properties are present both at the delegatee and the aggregate, then the former are supposed to win.
83 // So, we'll need an existence check.
84 ::std::set< OUString > aDelegatorProps;
86 // create the map for the delegator properties
87 sal_Int32 nMPLoop = 0;
88 for ( ; nMPLoop < nDelegatorProps; ++nMPLoop, ++pDelegateProps )
90 m_aPropertyAccessors[ pDelegateProps->Handle ] = OPropertyAccessor( -1, nMPLoop, false );
91 OSL_ENSURE( aDelegatorProps.find( pDelegateProps->Name ) == aDelegatorProps.end(),
92 "OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper: duplicate delegatee property!" );
93 aDelegatorProps.insert( pDelegateProps->Name );
96 // create the map for the aggregate properties
97 sal_Int32 nAggregateHandle = _nFirstAggregateId;
98 pMergedProps += nDelegatorProps;
99 for ( ; nMPLoop < nMergedProps; ++pAggregateProps )
101 // if the aggregate property is present at the delegatee already, ignore it
102 if ( aDelegatorProps.find( pAggregateProps->Name ) != aDelegatorProps.end() )
104 --nMergedProps;
105 continue;
108 // next aggregate property - remember it
109 *pMergedProps = *pAggregateProps;
111 // determine the handle for the property which we will expose to the outside world
112 sal_Int32 nHandle = -1;
113 // ask the infor service first
114 if ( _pInfoService )
115 nHandle = _pInfoService->getPreferredPropertyId( pMergedProps->Name );
117 if ( -1 == nHandle )
118 // no handle from the info service -> default
119 nHandle = nAggregateHandle++;
120 else
121 { // check if we alread have a property with the given handle
122 const Property* pPropsTilNow = m_aProperties.getConstArray();
123 for ( sal_Int32 nCheck = 0; nCheck < nMPLoop; ++nCheck, ++pPropsTilNow )
124 if ( pPropsTilNow->Handle == nHandle )
125 { // conflicts -> use another one (which we don't check anymore, assuming _nFirstAggregateId was large enough)
126 nHandle = nAggregateHandle++;
127 break;
131 // remember the accessor for this property
132 m_aPropertyAccessors[ nHandle ] = OPropertyAccessor( pMergedProps->Handle, nMPLoop, true );
133 pMergedProps->Handle = nHandle;
135 ++nMPLoop;
136 ++pMergedProps;
138 m_aProperties.realloc( nMergedProps );
139 pMergedProps = m_aProperties.getArray(); // reset, needed again below
141 // sort the properties by name
142 ::std::sort( pMergedProps, pMergedProps+nMergedProps, PropertyCompareByName());
144 pMergedProps = m_aProperties.getArray();
146 // sync the map positions
147 for ( nMPLoop = 0; nMPLoop < nMergedProps; ++nMPLoop, ++pMergedProps )
148 m_aPropertyAccessors[ pMergedProps->Handle ].nPos = nMPLoop;
152 OPropertyArrayAggregationHelper::PropertyOrigin OPropertyArrayAggregationHelper::classifyProperty( const OUString& _rName )
154 PropertyOrigin eOrigin = UNKNOWN_PROPERTY;
155 // look up the name
156 const Property* pPropertyDescriptor = lcl_findPropertyByName( m_aProperties, _rName );
157 if ( pPropertyDescriptor )
159 // look up the handle for this name
160 ConstPropertyAccessorMapIterator aPos = m_aPropertyAccessors.find( pPropertyDescriptor->Handle );
161 OSL_ENSURE( m_aPropertyAccessors.end() != aPos, "OPropertyArrayAggregationHelper::classifyProperty: should have this handle in my map!" );
162 if ( m_aPropertyAccessors.end() != aPos )
164 eOrigin = aPos->second.bAggregate ? AGGREGATE_PROPERTY : DELEGATOR_PROPERTY;
167 return eOrigin;
171 Property OPropertyArrayAggregationHelper::getPropertyByName( const OUString& _rPropertyName ) throw( UnknownPropertyException )
173 const Property* pProperty = findPropertyByName( _rPropertyName );
175 if ( !pProperty )
176 throw UnknownPropertyException();
178 return *pProperty;
182 sal_Bool OPropertyArrayAggregationHelper::hasPropertyByName(const OUString& _rPropertyName)
184 return NULL != findPropertyByName( _rPropertyName );
188 const Property* OPropertyArrayAggregationHelper::findPropertyByName(const :: OUString& _rName ) const
190 return lcl_findPropertyByName( m_aProperties, _rName );
194 sal_Int32 OPropertyArrayAggregationHelper::getHandleByName(const OUString& _rPropertyName)
196 const Property* pProperty = findPropertyByName( _rPropertyName );
197 return pProperty ? pProperty->Handle : -1;
201 sal_Bool OPropertyArrayAggregationHelper::fillPropertyMembersByHandle(
202 OUString* _pPropName, sal_Int16* _pAttributes, sal_Int32 _nHandle)
204 ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
205 bool bRet = i != m_aPropertyAccessors.end();
206 if (bRet)
208 const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos];
209 if (_pPropName)
210 *_pPropName = rProperty.Name;
211 if (_pAttributes)
212 *_pAttributes = rProperty.Attributes;
214 return bRet;
218 bool OPropertyArrayAggregationHelper::getPropertyByHandle( sal_Int32 _nHandle, Property& _rProperty ) const
220 ConstPropertyAccessorMapIterator pos = m_aPropertyAccessors.find(_nHandle);
221 if ( pos != m_aPropertyAccessors.end() )
223 _rProperty = m_aProperties[ pos->second.nPos ];
224 return true;
226 return false;
230 bool OPropertyArrayAggregationHelper::fillAggregatePropertyInfoByHandle(
231 OUString* _pPropName, sal_Int32* _pOriginalHandle, sal_Int32 _nHandle) const
233 ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
234 bool bRet = i != m_aPropertyAccessors.end() && (*i).second.bAggregate;
235 if (bRet)
237 if (_pOriginalHandle)
238 *_pOriginalHandle = (*i).second.nOriginalHandle;
239 if (_pPropName)
241 OSL_ENSURE((*i).second.nPos < m_aProperties.getLength(),"Invalid index for sequence!");
242 const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos];
243 *_pPropName = rProperty.Name;
246 return bRet;
251 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property> OPropertyArrayAggregationHelper::getProperties()
253 return m_aProperties;
258 sal_Int32 OPropertyArrayAggregationHelper::fillHandles(
259 sal_Int32* _pHandles, const ::com::sun::star::uno::Sequence< OUString >& _rPropNames )
261 sal_Int32 nHitCount = 0;
262 const OUString* pReqProps = _rPropNames.getConstArray();
263 sal_Int32 nReqLen = _rPropNames.getLength();
265 #if OSL_DEBUG_LEVEL > 0
266 // assure that the sequence is sorted
268 const OUString* pLookup = _rPropNames.getConstArray();
269 const OUString* pEnd = _rPropNames.getConstArray() + _rPropNames.getLength() - 1;
270 for (; pLookup < pEnd; ++pLookup)
272 const OUString* pCompare = pLookup + 1;
273 const OUString* pCompareEnd = pEnd + 1;
274 for (; pCompare < pCompareEnd; ++pCompare)
276 OSL_ENSURE(pLookup->compareTo(*pCompare) < 0, "OPropertyArrayAggregationHelper::fillHandles : property names are not sorted!");
280 #endif
282 const ::com::sun::star::beans::Property* pCur = m_aProperties.getConstArray();
283 const ::com::sun::star::beans::Property* pEnd = m_aProperties.getConstArray() + m_aProperties.getLength();
285 for( sal_Int32 i = 0; i < nReqLen; ++i )
287 // determine the logarithm
288 sal_uInt32 n = (sal_uInt32)(pEnd - pCur);
289 sal_Int32 nLog = 0;
290 while( n )
292 nLog += 1;
293 n = n >> 1;
296 // (Number of properties yet to be found) * (Log2 of properties yet to be searched)
297 if( (nReqLen - i) * nLog >= pEnd - pCur )
299 // linear search is better
300 while( pCur < pEnd && pReqProps[i] > pCur->Name )
302 pCur++;
304 if( pCur < pEnd && pReqProps[i] == pCur->Name )
306 _pHandles[i] = pCur->Handle;
307 nHitCount++;
309 else
310 _pHandles[i] = -1;
312 else
314 // binary search is better
315 sal_Int32 nCompVal = 1;
316 const ::com::sun::star::beans::Property* pOldEnd = pEnd--;
317 const ::com::sun::star::beans::Property* pMid = pCur;
319 while( nCompVal != 0 && pCur <= pEnd )
321 pMid = (pEnd - pCur) / 2 + pCur;
323 nCompVal = pReqProps[i].compareTo( pMid->Name );
325 if( nCompVal > 0 )
326 pCur = pMid + 1;
327 else
328 pEnd = pMid - 1;
331 if( nCompVal == 0 )
333 _pHandles[i] = pMid->Handle;
334 nHitCount++;
335 pCur = pMid +1;
337 else if( nCompVal > 0 )
339 _pHandles[i] = -1;
340 pCur = pMid + 1;
342 else
344 _pHandles[i] = -1;
345 pCur = pMid;
347 pEnd = pOldEnd;
350 return nHitCount;
354 //= PropertyForwarder
356 namespace internal
358 class PropertyForwarder
360 private:
361 OPropertySetAggregationHelper& m_rAggregationHelper;
362 ::std::set< sal_Int32 > m_aProperties;
363 sal_Int32 m_nCurrentlyForwarding;
365 public:
366 PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper );
367 ~PropertyForwarder();
369 /** declares that the forwarder should be responsible for the given property
371 @param _nHandle
372 the public handle (<em>not</em> the original handle!) of the property
374 void takeResponsibilityFor( sal_Int32 _nHandle );
376 /** checks whether the forwarder is responsible for the given property
378 bool isResponsibleFor( sal_Int32 _nHandle );
380 /// actually forwards a property value to the aggregate
381 void doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception );
383 sal_Int32 getCurrentlyForwardedProperty( ) const { return m_nCurrentlyForwarding; }
387 PropertyForwarder::PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper )
388 :m_rAggregationHelper( _rAggregationHelper )
389 ,m_nCurrentlyForwarding( -1 )
394 PropertyForwarder::~PropertyForwarder()
399 void PropertyForwarder::takeResponsibilityFor( sal_Int32 _nHandle )
401 m_aProperties.insert( _nHandle );
405 bool PropertyForwarder::isResponsibleFor( sal_Int32 _nHandle )
407 return m_aProperties.find( _nHandle ) != m_aProperties.end();
411 void PropertyForwarder::doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception )
413 OSL_ENSURE( m_rAggregationHelper.m_xAggregateSet.is(), "PropertyForwarder::doForward: no property set!" );
414 if ( m_rAggregationHelper.m_xAggregateSet.is() )
416 m_rAggregationHelper.forwardingPropertyValue( _nHandle );
418 OSL_ENSURE( m_nCurrentlyForwarding == -1, "PropertyForwarder::doForward: reentrance?" );
419 m_nCurrentlyForwarding = _nHandle;
423 m_rAggregationHelper.m_xAggregateSet->setPropertyValue( m_rAggregationHelper.getPropertyName( _nHandle ), _rValue );
424 // TODO: cache the property name? (it's a O(log n) search)
426 catch( const Exception& )
428 m_rAggregationHelper.forwardedPropertyValue( _nHandle );
429 throw;
432 m_nCurrentlyForwarding = -1;
434 m_rAggregationHelper.forwardedPropertyValue( _nHandle );
440 //= OPropertySetAggregationHelper
444 OPropertySetAggregationHelper::OPropertySetAggregationHelper( ::cppu::OBroadcastHelper& rBHlp )
445 :OPropertyStateHelper( rBHlp )
446 ,m_bListening( false )
448 m_pForwarder = new PropertyForwarder( *this );
452 OPropertySetAggregationHelper::~OPropertySetAggregationHelper()
454 delete m_pForwarder;
458 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::queryInterface(const ::com::sun::star::uno::Type& _rType) throw( ::com::sun::star::uno::RuntimeException, std::exception)
460 ::com::sun::star::uno::Any aReturn = OPropertyStateHelper::queryInterface(_rType);
462 if ( !aReturn.hasValue() )
463 aReturn = cppu::queryInterface(_rType
464 ,static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this)
465 ,static_cast< ::com::sun::star::beans::XVetoableChangeListener*>(this)
466 ,static_cast< ::com::sun::star::lang::XEventListener*>(static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this))
469 return aReturn;
473 void OPropertySetAggregationHelper::disposing()
475 osl::MutexGuard aGuard(rBHelper.rMutex);
477 if ( m_xAggregateSet.is() && m_bListening )
479 // register as a single listener
480 m_xAggregateMultiSet->removePropertiesChangeListener(this);
481 m_xAggregateSet->removeVetoableChangeListener(OUString(), this);
482 m_bListening = false;
485 OPropertyStateHelper::disposing();
489 void SAL_CALL OPropertySetAggregationHelper::disposing(const ::com::sun::star::lang::EventObject& _rSource) throw ( ::com::sun::star::uno::RuntimeException, std::exception)
491 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::disposing : don't have an aggregate anymore !");
492 if (_rSource.Source == m_xAggregateSet)
493 m_bListening = false;
497 void SAL_CALL OPropertySetAggregationHelper::propertiesChange(const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyChangeEvent>& _rEvents) throw( ::com::sun::star::uno::RuntimeException, std::exception)
499 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::propertiesChange : have no aggregate !");
501 sal_Int32 nLen = _rEvents.getLength();
502 cppu::IPropertyArrayHelper& rPH = getInfoHelper();
504 if (1 == nLen)
506 const ::com::sun::star::beans::PropertyChangeEvent& evt = _rEvents.getConstArray()[0];
507 OSL_ENSURE(!evt.PropertyName.isEmpty(), "OPropertySetAggregationHelper::propertiesChange : invalid event !");
508 // we had a bug where this assertion would have us saved a whole day :) (72514)
509 sal_Int32 nHandle = rPH.getHandleByName( evt.PropertyName );
511 // If nHandle is -1 the event marks a (aggregate) property which we hide to callers
512 // If isCurrentlyForwardingProperty( nHandle ) is <TRUE/>, then we ourself triggered
513 // setting this property. In this case, it will be notified later (by the OPropertySetHelper
514 // implementation)
516 if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
517 fire(&nHandle, &evt.NewValue, &evt.OldValue, 1, sal_False);
519 else
521 boost::scoped_array<sal_Int32> pHandles(new sal_Int32[nLen]);
522 boost::scoped_array< ::com::sun::star::uno::Any> pNewValues(new ::com::sun::star::uno::Any[nLen]);
523 boost::scoped_array< ::com::sun::star::uno::Any> pOldValues(new ::com::sun::star::uno::Any[nLen]);
525 const ::com::sun::star::beans::PropertyChangeEvent* pEvents = _rEvents.getConstArray();
526 sal_Int32 nDest = 0;
527 for (sal_Int32 nSource=0; nSource<nLen; ++nSource, ++pEvents)
529 sal_Int32 nHandle = rPH.getHandleByName(pEvents->PropertyName);
530 if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
531 { // same as above : -1 is valid (73247) ...
532 pHandles[nDest] = nHandle;
533 pNewValues[nDest] = pEvents->NewValue;
534 pOldValues[nDest] = pEvents->OldValue;
535 ++nDest;
539 if (nDest)
540 fire(pHandles.get(), pNewValues.get(), pOldValues.get(), nDest, sal_False);
545 void SAL_CALL OPropertySetAggregationHelper::vetoableChange(const ::com::sun::star::beans::PropertyChangeEvent& _rEvent) throw( ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException, std::exception)
547 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::vetoableChange : have no aggregate !");
549 cppu::IPropertyArrayHelper& rPH = getInfoHelper();
551 sal_Int32 nHandle = rPH.getHandleByName(_rEvent.PropertyName);
552 fire(&nHandle, &_rEvent.NewValue, &_rEvent.OldValue, 1, sal_True);
556 void OPropertySetAggregationHelper::setAggregation(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxDelegate)
557 throw( ::com::sun::star::lang::IllegalArgumentException )
559 osl::MutexGuard aGuard(rBHelper.rMutex);
561 if (m_bListening && m_xAggregateSet.is())
563 m_xAggregateMultiSet->removePropertiesChangeListener(this);
564 m_xAggregateSet->removeVetoableChangeListener(OUString(), this);
565 m_bListening = false;
568 m_xAggregateState = m_xAggregateState.query( _rxDelegate );
569 m_xAggregateSet = m_xAggregateSet.query( _rxDelegate );
570 m_xAggregateMultiSet = m_xAggregateMultiSet.query( _rxDelegate );
571 m_xAggregateFastSet = m_xAggregateFastSet.query( _rxDelegate );
573 // must support XPropertySet and XMultiPropertySet
574 if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() )
575 throw ::com::sun::star::lang::IllegalArgumentException();
579 void OPropertySetAggregationHelper::startListening()
581 osl::MutexGuard aGuard(rBHelper.rMutex);
583 if (!m_bListening && m_xAggregateSet.is())
585 // register as a single listener
586 ::com::sun::star::uno::Sequence< OUString > aPropertyNames;
587 m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this);
588 m_xAggregateSet->addVetoableChangeListener(OUString(), this);
590 m_bListening = true;
595 void SAL_CALL OPropertySetAggregationHelper::addVetoableChangeListener(const OUString& _rPropertyName,
596 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener>& _rxListener)
597 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception)
599 OPropertySetHelper::addVetoableChangeListener(_rPropertyName, _rxListener);
600 if (!m_bListening)
601 startListening();
605 void SAL_CALL OPropertySetAggregationHelper::addPropertyChangeListener(const OUString& _rPropertyName,
606 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener>& _rxListener)
607 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception)
609 OPropertySetHelper::addPropertyChangeListener(_rPropertyName, _rxListener);
610 if (!m_bListening)
611 startListening();
615 void SAL_CALL OPropertySetAggregationHelper::addPropertiesChangeListener(const ::com::sun::star::uno::Sequence< OUString >& _rPropertyNames,
616 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener>& _rxListener)
617 throw( ::com::sun::star::uno::RuntimeException, std::exception)
619 OPropertySetHelper::addPropertiesChangeListener(_rPropertyNames, _rxListener);
620 if (!m_bListening)
621 startListening();
625 sal_Int32 OPropertySetAggregationHelper::getOriginalHandle(sal_Int32 nHandle) const
627 OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper();
628 sal_Int32 nOriginalHandle = -1;
629 rPH.fillAggregatePropertyInfoByHandle(NULL, &nOriginalHandle, nHandle);
630 return nOriginalHandle;
634 OUString OPropertySetAggregationHelper::getPropertyName( sal_Int32 _nHandle ) const
636 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
637 Property aProperty;
638 OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
639 return aProperty.Name;
643 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue(sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rValue)
644 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException,
645 ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException,
646 ::com::sun::star::uno::RuntimeException, std::exception)
648 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
649 OUString aPropName;
650 sal_Int32 nOriginalHandle = -1;
652 // does the handle belong to the aggregation ?
653 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, _nHandle))
654 if (m_xAggregateFastSet.is())
655 m_xAggregateFastSet->setFastPropertyValue(nOriginalHandle, _rValue);
656 else
657 m_xAggregateSet->setPropertyValue(aPropName, _rValue);
658 else
659 OPropertySetHelper::setFastPropertyValue(_nHandle, _rValue);
663 void OPropertySetAggregationHelper::getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle) const
665 OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper();
666 OUString aPropName;
667 sal_Int32 nOriginalHandle = -1;
669 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
671 if (m_xAggregateFastSet.is())
672 rValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
673 else
674 rValue = m_xAggregateSet->getPropertyValue(aPropName);
676 else if ( m_pForwarder->isResponsibleFor( nHandle ) )
678 // this is a property which has been "overwritten" in our instance (thus
679 // fillAggregatePropertyInfoByHandle didn't find it)
680 rValue = m_xAggregateSet->getPropertyValue( getPropertyName( nHandle ) );
685 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getFastPropertyValue(sal_Int32 nHandle)
686 throw( ::com::sun::star::beans::UnknownPropertyException,
687 ::com::sun::star::lang::WrappedTargetException,
688 ::com::sun::star::uno::RuntimeException, std::exception)
690 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
691 OUString aPropName;
692 sal_Int32 nOriginalHandle = -1;
693 ::com::sun::star::uno::Any aValue;
695 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
697 if (m_xAggregateFastSet.is())
698 aValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
699 else
700 aValue = m_xAggregateSet->getPropertyValue(aPropName);
702 else
703 aValue = OPropertySetHelper::getFastPropertyValue(nHandle);
705 return aValue;
709 void SAL_CALL OPropertySetAggregationHelper::setPropertyValues(
710 const Sequence< OUString >& _rPropertyNames, const Sequence< Any >& _rValues )
711 throw ( PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException, std::exception )
713 OSL_ENSURE( !rBHelper.bInDispose, "OPropertySetAggregationHelper::setPropertyValues : do not use within the dispose call !");
714 OSL_ENSURE( !rBHelper.bDisposed, "OPropertySetAggregationHelper::setPropertyValues : object is disposed" );
716 // check where the properties come from
717 if (!m_xAggregateSet.is())
718 OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
719 else if (_rPropertyNames.getLength() == 1) // use the more efficient way
723 setPropertyValue( _rPropertyNames[0], _rValues[0] );
725 catch( const UnknownPropertyException& )
727 // by definition of XMultiPropertySet::setPropertyValues, unknown properties are to be ignored
728 #if OSL_DEBUG_LEVEL > 0
729 OStringBuffer aMessage;
730 aMessage.append( "OPropertySetAggregationHelper::setPropertyValues: unknown property '" );
731 aMessage.append( OUStringToOString( _rPropertyNames[0], RTL_TEXTENCODING_ASCII_US ) );
732 aMessage.append( "'" );
733 aMessage.append( "\n(implementation " );
734 aMessage.append( typeid( *this ).name() );
735 aMessage.append( ")" );
736 OSL_FAIL( aMessage.getStr() );
737 #endif
740 else
742 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
744 // determine which properties belong to the aggregate, and which ones to the delegator
745 const OUString* pNames = _rPropertyNames.getConstArray();
746 sal_Int32 nAggCount(0);
747 sal_Int32 nLen(_rPropertyNames.getLength());
749 for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames )
751 OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( *pNames );
752 if ( OPropertyArrayAggregationHelper::UNKNOWN_PROPERTY == ePropOrg )
753 throw WrappedTargetException( OUString(), static_cast< XMultiPropertySet* >( this ), makeAny( UnknownPropertyException( ) ) );
754 // due to a flaw in the API design, this method is not allowed to throw an UnknownPropertyException
755 // so we wrap it into a WrappedTargetException
757 if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == ePropOrg )
758 ++nAggCount;
761 pNames = _rPropertyNames.getConstArray(); // reset, we'll need it again below ...
763 // all properties belong to the aggregate
764 if (nAggCount == nLen)
765 m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues);
767 // all properties belong to the aggregating object
768 else if (nAggCount == 0)
769 OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
771 // mixed
772 else
774 const ::com::sun::star::uno::Any* pValues = _rValues.getConstArray();
778 // dividing the Names and _rValues
780 // aggregate's names
781 Sequence< OUString > AggPropertyNames( nAggCount );
782 OUString* pAggNames = AggPropertyNames.getArray();
783 // aggregate's values
784 Sequence< Any > AggValues( nAggCount );
785 Any* pAggValues = AggValues.getArray();
787 // delegator names
788 Sequence< OUString > DelPropertyNames( nLen - nAggCount );
789 OUString* pDelNames = DelPropertyNames.getArray();
791 // delegator values
792 Sequence< Any > DelValues( nLen - nAggCount );
793 Any* pDelValues = DelValues.getArray();
795 for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames, ++pValues )
797 if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == rPH.classifyProperty( *pNames ) )
799 *pAggNames++ = *pNames;
800 *pAggValues++ = *pValues;
802 else
804 *pDelNames++ = *pNames;
805 *pDelValues++ = *pValues;
809 // reset, needed below
810 pDelValues = DelValues.getArray();
812 boost::scoped_array<sal_Int32> pHandles(new sal_Int32[ nLen - nAggCount ]);
814 // get the map table
815 cppu::IPropertyArrayHelper& rPH2 = getInfoHelper();
817 // fill the handle array
818 sal_Int32 nHitCount = rPH2.fillHandles( pHandles.get(), DelPropertyNames );
819 if (nHitCount != 0)
821 boost::scoped_array< ::com::sun::star::uno::Any> pConvertedValues(new ::com::sun::star::uno::Any[ nHitCount ]);
822 boost::scoped_array< ::com::sun::star::uno::Any> pOldValues(new ::com::sun::star::uno::Any[ nHitCount ]);
823 nHitCount = 0;
824 sal_Int32 i;
827 // must lock the mutex outside the loop. So all values are consistent.
828 osl::MutexGuard aGuard( rBHelper.rMutex );
829 for( i = 0; i < (nLen - nAggCount); ++i )
831 if( pHandles[i] != -1 )
833 sal_Int16 nAttributes;
834 rPH2.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] );
835 if( nAttributes & ::com::sun::star::beans::PropertyAttribute::READONLY )
836 throw ::com::sun::star::beans::PropertyVetoException();
837 // Will the property change?
838 if( convertFastPropertyValue( pConvertedValues[ nHitCount ], pOldValues[nHitCount],
839 pHandles[i], pDelValues[i] ) )
841 // only increment if the property really change
842 pHandles[nHitCount] = pHandles[i];
843 nHitCount++;
847 // release guard to fire events
850 // fire vetoable events
851 fire( pHandles.get(), pConvertedValues.get(), pOldValues.get(), nHitCount, sal_True );
853 // setting the agg Properties
854 m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
857 // must lock the mutex outside the loop.
858 osl::MutexGuard aGuard( rBHelper.rMutex );
859 // Loop over all changed properties
860 for( i = 0; i < nHitCount; i++ )
862 // Will the property change?
863 setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
865 // release guard to fire events
868 // fire change events
869 fire( pHandles.get(), pConvertedValues.get(), pOldValues.get(), nHitCount, sal_False );
871 else
872 m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
875 catch(::com::sun::star::uno::Exception&)
877 throw;
883 // XPropertyState
885 ::com::sun::star::beans::PropertyState SAL_CALL OPropertySetAggregationHelper::getPropertyState(const OUString& _rPropertyName)
886 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException, std::exception)
888 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
889 sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName );
891 if (nHandle == -1)
893 throw ::com::sun::star::beans::UnknownPropertyException();
896 OUString aPropName;
897 sal_Int32 nOriginalHandle = -1;
898 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
900 if (m_xAggregateState.is())
901 return m_xAggregateState->getPropertyState(_rPropertyName);
902 else
903 return ::com::sun::star::beans::PropertyState_DIRECT_VALUE;
905 else
906 return getPropertyStateByHandle(nHandle);
910 void SAL_CALL OPropertySetAggregationHelper::setPropertyToDefault(const OUString& _rPropertyName)
911 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException, std::exception)
913 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
914 sal_Int32 nHandle = rPH.getHandleByName(_rPropertyName);
915 if (nHandle == -1)
917 throw ::com::sun::star::beans::UnknownPropertyException();
920 OUString aPropName;
921 sal_Int32 nOriginalHandle = -1;
922 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
924 if (m_xAggregateState.is())
925 m_xAggregateState->setPropertyToDefault(_rPropertyName);
927 else
931 setPropertyToDefaultByHandle( nHandle );
933 catch( const UnknownPropertyException& ) { throw; }
934 catch( const RuntimeException& ) { throw; }
935 catch( const Exception& )
937 OSL_FAIL( "OPropertySetAggregationHelper::setPropertyToDefault: caught an exception which is not allowed to leave here!" );
943 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getPropertyDefault(const OUString& aPropertyName)
944 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception)
946 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
947 sal_Int32 nHandle = rPH.getHandleByName( aPropertyName );
949 if ( nHandle == -1 )
950 throw ::com::sun::star::beans::UnknownPropertyException();
952 OUString aPropName;
953 sal_Int32 nOriginalHandle = -1;
954 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
956 if (m_xAggregateState.is())
957 return m_xAggregateState->getPropertyDefault(aPropertyName);
958 else
959 return ::com::sun::star::uno::Any();
961 else
962 return getPropertyDefaultByHandle(nHandle);
966 sal_Bool SAL_CALL OPropertySetAggregationHelper::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException)
968 bool bModified = false;
970 OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::convertFastPropertyValue: this is no forwarded property - did you use declareForwardedProperty for it?" );
971 if ( m_pForwarder->isResponsibleFor( _nHandle ) )
973 // need to determine the type of the property for conversion
974 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
975 Property aProperty;
976 OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
978 Any aCurrentValue;
979 getFastPropertyValue( aCurrentValue, _nHandle );
980 bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, aCurrentValue, aProperty.Type );
983 return bModified;
987 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception, std::exception )
989 OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast: this is no forwarded property - did you use declareForwardedProperty for it?" );
990 if ( m_pForwarder->isResponsibleFor( _nHandle ) )
991 m_pForwarder->doForward( _nHandle, _rValue );
995 void OPropertySetAggregationHelper::declareForwardedProperty( sal_Int32 _nHandle )
997 OSL_ENSURE( !m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::declareForwardedProperty: already declared!" );
998 m_pForwarder->takeResponsibilityFor( _nHandle );
1002 void OPropertySetAggregationHelper::forwardingPropertyValue( sal_Int32 )
1004 // not interested in
1008 void OPropertySetAggregationHelper::forwardedPropertyValue( sal_Int32 )
1010 // not interested in
1014 bool OPropertySetAggregationHelper::isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const
1016 return m_pForwarder->getCurrentlyForwardedProperty() == _nHandle;
1020 } // namespace comphelper
1023 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */