bump product version to 5.0.4.1
[LibreOffice.git] / comphelper / source / property / propagg.cxx
blob7abb03d31e592987a2de994ea19ce8c9f6168e8e
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::OPropertyArrayAggregationHelper(
63 const Sequence< Property >& _rProperties, const Sequence< Property >& _rAggProperties,
64 IPropertyInfoService* _pInfoService, sal_Int32 _nFirstAggregateId )
65 :m_aProperties( _rProperties )
67 sal_Int32 nDelegatorProps = _rProperties.getLength();
68 sal_Int32 nAggregateProps = _rAggProperties.getLength();
70 // make room for all properties
71 sal_Int32 nMergedProps = nDelegatorProps + nAggregateProps;
72 m_aProperties.realloc( nMergedProps );
74 const Property* pAggregateProps = _rAggProperties.getConstArray();
75 const Property* pDelegateProps = _rProperties.getConstArray();
76 Property* pMergedProps = m_aProperties.getArray();
78 // if properties are present both at the delegatee and the aggregate, then the former are supposed to win.
79 // So, we'll need an existence check.
80 ::std::set< OUString > aDelegatorProps;
82 // create the map for the delegator properties
83 sal_Int32 nMPLoop = 0;
84 for ( ; nMPLoop < nDelegatorProps; ++nMPLoop, ++pDelegateProps )
86 m_aPropertyAccessors[ pDelegateProps->Handle ] = OPropertyAccessor( -1, nMPLoop, false );
87 OSL_ENSURE( aDelegatorProps.find( pDelegateProps->Name ) == aDelegatorProps.end(),
88 "OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper: duplicate delegatee property!" );
89 aDelegatorProps.insert( pDelegateProps->Name );
92 // create the map for the aggregate properties
93 sal_Int32 nAggregateHandle = _nFirstAggregateId;
94 pMergedProps += nDelegatorProps;
95 for ( ; nMPLoop < nMergedProps; ++pAggregateProps )
97 // if the aggregate property is present at the delegatee already, ignore it
98 if ( aDelegatorProps.find( pAggregateProps->Name ) != aDelegatorProps.end() )
100 --nMergedProps;
101 continue;
104 // next aggregate property - remember it
105 *pMergedProps = *pAggregateProps;
107 // determine the handle for the property which we will expose to the outside world
108 sal_Int32 nHandle = -1;
109 // ask the infor service first
110 if ( _pInfoService )
111 nHandle = _pInfoService->getPreferredPropertyId( pMergedProps->Name );
113 if ( -1 == nHandle )
114 // no handle from the info service -> default
115 nHandle = nAggregateHandle++;
116 else
117 { // check if we alread have a property with the given handle
118 const Property* pPropsTilNow = m_aProperties.getConstArray();
119 for ( sal_Int32 nCheck = 0; nCheck < nMPLoop; ++nCheck, ++pPropsTilNow )
120 if ( pPropsTilNow->Handle == nHandle )
121 { // conflicts -> use another one (which we don't check anymore, assuming _nFirstAggregateId was large enough)
122 nHandle = nAggregateHandle++;
123 break;
127 // remember the accessor for this property
128 m_aPropertyAccessors[ nHandle ] = OPropertyAccessor( pMergedProps->Handle, nMPLoop, true );
129 pMergedProps->Handle = nHandle;
131 ++nMPLoop;
132 ++pMergedProps;
134 m_aProperties.realloc( nMergedProps );
135 pMergedProps = m_aProperties.getArray(); // reset, needed again below
137 // sort the properties by name
138 ::std::sort( pMergedProps, pMergedProps+nMergedProps, PropertyCompareByName());
140 pMergedProps = m_aProperties.getArray();
142 // sync the map positions
143 for ( nMPLoop = 0; nMPLoop < nMergedProps; ++nMPLoop, ++pMergedProps )
144 m_aPropertyAccessors[ pMergedProps->Handle ].nPos = nMPLoop;
148 OPropertyArrayAggregationHelper::PropertyOrigin OPropertyArrayAggregationHelper::classifyProperty( const OUString& _rName )
150 PropertyOrigin eOrigin = UNKNOWN_PROPERTY;
151 // look up the name
152 const Property* pPropertyDescriptor = lcl_findPropertyByName( m_aProperties, _rName );
153 if ( pPropertyDescriptor )
155 // look up the handle for this name
156 ConstPropertyAccessorMapIterator aPos = m_aPropertyAccessors.find( pPropertyDescriptor->Handle );
157 OSL_ENSURE( m_aPropertyAccessors.end() != aPos, "OPropertyArrayAggregationHelper::classifyProperty: should have this handle in my map!" );
158 if ( m_aPropertyAccessors.end() != aPos )
160 eOrigin = aPos->second.bAggregate ? AGGREGATE_PROPERTY : DELEGATOR_PROPERTY;
163 return eOrigin;
167 Property OPropertyArrayAggregationHelper::getPropertyByName( const OUString& _rPropertyName ) throw( UnknownPropertyException )
169 const Property* pProperty = findPropertyByName( _rPropertyName );
171 if ( !pProperty )
172 throw UnknownPropertyException();
174 return *pProperty;
178 sal_Bool OPropertyArrayAggregationHelper::hasPropertyByName(const OUString& _rPropertyName)
180 return NULL != findPropertyByName( _rPropertyName );
184 const Property* OPropertyArrayAggregationHelper::findPropertyByName(const :: OUString& _rName ) const
186 return lcl_findPropertyByName( m_aProperties, _rName );
190 sal_Int32 OPropertyArrayAggregationHelper::getHandleByName(const OUString& _rPropertyName)
192 const Property* pProperty = findPropertyByName( _rPropertyName );
193 return pProperty ? pProperty->Handle : -1;
197 sal_Bool OPropertyArrayAggregationHelper::fillPropertyMembersByHandle(
198 OUString* _pPropName, sal_Int16* _pAttributes, sal_Int32 _nHandle)
200 ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
201 bool bRet = i != m_aPropertyAccessors.end();
202 if (bRet)
204 const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos];
205 if (_pPropName)
206 *_pPropName = rProperty.Name;
207 if (_pAttributes)
208 *_pAttributes = rProperty.Attributes;
210 return bRet;
214 bool OPropertyArrayAggregationHelper::getPropertyByHandle( sal_Int32 _nHandle, Property& _rProperty ) const
216 ConstPropertyAccessorMapIterator pos = m_aPropertyAccessors.find(_nHandle);
217 if ( pos != m_aPropertyAccessors.end() )
219 _rProperty = m_aProperties[ pos->second.nPos ];
220 return true;
222 return false;
226 bool OPropertyArrayAggregationHelper::fillAggregatePropertyInfoByHandle(
227 OUString* _pPropName, sal_Int32* _pOriginalHandle, sal_Int32 _nHandle) const
229 ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
230 bool bRet = i != m_aPropertyAccessors.end() && (*i).second.bAggregate;
231 if (bRet)
233 if (_pOriginalHandle)
234 *_pOriginalHandle = (*i).second.nOriginalHandle;
235 if (_pPropName)
237 OSL_ENSURE((*i).second.nPos < m_aProperties.getLength(),"Invalid index for sequence!");
238 const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos];
239 *_pPropName = rProperty.Name;
242 return bRet;
247 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property> OPropertyArrayAggregationHelper::getProperties()
249 return m_aProperties;
254 sal_Int32 OPropertyArrayAggregationHelper::fillHandles(
255 sal_Int32* _pHandles, const ::com::sun::star::uno::Sequence< OUString >& _rPropNames )
257 sal_Int32 nHitCount = 0;
258 const OUString* pReqProps = _rPropNames.getConstArray();
259 sal_Int32 nReqLen = _rPropNames.getLength();
261 #if OSL_DEBUG_LEVEL > 0
262 // assure that the sequence is sorted
264 const OUString* pLookup = _rPropNames.getConstArray();
265 const OUString* pEnd = _rPropNames.getConstArray() + _rPropNames.getLength() - 1;
266 for (; pLookup < pEnd; ++pLookup)
268 const OUString* pCompare = pLookup + 1;
269 const OUString* pCompareEnd = pEnd + 1;
270 for (; pCompare < pCompareEnd; ++pCompare)
272 OSL_ENSURE(pLookup->compareTo(*pCompare) < 0, "OPropertyArrayAggregationHelper::fillHandles : property names are not sorted!");
276 #endif
278 const ::com::sun::star::beans::Property* pCur = m_aProperties.getConstArray();
279 const ::com::sun::star::beans::Property* pEnd = m_aProperties.getConstArray() + m_aProperties.getLength();
281 for( sal_Int32 i = 0; i < nReqLen; ++i )
283 // determine the logarithm
284 sal_uInt32 n = (sal_uInt32)(pEnd - pCur);
285 sal_Int32 nLog = 0;
286 while( n )
288 nLog += 1;
289 n = n >> 1;
292 // (Number of properties yet to be found) * (Log2 of properties yet to be searched)
293 if( (nReqLen - i) * nLog >= pEnd - pCur )
295 // linear search is better
296 while( pCur < pEnd && pReqProps[i] > pCur->Name )
298 pCur++;
300 if( pCur < pEnd && pReqProps[i] == pCur->Name )
302 _pHandles[i] = pCur->Handle;
303 nHitCount++;
305 else
306 _pHandles[i] = -1;
308 else
310 // binary search is better
311 sal_Int32 nCompVal = 1;
312 const ::com::sun::star::beans::Property* pOldEnd = pEnd--;
313 const ::com::sun::star::beans::Property* pMid = pCur;
315 while( nCompVal != 0 && pCur <= pEnd )
317 pMid = (pEnd - pCur) / 2 + pCur;
319 nCompVal = pReqProps[i].compareTo( pMid->Name );
321 if( nCompVal > 0 )
322 pCur = pMid + 1;
323 else
324 pEnd = pMid - 1;
327 if( nCompVal == 0 )
329 _pHandles[i] = pMid->Handle;
330 nHitCount++;
331 pCur = pMid +1;
333 else if( nCompVal > 0 )
335 _pHandles[i] = -1;
336 pCur = pMid + 1;
338 else
340 _pHandles[i] = -1;
341 pCur = pMid;
343 pEnd = pOldEnd;
346 return nHitCount;
349 namespace internal
351 class PropertyForwarder
353 private:
354 OPropertySetAggregationHelper& m_rAggregationHelper;
355 ::std::set< sal_Int32 > m_aProperties;
356 sal_Int32 m_nCurrentlyForwarding;
358 public:
359 PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper );
360 ~PropertyForwarder();
362 /** declares that the forwarder should be responsible for the given property
364 @param _nHandle
365 the public handle (<em>not</em> the original handle!) of the property
367 void takeResponsibilityFor( sal_Int32 _nHandle );
369 /** checks whether the forwarder is responsible for the given property
371 bool isResponsibleFor( sal_Int32 _nHandle );
373 /// actually forwards a property value to the aggregate
374 void doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception );
376 sal_Int32 getCurrentlyForwardedProperty( ) const { return m_nCurrentlyForwarding; }
380 PropertyForwarder::PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper )
381 :m_rAggregationHelper( _rAggregationHelper )
382 ,m_nCurrentlyForwarding( -1 )
387 PropertyForwarder::~PropertyForwarder()
392 void PropertyForwarder::takeResponsibilityFor( sal_Int32 _nHandle )
394 m_aProperties.insert( _nHandle );
398 bool PropertyForwarder::isResponsibleFor( sal_Int32 _nHandle )
400 return m_aProperties.find( _nHandle ) != m_aProperties.end();
404 void PropertyForwarder::doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception )
406 OSL_ENSURE( m_rAggregationHelper.m_xAggregateSet.is(), "PropertyForwarder::doForward: no property set!" );
407 if ( m_rAggregationHelper.m_xAggregateSet.is() )
409 m_rAggregationHelper.forwardingPropertyValue( _nHandle );
411 OSL_ENSURE( m_nCurrentlyForwarding == -1, "PropertyForwarder::doForward: reentrance?" );
412 m_nCurrentlyForwarding = _nHandle;
416 m_rAggregationHelper.m_xAggregateSet->setPropertyValue( m_rAggregationHelper.getPropertyName( _nHandle ), _rValue );
417 // TODO: cache the property name? (it's a O(log n) search)
419 catch( const Exception& )
421 m_rAggregationHelper.forwardedPropertyValue( _nHandle );
422 throw;
425 m_nCurrentlyForwarding = -1;
427 m_rAggregationHelper.forwardedPropertyValue( _nHandle );
432 OPropertySetAggregationHelper::OPropertySetAggregationHelper( ::cppu::OBroadcastHelper& rBHlp )
433 :OPropertyStateHelper( rBHlp )
434 ,m_bListening( false )
436 m_pForwarder = new PropertyForwarder( *this );
440 OPropertySetAggregationHelper::~OPropertySetAggregationHelper()
442 delete m_pForwarder;
446 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::queryInterface(const ::com::sun::star::uno::Type& _rType) throw( ::com::sun::star::uno::RuntimeException, std::exception)
448 ::com::sun::star::uno::Any aReturn = OPropertyStateHelper::queryInterface(_rType);
450 if ( !aReturn.hasValue() )
451 aReturn = cppu::queryInterface(_rType
452 ,static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this)
453 ,static_cast< ::com::sun::star::beans::XVetoableChangeListener*>(this)
454 ,static_cast< ::com::sun::star::lang::XEventListener*>(static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this))
457 return aReturn;
461 void OPropertySetAggregationHelper::disposing()
463 osl::MutexGuard aGuard(rBHelper.rMutex);
465 if ( m_xAggregateSet.is() && m_bListening )
467 // register as a single listener
468 m_xAggregateMultiSet->removePropertiesChangeListener(this);
469 m_xAggregateSet->removeVetoableChangeListener(OUString(), this);
470 m_bListening = false;
473 OPropertyStateHelper::disposing();
477 void SAL_CALL OPropertySetAggregationHelper::disposing(const ::com::sun::star::lang::EventObject& _rSource) throw ( ::com::sun::star::uno::RuntimeException, std::exception)
479 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::disposing : don't have an aggregate anymore !");
480 if (_rSource.Source == m_xAggregateSet)
481 m_bListening = false;
485 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)
487 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::propertiesChange : have no aggregate !");
489 sal_Int32 nLen = _rEvents.getLength();
490 cppu::IPropertyArrayHelper& rPH = getInfoHelper();
492 if (1 == nLen)
494 const ::com::sun::star::beans::PropertyChangeEvent& evt = _rEvents.getConstArray()[0];
495 OSL_ENSURE(!evt.PropertyName.isEmpty(), "OPropertySetAggregationHelper::propertiesChange : invalid event !");
496 // we had a bug where this assertion would have us saved a whole day :) (72514)
497 sal_Int32 nHandle = rPH.getHandleByName( evt.PropertyName );
499 // If nHandle is -1 the event marks a (aggregate) property which we hide to callers
500 // If isCurrentlyForwardingProperty( nHandle ) is <TRUE/>, then we ourself triggered
501 // setting this property. In this case, it will be notified later (by the OPropertySetHelper
502 // implementation)
504 if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
505 fire(&nHandle, &evt.NewValue, &evt.OldValue, 1, sal_False);
507 else
509 boost::scoped_array<sal_Int32> pHandles(new sal_Int32[nLen]);
510 boost::scoped_array< ::com::sun::star::uno::Any> pNewValues(new ::com::sun::star::uno::Any[nLen]);
511 boost::scoped_array< ::com::sun::star::uno::Any> pOldValues(new ::com::sun::star::uno::Any[nLen]);
513 const ::com::sun::star::beans::PropertyChangeEvent* pEvents = _rEvents.getConstArray();
514 sal_Int32 nDest = 0;
515 for (sal_Int32 nSource=0; nSource<nLen; ++nSource, ++pEvents)
517 sal_Int32 nHandle = rPH.getHandleByName(pEvents->PropertyName);
518 if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
519 { // same as above : -1 is valid (73247) ...
520 pHandles[nDest] = nHandle;
521 pNewValues[nDest] = pEvents->NewValue;
522 pOldValues[nDest] = pEvents->OldValue;
523 ++nDest;
527 if (nDest)
528 fire(pHandles.get(), pNewValues.get(), pOldValues.get(), nDest, sal_False);
533 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)
535 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::vetoableChange : have no aggregate !");
537 cppu::IPropertyArrayHelper& rPH = getInfoHelper();
539 sal_Int32 nHandle = rPH.getHandleByName(_rEvent.PropertyName);
540 fire(&nHandle, &_rEvent.NewValue, &_rEvent.OldValue, 1, sal_True);
544 void OPropertySetAggregationHelper::setAggregation(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxDelegate)
545 throw( ::com::sun::star::lang::IllegalArgumentException )
547 osl::MutexGuard aGuard(rBHelper.rMutex);
549 if (m_bListening && m_xAggregateSet.is())
551 m_xAggregateMultiSet->removePropertiesChangeListener(this);
552 m_xAggregateSet->removeVetoableChangeListener(OUString(), this);
553 m_bListening = false;
556 m_xAggregateState.set(_rxDelegate, css::uno::UNO_QUERY);
557 m_xAggregateSet.set(_rxDelegate, css::uno::UNO_QUERY);
558 m_xAggregateMultiSet.set(_rxDelegate, css::uno::UNO_QUERY);
559 m_xAggregateFastSet.set(_rxDelegate, css::uno::UNO_QUERY);
561 // must support XPropertySet and XMultiPropertySet
562 if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() )
563 throw ::com::sun::star::lang::IllegalArgumentException();
567 void OPropertySetAggregationHelper::startListening()
569 osl::MutexGuard aGuard(rBHelper.rMutex);
571 if (!m_bListening && m_xAggregateSet.is())
573 // register as a single listener
574 ::com::sun::star::uno::Sequence< OUString > aPropertyNames;
575 m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this);
576 m_xAggregateSet->addVetoableChangeListener(OUString(), this);
578 m_bListening = true;
583 void SAL_CALL OPropertySetAggregationHelper::addVetoableChangeListener(const OUString& _rPropertyName,
584 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener>& _rxListener)
585 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception)
587 OPropertySetHelper::addVetoableChangeListener(_rPropertyName, _rxListener);
588 if (!m_bListening)
589 startListening();
593 void SAL_CALL OPropertySetAggregationHelper::addPropertyChangeListener(const OUString& _rPropertyName,
594 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener>& _rxListener)
595 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception)
597 OPropertySetHelper::addPropertyChangeListener(_rPropertyName, _rxListener);
598 if (!m_bListening)
599 startListening();
603 void SAL_CALL OPropertySetAggregationHelper::addPropertiesChangeListener(const ::com::sun::star::uno::Sequence< OUString >& _rPropertyNames,
604 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener>& _rxListener)
605 throw( ::com::sun::star::uno::RuntimeException, std::exception)
607 OPropertySetHelper::addPropertiesChangeListener(_rPropertyNames, _rxListener);
608 if (!m_bListening)
609 startListening();
613 sal_Int32 OPropertySetAggregationHelper::getOriginalHandle(sal_Int32 nHandle) const
615 OPropertyArrayAggregationHelper& rPH = static_cast<OPropertyArrayAggregationHelper&>( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
616 sal_Int32 nOriginalHandle = -1;
617 (void)rPH.fillAggregatePropertyInfoByHandle(NULL, &nOriginalHandle, nHandle);
618 return nOriginalHandle;
622 OUString OPropertySetAggregationHelper::getPropertyName( sal_Int32 _nHandle ) const
624 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
625 Property aProperty;
626 OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
627 return aProperty.Name;
631 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue(sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rValue)
632 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException,
633 ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException,
634 ::com::sun::star::uno::RuntimeException, std::exception)
636 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
637 OUString aPropName;
638 sal_Int32 nOriginalHandle = -1;
640 // does the handle belong to the aggregation ?
641 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, _nHandle))
642 if (m_xAggregateFastSet.is())
643 m_xAggregateFastSet->setFastPropertyValue(nOriginalHandle, _rValue);
644 else
645 m_xAggregateSet->setPropertyValue(aPropName, _rValue);
646 else
647 OPropertySetHelper::setFastPropertyValue(_nHandle, _rValue);
651 void OPropertySetAggregationHelper::getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle) const
653 OPropertyArrayAggregationHelper& rPH = static_cast<OPropertyArrayAggregationHelper&>( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
654 OUString aPropName;
655 sal_Int32 nOriginalHandle = -1;
657 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
659 if (m_xAggregateFastSet.is())
660 rValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
661 else
662 rValue = m_xAggregateSet->getPropertyValue(aPropName);
664 else if ( m_pForwarder->isResponsibleFor( nHandle ) )
666 // this is a property which has been "overwritten" in our instance (thus
667 // fillAggregatePropertyInfoByHandle didn't find it)
668 rValue = m_xAggregateSet->getPropertyValue( getPropertyName( nHandle ) );
673 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getFastPropertyValue(sal_Int32 nHandle)
674 throw( ::com::sun::star::beans::UnknownPropertyException,
675 ::com::sun::star::lang::WrappedTargetException,
676 ::com::sun::star::uno::RuntimeException, std::exception)
678 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
679 OUString aPropName;
680 sal_Int32 nOriginalHandle = -1;
681 ::com::sun::star::uno::Any aValue;
683 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
685 if (m_xAggregateFastSet.is())
686 aValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
687 else
688 aValue = m_xAggregateSet->getPropertyValue(aPropName);
690 else
691 aValue = OPropertySetHelper::getFastPropertyValue(nHandle);
693 return aValue;
697 void SAL_CALL OPropertySetAggregationHelper::setPropertyValues(
698 const Sequence< OUString >& _rPropertyNames, const Sequence< Any >& _rValues )
699 throw ( PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException, std::exception )
701 OSL_ENSURE( !rBHelper.bInDispose, "OPropertySetAggregationHelper::setPropertyValues : do not use within the dispose call !");
702 OSL_ENSURE( !rBHelper.bDisposed, "OPropertySetAggregationHelper::setPropertyValues : object is disposed" );
704 // check where the properties come from
705 if (!m_xAggregateSet.is())
706 OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
707 else if (_rPropertyNames.getLength() == 1) // use the more efficient way
711 setPropertyValue( _rPropertyNames[0], _rValues[0] );
713 catch( const UnknownPropertyException& )
715 // by definition of XMultiPropertySet::setPropertyValues, unknown properties are to be ignored
716 #if OSL_DEBUG_LEVEL > 0
717 OStringBuffer aMessage;
718 aMessage.append( "OPropertySetAggregationHelper::setPropertyValues: unknown property '" );
719 aMessage.append( OUStringToOString( _rPropertyNames[0], RTL_TEXTENCODING_ASCII_US ) );
720 aMessage.append( "'" );
721 aMessage.append( "\n(implementation " );
722 aMessage.append( typeid( *this ).name() );
723 aMessage.append( ")" );
724 OSL_FAIL( aMessage.getStr() );
725 #endif
728 else
730 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
732 // determine which properties belong to the aggregate, and which ones to the delegator
733 const OUString* pNames = _rPropertyNames.getConstArray();
734 sal_Int32 nAggCount(0);
735 sal_Int32 nLen(_rPropertyNames.getLength());
737 for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames )
739 OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( *pNames );
740 if ( OPropertyArrayAggregationHelper::UNKNOWN_PROPERTY == ePropOrg )
741 throw WrappedTargetException( OUString(), static_cast< XMultiPropertySet* >( this ), makeAny( UnknownPropertyException( ) ) );
742 // due to a flaw in the API design, this method is not allowed to throw an UnknownPropertyException
743 // so we wrap it into a WrappedTargetException
745 if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == ePropOrg )
746 ++nAggCount;
749 pNames = _rPropertyNames.getConstArray(); // reset, we'll need it again below ...
751 // all properties belong to the aggregate
752 if (nAggCount == nLen)
753 m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues);
755 // all properties belong to the aggregating object
756 else if (nAggCount == 0)
757 OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
759 // mixed
760 else
762 const ::com::sun::star::uno::Any* pValues = _rValues.getConstArray();
766 // dividing the Names and _rValues
768 // aggregate's names
769 Sequence< OUString > AggPropertyNames( nAggCount );
770 OUString* pAggNames = AggPropertyNames.getArray();
771 // aggregate's values
772 Sequence< Any > AggValues( nAggCount );
773 Any* pAggValues = AggValues.getArray();
775 // delegator names
776 Sequence< OUString > DelPropertyNames( nLen - nAggCount );
777 OUString* pDelNames = DelPropertyNames.getArray();
779 // delegator values
780 Sequence< Any > DelValues( nLen - nAggCount );
781 Any* pDelValues = DelValues.getArray();
783 for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames, ++pValues )
785 if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == rPH.classifyProperty( *pNames ) )
787 *pAggNames++ = *pNames;
788 *pAggValues++ = *pValues;
790 else
792 *pDelNames++ = *pNames;
793 *pDelValues++ = *pValues;
797 // reset, needed below
798 pDelValues = DelValues.getArray();
800 boost::scoped_array<sal_Int32> pHandles(new sal_Int32[ nLen - nAggCount ]);
802 // get the map table
803 cppu::IPropertyArrayHelper& rPH2 = getInfoHelper();
805 // fill the handle array
806 sal_Int32 nHitCount = rPH2.fillHandles( pHandles.get(), DelPropertyNames );
807 if (nHitCount != 0)
809 boost::scoped_array< ::com::sun::star::uno::Any> pConvertedValues(new ::com::sun::star::uno::Any[ nHitCount ]);
810 boost::scoped_array< ::com::sun::star::uno::Any> pOldValues(new ::com::sun::star::uno::Any[ nHitCount ]);
811 nHitCount = 0;
812 sal_Int32 i;
815 // must lock the mutex outside the loop. So all values are consistent.
816 osl::MutexGuard aGuard( rBHelper.rMutex );
817 for( i = 0; i < (nLen - nAggCount); ++i )
819 if( pHandles[i] != -1 )
821 sal_Int16 nAttributes;
822 rPH2.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] );
823 if( nAttributes & ::com::sun::star::beans::PropertyAttribute::READONLY )
824 throw ::com::sun::star::beans::PropertyVetoException();
825 // Will the property change?
826 if( convertFastPropertyValue( pConvertedValues[ nHitCount ], pOldValues[nHitCount],
827 pHandles[i], pDelValues[i] ) )
829 // only increment if the property really change
830 pHandles[nHitCount] = pHandles[i];
831 nHitCount++;
835 // release guard to fire events
838 // fire vetoable events
839 fire( pHandles.get(), pConvertedValues.get(), pOldValues.get(), nHitCount, sal_True );
841 // setting the agg Properties
842 m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
845 // must lock the mutex outside the loop.
846 osl::MutexGuard aGuard( rBHelper.rMutex );
847 // Loop over all changed properties
848 for( i = 0; i < nHitCount; i++ )
850 // Will the property change?
851 setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
853 // release guard to fire events
856 // fire change events
857 fire( pHandles.get(), pConvertedValues.get(), pOldValues.get(), nHitCount, sal_False );
859 else
860 m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
863 catch(::com::sun::star::uno::Exception&)
865 throw;
871 // XPropertyState
873 ::com::sun::star::beans::PropertyState SAL_CALL OPropertySetAggregationHelper::getPropertyState(const OUString& _rPropertyName)
874 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException, std::exception)
876 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
877 sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName );
879 if (nHandle == -1)
881 throw ::com::sun::star::beans::UnknownPropertyException();
884 OUString aPropName;
885 sal_Int32 nOriginalHandle = -1;
886 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
888 if (m_xAggregateState.is())
889 return m_xAggregateState->getPropertyState(_rPropertyName);
890 else
891 return ::com::sun::star::beans::PropertyState_DIRECT_VALUE;
893 else
894 return getPropertyStateByHandle(nHandle);
898 void SAL_CALL OPropertySetAggregationHelper::setPropertyToDefault(const OUString& _rPropertyName)
899 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException, std::exception)
901 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
902 sal_Int32 nHandle = rPH.getHandleByName(_rPropertyName);
903 if (nHandle == -1)
905 throw ::com::sun::star::beans::UnknownPropertyException();
908 OUString aPropName;
909 sal_Int32 nOriginalHandle = -1;
910 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
912 if (m_xAggregateState.is())
913 m_xAggregateState->setPropertyToDefault(_rPropertyName);
915 else
919 setPropertyToDefaultByHandle( nHandle );
921 catch( const UnknownPropertyException& ) { throw; }
922 catch( const RuntimeException& ) { throw; }
923 catch( const Exception& )
925 OSL_FAIL( "OPropertySetAggregationHelper::setPropertyToDefault: caught an exception which is not allowed to leave here!" );
931 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getPropertyDefault(const OUString& aPropertyName)
932 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception)
934 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
935 sal_Int32 nHandle = rPH.getHandleByName( aPropertyName );
937 if ( nHandle == -1 )
938 throw ::com::sun::star::beans::UnknownPropertyException();
940 OUString aPropName;
941 sal_Int32 nOriginalHandle = -1;
942 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
944 if (m_xAggregateState.is())
945 return m_xAggregateState->getPropertyDefault(aPropertyName);
946 else
947 return ::com::sun::star::uno::Any();
949 else
950 return getPropertyDefaultByHandle(nHandle);
954 sal_Bool SAL_CALL OPropertySetAggregationHelper::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException)
956 bool bModified = false;
958 OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::convertFastPropertyValue: this is no forwarded property - did you use declareForwardedProperty for it?" );
959 if ( m_pForwarder->isResponsibleFor( _nHandle ) )
961 // need to determine the type of the property for conversion
962 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
963 Property aProperty;
964 OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
966 Any aCurrentValue;
967 getFastPropertyValue( aCurrentValue, _nHandle );
968 bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, aCurrentValue, aProperty.Type );
971 return bModified;
975 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception, std::exception )
977 OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast: this is no forwarded property - did you use declareForwardedProperty for it?" );
978 if ( m_pForwarder->isResponsibleFor( _nHandle ) )
979 m_pForwarder->doForward( _nHandle, _rValue );
983 void OPropertySetAggregationHelper::declareForwardedProperty( sal_Int32 _nHandle )
985 OSL_ENSURE( !m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::declareForwardedProperty: already declared!" );
986 m_pForwarder->takeResponsibilityFor( _nHandle );
990 void OPropertySetAggregationHelper::forwardingPropertyValue( sal_Int32 )
992 // not interested in
996 void OPropertySetAggregationHelper::forwardedPropertyValue( sal_Int32 )
998 // not interested in
1002 bool OPropertySetAggregationHelper::isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const
1004 return m_pForwarder->getCurrentlyForwardedProperty() == _nHandle;
1008 } // namespace comphelper
1011 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */