Bump version to 4.3-4
[LibreOffice.git] / cppuhelper / source / propshlp.cxx
blob37610f94c3a7670581f71c8449cd8625a3132ba4
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 .
21 #include "osl/diagnose.h"
22 #include "cppuhelper/implbase1.hxx"
23 #include "cppuhelper/weak.hxx"
24 #include "cppuhelper/propshlp.hxx"
25 #include "cppuhelper/exc_hlp.hxx"
26 #include "com/sun/star/beans/PropertyAttribute.hpp"
27 #include "com/sun/star/lang/DisposedException.hpp"
30 using namespace osl;
31 using namespace com::sun::star::uno;
32 using namespace com::sun::star::beans;
33 using namespace com::sun::star::lang;
34 using namespace cppu;
36 using ::rtl::OUString;
38 namespace cppu {
40 IPropertyArrayHelper::~IPropertyArrayHelper()
44 inline const ::com::sun::star::uno::Type & getPropertyTypeIdentifier( ) SAL_THROW(())
46 return ::getCppuType( (Reference< XPropertyChangeListener > *)0 );
48 inline const ::com::sun::star::uno::Type & getPropertiesTypeIdentifier() SAL_THROW(())
50 return ::getCppuType( (Reference< XPropertiesChangeListener > *)0 );
52 inline const ::com::sun::star::uno::Type & getVetoableTypeIdentifier() SAL_THROW(())
54 return ::getCppuType( (Reference< XVetoableChangeListener > *)0 );
57 extern "C" {
59 static int compare_OUString_Property_Impl( const void *arg1, const void *arg2 )
60 SAL_THROW_EXTERN_C()
62 return ((OUString *)arg1)->compareTo( ((Property *)arg2)->Name );
67 /**
68 * The class which implements the PropertySetInfo interface.
71 class OPropertySetHelperInfo_Impl
72 : public WeakImplHelper1< ::com::sun::star::beans::XPropertySetInfo >
74 Sequence < Property > aInfos;
76 public:
77 OPropertySetHelperInfo_Impl( IPropertyArrayHelper & rHelper_ ) SAL_THROW(());
79 // XPropertySetInfo-methods
80 virtual Sequence< Property > SAL_CALL getProperties(void) throw(::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
81 virtual Property SAL_CALL getPropertyByName(const OUString& PropertyName) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
82 virtual sal_Bool SAL_CALL hasPropertyByName(const OUString& PropertyName) throw(::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
86 /**
87 * Create an object that implements XPropertySetInfo IPropertyArrayHelper.
89 OPropertySetHelperInfo_Impl::OPropertySetHelperInfo_Impl(
90 IPropertyArrayHelper & rHelper_ )
91 SAL_THROW(())
92 :aInfos( rHelper_.getProperties() )
96 /**
97 * Return the sequence of properties, which are provided throug the constructor.
99 Sequence< Property > OPropertySetHelperInfo_Impl::getProperties(void) throw(::com::sun::star::uno::RuntimeException, std::exception)
102 return aInfos;
106 * Return the sequence of properties, which are provided throug the constructor.
108 Property OPropertySetHelperInfo_Impl::getPropertyByName( const OUString & PropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException, std::exception)
110 Property * pR;
111 pR = (Property *)bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(),
112 sizeof( Property ),
113 compare_OUString_Property_Impl );
114 if( !pR ) {
115 throw UnknownPropertyException();
118 return *pR;
122 * Return the sequence of properties, which are provided throug the constructor.
124 sal_Bool OPropertySetHelperInfo_Impl::hasPropertyByName( const OUString & PropertyName ) throw(::com::sun::star::uno::RuntimeException, std::exception)
126 Property * pR;
127 pR = (Property *)bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(),
128 sizeof( Property ),
129 compare_OUString_Property_Impl );
130 return pR != NULL;
134 // class PropertySetHelper_Impl
136 class OPropertySetHelper::Impl {
138 public:
139 Impl( bool i_bIgnoreRuntimeExceptionsWhileFiring,
140 IEventNotificationHook *i_pFireEvents
142 :m_bIgnoreRuntimeExceptionsWhileFiring( i_bIgnoreRuntimeExceptionsWhileFiring )
143 ,m_bFireEvents(true)
144 ,m_pFireEvents( i_pFireEvents )
148 bool m_bIgnoreRuntimeExceptionsWhileFiring;
149 bool m_bFireEvents;
150 class IEventNotificationHook * const m_pFireEvents;
152 ::std::vector< sal_Int32 > m_handles;
153 ::std::vector< Any > m_newValues;
154 ::std::vector< Any > m_oldValues;
159 // class PropertySetHelper
161 OPropertySetHelper::OPropertySetHelper(
162 OBroadcastHelper & rBHelper_ ) SAL_THROW(())
163 : rBHelper( rBHelper_ ),
164 aBoundLC( rBHelper_.rMutex ),
165 aVetoableLC( rBHelper_.rMutex ),
166 m_pReserved( new Impl(false, 0) )
170 OPropertySetHelper::OPropertySetHelper(
171 OBroadcastHelper & rBHelper_, bool bIgnoreRuntimeExceptionsWhileFiring )
172 : rBHelper( rBHelper_ ),
173 aBoundLC( rBHelper_.rMutex ),
174 aVetoableLC( rBHelper_.rMutex ),
175 m_pReserved( new Impl( bIgnoreRuntimeExceptionsWhileFiring, 0 ) )
179 OPropertySetHelper::OPropertySetHelper(
180 OBroadcastHelper & rBHelper_, IEventNotificationHook * i_pFireEvents,
181 bool bIgnoreRuntimeExceptionsWhileFiring)
182 : rBHelper( rBHelper_ ),
183 aBoundLC( rBHelper_.rMutex ),
184 aVetoableLC( rBHelper_.rMutex ),
185 m_pReserved(
186 new Impl( bIgnoreRuntimeExceptionsWhileFiring, i_pFireEvents) )
190 OPropertySetHelper2::OPropertySetHelper2(
191 OBroadcastHelper & irBHelper,
192 IEventNotificationHook *i_pFireEvents,
193 bool bIgnoreRuntimeExceptionsWhileFiring)
194 :OPropertySetHelper( irBHelper, i_pFireEvents, bIgnoreRuntimeExceptionsWhileFiring )
199 * You must call disposing before.
201 OPropertySetHelper::~OPropertySetHelper() SAL_THROW(())
204 OPropertySetHelper2::~OPropertySetHelper2() SAL_THROW(())
208 // XInterface
209 Any OPropertySetHelper::queryInterface( const ::com::sun::star::uno::Type & rType )
210 throw (RuntimeException, std::exception)
212 return ::cppu::queryInterface(
213 rType,
214 static_cast< XPropertySet * >( this ),
215 static_cast< XMultiPropertySet * >( this ),
216 static_cast< XFastPropertySet * >( this ) );
219 Any OPropertySetHelper2::queryInterface( const ::com::sun::star::uno::Type & rType )
220 throw (RuntimeException, std::exception)
222 Any cnd(cppu::queryInterface(rType, static_cast< XPropertySetOption * >(this)));
223 if ( cnd.hasValue() )
224 return cnd;
225 else
226 return OPropertySetHelper::queryInterface(rType);
230 * called from the derivee's XTypeProvider::getTypes implementation
232 ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > OPropertySetHelper::getTypes()
233 throw (RuntimeException)
235 Sequence< ::com::sun::star::uno::Type > aTypes( 4 );
236 aTypes[ 0 ] = XPropertySet::static_type();
237 aTypes[ 1 ] = XPropertySetOption::static_type();
238 aTypes[ 2 ] = XMultiPropertySet::static_type();
239 aTypes[ 3 ] = XFastPropertySet::static_type();
240 return aTypes;
243 // ComponentHelper
244 void OPropertySetHelper::disposing() SAL_THROW(())
246 // Create an event with this as sender
247 Reference < XPropertySet > rSource( (static_cast< XPropertySet * >(this)) , UNO_QUERY );
248 EventObject aEvt;
249 aEvt.Source = rSource;
251 // inform all listeners to release this object
252 // The listener containers are automatically cleared
253 aBoundLC.disposeAndClear( aEvt );
254 aVetoableLC.disposeAndClear( aEvt );
257 Reference < XPropertySetInfo > OPropertySetHelper::createPropertySetInfo(
258 IPropertyArrayHelper & rProperties ) SAL_THROW(())
260 return static_cast< XPropertySetInfo * >( new OPropertySetHelperInfo_Impl( rProperties ) );
263 // XPropertySet
264 void OPropertySetHelper::setPropertyValue(
265 const OUString& rPropertyName, const Any& rValue )
266 throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception)
268 // get the map table
269 IPropertyArrayHelper & rPH = getInfoHelper();
270 // map the name to the handle
271 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
272 // call the method of the XFastPropertySet interface
273 setFastPropertyValue( nHandle, rValue );
276 // XPropertySet
277 Any OPropertySetHelper::getPropertyValue(
278 const OUString& rPropertyName )
279 throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception)
281 // get the map table
282 IPropertyArrayHelper & rPH = getInfoHelper();
283 // map the name to the handle
284 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
285 // call the method of the XFastPropertySet interface
286 return getFastPropertyValue( nHandle );
289 // XPropertySet
290 void OPropertySetHelper::addPropertyChangeListener(
291 const OUString& rPropertyName,
292 const Reference < XPropertyChangeListener > & rxListener )
293 throw(::com::sun::star::beans::UnknownPropertyException,
294 ::com::sun::star::lang::WrappedTargetException,
295 ::com::sun::star::uno::RuntimeException, std::exception)
297 MutexGuard aGuard( rBHelper.rMutex );
298 OSL_ENSURE( !rBHelper.bInDispose, "do not addPropertyChangeListener in the dispose call" );
299 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
300 if( !rBHelper.bInDispose && !rBHelper.bDisposed )
302 // only add listeners if you are not disposed
303 // a listener with no name means all properties
304 if( !rPropertyName.isEmpty() )
306 // get the map table
307 IPropertyArrayHelper & rPH = getInfoHelper();
308 // map the name to the handle
309 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
310 if( nHandle == -1 ) {
311 // property not known throw exception
312 throw UnknownPropertyException() ;
315 sal_Int16 nAttributes;
316 rPH.fillPropertyMembersByHandle( NULL, &nAttributes, nHandle );
317 if( !(nAttributes & ::com::sun::star::beans::PropertyAttribute::BOUND) )
319 OSL_FAIL( "add listener to an unbound property" );
320 // silent ignore this
321 return;
323 // add the change listener to the helper container
325 aBoundLC.addInterface( (sal_Int32)nHandle, rxListener );
327 else
328 // add the change listener to the helper container
329 rBHelper.aLC.addInterface(
330 getPropertyTypeIdentifier( ),
331 rxListener
337 // XPropertySet
338 void OPropertySetHelper::removePropertyChangeListener(
339 const OUString& rPropertyName,
340 const Reference < XPropertyChangeListener >& rxListener )
341 throw(::com::sun::star::beans::UnknownPropertyException,
342 ::com::sun::star::lang::WrappedTargetException,
343 ::com::sun::star::uno::RuntimeException, std::exception)
345 MutexGuard aGuard( rBHelper.rMutex );
346 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
347 // all listeners are automatically released in a dispose call
348 if( !rBHelper.bInDispose && !rBHelper.bDisposed )
350 if( !rPropertyName.isEmpty() )
352 // get the map table
353 IPropertyArrayHelper & rPH = getInfoHelper();
354 // map the name to the handle
355 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
356 if( nHandle == -1 )
357 // property not known throw exception
358 throw UnknownPropertyException();
359 aBoundLC.removeInterface( (sal_Int32)nHandle, rxListener );
361 else {
362 // remove the change listener to the helper container
363 rBHelper.aLC.removeInterface(
364 getPropertyTypeIdentifier( ),
365 rxListener
371 // XPropertySet
372 void OPropertySetHelper::addVetoableChangeListener(
373 const OUString& rPropertyName,
374 const Reference< XVetoableChangeListener > & rxListener )
375 throw(::com::sun::star::beans::UnknownPropertyException,
376 ::com::sun::star::lang::WrappedTargetException,
377 ::com::sun::star::uno::RuntimeException, std::exception)
379 MutexGuard aGuard( rBHelper.rMutex );
380 OSL_ENSURE( !rBHelper.bInDispose, "do not addVetoableChangeListener in the dispose call" );
381 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
382 if( !rBHelper.bInDispose && !rBHelper.bDisposed )
384 // only add listeners if you are not disposed
385 // a listener with no name means all properties
386 if( !rPropertyName.isEmpty() )
388 // get the map table
389 IPropertyArrayHelper & rPH = getInfoHelper();
390 // map the name to the handle
391 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
392 if( nHandle == -1 ) {
393 // property not known throw exception
394 throw UnknownPropertyException();
397 sal_Int16 nAttributes;
398 rPH.fillPropertyMembersByHandle( NULL, &nAttributes, nHandle );
399 if( !(nAttributes & PropertyAttribute::CONSTRAINED) )
401 OSL_FAIL( "addVetoableChangeListener, and property is not constrained" );
402 // silent ignore this
403 return;
405 // add the vetoable listener to the helper container
406 aVetoableLC.addInterface( (sal_Int32)nHandle, rxListener );
408 else
409 // add the vetoable listener to the helper container
410 rBHelper.aLC.addInterface(
411 getVetoableTypeIdentifier( ),
412 rxListener
417 // XPropertySet
418 void OPropertySetHelper::removeVetoableChangeListener(
419 const OUString& rPropertyName,
420 const Reference < XVetoableChangeListener > & rxListener )
421 throw(::com::sun::star::beans::UnknownPropertyException,
422 ::com::sun::star::lang::WrappedTargetException,
423 ::com::sun::star::uno::RuntimeException, std::exception)
425 MutexGuard aGuard( rBHelper.rMutex );
426 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
427 // all listeners are automatically released in a dispose call
428 if( !rBHelper.bInDispose && !rBHelper.bDisposed )
430 if( !rPropertyName.isEmpty() )
432 // get the map table
433 IPropertyArrayHelper & rPH = getInfoHelper();
434 // map the name to the handle
435 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
436 if( nHandle == -1 ) {
437 // property not known throw exception
438 throw UnknownPropertyException();
440 // remove the vetoable listener to the helper container
441 aVetoableLC.removeInterface( (sal_Int32)nHandle, rxListener );
443 else
444 // add the vetoable listener to the helper container
445 rBHelper.aLC.removeInterface(
446 getVetoableTypeIdentifier( ),
447 rxListener
452 void OPropertySetHelper::setDependentFastPropertyValue( sal_Int32 i_handle, const ::com::sun::star::uno::Any& i_value )
454 //OSL_PRECOND( rBHelper.rMutex.isAcquired(), "OPropertySetHelper::setDependentFastPropertyValue: to be called with a locked mutex only!" );
455 // there is no such thing as Mutex.isAcquired, sadly ...
457 sal_Int16 nAttributes(0);
458 IPropertyArrayHelper& rInfo = getInfoHelper();
459 if ( !rInfo.fillPropertyMembersByHandle( NULL, &nAttributes, i_handle ) )
460 // unknown property
461 throw UnknownPropertyException();
463 // no need to check for READONLY-ness of the property. The method is intended to be called internally, which
464 // implies it might be invoked for properties which are read-only to the instance's clients, but well allowed
465 // to change their value.
467 Any aConverted, aOld;
468 bool bChanged = convertFastPropertyValue( aConverted, aOld, i_handle, i_value );
469 if ( !bChanged )
470 return;
472 // don't fire vetoable events. This method is called with our mutex locked, so calling into listeners would not be
473 // a good idea. The caler is responsible for not invoking this for constrained properties.
474 OSL_ENSURE( ( nAttributes & PropertyAttribute::CONSTRAINED ) == 0,
475 "OPropertySetHelper::setDependentFastPropertyValue: not to be used for constrained properties!" );
476 (void)nAttributes;
478 // actually set the new value
481 setFastPropertyValue_NoBroadcast( i_handle, aConverted );
483 catch (const UnknownPropertyException& ) { throw; /* allowed to leave */ }
484 catch (const PropertyVetoException& ) { throw; /* allowed to leave */ }
485 catch (const IllegalArgumentException& ) { throw; /* allowed to leave */ }
486 catch (const WrappedTargetException& ) { throw; /* allowed to leave */ }
487 catch (const RuntimeException& ) { throw; /* allowed to leave */ }
488 catch (const Exception& )
490 // not allowed to leave this meathod
491 WrappedTargetException aWrapped;
492 aWrapped.TargetException <<= ::cppu::getCaughtException();
493 aWrapped.Context = static_cast< XPropertySet* >( this );
494 throw aWrapped;
497 // remember the handle/values, for the events to be fired later
498 m_pReserved->m_handles.push_back( i_handle );
499 m_pReserved->m_newValues.push_back( aConverted ); // TODO: setFastPropertyValue notifies the unconverted value here ...?
500 m_pReserved->m_oldValues.push_back( aOld );
503 // XFastPropertySet
504 void OPropertySetHelper::setFastPropertyValue( sal_Int32 nHandle, const Any& rValue )
505 throw(::com::sun::star::beans::UnknownPropertyException,
506 ::com::sun::star::beans::PropertyVetoException,
507 ::com::sun::star::lang::IllegalArgumentException,
508 ::com::sun::star::lang::WrappedTargetException,
509 ::com::sun::star::uno::RuntimeException, std::exception)
511 OSL_ENSURE( !rBHelper.bInDispose, "do not setFastPropertyValue in the dispose call" );
512 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
514 IPropertyArrayHelper & rInfo = getInfoHelper();
515 sal_Int16 nAttributes;
516 if( !rInfo.fillPropertyMembersByHandle( NULL, &nAttributes, nHandle ) ) {
517 // unknown property
518 throw UnknownPropertyException();
520 if( nAttributes & PropertyAttribute::READONLY )
521 throw PropertyVetoException();
523 Any aConvertedVal;
524 Any aOldVal;
526 // Will the property change?
527 bool bChanged;
529 MutexGuard aGuard( rBHelper.rMutex );
530 bChanged = convertFastPropertyValue( aConvertedVal, aOldVal, nHandle, rValue );
531 // release guard to fire events
533 if( bChanged )
535 // Is it a constrained property?
536 if( nAttributes & PropertyAttribute::CONSTRAINED )
538 // In aValue is the converted rValue
539 // fire a constarined event
540 // second parameter NULL means constrained
541 fire( &nHandle, &rValue, &aOldVal, 1, sal_True );
545 MutexGuard aGuard( rBHelper.rMutex );
548 // set the property to the new value
549 setFastPropertyValue_NoBroadcast( nHandle, aConvertedVal );
551 catch (const ::com::sun::star::beans::UnknownPropertyException& ) { throw; /* allowed to leave */ }
552 catch (const ::com::sun::star::beans::PropertyVetoException& ) { throw; /* allowed to leave */ }
553 catch (const ::com::sun::star::lang::IllegalArgumentException& ) { throw; /* allowed to leave */ }
554 catch (const ::com::sun::star::lang::WrappedTargetException& ) { throw; /* allowed to leave */ }
555 catch (const ::com::sun::star::uno::RuntimeException& ) { throw; /* allowed to leave */ }
556 catch (const ::com::sun::star::uno::Exception& e )
558 // not allowed to leave this meathod
559 ::com::sun::star::lang::WrappedTargetException aWrap;
560 aWrap.Context = static_cast< ::com::sun::star::beans::XPropertySet* >( this );
561 aWrap.TargetException <<= e;
563 throw ::com::sun::star::lang::WrappedTargetException( aWrap );
566 // release guard to fire events
568 // file a change event, if the value changed
569 impl_fireAll( &nHandle, &rValue, &aOldVal, 1 );
573 // XFastPropertySet
574 Any OPropertySetHelper::getFastPropertyValue( sal_Int32 nHandle )
575 throw(::com::sun::star::beans::UnknownPropertyException,
576 ::com::sun::star::lang::WrappedTargetException,
577 ::com::sun::star::uno::RuntimeException, std::exception)
580 IPropertyArrayHelper & rInfo = getInfoHelper();
581 if( !rInfo.fillPropertyMembersByHandle( NULL, NULL, nHandle ) )
582 // unknown property
583 throw UnknownPropertyException();
585 Any aRet;
586 MutexGuard aGuard( rBHelper.rMutex );
587 getFastPropertyValue( aRet, nHandle );
588 return aRet;
592 void OPropertySetHelper::impl_fireAll( sal_Int32* i_handles, const Any* i_newValues, const Any* i_oldValues, sal_Int32 i_count )
594 ClearableMutexGuard aGuard( rBHelper.rMutex );
595 if ( m_pReserved->m_handles.empty() )
597 aGuard.clear();
598 fire( i_handles, i_newValues, i_oldValues, i_count, sal_False );
599 return;
602 const size_t additionalEvents = m_pReserved->m_handles.size();
603 OSL_ENSURE( additionalEvents == m_pReserved->m_newValues.size()
604 && additionalEvents == m_pReserved->m_oldValues.size(),
605 "OPropertySetHelper::impl_fireAll: inconsistency!" );
607 ::std::vector< sal_Int32 > allHandles( additionalEvents + i_count );
608 ::std::copy( m_pReserved->m_handles.begin(), m_pReserved->m_handles.end(), allHandles.begin() );
609 ::std::copy( i_handles, i_handles + i_count, allHandles.begin() + additionalEvents );
611 ::std::vector< Any > allNewValues( additionalEvents + i_count );
612 ::std::copy( m_pReserved->m_newValues.begin(), m_pReserved->m_newValues.end(), allNewValues.begin() );
613 ::std::copy( i_newValues, i_newValues + i_count, allNewValues.begin() + additionalEvents );
615 ::std::vector< Any > allOldValues( additionalEvents + i_count );
616 ::std::copy( m_pReserved->m_oldValues.begin(), m_pReserved->m_oldValues.end(), allOldValues.begin() );
617 ::std::copy( i_oldValues, i_oldValues + i_count, allOldValues.begin() + additionalEvents );
619 m_pReserved->m_handles.clear();
620 m_pReserved->m_newValues.clear();
621 m_pReserved->m_oldValues.clear();
623 aGuard.clear();
624 fire( &allHandles[0], &allNewValues[0], &allOldValues[0], additionalEvents + i_count, sal_False );
628 void OPropertySetHelper::fire
630 sal_Int32 * pnHandles,
631 const Any * pNewValues,
632 const Any * pOldValues,
633 sal_Int32 nHandles, // These is the Count of the array
634 sal_Bool bVetoable
637 OSL_ENSURE( m_pReserved.get(), "No OPropertySetHelper::Impl" );
639 if (! m_pReserved->m_bFireEvents)
640 return;
642 if (m_pReserved->m_pFireEvents) {
643 m_pReserved->m_pFireEvents->fireEvents(
644 pnHandles, nHandles, bVetoable,
645 m_pReserved->m_bIgnoreRuntimeExceptionsWhileFiring);
648 // Only fire, if one or more properties changed
649 if( nHandles )
651 // create the event sequence of all changed properties
652 Sequence< PropertyChangeEvent > aEvts( nHandles );
653 PropertyChangeEvent * pEvts = aEvts.getArray();
654 Reference < XInterface > xSource( (XPropertySet *)this, UNO_QUERY );
655 sal_Int32 i;
656 sal_Int32 nChangesLen = 0;
657 // Loop over all changed properties to fill the event struct
658 for( i = 0; i < nHandles; i++ )
660 // Vetoable fire and constrained attribute set or
661 // Change fire and Changed and bound attribute set
662 IPropertyArrayHelper & rInfo = getInfoHelper();
663 sal_Int16 nAttributes;
664 OUString aPropName;
665 rInfo.fillPropertyMembersByHandle( &aPropName, &nAttributes, pnHandles[i] );
668 (bVetoable && (nAttributes & PropertyAttribute::CONSTRAINED)) ||
669 (!bVetoable && (nAttributes & PropertyAttribute::BOUND))
672 pEvts[nChangesLen].Source = xSource;
673 pEvts[nChangesLen].PropertyName = aPropName;
674 pEvts[nChangesLen].PropertyHandle = pnHandles[i];
675 pEvts[nChangesLen].OldValue = pOldValues[i];
676 pEvts[nChangesLen].NewValue = pNewValues[i];
677 nChangesLen++;
681 bool bIgnoreRuntimeExceptionsWhileFiring =
682 m_pReserved->m_bIgnoreRuntimeExceptionsWhileFiring;
684 // fire the events for all changed properties
685 for( i = 0; i < nChangesLen; i++ )
687 // get the listener container for the property name
688 OInterfaceContainerHelper * pLC;
689 if( bVetoable ) // fire change Events?
690 pLC = aVetoableLC.getContainer( pEvts[i].PropertyHandle );
691 else
692 pLC = aBoundLC.getContainer( pEvts[i].PropertyHandle );
693 if( pLC )
695 // Iterate over all listeners and send events
696 OInterfaceIteratorHelper aIt( *pLC);
697 while( aIt.hasMoreElements() )
699 XInterface * pL = aIt.next();
704 if( bVetoable ) // fire change Events?
706 ((XVetoableChangeListener *)pL)->vetoableChange(
707 pEvts[i] );
709 else
711 ((XPropertyChangeListener *)pL)->propertyChange(
712 pEvts[i] );
715 catch (DisposedException & exc)
717 OSL_ENSURE( exc.Context.is(),
718 "DisposedException without Context!" );
719 if (exc.Context == pL)
720 aIt.remove();
721 else
722 throw;
725 catch (RuntimeException & exc)
727 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc.Message);
728 if (! bIgnoreRuntimeExceptionsWhileFiring)
729 throw;
733 // broadcast to all listeners with "" property name
734 if( bVetoable ){
735 // fire change Events?
736 pLC = rBHelper.aLC.getContainer(
737 getVetoableTypeIdentifier()
740 else {
741 pLC = rBHelper.aLC.getContainer(
742 getPropertyTypeIdentifier( )
745 if( pLC )
747 // Iterate over all listeners and send events.
748 OInterfaceIteratorHelper aIt( *pLC);
749 while( aIt.hasMoreElements() )
751 XInterface * pL = aIt.next();
756 if( bVetoable ) // fire change Events?
758 ((XVetoableChangeListener *)pL)->vetoableChange(
759 pEvts[i] );
761 else
763 ((XPropertyChangeListener *)pL)->propertyChange(
764 pEvts[i] );
767 catch (DisposedException & exc)
769 OSL_ENSURE( exc.Context.is(),
770 "DisposedException without Context!" );
771 if (exc.Context == pL)
772 aIt.remove();
773 else
774 throw;
777 catch (RuntimeException & exc)
779 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc.Message);
780 if (! bIgnoreRuntimeExceptionsWhileFiring)
781 throw;
787 // reduce array to changed properties
788 aEvts.realloc( nChangesLen );
790 if( !bVetoable )
792 OInterfaceContainerHelper * pCont = 0;
793 pCont = rBHelper.aLC.getContainer(
794 getPropertiesTypeIdentifier( )
796 if( pCont )
798 // Here is a Bug, unbound properties are also fired
799 OInterfaceIteratorHelper aIt( *pCont );
800 while( aIt.hasMoreElements() )
802 XPropertiesChangeListener * pL =
803 (XPropertiesChangeListener *)aIt.next();
808 // fire the hole event sequence to the
809 // XPropertiesChangeListener's
810 pL->propertiesChange( aEvts );
812 catch (DisposedException & exc)
814 OSL_ENSURE( exc.Context.is(),
815 "DisposedException without Context!" );
816 if (exc.Context == pL)
817 aIt.remove();
818 else
819 throw;
822 catch (RuntimeException & exc)
824 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc.Message);
825 if (! bIgnoreRuntimeExceptionsWhileFiring)
826 throw;
834 // OPropertySetHelper
835 void OPropertySetHelper::setFastPropertyValues(
836 sal_Int32 nSeqLen,
837 sal_Int32 * pHandles,
838 const Any * pValues,
839 sal_Int32 nHitCount )
840 SAL_THROW( (::com::sun::star::uno::Exception) )
842 OSL_ENSURE( !rBHelper.bInDispose, "do not getFastPropertyValue in the dispose call" );
843 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
845 Any * pConvertedValues = NULL;
846 Any * pOldValues = NULL;
850 // get the map table
851 IPropertyArrayHelper & rPH = getInfoHelper();
853 pConvertedValues = new Any[ nHitCount ];
854 pOldValues = new Any[ nHitCount ];
855 sal_Int32 n = 0;
856 sal_Int32 i;
859 // must lock the mutex outside the loop. So all values are consistent.
860 MutexGuard aGuard( rBHelper.rMutex );
861 for( i = 0; i < nSeqLen; i++ )
863 if( pHandles[i] != -1 )
865 sal_Int16 nAttributes;
866 rPH.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] );
867 if( nAttributes & PropertyAttribute::READONLY ) {
868 throw PropertyVetoException();
870 // Will the property change?
871 if( convertFastPropertyValue( pConvertedValues[ n ], pOldValues[n],
872 pHandles[i], pValues[i] ) )
874 // only increment if the property really change
875 pHandles[n] = pHandles[i];
876 n++;
880 // release guard to fire events
883 // fire vetoable events
884 fire( pHandles, pConvertedValues, pOldValues, n, sal_True );
887 // must lock the mutex outside the loop.
888 MutexGuard aGuard( rBHelper.rMutex );
889 // Loop over all changed properties
890 for( i = 0; i < n; i++ )
892 // Will the property change?
893 setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
895 // release guard to fire events
898 // fire change events
899 impl_fireAll( pHandles, pConvertedValues, pOldValues, n );
901 catch( ... )
903 delete [] pOldValues;
904 delete [] pConvertedValues;
905 throw;
907 delete [] pOldValues;
908 delete [] pConvertedValues;
911 // XMultiPropertySet
913 * The sequence may be conatain not known properties. The implementation
914 * must ignore these properties.
916 void OPropertySetHelper::setPropertyValues(
917 const Sequence<OUString>& rPropertyNames,
918 const Sequence<Any>& rValues )
919 throw(::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception)
921 sal_Int32 * pHandles = NULL;
924 sal_Int32 nSeqLen = rPropertyNames.getLength();
925 pHandles = new sal_Int32[ nSeqLen ];
926 // get the map table
927 IPropertyArrayHelper & rPH = getInfoHelper();
928 // fill the handle array
929 sal_Int32 nHitCount = rPH.fillHandles( pHandles, rPropertyNames );
930 if( nHitCount != 0 )
931 setFastPropertyValues( nSeqLen, pHandles, rValues.getConstArray(), nHitCount );
933 catch( ... )
935 delete [] pHandles;
936 throw;
938 delete [] pHandles;
941 // XMultiPropertySet
942 Sequence<Any> OPropertySetHelper::getPropertyValues( const Sequence<OUString>& rPropertyNames )
943 throw(::com::sun::star::uno::RuntimeException, std::exception)
945 sal_Int32 nSeqLen = rPropertyNames.getLength();
946 sal_Int32 * pHandles = new sal_Int32[ nSeqLen ];
947 Sequence< Any > aValues( nSeqLen );
949 // get the map table
950 IPropertyArrayHelper & rPH = getInfoHelper();
951 // fill the handle array
952 rPH.fillHandles( pHandles, rPropertyNames );
954 Any * pValues = aValues.getArray();
956 MutexGuard aGuard( rBHelper.rMutex );
957 // fill the sequence with the values
958 for( sal_Int32 i = 0; i < nSeqLen; i++ )
959 getFastPropertyValue( pValues[i], pHandles[i] );
961 delete [] pHandles;
962 return aValues;
965 // XMultiPropertySet
966 void OPropertySetHelper::addPropertiesChangeListener(
967 const Sequence<OUString> & ,
968 const Reference < XPropertiesChangeListener > & rListener )
969 throw(::com::sun::star::uno::RuntimeException, std::exception)
971 rBHelper.addListener( getCppuType(&rListener) , rListener );
974 // XMultiPropertySet
975 void OPropertySetHelper::removePropertiesChangeListener(
976 const Reference < XPropertiesChangeListener > & rListener )
977 throw(::com::sun::star::uno::RuntimeException, std::exception)
979 rBHelper.removeListener( getCppuType(&rListener) , rListener );
982 // XMultiPropertySet
983 void OPropertySetHelper::firePropertiesChangeEvent(
984 const Sequence<OUString>& rPropertyNames,
985 const Reference < XPropertiesChangeListener >& rListener )
986 throw(::com::sun::star::uno::RuntimeException, std::exception)
988 sal_Int32 nLen = rPropertyNames.getLength();
989 sal_Int32 * pHandles = new sal_Int32[nLen];
990 IPropertyArrayHelper & rPH = getInfoHelper();
991 rPH.fillHandles( pHandles, rPropertyNames );
992 const OUString* pNames = rPropertyNames.getConstArray();
994 // get the count of matching properties
995 sal_Int32 nFireLen = 0;
996 sal_Int32 i;
997 for( i = 0; i < nLen; i++ )
998 if( pHandles[i] != -1 )
999 nFireLen++;
1001 Sequence<PropertyChangeEvent> aChanges( nFireLen );
1002 PropertyChangeEvent* pChanges = aChanges.getArray();
1005 // must lock the mutex outside the loop. So all values are consistent.
1006 MutexGuard aGuard( rBHelper.rMutex );
1007 Reference < XInterface > xSource( (XPropertySet *)this, UNO_QUERY );
1008 sal_Int32 nFirePos = 0;
1009 for( i = 0; i < nLen; i++ )
1011 if( pHandles[i] != -1 )
1013 pChanges[nFirePos].Source = xSource;
1014 pChanges[nFirePos].PropertyName = pNames[i];
1015 pChanges[nFirePos].PropertyHandle = pHandles[i];
1016 getFastPropertyValue( pChanges[nFirePos].OldValue, pHandles[i] );
1017 pChanges[nFirePos].NewValue = pChanges[nFirePos].OldValue;
1018 nFirePos++;
1021 // release guard to fire events
1023 if( nFireLen )
1024 rListener->propertiesChange( aChanges );
1026 delete [] pHandles;
1029 void OPropertySetHelper2::enableChangeListenerNotification( sal_Bool bEnable )
1030 throw(::com::sun::star::uno::RuntimeException, std::exception)
1032 m_pReserved->m_bFireEvents = bEnable;
1036 //== OPropertyArrayHelper ================================================
1039 extern "C" {
1041 static int compare_Property_Impl( const void *arg1, const void *arg2 )
1042 SAL_THROW_EXTERN_C()
1044 return ((Property *)arg1)->Name.compareTo( ((Property *)arg2)->Name );
1049 void OPropertyArrayHelper::init( sal_Bool bSorted ) SAL_THROW(())
1051 sal_Int32 i, nElements = aInfos.getLength();
1052 const Property* pProperties = aInfos.getConstArray();
1054 for( i = 1; i < nElements; i++ )
1056 if( pProperties[i-1].Name >= pProperties[i].Name )
1058 if (bSorted) {
1059 OSL_FAIL( "Property array is not sorted" );
1061 // not sorted
1062 qsort( aInfos.getArray(), nElements, sizeof( Property ),
1063 compare_Property_Impl );
1064 break;
1067 // may be that the array is resorted
1068 pProperties = aInfos.getConstArray();
1069 for( i = 0; i < nElements; i++ )
1070 if( pProperties[i].Handle != i )
1071 return;
1072 // The handle is the index
1073 bRightOrdered = sal_True;
1076 OPropertyArrayHelper::OPropertyArrayHelper(
1077 Property * pProps,
1078 sal_Int32 nEle,
1079 sal_Bool bSorted )
1080 SAL_THROW(())
1081 : m_pReserved(NULL)
1082 , aInfos(pProps, nEle)
1083 , bRightOrdered( sal_False )
1085 init( bSorted );
1088 OPropertyArrayHelper::OPropertyArrayHelper(
1089 const Sequence< Property > & aProps,
1090 sal_Bool bSorted )
1091 SAL_THROW(())
1092 : m_pReserved(NULL)
1093 , aInfos(aProps)
1094 , bRightOrdered( sal_False )
1096 init( bSorted );
1100 sal_Int32 OPropertyArrayHelper::getCount() const
1102 return aInfos.getLength();
1106 sal_Bool OPropertyArrayHelper::fillPropertyMembersByHandle
1108 OUString * pPropName,
1109 sal_Int16 * pAttributes,
1110 sal_Int32 nHandle
1113 const Property* pProperties = aInfos.getConstArray();
1114 sal_Int32 nElements = aInfos.getLength();
1116 if( bRightOrdered )
1118 if( nHandle < 0 || nHandle >= nElements )
1119 return sal_False;
1120 if( pPropName )
1121 *pPropName = pProperties[ nHandle ].Name;
1122 if( pAttributes )
1123 *pAttributes = pProperties[ nHandle ].Attributes;
1124 return sal_True;
1126 else
1128 // normally the array is sorted
1129 for( sal_Int32 i = 0; i < nElements; i++ )
1131 if( pProperties[i].Handle == nHandle )
1133 if( pPropName )
1134 *pPropName = pProperties[ i ].Name;
1135 if( pAttributes )
1136 *pAttributes = pProperties[ i ].Attributes;
1137 return sal_True;
1141 return sal_False;
1145 Sequence< Property > OPropertyArrayHelper::getProperties(void)
1147 return aInfos;
1151 Property OPropertyArrayHelper::getPropertyByName(const OUString& aPropertyName)
1152 throw (UnknownPropertyException)
1154 Property * pR;
1155 pR = (Property *)bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(),
1156 sizeof( Property ),
1157 compare_OUString_Property_Impl );
1158 if( !pR ) {
1159 throw UnknownPropertyException();
1161 return *pR;
1165 sal_Bool OPropertyArrayHelper::hasPropertyByName(const OUString& aPropertyName)
1167 Property * pR;
1168 pR = (Property *)bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(),
1169 sizeof( Property ),
1170 compare_OUString_Property_Impl );
1171 return pR != NULL;
1175 sal_Int32 OPropertyArrayHelper::getHandleByName( const OUString & rPropName )
1177 Property * pR;
1178 pR = (Property *)bsearch( &rPropName, aInfos.getConstArray(), aInfos.getLength(),
1179 sizeof( Property ),
1180 compare_OUString_Property_Impl );
1181 return pR ? pR->Handle : -1;
1185 sal_Int32 OPropertyArrayHelper::fillHandles( sal_Int32 * pHandles, const Sequence< OUString > & rPropNames )
1187 sal_Int32 nHitCount = 0;
1188 const OUString * pReqProps = rPropNames.getConstArray();
1189 sal_Int32 nReqLen = rPropNames.getLength();
1190 const Property * pCur = aInfos.getConstArray();
1191 const Property * pEnd = pCur + aInfos.getLength();
1193 for( sal_Int32 i = 0; i < nReqLen; i++ )
1195 // Calculate logarithm
1196 sal_Int32 n = (sal_Int32)(pEnd - pCur);
1197 sal_Int32 nLog = 0;
1198 while( n )
1200 nLog += 1;
1201 n = n >> 1;
1204 // Number of properties to search for * Log2 of the number of remaining
1205 // properties to search in.
1206 if( (nReqLen - i) * nLog >= pEnd - pCur )
1208 // linear search is better
1209 while( pCur < pEnd && pReqProps[i] > pCur->Name )
1211 pCur++;
1213 if( pCur < pEnd && pReqProps[i] == pCur->Name )
1215 pHandles[i] = pCur->Handle;
1216 nHitCount++;
1218 else
1219 pHandles[i] = -1;
1221 else
1223 // binary search is better
1224 sal_Int32 nCompVal = 1;
1225 const Property * pOldEnd = pEnd--;
1226 const Property * pMid = pCur;
1228 while( nCompVal != 0 && pCur <= pEnd )
1230 pMid = (pEnd - pCur) / 2 + pCur;
1232 nCompVal = pReqProps[i].compareTo( pMid->Name );
1234 if( nCompVal > 0 )
1235 pCur = pMid + 1;
1236 else
1237 pEnd = pMid - 1;
1240 if( nCompVal == 0 )
1242 pHandles[i] = pMid->Handle;
1243 nHitCount++;
1244 pCur = pMid +1;
1246 else if( nCompVal > 0 )
1248 pHandles[i] = -1;
1249 pCur = pMid +1;
1251 else
1253 pHandles[i] = -1;
1254 pCur = pMid;
1256 pEnd = pOldEnd;
1259 return nHitCount;
1262 } // end namespace cppu
1266 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */