CWS-TOOLING: integrate CWS os146
[LibreOffice.git] / comphelper / source / property / propagg.cxx
blob9c2fd868d973d5a1b9fdc663cf6e6ef67ca5ab48
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_comphelper.hxx"
30 #include "comphelper/propagg.hxx"
31 #include "comphelper/property.hxx"
32 #include <cppuhelper/queryinterface.hxx>
33 #include <osl/diagnose.h>
34 #include <com/sun/star/beans/PropertyAttribute.hpp>
36 #if OSL_DEBUG_LEVEL > 0
37 #include <typeinfo>
38 #include <rtl/strbuf.hxx>
39 #endif
41 #include <algorithm>
42 #include <set>
44 //.........................................................................
45 namespace comphelper
47 //.........................................................................
49 using namespace ::com::sun::star::uno;
50 using namespace ::com::sun::star::lang;
51 using namespace ::com::sun::star::beans;
53 using namespace internal;
55 //------------------------------------------------------------------------------
56 namespace
58 const Property* lcl_findPropertyByName( const Sequence< Property >& _rProps, const ::rtl::OUString& _rName )
60 sal_Int32 nLen = _rProps.getLength();
61 const Property* pProperties = _rProps.getConstArray();
62 const Property* pResult = ::std::lower_bound(pProperties, pProperties + nLen,_rName, ::comphelper::PropertyStringLessFunctor());
63 if ( pResult && ( pResult == pProperties + nLen || pResult->Name != _rName) )
64 pResult = NULL;
66 return pResult;
69 //==================================================================
70 //= OPropertyArrayAggregationHelper
71 //==================================================================
73 //------------------------------------------------------------------------------
74 OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper(
75 const Sequence< Property >& _rProperties, const Sequence< Property >& _rAggProperties,
76 IPropertyInfoService* _pInfoService, sal_Int32 _nFirstAggregateId )
77 :m_aProperties( _rProperties )
79 sal_Int32 nDelegatorProps = _rProperties.getLength();
80 sal_Int32 nAggregateProps = _rAggProperties.getLength();
82 // make room for all properties
83 sal_Int32 nMergedProps = nDelegatorProps + nAggregateProps;
84 m_aProperties.realloc( nMergedProps );
86 const Property* pAggregateProps = _rAggProperties.getConstArray();
87 const Property* pDelegateProps = _rProperties.getConstArray();
88 Property* pMergedProps = m_aProperties.getArray();
90 // if properties are present both at the delegatee and the aggregate, then the former are supposed to win.
91 // So, we'll need an existence check.
92 ::std::set< ::rtl::OUString > aDelegatorProps;
94 // create the map for the delegator properties
95 sal_Int32 nMPLoop = 0;
96 for ( ; nMPLoop < nDelegatorProps; ++nMPLoop, ++pDelegateProps )
98 m_aPropertyAccessors[ pDelegateProps->Handle ] = OPropertyAccessor( -1, nMPLoop, sal_False );
99 OSL_ENSURE( aDelegatorProps.find( pDelegateProps->Name ) == aDelegatorProps.end(),
100 "OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper: duplicate delegatee property!" );
101 aDelegatorProps.insert( pDelegateProps->Name );
104 // create the map for the aggregate properties
105 sal_Int32 nAggregateHandle = _nFirstAggregateId;
106 pMergedProps += nDelegatorProps;
107 for ( ; nMPLoop < nMergedProps; ++pAggregateProps )
109 // if the aggregate property is present at the delegatee already, ignore it
110 if ( aDelegatorProps.find( pAggregateProps->Name ) != aDelegatorProps.end() )
112 --nMergedProps;
113 continue;
116 // next aggregate property - remember it
117 *pMergedProps = *pAggregateProps;
119 // determine the handle for the property which we will expose to the outside world
120 sal_Int32 nHandle = -1;
121 // ask the infor service first
122 if ( _pInfoService )
123 nHandle = _pInfoService->getPreferedPropertyId( pMergedProps->Name );
125 if ( -1 == nHandle )
126 // no handle from the info service -> default
127 nHandle = nAggregateHandle++;
128 else
129 { // check if we alread have a property with the given handle
130 const Property* pPropsTilNow = m_aProperties.getConstArray();
131 for ( sal_Int32 nCheck = 0; nCheck < nMPLoop; ++nCheck, ++pPropsTilNow )
132 if ( pPropsTilNow->Handle == nHandle )
133 { // conflicts -> use another one (which we don't check anymore, assuming _nFirstAggregateId was large enough)
134 nHandle = nAggregateHandle++;
135 break;
139 // remember the accessor for this property
140 m_aPropertyAccessors[ nHandle ] = OPropertyAccessor( pMergedProps->Handle, nMPLoop, sal_True );
141 pMergedProps->Handle = nHandle;
143 ++nMPLoop;
144 ++pMergedProps;
146 m_aProperties.realloc( nMergedProps );
147 pMergedProps = m_aProperties.getArray(); // reset, needed again below
149 // sortieren der Properties nach Namen
150 ::std::sort( pMergedProps, pMergedProps+nMergedProps, PropertyCompareByName());
152 pMergedProps = m_aProperties.getArray();
154 // Positionen in der Map abgleichen
155 for ( nMPLoop = 0; nMPLoop < nMergedProps; ++nMPLoop, ++pMergedProps )
156 m_aPropertyAccessors[ pMergedProps->Handle ].nPos = nMPLoop;
159 //------------------------------------------------------------------
160 OPropertyArrayAggregationHelper::PropertyOrigin OPropertyArrayAggregationHelper::classifyProperty( const ::rtl::OUString& _rName )
162 PropertyOrigin eOrigin = UNKNOWN_PROPERTY;
163 // look up the name
164 const Property* pPropertyDescriptor = lcl_findPropertyByName( m_aProperties, _rName );
165 if ( pPropertyDescriptor )
167 // look up the handle for this name
168 ConstPropertyAccessorMapIterator aPos = m_aPropertyAccessors.find( pPropertyDescriptor->Handle );
169 OSL_ENSURE( m_aPropertyAccessors.end() != aPos, "OPropertyArrayAggregationHelper::classifyProperty: should have this handle in my map!" );
170 if ( m_aPropertyAccessors.end() != aPos )
172 eOrigin = aPos->second.bAggregate ? AGGREGATE_PROPERTY : DELEGATOR_PROPERTY;
175 return eOrigin;
178 //------------------------------------------------------------------
179 Property OPropertyArrayAggregationHelper::getPropertyByName( const ::rtl::OUString& _rPropertyName ) throw( UnknownPropertyException )
181 const Property* pProperty = findPropertyByName( _rPropertyName );
183 if ( !pProperty )
184 throw UnknownPropertyException();
186 return *pProperty;
189 //------------------------------------------------------------------------------
190 sal_Bool OPropertyArrayAggregationHelper::hasPropertyByName(const ::rtl::OUString& _rPropertyName)
192 return NULL != findPropertyByName( _rPropertyName );
195 //------------------------------------------------------------------------------
196 const Property* OPropertyArrayAggregationHelper::findPropertyByName(const :: rtl::OUString& _rName ) const
198 return lcl_findPropertyByName( m_aProperties, _rName );
201 //------------------------------------------------------------------------------
202 sal_Int32 OPropertyArrayAggregationHelper::getHandleByName(const ::rtl::OUString& _rPropertyName)
204 const Property* pProperty = findPropertyByName( _rPropertyName );
205 return pProperty ? pProperty->Handle : -1;
208 //------------------------------------------------------------------------------
209 sal_Bool OPropertyArrayAggregationHelper::fillPropertyMembersByHandle(
210 ::rtl::OUString* _pPropName, sal_Int16* _pAttributes, sal_Int32 _nHandle)
212 ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
213 sal_Bool bRet = i != m_aPropertyAccessors.end();
214 if (bRet)
216 const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos];
217 if (_pPropName)
218 *_pPropName = rProperty.Name;
219 if (_pAttributes)
220 *_pAttributes = rProperty.Attributes;
222 return bRet;
225 //------------------------------------------------------------------------------
226 sal_Bool OPropertyArrayAggregationHelper::getPropertyByHandle( sal_Int32 _nHandle, Property& _rProperty ) const
228 ConstPropertyAccessorMapIterator pos = m_aPropertyAccessors.find(_nHandle);
229 if ( pos != m_aPropertyAccessors.end() )
231 _rProperty = m_aProperties[ pos->second.nPos ];
232 return sal_True;
234 return sal_False;
237 //------------------------------------------------------------------------------
238 sal_Bool OPropertyArrayAggregationHelper::fillAggregatePropertyInfoByHandle(
239 ::rtl::OUString* _pPropName, sal_Int32* _pOriginalHandle, sal_Int32 _nHandle) const
241 ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
242 sal_Bool bRet = i != m_aPropertyAccessors.end() && (*i).second.bAggregate;
243 if (bRet)
245 if (_pOriginalHandle)
246 *_pOriginalHandle = (*i).second.nOriginalHandle;
247 if (_pPropName)
249 OSL_ENSURE((*i).second.nPos < m_aProperties.getLength(),"Invalid index for sequence!");
250 const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos];
251 *_pPropName = rProperty.Name;
254 return bRet;
258 //------------------------------------------------------------------------------
259 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property> OPropertyArrayAggregationHelper::getProperties()
261 return m_aProperties;
265 //------------------------------------------------------------------------------
266 sal_Int32 OPropertyArrayAggregationHelper::fillHandles(
267 sal_Int32* _pHandles, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rPropNames )
269 sal_Int32 nHitCount = 0;
270 const ::rtl::OUString* pReqProps = _rPropNames.getConstArray();
271 sal_Int32 nReqLen = _rPropNames.getLength();
273 #if OSL_DEBUG_LEVEL > 0
274 // assure that the sequence is sorted
276 const ::rtl::OUString* pLookup = _rPropNames.getConstArray();
277 const ::rtl::OUString* pEnd = _rPropNames.getConstArray() + _rPropNames.getLength() - 1;
278 for (; pLookup < pEnd; ++pLookup)
280 const ::rtl::OUString* pCompare = pLookup + 1;
281 const ::rtl::OUString* pCompareEnd = pEnd + 1;
282 for (; pCompare < pCompareEnd; ++pCompare)
284 OSL_ENSURE(pLookup->compareTo(*pCompare) < 0, "OPropertyArrayAggregationHelper::fillHandles : property names are not sorted!");
288 #endif
290 const ::com::sun::star::beans::Property* pCur = m_aProperties.getConstArray();
291 const ::com::sun::star::beans::Property* pEnd = m_aProperties.getConstArray() + m_aProperties.getLength();
293 for( sal_Int32 i = 0; i < nReqLen; ++i )
295 // Logarithmus ermitteln
296 sal_uInt32 n = (sal_uInt32)(pEnd - pCur);
297 sal_Int32 nLog = 0;
298 while( n )
300 nLog += 1;
301 n = n >> 1;
304 // Anzahl der noch zu suchenden Properties * dem Log2 der verbleibenden
305 // zu dursuchenden Properties.
306 if( (nReqLen - i) * nLog >= pEnd - pCur )
308 // linear search is better
309 while( pCur < pEnd && pReqProps[i] > pCur->Name )
311 pCur++;
313 if( pCur < pEnd && pReqProps[i] == pCur->Name )
315 _pHandles[i] = pCur->Handle;
316 nHitCount++;
318 else
319 _pHandles[i] = -1;
321 else
323 // binary search is better
324 sal_Int32 nCompVal = 1;
325 const ::com::sun::star::beans::Property* pOldEnd = pEnd--;
326 const ::com::sun::star::beans::Property* pMid = pCur;
328 while( nCompVal != 0 && pCur <= pEnd )
330 pMid = (pEnd - pCur) / 2 + pCur;
332 nCompVal = pReqProps[i].compareTo( pMid->Name );
334 if( nCompVal > 0 )
335 pCur = pMid + 1;
336 else
337 pEnd = pMid - 1;
340 if( nCompVal == 0 )
342 _pHandles[i] = pMid->Handle;
343 nHitCount++;
344 pCur = pMid +1;
346 else if( nCompVal > 0 )
348 _pHandles[i] = -1;
349 pCur = pMid + 1;
351 else
353 _pHandles[i] = -1;
354 pCur = pMid;
356 pEnd = pOldEnd;
359 return nHitCount;
362 //==================================================================
363 //= PropertyForwarder
364 //==================================================================
365 namespace internal
367 class PropertyForwarder
369 private:
370 OPropertySetAggregationHelper& m_rAggregationHelper;
371 ::std::set< sal_Int32 > m_aProperties;
372 sal_Int32 m_nCurrentlyForwarding;
374 public:
375 PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper );
376 ~PropertyForwarder();
378 /** declares that the forwarder should be responsible for the given property
380 @param _nHandle
381 the public handle (<em>not</em> the original handle!) of the property
383 void takeResponsibilityFor( sal_Int32 _nHandle );
385 /** checks whether the forwarder is responsible for the given property
387 bool isResponsibleFor( sal_Int32 _nHandle );
389 /// actually forwards a property value to the aggregate
390 void doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception );
392 sal_Int32 getCurrentlyForwardedProperty( ) const { return m_nCurrentlyForwarding; }
395 //--------------------------------------------------------------------------
396 PropertyForwarder::PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper )
397 :m_rAggregationHelper( _rAggregationHelper )
398 ,m_nCurrentlyForwarding( -1 )
402 //--------------------------------------------------------------------------
403 PropertyForwarder::~PropertyForwarder()
407 //--------------------------------------------------------------------------
408 void PropertyForwarder::takeResponsibilityFor( sal_Int32 _nHandle )
410 m_aProperties.insert( _nHandle );
413 //--------------------------------------------------------------------------
414 bool PropertyForwarder::isResponsibleFor( sal_Int32 _nHandle )
416 return m_aProperties.find( _nHandle ) != m_aProperties.end();
419 //--------------------------------------------------------------------------
420 void PropertyForwarder::doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception )
422 OSL_ENSURE( m_rAggregationHelper.m_xAggregateSet.is(), "PropertyForwarder::doForward: no property set!" );
423 if ( m_rAggregationHelper.m_xAggregateSet.is() )
425 m_rAggregationHelper.forwardingPropertyValue( _nHandle );
427 OSL_ENSURE( m_nCurrentlyForwarding == -1, "PropertyForwarder::doForward: reentrance?" );
428 m_nCurrentlyForwarding = _nHandle;
432 m_rAggregationHelper.m_xAggregateSet->setPropertyValue( m_rAggregationHelper.getPropertyName( _nHandle ), _rValue );
433 // TODO: cache the property name? (it's a O(log n) search)
435 catch( const Exception& )
437 m_rAggregationHelper.forwardedPropertyValue( _nHandle, false );
438 throw;
441 m_nCurrentlyForwarding = -1;
443 m_rAggregationHelper.forwardedPropertyValue( _nHandle, true );
448 //==================================================================
449 //= OPropertySetAggregationHelper
450 //==================================================================
452 //------------------------------------------------------------------------------
453 OPropertySetAggregationHelper::OPropertySetAggregationHelper( ::cppu::OBroadcastHelper& rBHlp )
454 :OPropertyStateHelper( rBHlp )
455 ,m_bListening( sal_False )
457 m_pForwarder = new PropertyForwarder( *this );
460 //------------------------------------------------------------------------------
461 OPropertySetAggregationHelper::~OPropertySetAggregationHelper()
463 delete m_pForwarder;
466 //------------------------------------------------------------------------------
467 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::queryInterface(const ::com::sun::star::uno::Type& _rType) throw( ::com::sun::star::uno::RuntimeException)
469 ::com::sun::star::uno::Any aReturn = OPropertyStateHelper::queryInterface(_rType);
471 if ( !aReturn.hasValue() )
472 aReturn = cppu::queryInterface(_rType
473 ,static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this)
474 ,static_cast< ::com::sun::star::beans::XVetoableChangeListener*>(this)
475 ,static_cast< ::com::sun::star::lang::XEventListener*>(static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this))
478 return aReturn;
481 //------------------------------------------------------------------------------
482 void OPropertySetAggregationHelper::disposing()
484 osl::MutexGuard aGuard(rBHelper.rMutex);
486 if ( m_xAggregateSet.is() && m_bListening )
488 // als einziger Listener anmelden
489 m_xAggregateMultiSet->removePropertiesChangeListener(this);
490 m_xAggregateSet->removeVetoableChangeListener(::rtl::OUString(), this);
491 m_bListening = sal_False;
494 OPropertyStateHelper::disposing();
497 //------------------------------------------------------------------------------
498 void SAL_CALL OPropertySetAggregationHelper::disposing(const ::com::sun::star::lang::EventObject& _rSource) throw ( ::com::sun::star::uno::RuntimeException)
500 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::disposing : don't have an aggregate anymore !");
501 if (_rSource.Source == m_xAggregateSet)
502 m_bListening = sal_False;
505 //------------------------------------------------------------------------------
506 void SAL_CALL OPropertySetAggregationHelper::propertiesChange(const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyChangeEvent>& _rEvents) throw( ::com::sun::star::uno::RuntimeException)
508 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::propertiesChange : have no aggregate !");
510 sal_Int32 nLen = _rEvents.getLength();
511 cppu::IPropertyArrayHelper& rPH = getInfoHelper();
513 if (1 == nLen)
515 const ::com::sun::star::beans::PropertyChangeEvent& evt = _rEvents.getConstArray()[0];
516 OSL_ENSURE(evt.PropertyName.getLength() > 0, "OPropertySetAggregationHelper::propertiesChange : invalid event !");
517 // we had a bug where this assertion would have us saved a whole day :) (72514)
518 sal_Int32 nHandle = rPH.getHandleByName( evt.PropertyName );
520 // If nHandle is -1 the event marks a (aggregate) property which we hide to callers
521 // If isCurrentlyForwardingProperty( nHandle ) is <TRUE/>, then we ourself triggered
522 // setting this property. In this case, it will be notified later (by the OPropertySetHelper
523 // implementation)
525 if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
526 fire(&nHandle, &evt.NewValue, &evt.OldValue, 1, sal_False);
528 else
530 sal_Int32* pHandles = new sal_Int32[nLen];
531 ::com::sun::star::uno::Any* pNewValues = new ::com::sun::star::uno::Any[nLen];
532 ::com::sun::star::uno::Any* pOldValues = new ::com::sun::star::uno::Any[nLen];
534 const ::com::sun::star::beans::PropertyChangeEvent* pEvents = _rEvents.getConstArray();
535 sal_Int32 nDest = 0;
536 for (sal_Int32 nSource=0; nSource<nLen; ++nSource, ++pEvents)
538 sal_Int32 nHandle = rPH.getHandleByName(pEvents->PropertyName);
539 if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
540 { // same as above : -1 is valid (73247) ...
541 pHandles[nDest] = nHandle;
542 pNewValues[nDest] = pEvents->NewValue;
543 pOldValues[nDest] = pEvents->OldValue;
544 ++nDest;
548 if (nDest)
549 fire(pHandles, pNewValues, pOldValues, nDest, sal_False);
551 delete[] pHandles;
552 delete[] pNewValues;
553 delete[] pOldValues;
557 //------------------------------------------------------------------------------
558 void SAL_CALL OPropertySetAggregationHelper::vetoableChange(const ::com::sun::star::beans::PropertyChangeEvent& _rEvent) throw( ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException)
560 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::vetoableChange : have no aggregate !");
562 cppu::IPropertyArrayHelper& rPH = getInfoHelper();
564 sal_Int32 nHandle = rPH.getHandleByName(_rEvent.PropertyName);
565 fire(&nHandle, &_rEvent.NewValue, &_rEvent.OldValue, 1, sal_True);
568 //------------------------------------------------------------------------------
569 void OPropertySetAggregationHelper::setAggregation(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxDelegate)
570 throw( ::com::sun::star::lang::IllegalArgumentException )
572 osl::MutexGuard aGuard(rBHelper.rMutex);
574 if (m_bListening && m_xAggregateSet.is())
576 m_xAggregateMultiSet->removePropertiesChangeListener(this);
577 m_xAggregateSet->removeVetoableChangeListener(::rtl::OUString(), this);
578 m_bListening = sal_False;
581 m_xAggregateState = m_xAggregateState.query( _rxDelegate );
582 m_xAggregateSet = m_xAggregateSet.query( _rxDelegate );
583 m_xAggregateMultiSet = m_xAggregateMultiSet.query( _rxDelegate );
584 m_xAggregateFastSet = m_xAggregateFastSet.query( _rxDelegate );
586 // must support XPropertySet and XMultiPropertySet
587 if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() )
588 throw ::com::sun::star::lang::IllegalArgumentException();
591 //------------------------------------------------------------------------------
592 void OPropertySetAggregationHelper::startListening()
594 osl::MutexGuard aGuard(rBHelper.rMutex);
596 if (!m_bListening && m_xAggregateSet.is())
598 // als einziger Listener anmelden
599 ::com::sun::star::uno::Sequence< ::rtl::OUString > aPropertyNames;
600 m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this);
601 m_xAggregateSet->addVetoableChangeListener(::rtl::OUString(), this);
603 m_bListening = sal_True;
607 //------------------------------------------------------------------------------
608 void SAL_CALL OPropertySetAggregationHelper::addVetoableChangeListener(const ::rtl::OUString& _rPropertyName,
609 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener>& _rxListener)
610 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
612 OPropertySetHelper::addVetoableChangeListener(_rPropertyName, _rxListener);
613 if (!m_bListening)
614 startListening();
617 //------------------------------------------------------------------------------
618 void SAL_CALL OPropertySetAggregationHelper::addPropertyChangeListener(const ::rtl::OUString& _rPropertyName,
619 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener>& _rxListener)
620 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
622 OPropertySetHelper::addPropertyChangeListener(_rPropertyName, _rxListener);
623 if (!m_bListening)
624 startListening();
627 //------------------------------------------------------------------------------
628 void SAL_CALL OPropertySetAggregationHelper::addPropertiesChangeListener(const ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rPropertyNames,
629 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener>& _rxListener)
630 throw( ::com::sun::star::uno::RuntimeException)
632 OPropertySetHelper::addPropertiesChangeListener(_rPropertyNames, _rxListener);
633 if (!m_bListening)
634 startListening();
637 //------------------------------------------------------------------------------
638 sal_Int32 OPropertySetAggregationHelper::getOriginalHandle(sal_Int32 nHandle) const
640 OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper();
641 sal_Int32 nOriginalHandle = -1;
642 rPH.fillAggregatePropertyInfoByHandle(NULL, &nOriginalHandle, nHandle);
643 return nOriginalHandle;
646 //--------------------------------------------------------------------------
647 ::rtl::OUString OPropertySetAggregationHelper::getPropertyName( sal_Int32 _nHandle ) const
649 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
650 Property aProperty;
651 OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
652 return aProperty.Name;
655 //------------------------------------------------------------------------------
656 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue(sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rValue)
657 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException,
658 ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException,
659 ::com::sun::star::uno::RuntimeException)
661 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
662 ::rtl::OUString aPropName;
663 sal_Int32 nOriginalHandle = -1;
665 // does the handle belong to the aggregation ?
666 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, _nHandle))
667 if (m_xAggregateFastSet.is())
668 m_xAggregateFastSet->setFastPropertyValue(nOriginalHandle, _rValue);
669 else
670 m_xAggregateSet->setPropertyValue(aPropName, _rValue);
671 else
672 OPropertySetHelper::setFastPropertyValue(_nHandle, _rValue);
675 //------------------------------------------------------------------------------
676 void OPropertySetAggregationHelper::getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle) const
678 OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper();
679 ::rtl::OUString aPropName;
680 sal_Int32 nOriginalHandle = -1;
682 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
684 if (m_xAggregateFastSet.is())
685 rValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
686 else
687 rValue = m_xAggregateSet->getPropertyValue(aPropName);
689 else if ( m_pForwarder->isResponsibleFor( nHandle ) )
691 // this is a property which has been "overwritten" in our instance (thus
692 // fillAggregatePropertyInfoByHandle didn't find it)
693 rValue = m_xAggregateSet->getPropertyValue( getPropertyName( nHandle ) );
697 //------------------------------------------------------------------------------
698 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getFastPropertyValue(sal_Int32 nHandle)
699 throw( ::com::sun::star::beans::UnknownPropertyException,
700 ::com::sun::star::lang::WrappedTargetException,
701 ::com::sun::star::uno::RuntimeException)
703 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
704 ::rtl::OUString aPropName;
705 sal_Int32 nOriginalHandle = -1;
706 ::com::sun::star::uno::Any aValue;
708 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
710 if (m_xAggregateFastSet.is())
711 aValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
712 else
713 aValue = m_xAggregateSet->getPropertyValue(aPropName);
715 else
716 aValue = OPropertySetHelper::getFastPropertyValue(nHandle);
718 return aValue;
721 //------------------------------------------------------------------------------
722 void SAL_CALL OPropertySetAggregationHelper::setPropertyValues(
723 const Sequence< ::rtl::OUString >& _rPropertyNames, const Sequence< Any >& _rValues )
724 throw ( PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException )
726 OSL_ENSURE( !rBHelper.bInDispose, "OPropertySetAggregationHelper::setPropertyValues : do not use within the dispose call !");
727 OSL_ENSURE( !rBHelper.bDisposed, "OPropertySetAggregationHelper::setPropertyValues : object is disposed" );
729 // check where the properties come from
730 if (!m_xAggregateSet.is())
731 OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
732 else if (_rPropertyNames.getLength() == 1) // use the more efficient way
736 setPropertyValue( _rPropertyNames[0], _rValues[0] );
738 catch( const UnknownPropertyException& )
740 // by definition of XMultiPropertySet::setPropertyValues, unknown properties are to be ignored
741 #if OSL_DEBUG_LEVEL > 0
742 ::rtl::OStringBuffer aMessage;
743 aMessage.append( "OPropertySetAggregationHelper::setPropertyValues: unknown property '" );
744 aMessage.append( ::rtl::OUStringToOString( _rPropertyNames[0], RTL_TEXTENCODING_ASCII_US ) );
745 aMessage.append( "'" );
746 aMessage.append( "\n(implementation " );
747 aMessage.append( typeid( *this ).name() );
748 aMessage.append( ")" );
749 OSL_ENSURE( false, aMessage.getStr() );
750 #endif
753 else
755 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
757 // determine which properties belong to the aggregate, and which ones to the delegator
758 const ::rtl::OUString* pNames = _rPropertyNames.getConstArray();
759 sal_Int32 nAggCount(0);
760 sal_Int32 nLen(_rPropertyNames.getLength());
762 for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames )
764 OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( *pNames );
765 if ( OPropertyArrayAggregationHelper::UNKNOWN_PROPERTY == ePropOrg )
766 throw WrappedTargetException( ::rtl::OUString(), static_cast< XMultiPropertySet* >( this ), makeAny( UnknownPropertyException( ) ) );
767 // due to a flaw in the API design, this method is not allowed to throw an UnknownPropertyException
768 // so we wrap it into a WrappedTargetException
769 // #107545# - 2002-02-20 - fs@openoffice.org
771 if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == ePropOrg )
772 ++nAggCount;
775 pNames = _rPropertyNames.getConstArray(); // reset, we'll need it again below ...
777 // all properties belong to the aggregate
778 if (nAggCount == nLen)
779 m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues);
781 // all properties belong to the aggregating object
782 else if (nAggCount == 0)
783 OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
785 // mixed
786 else
788 const ::com::sun::star::uno::Any* pValues = _rValues.getConstArray();
789 ::com::sun::star::uno::Any* pConvertedValues = NULL;
790 ::com::sun::star::uno::Any* pOldValues = NULL;
791 sal_Int32* pHandles = NULL;
795 // dividing the Names and _rValues
797 // aggregate's names
798 Sequence< ::rtl::OUString > AggPropertyNames( nAggCount );
799 ::rtl::OUString* pAggNames = AggPropertyNames.getArray();
800 // aggregate's values
801 Sequence< Any > AggValues( nAggCount );
802 Any* pAggValues = AggValues.getArray();
804 // delegator names
805 Sequence< ::rtl::OUString > DelPropertyNames( nLen - nAggCount );
806 ::rtl::OUString* pDelNames = DelPropertyNames.getArray();
808 // delegator values
809 Sequence< Any > DelValues( nLen - nAggCount );
810 Any* pDelValues = DelValues.getArray();
812 for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames, ++pValues )
814 if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == rPH.classifyProperty( *pNames ) )
816 *pAggNames++ = *pNames;
817 *pAggValues++ = *pValues;
819 else
821 *pDelNames++ = *pNames;
822 *pDelValues++ = *pValues;
826 // reset, needed below
827 pDelValues = DelValues.getArray();
829 pHandles = new sal_Int32[ nLen - nAggCount ];
831 // get the map table
832 cppu::IPropertyArrayHelper& rPH2 = getInfoHelper();
834 // fill the handle array
835 sal_Int32 nHitCount = rPH2.fillHandles( pHandles, DelPropertyNames );
836 if (nHitCount != 0)
839 pConvertedValues = new ::com::sun::star::uno::Any[ nHitCount ];
840 pOldValues = new ::com::sun::star::uno::Any[ nHitCount ];
841 nHitCount = 0;
842 sal_Int32 i;
845 // must lock the mutex outside the loop. So all values are consistent.
846 osl::MutexGuard aGuard( rBHelper.rMutex );
847 for( i = 0; i < (nLen - nAggCount); ++i )
849 if( pHandles[i] != -1 )
851 sal_Int16 nAttributes;
852 rPH2.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] );
853 if( nAttributes & ::com::sun::star::beans::PropertyAttribute::READONLY )
854 throw ::com::sun::star::beans::PropertyVetoException();
855 // Will the property change?
856 if( convertFastPropertyValue( pConvertedValues[ nHitCount ], pOldValues[nHitCount],
857 pHandles[i], pDelValues[i] ) )
859 // only increment if the property really change
860 pHandles[nHitCount] = pHandles[i];
861 nHitCount++;
865 // release guard to fire events
868 // fire vetoable events
869 fire( pHandles, pConvertedValues, pOldValues, nHitCount, sal_True );
871 // setting the agg Properties
872 m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
875 // must lock the mutex outside the loop.
876 osl::MutexGuard aGuard( rBHelper.rMutex );
877 // Loop over all changed properties
878 for( i = 0; i < nHitCount; i++ )
880 // Will the property change?
881 setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
883 // release guard to fire events
886 // fire change events
887 fire( pHandles, pConvertedValues, pOldValues, nHitCount, sal_False );
889 else
890 m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
893 catch(::com::sun::star::uno::Exception&)
895 delete [] pHandles;
896 delete [] pOldValues;
897 delete [] pConvertedValues;
898 throw;
901 delete [] pHandles;
902 delete [] pOldValues;
903 delete [] pConvertedValues;
908 // XPropertyState
909 //------------------------------------------------------------------------------
910 ::com::sun::star::beans::PropertyState SAL_CALL OPropertySetAggregationHelper::getPropertyState(const ::rtl::OUString& _rPropertyName)
911 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException)
913 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
914 sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName );
916 if (nHandle == -1)
918 throw ::com::sun::star::beans::UnknownPropertyException();
921 ::rtl::OUString aPropName;
922 sal_Int32 nOriginalHandle = -1;
923 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
925 if (m_xAggregateState.is())
926 return m_xAggregateState->getPropertyState(_rPropertyName);
927 else
928 return ::com::sun::star::beans::PropertyState_DIRECT_VALUE;
930 else
931 return getPropertyStateByHandle(nHandle);
934 //------------------------------------------------------------------------------
935 void SAL_CALL OPropertySetAggregationHelper::setPropertyToDefault(const ::rtl::OUString& _rPropertyName)
936 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException)
938 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
939 sal_Int32 nHandle = rPH.getHandleByName(_rPropertyName);
940 if (nHandle == -1)
942 throw ::com::sun::star::beans::UnknownPropertyException();
945 ::rtl::OUString aPropName;
946 sal_Int32 nOriginalHandle = -1;
947 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
949 if (m_xAggregateState.is())
950 m_xAggregateState->setPropertyToDefault(_rPropertyName);
952 else
956 setPropertyToDefaultByHandle( nHandle );
958 catch( const UnknownPropertyException& ) { throw; }
959 catch( const RuntimeException& ) { throw; }
960 catch( const Exception& )
962 OSL_ENSURE( sal_False, "OPropertySetAggregationHelper::setPropertyToDefault: caught an exception which is not allowed to leave here!" );
967 //------------------------------------------------------------------------------
968 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getPropertyDefault(const ::rtl::OUString& aPropertyName)
969 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
971 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
972 sal_Int32 nHandle = rPH.getHandleByName( aPropertyName );
974 if ( nHandle == -1 )
975 throw ::com::sun::star::beans::UnknownPropertyException();
977 ::rtl::OUString aPropName;
978 sal_Int32 nOriginalHandle = -1;
979 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
981 if (m_xAggregateState.is())
982 return m_xAggregateState->getPropertyDefault(aPropertyName);
983 else
984 return ::com::sun::star::uno::Any();
986 else
987 return getPropertyDefaultByHandle(nHandle);
990 //------------------------------------------------------------------------------
991 sal_Bool SAL_CALL OPropertySetAggregationHelper::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException)
993 sal_Bool bModified = sal_False;
995 OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::convertFastPropertyValue: this is no forwarded property - did you use declareForwardedProperty for it?" );
996 if ( m_pForwarder->isResponsibleFor( _nHandle ) )
998 // need to determine the type of the property for conversion
999 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
1000 Property aProperty;
1001 OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
1003 Any aCurrentValue;
1004 getFastPropertyValue( aCurrentValue, _nHandle );
1005 bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, aCurrentValue, aProperty.Type );
1008 return bModified;
1011 //------------------------------------------------------------------------------
1012 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception )
1014 OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast: this is no forwarded property - did you use declareForwardedProperty for it?" );
1015 if ( m_pForwarder->isResponsibleFor( _nHandle ) )
1016 m_pForwarder->doForward( _nHandle, _rValue );
1019 //------------------------------------------------------------------------------
1020 void OPropertySetAggregationHelper::declareForwardedProperty( sal_Int32 _nHandle )
1022 OSL_ENSURE( !m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::declareForwardedProperty: already declared!" );
1023 m_pForwarder->takeResponsibilityFor( _nHandle );
1026 //------------------------------------------------------------------------------
1027 void SAL_CALL OPropertySetAggregationHelper::forwardingPropertyValue( sal_Int32 )
1029 // not interested in
1032 //------------------------------------------------------------------------------
1033 void SAL_CALL OPropertySetAggregationHelper::forwardedPropertyValue( sal_Int32, bool )
1035 // not interested in
1038 //------------------------------------------------------------------------------
1039 bool OPropertySetAggregationHelper::isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const
1041 return m_pForwarder->getCurrentlyForwardedProperty() == _nHandle;
1044 //.........................................................................
1045 } // namespace comphelper
1046 //.........................................................................