Version 4.0.0.1, tag libreoffice-4.0.0.1
[LibreOffice.git] / comphelper / source / property / propagg.cxx
blobbc24d94995274b4173e13b21237271fb88f519f2
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>
34 //.........................................................................
35 namespace comphelper
37 //.........................................................................
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;
45 //------------------------------------------------------------------------------
46 namespace
48 const Property* lcl_findPropertyByName( const Sequence< Property >& _rProps, const ::rtl::OUString& _rName )
50 sal_Int32 nLen = _rProps.getLength();
51 const Property* pProperties = _rProps.getConstArray();
52 Property aNameProp(_rName, 0, Type(), 0);
53 const Property* pResult = ::std::lower_bound(pProperties, pProperties + nLen, aNameProp, PropertyCompareByName());
54 if ( pResult && ( pResult == pProperties + nLen || pResult->Name != _rName) )
55 pResult = NULL;
57 return pResult;
60 //==================================================================
61 //= OPropertyArrayAggregationHelper
62 //==================================================================
64 //------------------------------------------------------------------------------
65 OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper(
66 const Sequence< Property >& _rProperties, const Sequence< Property >& _rAggProperties,
67 IPropertyInfoService* _pInfoService, sal_Int32 _nFirstAggregateId )
68 :m_aProperties( _rProperties )
70 sal_Int32 nDelegatorProps = _rProperties.getLength();
71 sal_Int32 nAggregateProps = _rAggProperties.getLength();
73 // make room for all properties
74 sal_Int32 nMergedProps = nDelegatorProps + nAggregateProps;
75 m_aProperties.realloc( nMergedProps );
77 const Property* pAggregateProps = _rAggProperties.getConstArray();
78 const Property* pDelegateProps = _rProperties.getConstArray();
79 Property* pMergedProps = m_aProperties.getArray();
81 // if properties are present both at the delegatee and the aggregate, then the former are supposed to win.
82 // So, we'll need an existence check.
83 ::std::set< ::rtl::OUString > aDelegatorProps;
85 // create the map for the delegator properties
86 sal_Int32 nMPLoop = 0;
87 for ( ; nMPLoop < nDelegatorProps; ++nMPLoop, ++pDelegateProps )
89 m_aPropertyAccessors[ pDelegateProps->Handle ] = OPropertyAccessor( -1, nMPLoop, sal_False );
90 OSL_ENSURE( aDelegatorProps.find( pDelegateProps->Name ) == aDelegatorProps.end(),
91 "OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper: duplicate delegatee property!" );
92 aDelegatorProps.insert( pDelegateProps->Name );
95 // create the map for the aggregate properties
96 sal_Int32 nAggregateHandle = _nFirstAggregateId;
97 pMergedProps += nDelegatorProps;
98 for ( ; nMPLoop < nMergedProps; ++pAggregateProps )
100 // if the aggregate property is present at the delegatee already, ignore it
101 if ( aDelegatorProps.find( pAggregateProps->Name ) != aDelegatorProps.end() )
103 --nMergedProps;
104 continue;
107 // next aggregate property - remember it
108 *pMergedProps = *pAggregateProps;
110 // determine the handle for the property which we will expose to the outside world
111 sal_Int32 nHandle = -1;
112 // ask the infor service first
113 if ( _pInfoService )
114 nHandle = _pInfoService->getPreferedPropertyId( pMergedProps->Name );
116 if ( -1 == nHandle )
117 // no handle from the info service -> default
118 nHandle = nAggregateHandle++;
119 else
120 { // check if we alread have a property with the given handle
121 const Property* pPropsTilNow = m_aProperties.getConstArray();
122 for ( sal_Int32 nCheck = 0; nCheck < nMPLoop; ++nCheck, ++pPropsTilNow )
123 if ( pPropsTilNow->Handle == nHandle )
124 { // conflicts -> use another one (which we don't check anymore, assuming _nFirstAggregateId was large enough)
125 nHandle = nAggregateHandle++;
126 break;
130 // remember the accessor for this property
131 m_aPropertyAccessors[ nHandle ] = OPropertyAccessor( pMergedProps->Handle, nMPLoop, sal_True );
132 pMergedProps->Handle = nHandle;
134 ++nMPLoop;
135 ++pMergedProps;
137 m_aProperties.realloc( nMergedProps );
138 pMergedProps = m_aProperties.getArray(); // reset, needed again below
140 // sort the properties by name
141 ::std::sort( pMergedProps, pMergedProps+nMergedProps, PropertyCompareByName());
143 pMergedProps = m_aProperties.getArray();
145 // sync the map positions
146 for ( nMPLoop = 0; nMPLoop < nMergedProps; ++nMPLoop, ++pMergedProps )
147 m_aPropertyAccessors[ pMergedProps->Handle ].nPos = nMPLoop;
150 //------------------------------------------------------------------
151 OPropertyArrayAggregationHelper::PropertyOrigin OPropertyArrayAggregationHelper::classifyProperty( const ::rtl::OUString& _rName )
153 PropertyOrigin eOrigin = UNKNOWN_PROPERTY;
154 // look up the name
155 const Property* pPropertyDescriptor = lcl_findPropertyByName( m_aProperties, _rName );
156 if ( pPropertyDescriptor )
158 // look up the handle for this name
159 ConstPropertyAccessorMapIterator aPos = m_aPropertyAccessors.find( pPropertyDescriptor->Handle );
160 OSL_ENSURE( m_aPropertyAccessors.end() != aPos, "OPropertyArrayAggregationHelper::classifyProperty: should have this handle in my map!" );
161 if ( m_aPropertyAccessors.end() != aPos )
163 eOrigin = aPos->second.bAggregate ? AGGREGATE_PROPERTY : DELEGATOR_PROPERTY;
166 return eOrigin;
169 //------------------------------------------------------------------
170 Property OPropertyArrayAggregationHelper::getPropertyByName( const ::rtl::OUString& _rPropertyName ) throw( UnknownPropertyException )
172 const Property* pProperty = findPropertyByName( _rPropertyName );
174 if ( !pProperty )
175 throw UnknownPropertyException();
177 return *pProperty;
180 //------------------------------------------------------------------------------
181 sal_Bool OPropertyArrayAggregationHelper::hasPropertyByName(const ::rtl::OUString& _rPropertyName)
183 return NULL != findPropertyByName( _rPropertyName );
186 //------------------------------------------------------------------------------
187 const Property* OPropertyArrayAggregationHelper::findPropertyByName(const :: rtl::OUString& _rName ) const
189 return lcl_findPropertyByName( m_aProperties, _rName );
192 //------------------------------------------------------------------------------
193 sal_Int32 OPropertyArrayAggregationHelper::getHandleByName(const ::rtl::OUString& _rPropertyName)
195 const Property* pProperty = findPropertyByName( _rPropertyName );
196 return pProperty ? pProperty->Handle : -1;
199 //------------------------------------------------------------------------------
200 sal_Bool OPropertyArrayAggregationHelper::fillPropertyMembersByHandle(
201 ::rtl::OUString* _pPropName, sal_Int16* _pAttributes, sal_Int32 _nHandle)
203 ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
204 sal_Bool bRet = i != m_aPropertyAccessors.end();
205 if (bRet)
207 const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos];
208 if (_pPropName)
209 *_pPropName = rProperty.Name;
210 if (_pAttributes)
211 *_pAttributes = rProperty.Attributes;
213 return bRet;
216 //------------------------------------------------------------------------------
217 sal_Bool OPropertyArrayAggregationHelper::getPropertyByHandle( sal_Int32 _nHandle, Property& _rProperty ) const
219 ConstPropertyAccessorMapIterator pos = m_aPropertyAccessors.find(_nHandle);
220 if ( pos != m_aPropertyAccessors.end() )
222 _rProperty = m_aProperties[ pos->second.nPos ];
223 return sal_True;
225 return sal_False;
228 //------------------------------------------------------------------------------
229 bool OPropertyArrayAggregationHelper::fillAggregatePropertyInfoByHandle(
230 ::rtl::OUString* _pPropName, sal_Int32* _pOriginalHandle, sal_Int32 _nHandle) const
232 ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
233 bool bRet = i != m_aPropertyAccessors.end() && (*i).second.bAggregate;
234 if (bRet)
236 if (_pOriginalHandle)
237 *_pOriginalHandle = (*i).second.nOriginalHandle;
238 if (_pPropName)
240 OSL_ENSURE((*i).second.nPos < m_aProperties.getLength(),"Invalid index for sequence!");
241 const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos];
242 *_pPropName = rProperty.Name;
245 return bRet;
249 //------------------------------------------------------------------------------
250 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property> OPropertyArrayAggregationHelper::getProperties()
252 return m_aProperties;
256 //------------------------------------------------------------------------------
257 sal_Int32 OPropertyArrayAggregationHelper::fillHandles(
258 sal_Int32* _pHandles, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rPropNames )
260 sal_Int32 nHitCount = 0;
261 const ::rtl::OUString* pReqProps = _rPropNames.getConstArray();
262 sal_Int32 nReqLen = _rPropNames.getLength();
264 #if OSL_DEBUG_LEVEL > 0
265 // assure that the sequence is sorted
267 const ::rtl::OUString* pLookup = _rPropNames.getConstArray();
268 const ::rtl::OUString* pEnd = _rPropNames.getConstArray() + _rPropNames.getLength() - 1;
269 for (; pLookup < pEnd; ++pLookup)
271 const ::rtl::OUString* pCompare = pLookup + 1;
272 const ::rtl::OUString* pCompareEnd = pEnd + 1;
273 for (; pCompare < pCompareEnd; ++pCompare)
275 OSL_ENSURE(pLookup->compareTo(*pCompare) < 0, "OPropertyArrayAggregationHelper::fillHandles : property names are not sorted!");
279 #endif
281 const ::com::sun::star::beans::Property* pCur = m_aProperties.getConstArray();
282 const ::com::sun::star::beans::Property* pEnd = m_aProperties.getConstArray() + m_aProperties.getLength();
284 for( sal_Int32 i = 0; i < nReqLen; ++i )
286 // determine the logarithm
287 sal_uInt32 n = (sal_uInt32)(pEnd - pCur);
288 sal_Int32 nLog = 0;
289 while( n )
291 nLog += 1;
292 n = n >> 1;
295 // (Number of properties yet to be found) * (Log2 of properties yet to be searched)
296 if( (nReqLen - i) * nLog >= pEnd - pCur )
298 // linear search is better
299 while( pCur < pEnd && pReqProps[i] > pCur->Name )
301 pCur++;
303 if( pCur < pEnd && pReqProps[i] == pCur->Name )
305 _pHandles[i] = pCur->Handle;
306 nHitCount++;
308 else
309 _pHandles[i] = -1;
311 else
313 // binary search is better
314 sal_Int32 nCompVal = 1;
315 const ::com::sun::star::beans::Property* pOldEnd = pEnd--;
316 const ::com::sun::star::beans::Property* pMid = pCur;
318 while( nCompVal != 0 && pCur <= pEnd )
320 pMid = (pEnd - pCur) / 2 + pCur;
322 nCompVal = pReqProps[i].compareTo( pMid->Name );
324 if( nCompVal > 0 )
325 pCur = pMid + 1;
326 else
327 pEnd = pMid - 1;
330 if( nCompVal == 0 )
332 _pHandles[i] = pMid->Handle;
333 nHitCount++;
334 pCur = pMid +1;
336 else if( nCompVal > 0 )
338 _pHandles[i] = -1;
339 pCur = pMid + 1;
341 else
343 _pHandles[i] = -1;
344 pCur = pMid;
346 pEnd = pOldEnd;
349 return nHitCount;
352 //==================================================================
353 //= PropertyForwarder
354 //==================================================================
355 namespace internal
357 class PropertyForwarder
359 private:
360 OPropertySetAggregationHelper& m_rAggregationHelper;
361 ::std::set< sal_Int32 > m_aProperties;
362 sal_Int32 m_nCurrentlyForwarding;
364 public:
365 PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper );
366 ~PropertyForwarder();
368 /** declares that the forwarder should be responsible for the given property
370 @param _nHandle
371 the public handle (<em>not</em> the original handle!) of the property
373 void takeResponsibilityFor( sal_Int32 _nHandle );
375 /** checks whether the forwarder is responsible for the given property
377 bool isResponsibleFor( sal_Int32 _nHandle );
379 /// actually forwards a property value to the aggregate
380 void doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception );
382 sal_Int32 getCurrentlyForwardedProperty( ) const { return m_nCurrentlyForwarding; }
385 //--------------------------------------------------------------------------
386 PropertyForwarder::PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper )
387 :m_rAggregationHelper( _rAggregationHelper )
388 ,m_nCurrentlyForwarding( -1 )
392 //--------------------------------------------------------------------------
393 PropertyForwarder::~PropertyForwarder()
397 //--------------------------------------------------------------------------
398 void PropertyForwarder::takeResponsibilityFor( sal_Int32 _nHandle )
400 m_aProperties.insert( _nHandle );
403 //--------------------------------------------------------------------------
404 bool PropertyForwarder::isResponsibleFor( sal_Int32 _nHandle )
406 return m_aProperties.find( _nHandle ) != m_aProperties.end();
409 //--------------------------------------------------------------------------
410 void PropertyForwarder::doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception )
412 OSL_ENSURE( m_rAggregationHelper.m_xAggregateSet.is(), "PropertyForwarder::doForward: no property set!" );
413 if ( m_rAggregationHelper.m_xAggregateSet.is() )
415 m_rAggregationHelper.forwardingPropertyValue( _nHandle );
417 OSL_ENSURE( m_nCurrentlyForwarding == -1, "PropertyForwarder::doForward: reentrance?" );
418 m_nCurrentlyForwarding = _nHandle;
422 m_rAggregationHelper.m_xAggregateSet->setPropertyValue( m_rAggregationHelper.getPropertyName( _nHandle ), _rValue );
423 // TODO: cache the property name? (it's a O(log n) search)
425 catch( const Exception& )
427 m_rAggregationHelper.forwardedPropertyValue( _nHandle, false );
428 throw;
431 m_nCurrentlyForwarding = -1;
433 m_rAggregationHelper.forwardedPropertyValue( _nHandle, true );
438 //==================================================================
439 //= OPropertySetAggregationHelper
440 //==================================================================
442 //------------------------------------------------------------------------------
443 OPropertySetAggregationHelper::OPropertySetAggregationHelper( ::cppu::OBroadcastHelper& rBHlp )
444 :OPropertyStateHelper( rBHlp )
445 ,m_bListening( sal_False )
447 m_pForwarder = new PropertyForwarder( *this );
450 //------------------------------------------------------------------------------
451 OPropertySetAggregationHelper::~OPropertySetAggregationHelper()
453 delete m_pForwarder;
456 //------------------------------------------------------------------------------
457 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::queryInterface(const ::com::sun::star::uno::Type& _rType) throw( ::com::sun::star::uno::RuntimeException)
459 ::com::sun::star::uno::Any aReturn = OPropertyStateHelper::queryInterface(_rType);
461 if ( !aReturn.hasValue() )
462 aReturn = cppu::queryInterface(_rType
463 ,static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this)
464 ,static_cast< ::com::sun::star::beans::XVetoableChangeListener*>(this)
465 ,static_cast< ::com::sun::star::lang::XEventListener*>(static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this))
468 return aReturn;
471 //------------------------------------------------------------------------------
472 void OPropertySetAggregationHelper::disposing()
474 osl::MutexGuard aGuard(rBHelper.rMutex);
476 if ( m_xAggregateSet.is() && m_bListening )
478 // register as a single listener
479 m_xAggregateMultiSet->removePropertiesChangeListener(this);
480 m_xAggregateSet->removeVetoableChangeListener(::rtl::OUString(), this);
481 m_bListening = sal_False;
484 OPropertyStateHelper::disposing();
487 //------------------------------------------------------------------------------
488 void SAL_CALL OPropertySetAggregationHelper::disposing(const ::com::sun::star::lang::EventObject& _rSource) throw ( ::com::sun::star::uno::RuntimeException)
490 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::disposing : don't have an aggregate anymore !");
491 if (_rSource.Source == m_xAggregateSet)
492 m_bListening = sal_False;
495 //------------------------------------------------------------------------------
496 void SAL_CALL OPropertySetAggregationHelper::propertiesChange(const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyChangeEvent>& _rEvents) throw( ::com::sun::star::uno::RuntimeException)
498 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::propertiesChange : have no aggregate !");
500 sal_Int32 nLen = _rEvents.getLength();
501 cppu::IPropertyArrayHelper& rPH = getInfoHelper();
503 if (1 == nLen)
505 const ::com::sun::star::beans::PropertyChangeEvent& evt = _rEvents.getConstArray()[0];
506 OSL_ENSURE(!evt.PropertyName.isEmpty(), "OPropertySetAggregationHelper::propertiesChange : invalid event !");
507 // we had a bug where this assertion would have us saved a whole day :) (72514)
508 sal_Int32 nHandle = rPH.getHandleByName( evt.PropertyName );
510 // If nHandle is -1 the event marks a (aggregate) property which we hide to callers
511 // If isCurrentlyForwardingProperty( nHandle ) is <TRUE/>, then we ourself triggered
512 // setting this property. In this case, it will be notified later (by the OPropertySetHelper
513 // implementation)
515 if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
516 fire(&nHandle, &evt.NewValue, &evt.OldValue, 1, sal_False);
518 else
520 sal_Int32* pHandles = new sal_Int32[nLen];
521 ::com::sun::star::uno::Any* pNewValues = new ::com::sun::star::uno::Any[nLen];
522 ::com::sun::star::uno::Any* pOldValues = new ::com::sun::star::uno::Any[nLen];
524 const ::com::sun::star::beans::PropertyChangeEvent* pEvents = _rEvents.getConstArray();
525 sal_Int32 nDest = 0;
526 for (sal_Int32 nSource=0; nSource<nLen; ++nSource, ++pEvents)
528 sal_Int32 nHandle = rPH.getHandleByName(pEvents->PropertyName);
529 if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
530 { // same as above : -1 is valid (73247) ...
531 pHandles[nDest] = nHandle;
532 pNewValues[nDest] = pEvents->NewValue;
533 pOldValues[nDest] = pEvents->OldValue;
534 ++nDest;
538 if (nDest)
539 fire(pHandles, pNewValues, pOldValues, nDest, sal_False);
541 delete[] pHandles;
542 delete[] pNewValues;
543 delete[] pOldValues;
547 //------------------------------------------------------------------------------
548 void SAL_CALL OPropertySetAggregationHelper::vetoableChange(const ::com::sun::star::beans::PropertyChangeEvent& _rEvent) throw( ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException)
550 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::vetoableChange : have no aggregate !");
552 cppu::IPropertyArrayHelper& rPH = getInfoHelper();
554 sal_Int32 nHandle = rPH.getHandleByName(_rEvent.PropertyName);
555 fire(&nHandle, &_rEvent.NewValue, &_rEvent.OldValue, 1, sal_True);
558 //------------------------------------------------------------------------------
559 void OPropertySetAggregationHelper::setAggregation(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxDelegate)
560 throw( ::com::sun::star::lang::IllegalArgumentException )
562 osl::MutexGuard aGuard(rBHelper.rMutex);
564 if (m_bListening && m_xAggregateSet.is())
566 m_xAggregateMultiSet->removePropertiesChangeListener(this);
567 m_xAggregateSet->removeVetoableChangeListener(::rtl::OUString(), this);
568 m_bListening = sal_False;
571 m_xAggregateState = m_xAggregateState.query( _rxDelegate );
572 m_xAggregateSet = m_xAggregateSet.query( _rxDelegate );
573 m_xAggregateMultiSet = m_xAggregateMultiSet.query( _rxDelegate );
574 m_xAggregateFastSet = m_xAggregateFastSet.query( _rxDelegate );
576 // must support XPropertySet and XMultiPropertySet
577 if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() )
578 throw ::com::sun::star::lang::IllegalArgumentException();
581 //------------------------------------------------------------------------------
582 void OPropertySetAggregationHelper::startListening()
584 osl::MutexGuard aGuard(rBHelper.rMutex);
586 if (!m_bListening && m_xAggregateSet.is())
588 // register as a single listener
589 ::com::sun::star::uno::Sequence< ::rtl::OUString > aPropertyNames;
590 m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this);
591 m_xAggregateSet->addVetoableChangeListener(::rtl::OUString(), this);
593 m_bListening = sal_True;
597 //------------------------------------------------------------------------------
598 void SAL_CALL OPropertySetAggregationHelper::addVetoableChangeListener(const ::rtl::OUString& _rPropertyName,
599 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener>& _rxListener)
600 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
602 OPropertySetHelper::addVetoableChangeListener(_rPropertyName, _rxListener);
603 if (!m_bListening)
604 startListening();
607 //------------------------------------------------------------------------------
608 void SAL_CALL OPropertySetAggregationHelper::addPropertyChangeListener(const ::rtl::OUString& _rPropertyName,
609 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener>& _rxListener)
610 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
612 OPropertySetHelper::addPropertyChangeListener(_rPropertyName, _rxListener);
613 if (!m_bListening)
614 startListening();
617 //------------------------------------------------------------------------------
618 void SAL_CALL OPropertySetAggregationHelper::addPropertiesChangeListener(const ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rPropertyNames,
619 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener>& _rxListener)
620 throw( ::com::sun::star::uno::RuntimeException)
622 OPropertySetHelper::addPropertiesChangeListener(_rPropertyNames, _rxListener);
623 if (!m_bListening)
624 startListening();
627 //------------------------------------------------------------------------------
628 sal_Int32 OPropertySetAggregationHelper::getOriginalHandle(sal_Int32 nHandle) const
630 OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper();
631 sal_Int32 nOriginalHandle = -1;
632 rPH.fillAggregatePropertyInfoByHandle(NULL, &nOriginalHandle, nHandle);
633 return nOriginalHandle;
636 //--------------------------------------------------------------------------
637 ::rtl::OUString OPropertySetAggregationHelper::getPropertyName( sal_Int32 _nHandle ) const
639 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
640 Property aProperty;
641 OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
642 return aProperty.Name;
645 //------------------------------------------------------------------------------
646 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue(sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rValue)
647 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException,
648 ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException,
649 ::com::sun::star::uno::RuntimeException)
651 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
652 ::rtl::OUString aPropName;
653 sal_Int32 nOriginalHandle = -1;
655 // does the handle belong to the aggregation ?
656 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, _nHandle))
657 if (m_xAggregateFastSet.is())
658 m_xAggregateFastSet->setFastPropertyValue(nOriginalHandle, _rValue);
659 else
660 m_xAggregateSet->setPropertyValue(aPropName, _rValue);
661 else
662 OPropertySetHelper::setFastPropertyValue(_nHandle, _rValue);
665 //------------------------------------------------------------------------------
666 void OPropertySetAggregationHelper::getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle) const
668 OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper();
669 ::rtl::OUString aPropName;
670 sal_Int32 nOriginalHandle = -1;
672 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
674 if (m_xAggregateFastSet.is())
675 rValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
676 else
677 rValue = m_xAggregateSet->getPropertyValue(aPropName);
679 else if ( m_pForwarder->isResponsibleFor( nHandle ) )
681 // this is a property which has been "overwritten" in our instance (thus
682 // fillAggregatePropertyInfoByHandle didn't find it)
683 rValue = m_xAggregateSet->getPropertyValue( getPropertyName( nHandle ) );
687 //------------------------------------------------------------------------------
688 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getFastPropertyValue(sal_Int32 nHandle)
689 throw( ::com::sun::star::beans::UnknownPropertyException,
690 ::com::sun::star::lang::WrappedTargetException,
691 ::com::sun::star::uno::RuntimeException)
693 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
694 ::rtl::OUString aPropName;
695 sal_Int32 nOriginalHandle = -1;
696 ::com::sun::star::uno::Any aValue;
698 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
700 if (m_xAggregateFastSet.is())
701 aValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
702 else
703 aValue = m_xAggregateSet->getPropertyValue(aPropName);
705 else
706 aValue = OPropertySetHelper::getFastPropertyValue(nHandle);
708 return aValue;
711 //------------------------------------------------------------------------------
712 void SAL_CALL OPropertySetAggregationHelper::setPropertyValues(
713 const Sequence< ::rtl::OUString >& _rPropertyNames, const Sequence< Any >& _rValues )
714 throw ( PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException )
716 OSL_ENSURE( !rBHelper.bInDispose, "OPropertySetAggregationHelper::setPropertyValues : do not use within the dispose call !");
717 OSL_ENSURE( !rBHelper.bDisposed, "OPropertySetAggregationHelper::setPropertyValues : object is disposed" );
719 // check where the properties come from
720 if (!m_xAggregateSet.is())
721 OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
722 else if (_rPropertyNames.getLength() == 1) // use the more efficient way
726 setPropertyValue( _rPropertyNames[0], _rValues[0] );
728 catch( const UnknownPropertyException& )
730 // by definition of XMultiPropertySet::setPropertyValues, unknown properties are to be ignored
731 #if OSL_DEBUG_LEVEL > 0
732 ::rtl::OStringBuffer aMessage;
733 aMessage.append( "OPropertySetAggregationHelper::setPropertyValues: unknown property '" );
734 aMessage.append( ::rtl::OUStringToOString( _rPropertyNames[0], RTL_TEXTENCODING_ASCII_US ) );
735 aMessage.append( "'" );
736 aMessage.append( "\n(implementation " );
737 aMessage.append( typeid( *this ).name() );
738 aMessage.append( ")" );
739 OSL_FAIL( aMessage.getStr() );
740 #endif
743 else
745 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
747 // determine which properties belong to the aggregate, and which ones to the delegator
748 const ::rtl::OUString* pNames = _rPropertyNames.getConstArray();
749 sal_Int32 nAggCount(0);
750 sal_Int32 nLen(_rPropertyNames.getLength());
752 for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames )
754 OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( *pNames );
755 if ( OPropertyArrayAggregationHelper::UNKNOWN_PROPERTY == ePropOrg )
756 throw WrappedTargetException( ::rtl::OUString(), static_cast< XMultiPropertySet* >( this ), makeAny( UnknownPropertyException( ) ) );
757 // due to a flaw in the API design, this method is not allowed to throw an UnknownPropertyException
758 // so we wrap it into a WrappedTargetException
760 if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == ePropOrg )
761 ++nAggCount;
764 pNames = _rPropertyNames.getConstArray(); // reset, we'll need it again below ...
766 // all properties belong to the aggregate
767 if (nAggCount == nLen)
768 m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues);
770 // all properties belong to the aggregating object
771 else if (nAggCount == 0)
772 OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
774 // mixed
775 else
777 const ::com::sun::star::uno::Any* pValues = _rValues.getConstArray();
778 ::com::sun::star::uno::Any* pConvertedValues = NULL;
779 ::com::sun::star::uno::Any* pOldValues = NULL;
780 sal_Int32* pHandles = NULL;
784 // dividing the Names and _rValues
786 // aggregate's names
787 Sequence< ::rtl::OUString > AggPropertyNames( nAggCount );
788 ::rtl::OUString* pAggNames = AggPropertyNames.getArray();
789 // aggregate's values
790 Sequence< Any > AggValues( nAggCount );
791 Any* pAggValues = AggValues.getArray();
793 // delegator names
794 Sequence< ::rtl::OUString > DelPropertyNames( nLen - nAggCount );
795 ::rtl::OUString* pDelNames = DelPropertyNames.getArray();
797 // delegator values
798 Sequence< Any > DelValues( nLen - nAggCount );
799 Any* pDelValues = DelValues.getArray();
801 for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames, ++pValues )
803 if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == rPH.classifyProperty( *pNames ) )
805 *pAggNames++ = *pNames;
806 *pAggValues++ = *pValues;
808 else
810 *pDelNames++ = *pNames;
811 *pDelValues++ = *pValues;
815 // reset, needed below
816 pDelValues = DelValues.getArray();
818 pHandles = new sal_Int32[ nLen - nAggCount ];
820 // get the map table
821 cppu::IPropertyArrayHelper& rPH2 = getInfoHelper();
823 // fill the handle array
824 sal_Int32 nHitCount = rPH2.fillHandles( pHandles, DelPropertyNames );
825 if (nHitCount != 0)
828 pConvertedValues = new ::com::sun::star::uno::Any[ nHitCount ];
829 pOldValues = new ::com::sun::star::uno::Any[ nHitCount ];
830 nHitCount = 0;
831 sal_Int32 i;
834 // must lock the mutex outside the loop. So all values are consistent.
835 osl::MutexGuard aGuard( rBHelper.rMutex );
836 for( i = 0; i < (nLen - nAggCount); ++i )
838 if( pHandles[i] != -1 )
840 sal_Int16 nAttributes;
841 rPH2.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] );
842 if( nAttributes & ::com::sun::star::beans::PropertyAttribute::READONLY )
843 throw ::com::sun::star::beans::PropertyVetoException();
844 // Will the property change?
845 if( convertFastPropertyValue( pConvertedValues[ nHitCount ], pOldValues[nHitCount],
846 pHandles[i], pDelValues[i] ) )
848 // only increment if the property really change
849 pHandles[nHitCount] = pHandles[i];
850 nHitCount++;
854 // release guard to fire events
857 // fire vetoable events
858 fire( pHandles, pConvertedValues, pOldValues, nHitCount, sal_True );
860 // setting the agg Properties
861 m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
864 // must lock the mutex outside the loop.
865 osl::MutexGuard aGuard( rBHelper.rMutex );
866 // Loop over all changed properties
867 for( i = 0; i < nHitCount; i++ )
869 // Will the property change?
870 setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
872 // release guard to fire events
875 // fire change events
876 fire( pHandles, pConvertedValues, pOldValues, nHitCount, sal_False );
878 else
879 m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
882 catch(::com::sun::star::uno::Exception&)
884 delete [] pHandles;
885 delete [] pOldValues;
886 delete [] pConvertedValues;
887 throw;
890 delete [] pHandles;
891 delete [] pOldValues;
892 delete [] pConvertedValues;
897 // XPropertyState
898 //------------------------------------------------------------------------------
899 ::com::sun::star::beans::PropertyState SAL_CALL OPropertySetAggregationHelper::getPropertyState(const ::rtl::OUString& _rPropertyName)
900 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException)
902 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
903 sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName );
905 if (nHandle == -1)
907 throw ::com::sun::star::beans::UnknownPropertyException();
910 ::rtl::OUString aPropName;
911 sal_Int32 nOriginalHandle = -1;
912 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
914 if (m_xAggregateState.is())
915 return m_xAggregateState->getPropertyState(_rPropertyName);
916 else
917 return ::com::sun::star::beans::PropertyState_DIRECT_VALUE;
919 else
920 return getPropertyStateByHandle(nHandle);
923 //------------------------------------------------------------------------------
924 void SAL_CALL OPropertySetAggregationHelper::setPropertyToDefault(const ::rtl::OUString& _rPropertyName)
925 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException)
927 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
928 sal_Int32 nHandle = rPH.getHandleByName(_rPropertyName);
929 if (nHandle == -1)
931 throw ::com::sun::star::beans::UnknownPropertyException();
934 ::rtl::OUString aPropName;
935 sal_Int32 nOriginalHandle = -1;
936 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
938 if (m_xAggregateState.is())
939 m_xAggregateState->setPropertyToDefault(_rPropertyName);
941 else
945 setPropertyToDefaultByHandle( nHandle );
947 catch( const UnknownPropertyException& ) { throw; }
948 catch( const RuntimeException& ) { throw; }
949 catch( const Exception& )
951 OSL_FAIL( "OPropertySetAggregationHelper::setPropertyToDefault: caught an exception which is not allowed to leave here!" );
956 //------------------------------------------------------------------------------
957 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getPropertyDefault(const ::rtl::OUString& aPropertyName)
958 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
960 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
961 sal_Int32 nHandle = rPH.getHandleByName( aPropertyName );
963 if ( nHandle == -1 )
964 throw ::com::sun::star::beans::UnknownPropertyException();
966 ::rtl::OUString aPropName;
967 sal_Int32 nOriginalHandle = -1;
968 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
970 if (m_xAggregateState.is())
971 return m_xAggregateState->getPropertyDefault(aPropertyName);
972 else
973 return ::com::sun::star::uno::Any();
975 else
976 return getPropertyDefaultByHandle(nHandle);
979 //------------------------------------------------------------------------------
980 sal_Bool SAL_CALL OPropertySetAggregationHelper::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException)
982 sal_Bool bModified = sal_False;
984 OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::convertFastPropertyValue: this is no forwarded property - did you use declareForwardedProperty for it?" );
985 if ( m_pForwarder->isResponsibleFor( _nHandle ) )
987 // need to determine the type of the property for conversion
988 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
989 Property aProperty;
990 OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
992 Any aCurrentValue;
993 getFastPropertyValue( aCurrentValue, _nHandle );
994 bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, aCurrentValue, aProperty.Type );
997 return bModified;
1000 //------------------------------------------------------------------------------
1001 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception )
1003 OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast: this is no forwarded property - did you use declareForwardedProperty for it?" );
1004 if ( m_pForwarder->isResponsibleFor( _nHandle ) )
1005 m_pForwarder->doForward( _nHandle, _rValue );
1008 //------------------------------------------------------------------------------
1009 void OPropertySetAggregationHelper::declareForwardedProperty( sal_Int32 _nHandle )
1011 OSL_ENSURE( !m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::declareForwardedProperty: already declared!" );
1012 m_pForwarder->takeResponsibilityFor( _nHandle );
1015 //------------------------------------------------------------------------------
1016 void SAL_CALL OPropertySetAggregationHelper::forwardingPropertyValue( sal_Int32 )
1018 // not interested in
1021 //------------------------------------------------------------------------------
1022 void SAL_CALL OPropertySetAggregationHelper::forwardedPropertyValue( sal_Int32, bool )
1024 // not interested in
1027 //------------------------------------------------------------------------------
1028 bool OPropertySetAggregationHelper::isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const
1030 return m_pForwarder->getCurrentlyForwardedProperty() == _nHandle;
1033 //.........................................................................
1034 } // namespace comphelper
1035 //.........................................................................
1037 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */