update credits
[LibreOffice.git] / cppuhelper / source / propshlp.cxx
blob4b45c54ef04e25a593ecf88032646eca1df70907
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;
37 using ::rtl::OUStringToOString;
39 namespace cppu {
41 IPropertyArrayHelper::~IPropertyArrayHelper()
45 inline const ::com::sun::star::uno::Type & getPropertyTypeIdentifier( ) SAL_THROW(())
47 return ::getCppuType( (Reference< XPropertyChangeListener > *)0 );
49 inline const ::com::sun::star::uno::Type & getPropertiesTypeIdentifier() SAL_THROW(())
51 return ::getCppuType( (Reference< XPropertiesChangeListener > *)0 );
53 inline const ::com::sun::star::uno::Type & getVetoableTypeIdentifier() SAL_THROW(())
55 return ::getCppuType( (Reference< XVetoableChangeListener > *)0 );
58 extern "C" {
60 static int compare_OUString_Property_Impl( const void *arg1, const void *arg2 )
61 SAL_THROW_EXTERN_C()
63 return ((OUString *)arg1)->compareTo( ((Property *)arg2)->Name );
68 /**
69 * The class which implements the PropertySetInfo interface.
72 class OPropertySetHelperInfo_Impl
73 : public WeakImplHelper1< ::com::sun::star::beans::XPropertySetInfo >
75 Sequence < Property > aInfos;
77 public:
78 OPropertySetHelperInfo_Impl( IPropertyArrayHelper & rHelper_ ) SAL_THROW(());
80 // XPropertySetInfo-methods
81 virtual Sequence< Property > SAL_CALL getProperties(void) throw(::com::sun::star::uno::RuntimeException);
82 virtual Property SAL_CALL getPropertyByName(const OUString& PropertyName) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
83 virtual sal_Bool SAL_CALL hasPropertyByName(const OUString& PropertyName) throw(::com::sun::star::uno::RuntimeException);
87 /**
88 * Create an object that implements XPropertySetInfo IPropertyArrayHelper.
90 OPropertySetHelperInfo_Impl::OPropertySetHelperInfo_Impl(
91 IPropertyArrayHelper & rHelper_ )
92 SAL_THROW(())
93 :aInfos( rHelper_.getProperties() )
97 /**
98 * Return the sequence of properties, which are provided throug the constructor.
100 Sequence< Property > OPropertySetHelperInfo_Impl::getProperties(void) throw(::com::sun::star::uno::RuntimeException)
103 return aInfos;
107 * Return the sequence of properties, which are provided throug the constructor.
109 Property OPropertySetHelperInfo_Impl::getPropertyByName( const OUString & PropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException)
111 Property * pR;
112 pR = (Property *)bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(),
113 sizeof( Property ),
114 compare_OUString_Property_Impl );
115 if( !pR ) {
116 throw UnknownPropertyException();
119 return *pR;
123 * Return the sequence of properties, which are provided throug the constructor.
125 sal_Bool OPropertySetHelperInfo_Impl::hasPropertyByName( const OUString & PropertyName ) throw(::com::sun::star::uno::RuntimeException)
127 Property * pR;
128 pR = (Property *)bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(),
129 sizeof( Property ),
130 compare_OUString_Property_Impl );
131 return pR != NULL;
134 // ----------------------------------------------------
135 // class PropertySetHelper_Impl
136 // ----------------------------------------------------
137 class OPropertySetHelper::Impl {
139 public:
140 Impl( bool i_bIgnoreRuntimeExceptionsWhileFiring,
141 IEventNotificationHook *i_pFireEvents
143 :m_bIgnoreRuntimeExceptionsWhileFiring( i_bIgnoreRuntimeExceptionsWhileFiring )
144 ,m_bFireEvents(true)
145 ,m_pFireEvents( i_pFireEvents )
149 bool m_bIgnoreRuntimeExceptionsWhileFiring;
150 bool m_bFireEvents;
151 class IEventNotificationHook * const m_pFireEvents;
153 ::std::vector< sal_Int32 > m_handles;
154 ::std::vector< Any > m_newValues;
155 ::std::vector< Any > m_oldValues;
159 // ----------------------------------------------------
160 // class PropertySetHelper
161 // ----------------------------------------------------
162 OPropertySetHelper::OPropertySetHelper(
163 OBroadcastHelper & rBHelper_ ) SAL_THROW(())
164 : rBHelper( rBHelper_ ),
165 aBoundLC( rBHelper_.rMutex ),
166 aVetoableLC( rBHelper_.rMutex ),
167 m_pReserved( new Impl(false, 0) )
171 OPropertySetHelper::OPropertySetHelper(
172 OBroadcastHelper & rBHelper_, bool bIgnoreRuntimeExceptionsWhileFiring )
173 : rBHelper( rBHelper_ ),
174 aBoundLC( rBHelper_.rMutex ),
175 aVetoableLC( rBHelper_.rMutex ),
176 m_pReserved( new Impl( bIgnoreRuntimeExceptionsWhileFiring, 0 ) )
180 OPropertySetHelper::OPropertySetHelper(
181 OBroadcastHelper & rBHelper_, IEventNotificationHook * i_pFireEvents,
182 bool bIgnoreRuntimeExceptionsWhileFiring)
183 : rBHelper( rBHelper_ ),
184 aBoundLC( rBHelper_.rMutex ),
185 aVetoableLC( rBHelper_.rMutex ),
186 m_pReserved(
187 new Impl( bIgnoreRuntimeExceptionsWhileFiring, i_pFireEvents) )
191 OPropertySetHelper2::OPropertySetHelper2(
192 OBroadcastHelper & irBHelper,
193 IEventNotificationHook *i_pFireEvents,
194 bool bIgnoreRuntimeExceptionsWhileFiring)
195 :OPropertySetHelper( irBHelper, i_pFireEvents, bIgnoreRuntimeExceptionsWhileFiring )
200 * You must call disposing before.
202 OPropertySetHelper::~OPropertySetHelper() SAL_THROW(())
205 OPropertySetHelper2::~OPropertySetHelper2() SAL_THROW(())
209 // XInterface
210 Any OPropertySetHelper::queryInterface( const ::com::sun::star::uno::Type & rType )
211 throw (RuntimeException)
213 return ::cppu::queryInterface(
214 rType,
215 static_cast< XPropertySet * >( this ),
216 static_cast< XMultiPropertySet * >( this ),
217 static_cast< XFastPropertySet * >( this ) );
220 Any OPropertySetHelper2::queryInterface( const ::com::sun::star::uno::Type & rType )
221 throw (RuntimeException)
223 Any cnd(cppu::queryInterface(rType, static_cast< XPropertySetOption * >(this)));
224 if ( cnd.hasValue() )
225 return cnd;
226 else
227 return OPropertySetHelper::queryInterface(rType);
231 * called from the derivee's XTypeProvider::getTypes implementation
233 ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > OPropertySetHelper::getTypes()
234 throw (RuntimeException)
236 Sequence< ::com::sun::star::uno::Type > aTypes( 4 );
237 aTypes[ 0 ] = XPropertySet::static_type();
238 aTypes[ 1 ] = XPropertySetOption::static_type();
239 aTypes[ 2 ] = XMultiPropertySet::static_type();
240 aTypes[ 3 ] = XFastPropertySet::static_type();
241 return aTypes;
244 // ComponentHelper
245 void OPropertySetHelper::disposing() SAL_THROW(())
247 // Create an event with this as sender
248 Reference < XPropertySet > rSource( (static_cast< XPropertySet * >(this)) , UNO_QUERY );
249 EventObject aEvt;
250 aEvt.Source = rSource;
252 // inform all listeners to release this object
253 // The listener containers are automatically cleared
254 aBoundLC.disposeAndClear( aEvt );
255 aVetoableLC.disposeAndClear( aEvt );
258 Reference < XPropertySetInfo > OPropertySetHelper::createPropertySetInfo(
259 IPropertyArrayHelper & rProperties ) SAL_THROW(())
261 return static_cast< XPropertySetInfo * >( new OPropertySetHelperInfo_Impl( rProperties ) );
264 // XPropertySet
265 void OPropertySetHelper::setPropertyValue(
266 const OUString& rPropertyName, const Any& rValue )
267 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)
269 // get the map table
270 IPropertyArrayHelper & rPH = getInfoHelper();
271 // map the name to the handle
272 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
273 // call the method of the XFastPropertySet interface
274 setFastPropertyValue( nHandle, rValue );
277 // XPropertySet
278 Any OPropertySetHelper::getPropertyValue(
279 const OUString& rPropertyName )
280 throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
282 // get the map table
283 IPropertyArrayHelper & rPH = getInfoHelper();
284 // map the name to the handle
285 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
286 // call the method of the XFastPropertySet interface
287 return getFastPropertyValue( nHandle );
290 // XPropertySet
291 void OPropertySetHelper::addPropertyChangeListener(
292 const OUString& rPropertyName,
293 const Reference < XPropertyChangeListener > & rxListener )
294 throw(::com::sun::star::beans::UnknownPropertyException,
295 ::com::sun::star::lang::WrappedTargetException,
296 ::com::sun::star::uno::RuntimeException)
298 MutexGuard aGuard( rBHelper.rMutex );
299 OSL_ENSURE( !rBHelper.bInDispose, "do not addPropertyChangeListener in the dispose call" );
300 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
301 if( !rBHelper.bInDispose && !rBHelper.bDisposed )
303 // only add listeners if you are not disposed
304 // a listener with no name means all properties
305 if( !rPropertyName.isEmpty() )
307 // get the map table
308 IPropertyArrayHelper & rPH = getInfoHelper();
309 // map the name to the handle
310 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
311 if( nHandle == -1 ) {
312 // property not known throw exception
313 throw UnknownPropertyException() ;
316 sal_Int16 nAttributes;
317 rPH.fillPropertyMembersByHandle( NULL, &nAttributes, nHandle );
318 if( !(nAttributes & ::com::sun::star::beans::PropertyAttribute::BOUND) )
320 OSL_FAIL( "add listener to an unbound property" );
321 // silent ignore this
322 return;
324 // add the change listener to the helper container
326 aBoundLC.addInterface( (sal_Int32)nHandle, rxListener );
328 else
329 // add the change listener to the helper container
330 rBHelper.aLC.addInterface(
331 getPropertyTypeIdentifier( ),
332 rxListener
338 // XPropertySet
339 void OPropertySetHelper::removePropertyChangeListener(
340 const OUString& rPropertyName,
341 const Reference < XPropertyChangeListener >& rxListener )
342 throw(::com::sun::star::beans::UnknownPropertyException,
343 ::com::sun::star::lang::WrappedTargetException,
344 ::com::sun::star::uno::RuntimeException)
346 MutexGuard aGuard( rBHelper.rMutex );
347 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
348 // all listeners are automaticly released in a dispose call
349 if( !rBHelper.bInDispose && !rBHelper.bDisposed )
351 if( !rPropertyName.isEmpty() )
353 // get the map table
354 IPropertyArrayHelper & rPH = getInfoHelper();
355 // map the name to the handle
356 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
357 if( nHandle == -1 )
358 // property not known throw exception
359 throw UnknownPropertyException();
360 aBoundLC.removeInterface( (sal_Int32)nHandle, rxListener );
362 else {
363 // remove the change listener to the helper container
364 rBHelper.aLC.removeInterface(
365 getPropertyTypeIdentifier( ),
366 rxListener
372 // XPropertySet
373 void OPropertySetHelper::addVetoableChangeListener(
374 const OUString& rPropertyName,
375 const Reference< XVetoableChangeListener > & rxListener )
376 throw(::com::sun::star::beans::UnknownPropertyException,
377 ::com::sun::star::lang::WrappedTargetException,
378 ::com::sun::star::uno::RuntimeException)
380 MutexGuard aGuard( rBHelper.rMutex );
381 OSL_ENSURE( !rBHelper.bInDispose, "do not addVetoableChangeListener in the dispose call" );
382 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
383 if( !rBHelper.bInDispose && !rBHelper.bDisposed )
385 // only add listeners if you are not disposed
386 // a listener with no name means all properties
387 if( !rPropertyName.isEmpty() )
389 // get the map table
390 IPropertyArrayHelper & rPH = getInfoHelper();
391 // map the name to the handle
392 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
393 if( nHandle == -1 ) {
394 // property not known throw exception
395 throw UnknownPropertyException();
398 sal_Int16 nAttributes;
399 rPH.fillPropertyMembersByHandle( NULL, &nAttributes, nHandle );
400 if( !(nAttributes & PropertyAttribute::CONSTRAINED) )
402 OSL_FAIL( "addVetoableChangeListener, and property is not constrained" );
403 // silent ignore this
404 return;
406 // add the vetoable listener to the helper container
407 aVetoableLC.addInterface( (sal_Int32)nHandle, rxListener );
409 else
410 // add the vetoable listener to the helper container
411 rBHelper.aLC.addInterface(
412 getVetoableTypeIdentifier( ),
413 rxListener
418 // XPropertySet
419 void OPropertySetHelper::removeVetoableChangeListener(
420 const OUString& rPropertyName,
421 const Reference < XVetoableChangeListener > & rxListener )
422 throw(::com::sun::star::beans::UnknownPropertyException,
423 ::com::sun::star::lang::WrappedTargetException,
424 ::com::sun::star::uno::RuntimeException)
426 MutexGuard aGuard( rBHelper.rMutex );
427 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
428 // all listeners are automaticly released in a dispose call
429 if( !rBHelper.bInDispose && !rBHelper.bDisposed )
431 if( !rPropertyName.isEmpty() )
433 // get the map table
434 IPropertyArrayHelper & rPH = getInfoHelper();
435 // map the name to the handle
436 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
437 if( nHandle == -1 ) {
438 // property not known throw exception
439 throw UnknownPropertyException();
441 // remove the vetoable listener to the helper container
442 aVetoableLC.removeInterface( (sal_Int32)nHandle, rxListener );
444 else
445 // add the vetoable listener to the helper container
446 rBHelper.aLC.removeInterface(
447 getVetoableTypeIdentifier( ),
448 rxListener
453 void OPropertySetHelper::setDependentFastPropertyValue( sal_Int32 i_handle, const ::com::sun::star::uno::Any& i_value )
455 //OSL_PRECOND( rBHelper.rMutex.isAcquired(), "OPropertySetHelper::setDependentFastPropertyValue: to be called with a locked mutex only!" );
456 // there is no such thing as Mutex.isAcquired, sadly ...
458 sal_Int16 nAttributes(0);
459 IPropertyArrayHelper& rInfo = getInfoHelper();
460 if ( !rInfo.fillPropertyMembersByHandle( NULL, &nAttributes, i_handle ) )
461 // unknown property
462 throw UnknownPropertyException();
464 // no need to check for READONLY-ness of the property. The method is intended to be called internally, which
465 // implies it might be invoked for properties which are read-only to the instance's clients, but well allowed
466 // to change their value.
468 Any aConverted, aOld;
469 sal_Bool bChanged = convertFastPropertyValue( aConverted, aOld, i_handle, i_value );
470 if ( !bChanged )
471 return;
473 // don't fire vetoable events. This method is called with our mutex locked, so calling into listeners would not be
474 // a good idea. The caler is responsible for not invoking this for constrained properties.
475 OSL_ENSURE( ( nAttributes & PropertyAttribute::CONSTRAINED ) == 0,
476 "OPropertySetHelper::setDependentFastPropertyValue: not to be used for constrained properties!" );
477 (void)nAttributes;
479 // actually set the new value
482 setFastPropertyValue_NoBroadcast( i_handle, aConverted );
484 catch (const UnknownPropertyException& ) { throw; /* allowed to leave */ }
485 catch (const PropertyVetoException& ) { throw; /* allowed to leave */ }
486 catch (const IllegalArgumentException& ) { throw; /* allowed to leave */ }
487 catch (const WrappedTargetException& ) { throw; /* allowed to leave */ }
488 catch (const RuntimeException& ) { throw; /* allowed to leave */ }
489 catch (const Exception& )
491 // not allowed to leave this meathod
492 WrappedTargetException aWrapped;
493 aWrapped.TargetException <<= ::cppu::getCaughtException();
494 aWrapped.Context = static_cast< XPropertySet* >( this );
495 throw aWrapped;
498 // remember the handle/values, for the events to be fired later
499 m_pReserved->m_handles.push_back( i_handle );
500 m_pReserved->m_newValues.push_back( aConverted ); // TODO: setFastPropertyValue notifies the unconverted value here ...?
501 m_pReserved->m_oldValues.push_back( aOld );
504 // XFastPropertySet
505 void OPropertySetHelper::setFastPropertyValue( sal_Int32 nHandle, const Any& rValue )
506 throw(::com::sun::star::beans::UnknownPropertyException,
507 ::com::sun::star::beans::PropertyVetoException,
508 ::com::sun::star::lang::IllegalArgumentException,
509 ::com::sun::star::lang::WrappedTargetException,
510 ::com::sun::star::uno::RuntimeException)
512 OSL_ENSURE( !rBHelper.bInDispose, "do not setFastPropertyValue in the dispose call" );
513 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
515 IPropertyArrayHelper & rInfo = getInfoHelper();
516 sal_Int16 nAttributes;
517 if( !rInfo.fillPropertyMembersByHandle( NULL, &nAttributes, nHandle ) ) {
518 // unknown property
519 throw UnknownPropertyException();
521 if( nAttributes & PropertyAttribute::READONLY )
522 throw PropertyVetoException();
524 Any aConvertedVal;
525 Any aOldVal;
527 // Will the property change?
528 sal_Bool bChanged;
530 MutexGuard aGuard( rBHelper.rMutex );
531 bChanged = convertFastPropertyValue( aConvertedVal, aOldVal, nHandle, rValue );
532 // release guard to fire events
534 if( bChanged )
536 // Is it a constrained property?
537 if( nAttributes & PropertyAttribute::CONSTRAINED )
539 // In aValue is the converted rValue
540 // fire a constarined event
541 // second parameter NULL means constrained
542 fire( &nHandle, &rValue, &aOldVal, 1, sal_True );
546 MutexGuard aGuard( rBHelper.rMutex );
549 // set the property to the new value
550 setFastPropertyValue_NoBroadcast( nHandle, aConvertedVal );
552 catch (const ::com::sun::star::beans::UnknownPropertyException& ) { throw; /* allowed to leave */ }
553 catch (const ::com::sun::star::beans::PropertyVetoException& ) { throw; /* allowed to leave */ }
554 catch (const ::com::sun::star::lang::IllegalArgumentException& ) { throw; /* allowed to leave */ }
555 catch (const ::com::sun::star::lang::WrappedTargetException& ) { throw; /* allowed to leave */ }
556 catch (const ::com::sun::star::uno::RuntimeException& ) { throw; /* allowed to leave */ }
557 catch (const ::com::sun::star::uno::Exception& e )
559 // not allowed to leave this meathod
560 ::com::sun::star::lang::WrappedTargetException aWrap;
561 aWrap.Context = static_cast< ::com::sun::star::beans::XPropertySet* >( this );
562 aWrap.TargetException <<= e;
564 throw ::com::sun::star::lang::WrappedTargetException( aWrap );
567 // release guard to fire events
569 // file a change event, if the value changed
570 impl_fireAll( &nHandle, &rValue, &aOldVal, 1 );
574 // XFastPropertySet
575 Any OPropertySetHelper::getFastPropertyValue( sal_Int32 nHandle )
576 throw(::com::sun::star::beans::UnknownPropertyException,
577 ::com::sun::star::lang::WrappedTargetException,
578 ::com::sun::star::uno::RuntimeException)
581 IPropertyArrayHelper & rInfo = getInfoHelper();
582 if( !rInfo.fillPropertyMembersByHandle( NULL, NULL, nHandle ) )
583 // unknown property
584 throw UnknownPropertyException();
586 Any aRet;
587 MutexGuard aGuard( rBHelper.rMutex );
588 getFastPropertyValue( aRet, nHandle );
589 return aRet;
592 //--------------------------------------------------------------------------
593 void OPropertySetHelper::impl_fireAll( sal_Int32* i_handles, const Any* i_newValues, const Any* i_oldValues, sal_Int32 i_count )
595 ClearableMutexGuard aGuard( rBHelper.rMutex );
596 if ( m_pReserved->m_handles.empty() )
598 aGuard.clear();
599 fire( i_handles, i_newValues, i_oldValues, i_count, sal_False );
600 return;
603 const size_t additionalEvents = m_pReserved->m_handles.size();
604 OSL_ENSURE( additionalEvents == m_pReserved->m_newValues.size()
605 && additionalEvents == m_pReserved->m_oldValues.size(),
606 "OPropertySetHelper::impl_fireAll: inconsistency!" );
608 ::std::vector< sal_Int32 > allHandles( additionalEvents + i_count );
609 ::std::copy( m_pReserved->m_handles.begin(), m_pReserved->m_handles.end(), allHandles.begin() );
610 ::std::copy( i_handles, i_handles + i_count, allHandles.begin() + additionalEvents );
612 ::std::vector< Any > allNewValues( additionalEvents + i_count );
613 ::std::copy( m_pReserved->m_newValues.begin(), m_pReserved->m_newValues.end(), allNewValues.begin() );
614 ::std::copy( i_newValues, i_newValues + i_count, allNewValues.begin() + additionalEvents );
616 ::std::vector< Any > allOldValues( additionalEvents + i_count );
617 ::std::copy( m_pReserved->m_oldValues.begin(), m_pReserved->m_oldValues.end(), allOldValues.begin() );
618 ::std::copy( i_oldValues, i_oldValues + i_count, allOldValues.begin() + additionalEvents );
620 m_pReserved->m_handles.clear();
621 m_pReserved->m_newValues.clear();
622 m_pReserved->m_oldValues.clear();
624 aGuard.clear();
625 fire( &allHandles[0], &allNewValues[0], &allOldValues[0], additionalEvents + i_count, sal_False );
628 //--------------------------------------------------------------------------
629 void OPropertySetHelper::fire
631 sal_Int32 * pnHandles,
632 const Any * pNewValues,
633 const Any * pOldValues,
634 sal_Int32 nHandles, // These is the Count of the array
635 sal_Bool bVetoable
638 OSL_ENSURE( m_pReserved.get(), "No OPropertySetHelper::Impl" );
640 if (! m_pReserved->m_bFireEvents)
641 return;
643 if (m_pReserved->m_pFireEvents) {
644 m_pReserved->m_pFireEvents->fireEvents(
645 pnHandles, nHandles, bVetoable,
646 m_pReserved->m_bIgnoreRuntimeExceptionsWhileFiring);
649 // Only fire, if one or more properties changed
650 if( nHandles )
652 // create the event sequence of all changed properties
653 Sequence< PropertyChangeEvent > aEvts( nHandles );
654 PropertyChangeEvent * pEvts = aEvts.getArray();
655 Reference < XInterface > xSource( (XPropertySet *)this, UNO_QUERY );
656 sal_Int32 i;
657 sal_Int32 nChangesLen = 0;
658 // Loop over all changed properties to fill the event struct
659 for( i = 0; i < nHandles; i++ )
661 // Vetoable fire and constrained attribute set or
662 // Change fire and Changed and bound attribute set
663 IPropertyArrayHelper & rInfo = getInfoHelper();
664 sal_Int16 nAttributes;
665 OUString aPropName;
666 rInfo.fillPropertyMembersByHandle( &aPropName, &nAttributes, pnHandles[i] );
669 (bVetoable && (nAttributes & PropertyAttribute::CONSTRAINED)) ||
670 (!bVetoable && (nAttributes & PropertyAttribute::BOUND))
673 pEvts[nChangesLen].Source = xSource;
674 pEvts[nChangesLen].PropertyName = aPropName;
675 pEvts[nChangesLen].PropertyHandle = pnHandles[i];
676 pEvts[nChangesLen].OldValue = pOldValues[i];
677 pEvts[nChangesLen].NewValue = pNewValues[i];
678 nChangesLen++;
682 bool bIgnoreRuntimeExceptionsWhileFiring =
683 m_pReserved->m_bIgnoreRuntimeExceptionsWhileFiring;
685 // fire the events for all changed properties
686 for( i = 0; i < nChangesLen; i++ )
688 // get the listener container for the property name
689 OInterfaceContainerHelper * pLC;
690 if( bVetoable ) // fire change Events?
691 pLC = aVetoableLC.getContainer( pEvts[i].PropertyHandle );
692 else
693 pLC = aBoundLC.getContainer( pEvts[i].PropertyHandle );
694 if( pLC )
696 // Iterate over all listeners and send events
697 OInterfaceIteratorHelper aIt( *pLC);
698 while( aIt.hasMoreElements() )
700 XInterface * pL = aIt.next();
705 if( bVetoable ) // fire change Events?
707 ((XVetoableChangeListener *)pL)->vetoableChange(
708 pEvts[i] );
710 else
712 ((XPropertyChangeListener *)pL)->propertyChange(
713 pEvts[i] );
716 catch (DisposedException & exc)
718 OSL_ENSURE( exc.Context.is(),
719 "DisposedException without Context!" );
720 if (exc.Context == pL)
721 aIt.remove();
722 else
723 throw;
726 catch (RuntimeException & exc)
728 OSL_TRACE(
729 OUStringToOString(
730 OUString( RTL_CONSTASCII_USTRINGPARAM(
731 "caught RuntimeException while "
732 "firing listeners: ") ) +
733 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
734 if (! bIgnoreRuntimeExceptionsWhileFiring)
735 throw;
739 // broadcast to all listeners with "" property name
740 if( bVetoable ){
741 // fire change Events?
742 pLC = rBHelper.aLC.getContainer(
743 getVetoableTypeIdentifier()
746 else {
747 pLC = rBHelper.aLC.getContainer(
748 getPropertyTypeIdentifier( )
751 if( pLC )
753 // Iterate over all listeners and send events.
754 OInterfaceIteratorHelper aIt( *pLC);
755 while( aIt.hasMoreElements() )
757 XInterface * pL = aIt.next();
762 if( bVetoable ) // fire change Events?
764 ((XVetoableChangeListener *)pL)->vetoableChange(
765 pEvts[i] );
767 else
769 ((XPropertyChangeListener *)pL)->propertyChange(
770 pEvts[i] );
773 catch (DisposedException & exc)
775 OSL_ENSURE( exc.Context.is(),
776 "DisposedException without Context!" );
777 if (exc.Context == pL)
778 aIt.remove();
779 else
780 throw;
783 catch (RuntimeException & exc)
785 OSL_TRACE(
786 OUStringToOString(
787 OUString( RTL_CONSTASCII_USTRINGPARAM(
788 "caught RuntimeException while "
789 "firing listeners: ") ) +
790 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
791 if (! bIgnoreRuntimeExceptionsWhileFiring)
792 throw;
798 // reduce array to changed properties
799 aEvts.realloc( nChangesLen );
801 if( !bVetoable )
803 OInterfaceContainerHelper * pCont = 0;
804 pCont = rBHelper.aLC.getContainer(
805 getPropertiesTypeIdentifier( )
807 if( pCont )
809 // Here is a Bug, unbound properties are also fired
810 OInterfaceIteratorHelper aIt( *pCont );
811 while( aIt.hasMoreElements() )
813 XPropertiesChangeListener * pL =
814 (XPropertiesChangeListener *)aIt.next();
819 // fire the hole event sequence to the
820 // XPropertiesChangeListener's
821 pL->propertiesChange( aEvts );
823 catch (DisposedException & exc)
825 OSL_ENSURE( exc.Context.is(),
826 "DisposedException without Context!" );
827 if (exc.Context == pL)
828 aIt.remove();
829 else
830 throw;
833 catch (RuntimeException & exc)
835 OSL_TRACE(
836 OUStringToOString(
837 OUString( RTL_CONSTASCII_USTRINGPARAM(
838 "caught RuntimeException while "
839 "firing listeners: ") ) +
840 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
841 if (! bIgnoreRuntimeExceptionsWhileFiring)
842 throw;
850 // OPropertySetHelper
851 void OPropertySetHelper::setFastPropertyValues(
852 sal_Int32 nSeqLen,
853 sal_Int32 * pHandles,
854 const Any * pValues,
855 sal_Int32 nHitCount )
856 SAL_THROW( (::com::sun::star::uno::Exception) )
858 OSL_ENSURE( !rBHelper.bInDispose, "do not getFastPropertyValue in the dispose call" );
859 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
861 Any * pConvertedValues = NULL;
862 Any * pOldValues = NULL;
866 // get the map table
867 IPropertyArrayHelper & rPH = getInfoHelper();
869 pConvertedValues = new Any[ nHitCount ];
870 pOldValues = new Any[ nHitCount ];
871 sal_Int32 n = 0;
872 sal_Int32 i;
875 // must lock the mutex outside the loop. So all values are consistent.
876 MutexGuard aGuard( rBHelper.rMutex );
877 for( i = 0; i < nSeqLen; i++ )
879 if( pHandles[i] != -1 )
881 sal_Int16 nAttributes;
882 rPH.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] );
883 if( nAttributes & PropertyAttribute::READONLY ) {
884 throw PropertyVetoException();
886 // Will the property change?
887 if( convertFastPropertyValue( pConvertedValues[ n ], pOldValues[n],
888 pHandles[i], pValues[i] ) )
890 // only increment if the property really change
891 pHandles[n] = pHandles[i];
892 n++;
896 // release guard to fire events
899 // fire vetoable events
900 fire( pHandles, pConvertedValues, pOldValues, n, sal_True );
903 // must lock the mutex outside the loop.
904 MutexGuard aGuard( rBHelper.rMutex );
905 // Loop over all changed properties
906 for( i = 0; i < n; i++ )
908 // Will the property change?
909 setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
911 // release guard to fire events
914 // fire change events
915 impl_fireAll( pHandles, pConvertedValues, pOldValues, n );
917 catch( ... )
919 delete [] pOldValues;
920 delete [] pConvertedValues;
921 throw;
923 delete [] pOldValues;
924 delete [] pConvertedValues;
927 // XMultiPropertySet
929 * The sequence may be conatain not known properties. The implementation
930 * must ignore these properties.
932 void OPropertySetHelper::setPropertyValues(
933 const Sequence<OUString>& rPropertyNames,
934 const Sequence<Any>& rValues )
935 throw(::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
937 sal_Int32 * pHandles = NULL;
940 sal_Int32 nSeqLen = rPropertyNames.getLength();
941 pHandles = new sal_Int32[ nSeqLen ];
942 // get the map table
943 IPropertyArrayHelper & rPH = getInfoHelper();
944 // fill the handle array
945 sal_Int32 nHitCount = rPH.fillHandles( pHandles, rPropertyNames );
946 if( nHitCount != 0 )
947 setFastPropertyValues( nSeqLen, pHandles, rValues.getConstArray(), nHitCount );
949 catch( ... )
951 delete [] pHandles;
952 throw;
954 delete [] pHandles;
957 // XMultiPropertySet
958 Sequence<Any> OPropertySetHelper::getPropertyValues( const Sequence<OUString>& rPropertyNames )
959 throw(::com::sun::star::uno::RuntimeException)
961 sal_Int32 nSeqLen = rPropertyNames.getLength();
962 sal_Int32 * pHandles = new sal_Int32[ nSeqLen ];
963 Sequence< Any > aValues( nSeqLen );
965 // get the map table
966 IPropertyArrayHelper & rPH = getInfoHelper();
967 // fill the handle array
968 rPH.fillHandles( pHandles, rPropertyNames );
970 Any * pValues = aValues.getArray();
972 MutexGuard aGuard( rBHelper.rMutex );
973 // fill the sequence with the values
974 for( sal_Int32 i = 0; i < nSeqLen; i++ )
975 getFastPropertyValue( pValues[i], pHandles[i] );
977 delete [] pHandles;
978 return aValues;
981 // XMultiPropertySet
982 void OPropertySetHelper::addPropertiesChangeListener(
983 const Sequence<OUString> & ,
984 const Reference < XPropertiesChangeListener > & rListener )
985 throw(::com::sun::star::uno::RuntimeException)
987 rBHelper.addListener( getCppuType(&rListener) , rListener );
990 // XMultiPropertySet
991 void OPropertySetHelper::removePropertiesChangeListener(
992 const Reference < XPropertiesChangeListener > & rListener )
993 throw(::com::sun::star::uno::RuntimeException)
995 rBHelper.removeListener( getCppuType(&rListener) , rListener );
998 // XMultiPropertySet
999 void OPropertySetHelper::firePropertiesChangeEvent(
1000 const Sequence<OUString>& rPropertyNames,
1001 const Reference < XPropertiesChangeListener >& rListener )
1002 throw(::com::sun::star::uno::RuntimeException)
1004 sal_Int32 nLen = rPropertyNames.getLength();
1005 sal_Int32 * pHandles = new sal_Int32[nLen];
1006 IPropertyArrayHelper & rPH = getInfoHelper();
1007 rPH.fillHandles( pHandles, rPropertyNames );
1008 const OUString* pNames = rPropertyNames.getConstArray();
1010 // get the count of matching properties
1011 sal_Int32 nFireLen = 0;
1012 sal_Int32 i;
1013 for( i = 0; i < nLen; i++ )
1014 if( pHandles[i] != -1 )
1015 nFireLen++;
1017 Sequence<PropertyChangeEvent> aChanges( nFireLen );
1018 PropertyChangeEvent* pChanges = aChanges.getArray();
1021 // must lock the mutex outside the loop. So all values are consistent.
1022 MutexGuard aGuard( rBHelper.rMutex );
1023 Reference < XInterface > xSource( (XPropertySet *)this, UNO_QUERY );
1024 sal_Int32 nFirePos = 0;
1025 for( i = 0; i < nLen; i++ )
1027 if( pHandles[i] != -1 )
1029 pChanges[nFirePos].Source = xSource;
1030 pChanges[nFirePos].PropertyName = pNames[i];
1031 pChanges[nFirePos].PropertyHandle = pHandles[i];
1032 getFastPropertyValue( pChanges[nFirePos].OldValue, pHandles[i] );
1033 pChanges[nFirePos].NewValue = pChanges[nFirePos].OldValue;
1034 nFirePos++;
1037 // release guard to fire events
1039 if( nFireLen )
1040 rListener->propertiesChange( aChanges );
1042 delete [] pHandles;
1045 void OPropertySetHelper2::enableChangeListenerNotification( sal_Bool bEnable )
1046 throw(::com::sun::star::uno::RuntimeException)
1048 m_pReserved->m_bFireEvents = bEnable;
1051 //========================================================================
1052 //== OPropertyArrayHelper ================================================
1053 //========================================================================
1055 extern "C" {
1057 static int compare_Property_Impl( const void *arg1, const void *arg2 )
1058 SAL_THROW_EXTERN_C()
1060 return ((Property *)arg1)->Name.compareTo( ((Property *)arg2)->Name );
1065 void OPropertyArrayHelper::init( sal_Bool bSorted ) SAL_THROW(())
1067 sal_Int32 i, nElements = aInfos.getLength();
1068 const Property* pProperties = aInfos.getConstArray();
1070 for( i = 1; i < nElements; i++ )
1072 if( pProperties[i-1].Name >= pProperties[i].Name )
1074 if (bSorted) {
1075 OSL_FAIL( "Property array is not sorted" );
1077 // not sorted
1078 qsort( aInfos.getArray(), nElements, sizeof( Property ),
1079 compare_Property_Impl );
1080 break;
1083 // may be that the array is resorted
1084 pProperties = aInfos.getConstArray();
1085 for( i = 0; i < nElements; i++ )
1086 if( pProperties[i].Handle != i )
1087 return;
1088 // The handle is the index
1089 bRightOrdered = sal_True;
1092 OPropertyArrayHelper::OPropertyArrayHelper(
1093 Property * pProps,
1094 sal_Int32 nEle,
1095 sal_Bool bSorted )
1096 SAL_THROW(())
1097 : aInfos(pProps, nEle)
1098 , bRightOrdered( sal_False )
1100 init( bSorted );
1103 OPropertyArrayHelper::OPropertyArrayHelper(
1104 const Sequence< Property > & aProps,
1105 sal_Bool bSorted )
1106 SAL_THROW(())
1107 : aInfos(aProps)
1108 , bRightOrdered( sal_False )
1110 init( bSorted );
1113 //========================================================================
1114 sal_Int32 OPropertyArrayHelper::getCount() const
1116 return aInfos.getLength();
1119 //========================================================================
1120 sal_Bool OPropertyArrayHelper::fillPropertyMembersByHandle
1122 OUString * pPropName,
1123 sal_Int16 * pAttributes,
1124 sal_Int32 nHandle
1127 const Property* pProperties = aInfos.getConstArray();
1128 sal_Int32 nElements = aInfos.getLength();
1130 if( bRightOrdered )
1132 if( nHandle < 0 || nHandle >= nElements )
1133 return sal_False;
1134 if( pPropName )
1135 *pPropName = pProperties[ nHandle ].Name;
1136 if( pAttributes )
1137 *pAttributes = pProperties[ nHandle ].Attributes;
1138 return sal_True;
1140 else
1142 // normally the array is sorted
1143 for( sal_Int32 i = 0; i < nElements; i++ )
1145 if( pProperties[i].Handle == nHandle )
1147 if( pPropName )
1148 *pPropName = pProperties[ i ].Name;
1149 if( pAttributes )
1150 *pAttributes = pProperties[ i ].Attributes;
1151 return sal_True;
1155 return sal_False;
1158 //========================================================================
1159 Sequence< Property > OPropertyArrayHelper::getProperties(void)
1161 return aInfos;
1164 //========================================================================
1165 Property OPropertyArrayHelper::getPropertyByName(const OUString& aPropertyName)
1166 throw (UnknownPropertyException)
1168 Property * pR;
1169 pR = (Property *)bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(),
1170 sizeof( Property ),
1171 compare_OUString_Property_Impl );
1172 if( !pR ) {
1173 throw UnknownPropertyException();
1175 return *pR;
1178 //========================================================================
1179 sal_Bool OPropertyArrayHelper::hasPropertyByName(const OUString& aPropertyName)
1181 Property * pR;
1182 pR = (Property *)bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(),
1183 sizeof( Property ),
1184 compare_OUString_Property_Impl );
1185 return pR != NULL;
1188 //========================================================================
1189 sal_Int32 OPropertyArrayHelper::getHandleByName( const OUString & rPropName )
1191 Property * pR;
1192 pR = (Property *)bsearch( &rPropName, aInfos.getConstArray(), aInfos.getLength(),
1193 sizeof( Property ),
1194 compare_OUString_Property_Impl );
1195 return pR ? pR->Handle : -1;
1198 //========================================================================
1199 sal_Int32 OPropertyArrayHelper::fillHandles( sal_Int32 * pHandles, const Sequence< OUString > & rPropNames )
1201 sal_Int32 nHitCount = 0;
1202 const OUString * pReqProps = rPropNames.getConstArray();
1203 sal_Int32 nReqLen = rPropNames.getLength();
1204 const Property * pCur = aInfos.getConstArray();
1205 const Property * pEnd = pCur + aInfos.getLength();
1207 for( sal_Int32 i = 0; i < nReqLen; i++ )
1209 // Calculate logarithm
1210 sal_Int32 n = (sal_Int32)(pEnd - pCur);
1211 sal_Int32 nLog = 0;
1212 while( n )
1214 nLog += 1;
1215 n = n >> 1;
1218 // Number of properties to search for * Log2 of the number of remaining
1219 // properties to search in.
1220 if( (nReqLen - i) * nLog >= pEnd - pCur )
1222 // linear search is better
1223 while( pCur < pEnd && pReqProps[i] > pCur->Name )
1225 pCur++;
1227 if( pCur < pEnd && pReqProps[i] == pCur->Name )
1229 pHandles[i] = pCur->Handle;
1230 nHitCount++;
1232 else
1233 pHandles[i] = -1;
1235 else
1237 // binary search is better
1238 sal_Int32 nCompVal = 1;
1239 const Property * pOldEnd = pEnd--;
1240 const Property * pMid = pCur;
1242 while( nCompVal != 0 && pCur <= pEnd )
1244 pMid = (pEnd - pCur) / 2 + pCur;
1246 nCompVal = pReqProps[i].compareTo( pMid->Name );
1248 if( nCompVal > 0 )
1249 pCur = pMid + 1;
1250 else
1251 pEnd = pMid - 1;
1254 if( nCompVal == 0 )
1256 pHandles[i] = pMid->Handle;
1257 nHitCount++;
1258 pCur = pMid +1;
1260 else if( nCompVal > 0 )
1262 pHandles[i] = -1;
1263 pCur = pMid +1;
1265 else
1267 pHandles[i] = -1;
1268 pCur = pMid;
1270 pEnd = pOldEnd;
1273 return nHitCount;
1276 } // end namespace cppu
1280 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */