Version 3.6.0.2, tag libreoffice-3.6.0.2
[LibreOffice.git] / cppuhelper / source / propshlp.cxx
blobce8ff96253ac285f5c5c1c3b81651e716f1ad206
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "osl/diagnose.h"
31 #include "cppuhelper/implbase1.hxx"
32 #include "cppuhelper/weak.hxx"
33 #include "cppuhelper/propshlp.hxx"
34 #include "cppuhelper/exc_hlp.hxx"
35 #include "com/sun/star/beans/PropertyAttribute.hpp"
36 #include "com/sun/star/lang/DisposedException.hpp"
39 using namespace osl;
40 using namespace com::sun::star::uno;
41 using namespace com::sun::star::beans;
42 using namespace com::sun::star::lang;
43 using namespace cppu;
45 using ::rtl::OUString;
46 using ::rtl::OUStringToOString;
48 namespace cppu {
50 IPropertyArrayHelper::~IPropertyArrayHelper()
54 inline const ::com::sun::star::uno::Type & getPropertyTypeIdentifier( ) SAL_THROW(())
56 return ::getCppuType( (Reference< XPropertyChangeListener > *)0 );
58 inline const ::com::sun::star::uno::Type & getPropertiesTypeIdentifier() SAL_THROW(())
60 return ::getCppuType( (Reference< XPropertiesChangeListener > *)0 );
62 inline const ::com::sun::star::uno::Type & getVetoableTypeIdentifier() SAL_THROW(())
64 return ::getCppuType( (Reference< XVetoableChangeListener > *)0 );
67 extern "C" {
69 static int compare_OUString_Property_Impl( const void *arg1, const void *arg2 )
70 SAL_THROW_EXTERN_C()
72 return ((OUString *)arg1)->compareTo( ((Property *)arg2)->Name );
77 /**
78 * The class which implements the PropertySetInfo interface.
81 class OPropertySetHelperInfo_Impl
82 : public WeakImplHelper1< ::com::sun::star::beans::XPropertySetInfo >
84 Sequence < Property > aInfos;
86 public:
87 OPropertySetHelperInfo_Impl( IPropertyArrayHelper & rHelper_ ) SAL_THROW(());
89 // XPropertySetInfo-methods
90 virtual Sequence< Property > SAL_CALL getProperties(void) throw(::com::sun::star::uno::RuntimeException);
91 virtual Property SAL_CALL getPropertyByName(const OUString& PropertyName) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
92 virtual sal_Bool SAL_CALL hasPropertyByName(const OUString& PropertyName) throw(::com::sun::star::uno::RuntimeException);
96 /**
97 * Create an object that implements XPropertySetInfo IPropertyArrayHelper.
99 OPropertySetHelperInfo_Impl::OPropertySetHelperInfo_Impl(
100 IPropertyArrayHelper & rHelper_ )
101 SAL_THROW(())
102 :aInfos( rHelper_.getProperties() )
107 * Return the sequence of properties, which are provided throug the constructor.
109 Sequence< Property > OPropertySetHelperInfo_Impl::getProperties(void) throw(::com::sun::star::uno::RuntimeException)
112 return aInfos;
116 * Return the sequence of properties, which are provided throug the constructor.
118 Property OPropertySetHelperInfo_Impl::getPropertyByName( const OUString & PropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException)
120 Property * pR;
121 pR = (Property *)bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(),
122 sizeof( Property ),
123 compare_OUString_Property_Impl );
124 if( !pR ) {
125 throw UnknownPropertyException();
128 return *pR;
132 * Return the sequence of properties, which are provided throug the constructor.
134 sal_Bool OPropertySetHelperInfo_Impl::hasPropertyByName( const OUString & PropertyName ) throw(::com::sun::star::uno::RuntimeException)
136 Property * pR;
137 pR = (Property *)bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(),
138 sizeof( Property ),
139 compare_OUString_Property_Impl );
140 return pR != NULL;
143 // ----------------------------------------------------
144 // class PropertySetHelper_Impl
145 // ----------------------------------------------------
146 class OPropertySetHelper::Impl {
148 public:
149 Impl( bool i_bIgnoreRuntimeExceptionsWhileFiring,
150 IEventNotificationHook *i_pFireEvents
152 :m_bIgnoreRuntimeExceptionsWhileFiring( i_bIgnoreRuntimeExceptionsWhileFiring )
153 ,m_bFireEvents(true)
154 ,m_pFireEvents( i_pFireEvents )
158 bool m_bIgnoreRuntimeExceptionsWhileFiring;
159 bool m_bFireEvents;
160 class IEventNotificationHook * const m_pFireEvents;
162 ::std::vector< sal_Int32 > m_handles;
163 ::std::vector< Any > m_newValues;
164 ::std::vector< Any > m_oldValues;
168 // ----------------------------------------------------
169 // class PropertySetHelper
170 // ----------------------------------------------------
171 OPropertySetHelper::OPropertySetHelper(
172 OBroadcastHelper & rBHelper_ ) SAL_THROW(())
173 : rBHelper( rBHelper_ ),
174 aBoundLC( rBHelper_.rMutex ),
175 aVetoableLC( rBHelper_.rMutex ),
176 m_pReserved( new Impl(false, 0) )
180 OPropertySetHelper::OPropertySetHelper(
181 OBroadcastHelper & rBHelper_, bool bIgnoreRuntimeExceptionsWhileFiring )
182 : rBHelper( rBHelper_ ),
183 aBoundLC( rBHelper_.rMutex ),
184 aVetoableLC( rBHelper_.rMutex ),
185 m_pReserved( new Impl( bIgnoreRuntimeExceptionsWhileFiring, 0 ) )
189 OPropertySetHelper::OPropertySetHelper(
190 OBroadcastHelper & rBHelper_, IEventNotificationHook * i_pFireEvents,
191 bool bIgnoreRuntimeExceptionsWhileFiring)
192 : rBHelper( rBHelper_ ),
193 aBoundLC( rBHelper_.rMutex ),
194 aVetoableLC( rBHelper_.rMutex ),
195 m_pReserved(
196 new Impl( bIgnoreRuntimeExceptionsWhileFiring, i_pFireEvents) )
200 OPropertySetHelper2::OPropertySetHelper2(
201 OBroadcastHelper & irBHelper,
202 IEventNotificationHook *i_pFireEvents,
203 bool bIgnoreRuntimeExceptionsWhileFiring)
204 :OPropertySetHelper( irBHelper, i_pFireEvents, bIgnoreRuntimeExceptionsWhileFiring )
209 * You must call disposing before.
211 OPropertySetHelper::~OPropertySetHelper() SAL_THROW(())
214 OPropertySetHelper2::~OPropertySetHelper2() SAL_THROW(())
218 // XInterface
219 Any OPropertySetHelper::queryInterface( const ::com::sun::star::uno::Type & rType )
220 throw (RuntimeException)
222 return ::cppu::queryInterface(
223 rType,
224 static_cast< XPropertySet * >( this ),
225 static_cast< XMultiPropertySet * >( this ),
226 static_cast< XFastPropertySet * >( this ) );
229 Any OPropertySetHelper2::queryInterface( const ::com::sun::star::uno::Type & rType )
230 throw (RuntimeException)
232 Any cnd(cppu::queryInterface(rType, static_cast< XPropertySetOption * >(this)));
233 if ( cnd.hasValue() )
234 return cnd;
235 else
236 return OPropertySetHelper::queryInterface(rType);
240 * called from the derivee's XTypeProvider::getTypes implementation
242 ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > OPropertySetHelper::getTypes()
243 throw (RuntimeException)
245 Sequence< ::com::sun::star::uno::Type > aTypes( 4 );
246 aTypes[ 0 ] = XPropertySet::static_type();
247 aTypes[ 1 ] = XPropertySetOption::static_type();
248 aTypes[ 2 ] = XMultiPropertySet::static_type();
249 aTypes[ 3 ] = XFastPropertySet::static_type();
250 return aTypes;
253 // ComponentHelper
254 void OPropertySetHelper::disposing() SAL_THROW(())
256 // Create an event with this as sender
257 Reference < XPropertySet > rSource( (static_cast< XPropertySet * >(this)) , UNO_QUERY );
258 EventObject aEvt;
259 aEvt.Source = rSource;
261 // inform all listeners to release this object
262 // The listener containers are automatically cleared
263 aBoundLC.disposeAndClear( aEvt );
264 aVetoableLC.disposeAndClear( aEvt );
267 Reference < XPropertySetInfo > OPropertySetHelper::createPropertySetInfo(
268 IPropertyArrayHelper & rProperties ) SAL_THROW(())
270 return static_cast< XPropertySetInfo * >( new OPropertySetHelperInfo_Impl( rProperties ) );
273 // XPropertySet
274 void OPropertySetHelper::setPropertyValue(
275 const OUString& rPropertyName, const Any& rValue )
276 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)
278 // get the map table
279 IPropertyArrayHelper & rPH = getInfoHelper();
280 // map the name to the handle
281 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
282 // call the method of the XFastPropertySet interface
283 setFastPropertyValue( nHandle, rValue );
286 // XPropertySet
287 Any OPropertySetHelper::getPropertyValue(
288 const OUString& rPropertyName )
289 throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
291 // get the map table
292 IPropertyArrayHelper & rPH = getInfoHelper();
293 // map the name to the handle
294 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
295 // call the method of the XFastPropertySet interface
296 return getFastPropertyValue( nHandle );
299 // XPropertySet
300 void OPropertySetHelper::addPropertyChangeListener(
301 const OUString& rPropertyName,
302 const Reference < XPropertyChangeListener > & rxListener )
303 throw(::com::sun::star::beans::UnknownPropertyException,
304 ::com::sun::star::lang::WrappedTargetException,
305 ::com::sun::star::uno::RuntimeException)
307 MutexGuard aGuard( rBHelper.rMutex );
308 OSL_ENSURE( !rBHelper.bInDispose, "do not addPropertyChangeListener in the dispose call" );
309 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
310 if( !rBHelper.bInDispose && !rBHelper.bDisposed )
312 // only add listeners if you are not disposed
313 // a listener with no name means all properties
314 if( !rPropertyName.isEmpty() )
316 // get the map table
317 IPropertyArrayHelper & rPH = getInfoHelper();
318 // map the name to the handle
319 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
320 if( nHandle == -1 ) {
321 // property not known throw exception
322 throw UnknownPropertyException() ;
325 sal_Int16 nAttributes;
326 rPH.fillPropertyMembersByHandle( NULL, &nAttributes, nHandle );
327 if( !(nAttributes & ::com::sun::star::beans::PropertyAttribute::BOUND) )
329 OSL_FAIL( "add listener to an unbound property" );
330 // silent ignore this
331 return;
333 // add the change listener to the helper container
335 aBoundLC.addInterface( (sal_Int32)nHandle, rxListener );
337 else
338 // add the change listener to the helper container
339 rBHelper.aLC.addInterface(
340 getPropertyTypeIdentifier( ),
341 rxListener
347 // XPropertySet
348 void OPropertySetHelper::removePropertyChangeListener(
349 const OUString& rPropertyName,
350 const Reference < XPropertyChangeListener >& rxListener )
351 throw(::com::sun::star::beans::UnknownPropertyException,
352 ::com::sun::star::lang::WrappedTargetException,
353 ::com::sun::star::uno::RuntimeException)
355 MutexGuard aGuard( rBHelper.rMutex );
356 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
357 // all listeners are automaticly released in a dispose call
358 if( !rBHelper.bInDispose && !rBHelper.bDisposed )
360 if( !rPropertyName.isEmpty() )
362 // get the map table
363 IPropertyArrayHelper & rPH = getInfoHelper();
364 // map the name to the handle
365 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
366 if( nHandle == -1 )
367 // property not known throw exception
368 throw UnknownPropertyException();
369 aBoundLC.removeInterface( (sal_Int32)nHandle, rxListener );
371 else {
372 // remove the change listener to the helper container
373 rBHelper.aLC.removeInterface(
374 getPropertyTypeIdentifier( ),
375 rxListener
381 // XPropertySet
382 void OPropertySetHelper::addVetoableChangeListener(
383 const OUString& rPropertyName,
384 const Reference< XVetoableChangeListener > & rxListener )
385 throw(::com::sun::star::beans::UnknownPropertyException,
386 ::com::sun::star::lang::WrappedTargetException,
387 ::com::sun::star::uno::RuntimeException)
389 MutexGuard aGuard( rBHelper.rMutex );
390 OSL_ENSURE( !rBHelper.bInDispose, "do not addVetoableChangeListener in the dispose call" );
391 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
392 if( !rBHelper.bInDispose && !rBHelper.bDisposed )
394 // only add listeners if you are not disposed
395 // a listener with no name means all properties
396 if( !rPropertyName.isEmpty() )
398 // get the map table
399 IPropertyArrayHelper & rPH = getInfoHelper();
400 // map the name to the handle
401 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
402 if( nHandle == -1 ) {
403 // property not known throw exception
404 throw UnknownPropertyException();
407 sal_Int16 nAttributes;
408 rPH.fillPropertyMembersByHandle( NULL, &nAttributes, nHandle );
409 if( !(nAttributes & PropertyAttribute::CONSTRAINED) )
411 OSL_FAIL( "addVetoableChangeListener, and property is not constrained" );
412 // silent ignore this
413 return;
415 // add the vetoable listener to the helper container
416 aVetoableLC.addInterface( (sal_Int32)nHandle, rxListener );
418 else
419 // add the vetoable listener to the helper container
420 rBHelper.aLC.addInterface(
421 getVetoableTypeIdentifier( ),
422 rxListener
427 // XPropertySet
428 void OPropertySetHelper::removeVetoableChangeListener(
429 const OUString& rPropertyName,
430 const Reference < XVetoableChangeListener > & rxListener )
431 throw(::com::sun::star::beans::UnknownPropertyException,
432 ::com::sun::star::lang::WrappedTargetException,
433 ::com::sun::star::uno::RuntimeException)
435 MutexGuard aGuard( rBHelper.rMutex );
436 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
437 // all listeners are automaticly released in a dispose call
438 if( !rBHelper.bInDispose && !rBHelper.bDisposed )
440 if( !rPropertyName.isEmpty() )
442 // get the map table
443 IPropertyArrayHelper & rPH = getInfoHelper();
444 // map the name to the handle
445 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
446 if( nHandle == -1 ) {
447 // property not known throw exception
448 throw UnknownPropertyException();
450 // remove the vetoable listener to the helper container
451 aVetoableLC.removeInterface( (sal_Int32)nHandle, rxListener );
453 else
454 // add the vetoable listener to the helper container
455 rBHelper.aLC.removeInterface(
456 getVetoableTypeIdentifier( ),
457 rxListener
462 void OPropertySetHelper::setDependentFastPropertyValue( sal_Int32 i_handle, const ::com::sun::star::uno::Any& i_value )
464 //OSL_PRECOND( rBHelper.rMutex.isAcquired(), "OPropertySetHelper::setDependentFastPropertyValue: to be called with a locked mutex only!" );
465 // there is no such thing as Mutex.isAcquired, sadly ...
467 sal_Int16 nAttributes(0);
468 IPropertyArrayHelper& rInfo = getInfoHelper();
469 if ( !rInfo.fillPropertyMembersByHandle( NULL, &nAttributes, i_handle ) )
470 // unknown property
471 throw UnknownPropertyException();
473 // no need to check for READONLY-ness of the property. The method is intended to be called internally, which
474 // implies it might be invoked for properties which are read-only to the instance's clients, but well allowed
475 // to change their value.
477 Any aConverted, aOld;
478 sal_Bool bChanged = convertFastPropertyValue( aConverted, aOld, i_handle, i_value );
479 if ( !bChanged )
480 return;
482 // don't fire vetoable events. This method is called with our mutex locked, so calling into listeners would not be
483 // a good idea. The caler is responsible for not invoking this for constrained properties.
484 OSL_ENSURE( ( nAttributes & PropertyAttribute::CONSTRAINED ) == 0,
485 "OPropertySetHelper::setDependentFastPropertyValue: not to be used for constrained properties!" );
486 (void)nAttributes;
488 // actually set the new value
491 setFastPropertyValue_NoBroadcast( i_handle, aConverted );
493 catch (const UnknownPropertyException& ) { throw; /* allowed to leave */ }
494 catch (const PropertyVetoException& ) { throw; /* allowed to leave */ }
495 catch (const IllegalArgumentException& ) { throw; /* allowed to leave */ }
496 catch (const WrappedTargetException& ) { throw; /* allowed to leave */ }
497 catch (const RuntimeException& ) { throw; /* allowed to leave */ }
498 catch (const Exception& )
500 // not allowed to leave this meathod
501 WrappedTargetException aWrapped;
502 aWrapped.TargetException <<= ::cppu::getCaughtException();
503 aWrapped.Context = static_cast< XPropertySet* >( this );
504 throw aWrapped;
507 // remember the handle/values, for the events to be fired later
508 m_pReserved->m_handles.push_back( i_handle );
509 m_pReserved->m_newValues.push_back( aConverted ); // TODO: setFastPropertyValue notifies the unconverted value here ...?
510 m_pReserved->m_oldValues.push_back( aOld );
513 // XFastPropertySet
514 void OPropertySetHelper::setFastPropertyValue( sal_Int32 nHandle, const Any& rValue )
515 throw(::com::sun::star::beans::UnknownPropertyException,
516 ::com::sun::star::beans::PropertyVetoException,
517 ::com::sun::star::lang::IllegalArgumentException,
518 ::com::sun::star::lang::WrappedTargetException,
519 ::com::sun::star::uno::RuntimeException)
521 OSL_ENSURE( !rBHelper.bInDispose, "do not setFastPropertyValue in the dispose call" );
522 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
524 IPropertyArrayHelper & rInfo = getInfoHelper();
525 sal_Int16 nAttributes;
526 if( !rInfo.fillPropertyMembersByHandle( NULL, &nAttributes, nHandle ) ) {
527 // unknown property
528 throw UnknownPropertyException();
530 if( nAttributes & PropertyAttribute::READONLY )
531 throw PropertyVetoException();
533 Any aConvertedVal;
534 Any aOldVal;
536 // Will the property change?
537 sal_Bool bChanged;
539 MutexGuard aGuard( rBHelper.rMutex );
540 bChanged = convertFastPropertyValue( aConvertedVal, aOldVal, nHandle, rValue );
541 // release guard to fire events
543 if( bChanged )
545 // Is it a constrained property?
546 if( nAttributes & PropertyAttribute::CONSTRAINED )
548 // In aValue is the converted rValue
549 // fire a constarined event
550 // second parameter NULL means constrained
551 fire( &nHandle, &rValue, &aOldVal, 1, sal_True );
555 MutexGuard aGuard( rBHelper.rMutex );
558 // set the property to the new value
559 setFastPropertyValue_NoBroadcast( nHandle, aConvertedVal );
561 catch (const ::com::sun::star::beans::UnknownPropertyException& ) { throw; /* allowed to leave */ }
562 catch (const ::com::sun::star::beans::PropertyVetoException& ) { throw; /* allowed to leave */ }
563 catch (const ::com::sun::star::lang::IllegalArgumentException& ) { throw; /* allowed to leave */ }
564 catch (const ::com::sun::star::lang::WrappedTargetException& ) { throw; /* allowed to leave */ }
565 catch (const ::com::sun::star::uno::RuntimeException& ) { throw; /* allowed to leave */ }
566 catch (const ::com::sun::star::uno::Exception& e )
568 // not allowed to leave this meathod
569 ::com::sun::star::lang::WrappedTargetException aWrap;
570 aWrap.Context = static_cast< ::com::sun::star::beans::XPropertySet* >( this );
571 aWrap.TargetException <<= e;
573 throw ::com::sun::star::lang::WrappedTargetException( aWrap );
576 // release guard to fire events
578 // file a change event, if the value changed
579 impl_fireAll( &nHandle, &rValue, &aOldVal, 1 );
583 // XFastPropertySet
584 Any OPropertySetHelper::getFastPropertyValue( sal_Int32 nHandle )
585 throw(::com::sun::star::beans::UnknownPropertyException,
586 ::com::sun::star::lang::WrappedTargetException,
587 ::com::sun::star::uno::RuntimeException)
590 IPropertyArrayHelper & rInfo = getInfoHelper();
591 if( !rInfo.fillPropertyMembersByHandle( NULL, NULL, nHandle ) )
592 // unknown property
593 throw UnknownPropertyException();
595 Any aRet;
596 MutexGuard aGuard( rBHelper.rMutex );
597 getFastPropertyValue( aRet, nHandle );
598 return aRet;
601 //--------------------------------------------------------------------------
602 void OPropertySetHelper::impl_fireAll( sal_Int32* i_handles, const Any* i_newValues, const Any* i_oldValues, sal_Int32 i_count )
604 ClearableMutexGuard aGuard( rBHelper.rMutex );
605 if ( m_pReserved->m_handles.empty() )
607 aGuard.clear();
608 fire( i_handles, i_newValues, i_oldValues, i_count, sal_False );
609 return;
612 const size_t additionalEvents = m_pReserved->m_handles.size();
613 OSL_ENSURE( additionalEvents == m_pReserved->m_newValues.size()
614 && additionalEvents == m_pReserved->m_oldValues.size(),
615 "OPropertySetHelper::impl_fireAll: inconsistency!" );
617 ::std::vector< sal_Int32 > allHandles( additionalEvents + i_count );
618 ::std::copy( m_pReserved->m_handles.begin(), m_pReserved->m_handles.end(), allHandles.begin() );
619 ::std::copy( i_handles, i_handles + i_count, allHandles.begin() + additionalEvents );
621 ::std::vector< Any > allNewValues( additionalEvents + i_count );
622 ::std::copy( m_pReserved->m_newValues.begin(), m_pReserved->m_newValues.end(), allNewValues.begin() );
623 ::std::copy( i_newValues, i_newValues + i_count, allNewValues.begin() + additionalEvents );
625 ::std::vector< Any > allOldValues( additionalEvents + i_count );
626 ::std::copy( m_pReserved->m_oldValues.begin(), m_pReserved->m_oldValues.end(), allOldValues.begin() );
627 ::std::copy( i_oldValues, i_oldValues + i_count, allOldValues.begin() + additionalEvents );
629 m_pReserved->m_handles.clear();
630 m_pReserved->m_newValues.clear();
631 m_pReserved->m_oldValues.clear();
633 aGuard.clear();
634 fire( &allHandles[0], &allNewValues[0], &allOldValues[0], additionalEvents + i_count, sal_False );
637 //--------------------------------------------------------------------------
638 void OPropertySetHelper::fire
640 sal_Int32 * pnHandles,
641 const Any * pNewValues,
642 const Any * pOldValues,
643 sal_Int32 nHandles, // These is the Count of the array
644 sal_Bool bVetoable
647 OSL_ENSURE( m_pReserved.get(), "No OPropertySetHelper::Impl" );
649 if (! m_pReserved->m_bFireEvents)
650 return;
652 if (m_pReserved->m_pFireEvents) {
653 m_pReserved->m_pFireEvents->fireEvents(
654 pnHandles, nHandles, bVetoable,
655 m_pReserved->m_bIgnoreRuntimeExceptionsWhileFiring);
658 // Only fire, if one or more properties changed
659 if( nHandles )
661 // create the event sequence of all changed properties
662 Sequence< PropertyChangeEvent > aEvts( nHandles );
663 PropertyChangeEvent * pEvts = aEvts.getArray();
664 Reference < XInterface > xSource( (XPropertySet *)this, UNO_QUERY );
665 sal_Int32 i;
666 sal_Int32 nChangesLen = 0;
667 // Loop over all changed properties to fill the event struct
668 for( i = 0; i < nHandles; i++ )
670 // Vetoable fire and constrained attribute set or
671 // Change fire and Changed and bound attribute set
672 IPropertyArrayHelper & rInfo = getInfoHelper();
673 sal_Int16 nAttributes;
674 OUString aPropName;
675 rInfo.fillPropertyMembersByHandle( &aPropName, &nAttributes, pnHandles[i] );
678 (bVetoable && (nAttributes & PropertyAttribute::CONSTRAINED)) ||
679 (!bVetoable && (nAttributes & PropertyAttribute::BOUND))
682 pEvts[nChangesLen].Source = xSource;
683 pEvts[nChangesLen].PropertyName = aPropName;
684 pEvts[nChangesLen].PropertyHandle = pnHandles[i];
685 pEvts[nChangesLen].OldValue = pOldValues[i];
686 pEvts[nChangesLen].NewValue = pNewValues[i];
687 nChangesLen++;
691 bool bIgnoreRuntimeExceptionsWhileFiring =
692 m_pReserved->m_bIgnoreRuntimeExceptionsWhileFiring;
694 // fire the events for all changed properties
695 for( i = 0; i < nChangesLen; i++ )
697 // get the listener container for the property name
698 OInterfaceContainerHelper * pLC;
699 if( bVetoable ) // fire change Events?
700 pLC = aVetoableLC.getContainer( pEvts[i].PropertyHandle );
701 else
702 pLC = aBoundLC.getContainer( pEvts[i].PropertyHandle );
703 if( pLC )
705 // Iterate over all listeners and send events
706 OInterfaceIteratorHelper aIt( *pLC);
707 while( aIt.hasMoreElements() )
709 XInterface * pL = aIt.next();
714 if( bVetoable ) // fire change Events?
716 ((XVetoableChangeListener *)pL)->vetoableChange(
717 pEvts[i] );
719 else
721 ((XPropertyChangeListener *)pL)->propertyChange(
722 pEvts[i] );
725 catch (DisposedException & exc)
727 OSL_ENSURE( exc.Context.is(),
728 "DisposedException without Context!" );
729 if (exc.Context == pL)
730 aIt.remove();
731 else
732 throw;
735 catch (RuntimeException & exc)
737 OSL_TRACE(
738 OUStringToOString(
739 OUString( RTL_CONSTASCII_USTRINGPARAM(
740 "caught RuntimeException while "
741 "firing listeners: ") ) +
742 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
743 if (! bIgnoreRuntimeExceptionsWhileFiring)
744 throw;
748 // broadcast to all listeners with "" property name
749 if( bVetoable ){
750 // fire change Events?
751 pLC = rBHelper.aLC.getContainer(
752 getVetoableTypeIdentifier()
755 else {
756 pLC = rBHelper.aLC.getContainer(
757 getPropertyTypeIdentifier( )
760 if( pLC )
762 // Iterate over all listeners and send events.
763 OInterfaceIteratorHelper aIt( *pLC);
764 while( aIt.hasMoreElements() )
766 XInterface * pL = aIt.next();
771 if( bVetoable ) // fire change Events?
773 ((XVetoableChangeListener *)pL)->vetoableChange(
774 pEvts[i] );
776 else
778 ((XPropertyChangeListener *)pL)->propertyChange(
779 pEvts[i] );
782 catch (DisposedException & exc)
784 OSL_ENSURE( exc.Context.is(),
785 "DisposedException without Context!" );
786 if (exc.Context == pL)
787 aIt.remove();
788 else
789 throw;
792 catch (RuntimeException & exc)
794 OSL_TRACE(
795 OUStringToOString(
796 OUString( RTL_CONSTASCII_USTRINGPARAM(
797 "caught RuntimeException while "
798 "firing listeners: ") ) +
799 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
800 if (! bIgnoreRuntimeExceptionsWhileFiring)
801 throw;
807 // reduce array to changed properties
808 aEvts.realloc( nChangesLen );
810 if( !bVetoable )
812 OInterfaceContainerHelper * pCont = 0;
813 pCont = rBHelper.aLC.getContainer(
814 getPropertiesTypeIdentifier( )
816 if( pCont )
818 // Here is a Bug, unbound properties are also fired
819 OInterfaceIteratorHelper aIt( *pCont );
820 while( aIt.hasMoreElements() )
822 XPropertiesChangeListener * pL =
823 (XPropertiesChangeListener *)aIt.next();
828 // fire the hole event sequence to the
829 // XPropertiesChangeListener's
830 pL->propertiesChange( aEvts );
832 catch (DisposedException & exc)
834 OSL_ENSURE( exc.Context.is(),
835 "DisposedException without Context!" );
836 if (exc.Context == pL)
837 aIt.remove();
838 else
839 throw;
842 catch (RuntimeException & exc)
844 OSL_TRACE(
845 OUStringToOString(
846 OUString( RTL_CONSTASCII_USTRINGPARAM(
847 "caught RuntimeException while "
848 "firing listeners: ") ) +
849 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
850 if (! bIgnoreRuntimeExceptionsWhileFiring)
851 throw;
859 // OPropertySetHelper
860 void OPropertySetHelper::setFastPropertyValues(
861 sal_Int32 nSeqLen,
862 sal_Int32 * pHandles,
863 const Any * pValues,
864 sal_Int32 nHitCount )
865 SAL_THROW( (::com::sun::star::uno::Exception) )
867 OSL_ENSURE( !rBHelper.bInDispose, "do not getFastPropertyValue in the dispose call" );
868 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
870 Any * pConvertedValues = NULL;
871 Any * pOldValues = NULL;
875 // get the map table
876 IPropertyArrayHelper & rPH = getInfoHelper();
878 pConvertedValues = new Any[ nHitCount ];
879 pOldValues = new Any[ nHitCount ];
880 sal_Int32 n = 0;
881 sal_Int32 i;
884 // must lock the mutex outside the loop. So all values are consistent.
885 MutexGuard aGuard( rBHelper.rMutex );
886 for( i = 0; i < nSeqLen; i++ )
888 if( pHandles[i] != -1 )
890 sal_Int16 nAttributes;
891 rPH.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] );
892 if( nAttributes & PropertyAttribute::READONLY ) {
893 throw PropertyVetoException();
895 // Will the property change?
896 if( convertFastPropertyValue( pConvertedValues[ n ], pOldValues[n],
897 pHandles[i], pValues[i] ) )
899 // only increment if the property really change
900 pHandles[n] = pHandles[i];
901 n++;
905 // release guard to fire events
908 // fire vetoable events
909 fire( pHandles, pConvertedValues, pOldValues, n, sal_True );
912 // must lock the mutex outside the loop.
913 MutexGuard aGuard( rBHelper.rMutex );
914 // Loop over all changed properties
915 for( i = 0; i < n; i++ )
917 // Will the property change?
918 setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
920 // release guard to fire events
923 // fire change events
924 impl_fireAll( pHandles, pConvertedValues, pOldValues, n );
926 catch( ... )
928 delete [] pOldValues;
929 delete [] pConvertedValues;
930 throw;
932 delete [] pOldValues;
933 delete [] pConvertedValues;
936 // XMultiPropertySet
938 * The sequence may be conatain not known properties. The implementation
939 * must ignore these properties.
941 void OPropertySetHelper::setPropertyValues(
942 const Sequence<OUString>& rPropertyNames,
943 const Sequence<Any>& rValues )
944 throw(::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
946 sal_Int32 * pHandles = NULL;
949 sal_Int32 nSeqLen = rPropertyNames.getLength();
950 pHandles = new sal_Int32[ nSeqLen ];
951 // get the map table
952 IPropertyArrayHelper & rPH = getInfoHelper();
953 // fill the handle array
954 sal_Int32 nHitCount = rPH.fillHandles( pHandles, rPropertyNames );
955 if( nHitCount != 0 )
956 setFastPropertyValues( nSeqLen, pHandles, rValues.getConstArray(), nHitCount );
958 catch( ... )
960 delete [] pHandles;
961 throw;
963 delete [] pHandles;
966 // XMultiPropertySet
967 Sequence<Any> OPropertySetHelper::getPropertyValues( const Sequence<OUString>& rPropertyNames )
968 throw(::com::sun::star::uno::RuntimeException)
970 sal_Int32 nSeqLen = rPropertyNames.getLength();
971 sal_Int32 * pHandles = new sal_Int32[ nSeqLen ];
972 Sequence< Any > aValues( nSeqLen );
974 // get the map table
975 IPropertyArrayHelper & rPH = getInfoHelper();
976 // fill the handle array
977 rPH.fillHandles( pHandles, rPropertyNames );
979 Any * pValues = aValues.getArray();
981 MutexGuard aGuard( rBHelper.rMutex );
982 // fill the sequence with the values
983 for( sal_Int32 i = 0; i < nSeqLen; i++ )
984 getFastPropertyValue( pValues[i], pHandles[i] );
986 delete [] pHandles;
987 return aValues;
990 // XMultiPropertySet
991 void OPropertySetHelper::addPropertiesChangeListener(
992 const Sequence<OUString> & ,
993 const Reference < XPropertiesChangeListener > & rListener )
994 throw(::com::sun::star::uno::RuntimeException)
996 rBHelper.addListener( getCppuType(&rListener) , rListener );
999 // XMultiPropertySet
1000 void OPropertySetHelper::removePropertiesChangeListener(
1001 const Reference < XPropertiesChangeListener > & rListener )
1002 throw(::com::sun::star::uno::RuntimeException)
1004 rBHelper.removeListener( getCppuType(&rListener) , rListener );
1007 // XMultiPropertySet
1008 void OPropertySetHelper::firePropertiesChangeEvent(
1009 const Sequence<OUString>& rPropertyNames,
1010 const Reference < XPropertiesChangeListener >& rListener )
1011 throw(::com::sun::star::uno::RuntimeException)
1013 sal_Int32 nLen = rPropertyNames.getLength();
1014 sal_Int32 * pHandles = new sal_Int32[nLen];
1015 IPropertyArrayHelper & rPH = getInfoHelper();
1016 rPH.fillHandles( pHandles, rPropertyNames );
1017 const OUString* pNames = rPropertyNames.getConstArray();
1019 // get the count of matching properties
1020 sal_Int32 nFireLen = 0;
1021 sal_Int32 i;
1022 for( i = 0; i < nLen; i++ )
1023 if( pHandles[i] != -1 )
1024 nFireLen++;
1026 Sequence<PropertyChangeEvent> aChanges( nFireLen );
1027 PropertyChangeEvent* pChanges = aChanges.getArray();
1030 // must lock the mutex outside the loop. So all values are consistent.
1031 MutexGuard aGuard( rBHelper.rMutex );
1032 Reference < XInterface > xSource( (XPropertySet *)this, UNO_QUERY );
1033 sal_Int32 nFirePos = 0;
1034 for( i = 0; i < nLen; i++ )
1036 if( pHandles[i] != -1 )
1038 pChanges[nFirePos].Source = xSource;
1039 pChanges[nFirePos].PropertyName = pNames[i];
1040 pChanges[nFirePos].PropertyHandle = pHandles[i];
1041 getFastPropertyValue( pChanges[nFirePos].OldValue, pHandles[i] );
1042 pChanges[nFirePos].NewValue = pChanges[nFirePos].OldValue;
1043 nFirePos++;
1046 // release guard to fire events
1048 if( nFireLen )
1049 rListener->propertiesChange( aChanges );
1051 delete [] pHandles;
1054 void OPropertySetHelper2::enableChangeListenerNotification( sal_Bool bEnable )
1055 throw(::com::sun::star::uno::RuntimeException)
1057 m_pReserved->m_bFireEvents = bEnable;
1060 //========================================================================
1061 //== OPropertyArrayHelper ================================================
1062 //========================================================================
1064 extern "C" {
1066 static int compare_Property_Impl( const void *arg1, const void *arg2 )
1067 SAL_THROW_EXTERN_C()
1069 return ((Property *)arg1)->Name.compareTo( ((Property *)arg2)->Name );
1074 void OPropertyArrayHelper::init( sal_Bool bSorted ) SAL_THROW(())
1076 sal_Int32 i, nElements = aInfos.getLength();
1077 const Property* pProperties = aInfos.getConstArray();
1079 for( i = 1; i < nElements; i++ )
1081 if( pProperties[i-1].Name >= pProperties[i].Name )
1083 if (bSorted) {
1084 OSL_FAIL( "Property array is not sorted" );
1086 // not sorted
1087 qsort( aInfos.getArray(), nElements, sizeof( Property ),
1088 compare_Property_Impl );
1089 break;
1092 // may be that the array is resorted
1093 pProperties = aInfos.getConstArray();
1094 for( i = 0; i < nElements; i++ )
1095 if( pProperties[i].Handle != i )
1096 return;
1097 // The handle is the index
1098 bRightOrdered = sal_True;
1101 OPropertyArrayHelper::OPropertyArrayHelper(
1102 Property * pProps,
1103 sal_Int32 nEle,
1104 sal_Bool bSorted )
1105 SAL_THROW(())
1106 : aInfos(pProps, nEle)
1107 , bRightOrdered( sal_False )
1109 init( bSorted );
1112 OPropertyArrayHelper::OPropertyArrayHelper(
1113 const Sequence< Property > & aProps,
1114 sal_Bool bSorted )
1115 SAL_THROW(())
1116 : aInfos(aProps)
1117 , bRightOrdered( sal_False )
1119 init( bSorted );
1122 //========================================================================
1123 sal_Int32 OPropertyArrayHelper::getCount() const
1125 return aInfos.getLength();
1128 //========================================================================
1129 sal_Bool OPropertyArrayHelper::fillPropertyMembersByHandle
1131 OUString * pPropName,
1132 sal_Int16 * pAttributes,
1133 sal_Int32 nHandle
1136 const Property* pProperties = aInfos.getConstArray();
1137 sal_Int32 nElements = aInfos.getLength();
1139 if( bRightOrdered )
1141 if( nHandle < 0 || nHandle >= nElements )
1142 return sal_False;
1143 if( pPropName )
1144 *pPropName = pProperties[ nHandle ].Name;
1145 if( pAttributes )
1146 *pAttributes = pProperties[ nHandle ].Attributes;
1147 return sal_True;
1149 else
1151 // normally the array is sorted
1152 for( sal_Int32 i = 0; i < nElements; i++ )
1154 if( pProperties[i].Handle == nHandle )
1156 if( pPropName )
1157 *pPropName = pProperties[ i ].Name;
1158 if( pAttributes )
1159 *pAttributes = pProperties[ i ].Attributes;
1160 return sal_True;
1164 return sal_False;
1167 //========================================================================
1168 Sequence< Property > OPropertyArrayHelper::getProperties(void)
1170 return aInfos;
1173 //========================================================================
1174 Property OPropertyArrayHelper::getPropertyByName(const OUString& aPropertyName)
1175 throw (UnknownPropertyException)
1177 Property * pR;
1178 pR = (Property *)bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(),
1179 sizeof( Property ),
1180 compare_OUString_Property_Impl );
1181 if( !pR ) {
1182 throw UnknownPropertyException();
1184 return *pR;
1187 //========================================================================
1188 sal_Bool OPropertyArrayHelper::hasPropertyByName(const OUString& aPropertyName)
1190 Property * pR;
1191 pR = (Property *)bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(),
1192 sizeof( Property ),
1193 compare_OUString_Property_Impl );
1194 return pR != NULL;
1197 //========================================================================
1198 sal_Int32 OPropertyArrayHelper::getHandleByName( const OUString & rPropName )
1200 Property * pR;
1201 pR = (Property *)bsearch( &rPropName, aInfos.getConstArray(), aInfos.getLength(),
1202 sizeof( Property ),
1203 compare_OUString_Property_Impl );
1204 return pR ? pR->Handle : -1;
1207 //========================================================================
1208 sal_Int32 OPropertyArrayHelper::fillHandles( sal_Int32 * pHandles, const Sequence< OUString > & rPropNames )
1210 sal_Int32 nHitCount = 0;
1211 const OUString * pReqProps = rPropNames.getConstArray();
1212 sal_Int32 nReqLen = rPropNames.getLength();
1213 const Property * pCur = aInfos.getConstArray();
1214 const Property * pEnd = pCur + aInfos.getLength();
1216 for( sal_Int32 i = 0; i < nReqLen; i++ )
1218 // Calculate logarithm
1219 sal_Int32 n = (sal_Int32)(pEnd - pCur);
1220 sal_Int32 nLog = 0;
1221 while( n )
1223 nLog += 1;
1224 n = n >> 1;
1227 // Number of properties to search for * Log2 of the number of remaining
1228 // properties to search in.
1229 if( (nReqLen - i) * nLog >= pEnd - pCur )
1231 // linear search is better
1232 while( pCur < pEnd && pReqProps[i] > pCur->Name )
1234 pCur++;
1236 if( pCur < pEnd && pReqProps[i] == pCur->Name )
1238 pHandles[i] = pCur->Handle;
1239 nHitCount++;
1241 else
1242 pHandles[i] = -1;
1244 else
1246 // binary search is better
1247 sal_Int32 nCompVal = 1;
1248 const Property * pOldEnd = pEnd--;
1249 const Property * pMid = pCur;
1251 while( nCompVal != 0 && pCur <= pEnd )
1253 pMid = (pEnd - pCur) / 2 + pCur;
1255 nCompVal = pReqProps[i].compareTo( pMid->Name );
1257 if( nCompVal > 0 )
1258 pCur = pMid + 1;
1259 else
1260 pEnd = pMid - 1;
1263 if( nCompVal == 0 )
1265 pHandles[i] = pMid->Handle;
1266 nHitCount++;
1267 pCur = pMid +1;
1269 else if( nCompVal > 0 )
1271 pHandles[i] = -1;
1272 pCur = pMid +1;
1274 else
1276 pHandles[i] = -1;
1277 pCur = pMid;
1279 pEnd = pOldEnd;
1282 return nHitCount;
1285 } // end namespace cppu
1289 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */