1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/implbase.hxx>
23 #include <cppuhelper/queryinterface.hxx>
24 #include <cppuhelper/weak.hxx>
25 #include <cppuhelper/propshlp.hxx>
26 #include <cppuhelper/exc_hlp.hxx>
27 #include <com/sun/star/beans/PropertyAttribute.hpp>
28 #include <com/sun/star/lang/DisposedException.hpp>
30 #include <sal/log.hxx>
33 using namespace com::sun::star::uno
;
34 using namespace com::sun::star::beans
;
35 using namespace com::sun::star::lang
;
38 using ::rtl::OUString
;
42 IPropertyArrayHelper::~IPropertyArrayHelper()
46 inline const css::uno::Type
& getPropertyTypeIdentifier( )
48 return cppu::UnoType
<XPropertyChangeListener
>::get();
50 inline const css::uno::Type
& getPropertiesTypeIdentifier()
52 return cppu::UnoType
<XPropertiesChangeListener
>::get();
54 inline const css::uno::Type
& getVetoableTypeIdentifier()
56 return cppu::UnoType
<XVetoableChangeListener
>::get();
61 static int compare_OUString_Property_Impl( const void *arg1
, const void *arg2
)
64 return static_cast<OUString
const *>(arg1
)->compareTo( static_cast<Property
const *>(arg2
)->Name
);
70 * The class which implements the PropertySetInfo interface.
73 class OPropertySetHelperInfo_Impl
74 : public WeakImplHelper
< css::beans::XPropertySetInfo
>
76 Sequence
< Property
> aInfos
;
79 explicit OPropertySetHelperInfo_Impl( IPropertyArrayHelper
& rHelper_
);
81 // XPropertySetInfo-methods
82 virtual Sequence
< Property
> SAL_CALL
getProperties() override
;
83 virtual Property SAL_CALL
getPropertyByName(const OUString
& PropertyName
) override
;
84 virtual sal_Bool SAL_CALL
hasPropertyByName(const OUString
& PropertyName
) override
;
89 * Create an object that implements XPropertySetInfo IPropertyArrayHelper.
91 OPropertySetHelperInfo_Impl::OPropertySetHelperInfo_Impl(
92 IPropertyArrayHelper
& rHelper_
)
93 :aInfos( rHelper_
.getProperties() )
98 * Return the sequence of properties, which are provided through the constructor.
100 Sequence
< Property
> OPropertySetHelperInfo_Impl::getProperties()
106 * Return the sequence of properties, which are provided through the constructor.
108 Property
OPropertySetHelperInfo_Impl::getPropertyByName( const OUString
& PropertyName
)
111 pR
= static_cast<Property
*>(bsearch( &PropertyName
, aInfos
.getConstArray(), aInfos
.getLength(),
113 compare_OUString_Property_Impl
));
115 throw UnknownPropertyException();
122 * Return the sequence of properties, which are provided through the constructor.
124 sal_Bool
OPropertySetHelperInfo_Impl::hasPropertyByName( const OUString
& PropertyName
)
127 pR
= static_cast<Property
*>(bsearch( &PropertyName
, aInfos
.getConstArray(), aInfos
.getLength(),
129 compare_OUString_Property_Impl
));
130 return pR
!= nullptr;
134 // class PropertySetHelper_Impl
136 class OPropertySetHelper::Impl
{
139 Impl( bool i_bIgnoreRuntimeExceptionsWhileFiring
,
140 IEventNotificationHook
*i_pFireEvents
142 :m_bIgnoreRuntimeExceptionsWhileFiring( i_bIgnoreRuntimeExceptionsWhileFiring
)
144 ,m_pFireEvents( i_pFireEvents
)
148 bool m_bIgnoreRuntimeExceptionsWhileFiring
;
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
;
158 // class PropertySetHelper
160 OPropertySetHelper::OPropertySetHelper(
161 OBroadcastHelper
& rBHelper_
)
162 : rBHelper( rBHelper_
),
163 aBoundLC( rBHelper_
.rMutex
),
164 aVetoableLC( rBHelper_
.rMutex
),
165 m_pReserved( new Impl(false, nullptr) )
169 OPropertySetHelper::OPropertySetHelper(
170 OBroadcastHelper
& rBHelper_
, bool bIgnoreRuntimeExceptionsWhileFiring
)
171 : rBHelper( rBHelper_
),
172 aBoundLC( rBHelper_
.rMutex
),
173 aVetoableLC( rBHelper_
.rMutex
),
174 m_pReserved( new Impl( bIgnoreRuntimeExceptionsWhileFiring
, nullptr ) )
178 OPropertySetHelper::OPropertySetHelper(
179 OBroadcastHelper
& rBHelper_
, IEventNotificationHook
* i_pFireEvents
,
180 bool bIgnoreRuntimeExceptionsWhileFiring
)
181 : rBHelper( rBHelper_
),
182 aBoundLC( rBHelper_
.rMutex
),
183 aVetoableLC( rBHelper_
.rMutex
),
185 new Impl( bIgnoreRuntimeExceptionsWhileFiring
, i_pFireEvents
) )
189 OPropertySetHelper2::OPropertySetHelper2(
190 OBroadcastHelper
& irBHelper
,
191 IEventNotificationHook
*i_pFireEvents
,
192 bool bIgnoreRuntimeExceptionsWhileFiring
)
193 :OPropertySetHelper( irBHelper
, i_pFireEvents
, bIgnoreRuntimeExceptionsWhileFiring
)
198 * You must call disposing before.
200 OPropertySetHelper::~OPropertySetHelper()
204 OPropertySetHelper2::~OPropertySetHelper2()
209 Any
OPropertySetHelper::queryInterface( const css::uno::Type
& rType
)
211 return ::cppu::queryInterface(
213 static_cast< XPropertySet
* >( this ),
214 static_cast< XMultiPropertySet
* >( this ),
215 static_cast< XFastPropertySet
* >( this ) );
218 Any
OPropertySetHelper2::queryInterface( const css::uno::Type
& rType
)
220 Any
cnd(cppu::queryInterface(rType
, static_cast< XPropertySetOption
* >(this)));
221 if ( cnd
.hasValue() )
223 return OPropertySetHelper::queryInterface(rType
);
227 * called from the derivee's XTypeProvider::getTypes implementation
229 css::uno::Sequence
< css::uno::Type
> OPropertySetHelper::getTypes()
232 UnoType
<css::beans::XPropertySet
>::get(),
233 UnoType
<css::beans::XMultiPropertySet
>::get(),
234 UnoType
<css::beans::XFastPropertySet
>::get()};
238 void OPropertySetHelper::disposing()
240 // Create an event with this as sender
241 Reference
< XPropertySet
> rSource( static_cast< XPropertySet
* >(this), UNO_QUERY
);
243 aEvt
.Source
= rSource
;
245 // inform all listeners to release this object
246 // The listener containers are automatically cleared
247 aBoundLC
.disposeAndClear( aEvt
);
248 aVetoableLC
.disposeAndClear( aEvt
);
251 Reference
< XPropertySetInfo
> OPropertySetHelper::createPropertySetInfo(
252 IPropertyArrayHelper
& rProperties
)
254 return static_cast< XPropertySetInfo
* >( new OPropertySetHelperInfo_Impl( rProperties
) );
258 void OPropertySetHelper::setPropertyValue(
259 const OUString
& rPropertyName
, const Any
& rValue
)
262 IPropertyArrayHelper
& rPH
= getInfoHelper();
263 // map the name to the handle
264 sal_Int32 nHandle
= rPH
.getHandleByName( rPropertyName
);
265 // call the method of the XFastPropertySet interface
266 setFastPropertyValue( nHandle
, rValue
);
270 Any
OPropertySetHelper::getPropertyValue(
271 const OUString
& rPropertyName
)
274 IPropertyArrayHelper
& rPH
= getInfoHelper();
275 // map the name to the handle
276 sal_Int32 nHandle
= rPH
.getHandleByName( rPropertyName
);
277 // call the method of the XFastPropertySet interface
278 return getFastPropertyValue( nHandle
);
282 void OPropertySetHelper::addPropertyChangeListener(
283 const OUString
& rPropertyName
,
284 const Reference
< XPropertyChangeListener
> & rxListener
)
286 MutexGuard
aGuard( rBHelper
.rMutex
);
287 OSL_ENSURE( !rBHelper
.bInDispose
, "do not addPropertyChangeListener in the dispose call" );
288 OSL_ENSURE( !rBHelper
.bDisposed
, "object is disposed" );
289 if( !rBHelper
.bInDispose
&& !rBHelper
.bDisposed
)
291 // only add listeners if you are not disposed
292 // a listener with no name means all properties
293 if( !rPropertyName
.isEmpty() )
296 IPropertyArrayHelper
& rPH
= getInfoHelper();
297 // map the name to the handle
298 sal_Int32 nHandle
= rPH
.getHandleByName( rPropertyName
);
299 if( nHandle
== -1 ) {
300 // property not known throw exception
301 throw UnknownPropertyException() ;
304 sal_Int16 nAttributes
;
305 rPH
.fillPropertyMembersByHandle( nullptr, &nAttributes
, nHandle
);
306 if( !(nAttributes
& css::beans::PropertyAttribute::BOUND
) )
308 OSL_FAIL( "add listener to an unbound property" );
309 // silent ignore this
312 // add the change listener to the helper container
314 aBoundLC
.addInterface( nHandle
, rxListener
);
317 // add the change listener to the helper container
318 rBHelper
.aLC
.addInterface(
319 getPropertyTypeIdentifier( ),
327 void OPropertySetHelper::removePropertyChangeListener(
328 const OUString
& rPropertyName
,
329 const Reference
< XPropertyChangeListener
>& rxListener
)
331 MutexGuard
aGuard( rBHelper
.rMutex
);
332 OSL_ENSURE( !rBHelper
.bDisposed
, "object is disposed" );
333 // all listeners are automatically released in a dispose call
334 if( !rBHelper
.bInDispose
&& !rBHelper
.bDisposed
)
336 if( !rPropertyName
.isEmpty() )
339 IPropertyArrayHelper
& rPH
= getInfoHelper();
340 // map the name to the handle
341 sal_Int32 nHandle
= rPH
.getHandleByName( rPropertyName
);
343 // property not known throw exception
344 throw UnknownPropertyException();
345 aBoundLC
.removeInterface( nHandle
, rxListener
);
348 // remove the change listener to the helper container
349 rBHelper
.aLC
.removeInterface(
350 getPropertyTypeIdentifier( ),
358 void OPropertySetHelper::addVetoableChangeListener(
359 const OUString
& rPropertyName
,
360 const Reference
< XVetoableChangeListener
> & rxListener
)
362 MutexGuard
aGuard( rBHelper
.rMutex
);
363 OSL_ENSURE( !rBHelper
.bInDispose
, "do not addVetoableChangeListener in the dispose call" );
364 OSL_ENSURE( !rBHelper
.bDisposed
, "object is disposed" );
365 if( !rBHelper
.bInDispose
&& !rBHelper
.bDisposed
)
367 // only add listeners if you are not disposed
368 // a listener with no name means all properties
369 if( !rPropertyName
.isEmpty() )
372 IPropertyArrayHelper
& rPH
= getInfoHelper();
373 // map the name to the handle
374 sal_Int32 nHandle
= rPH
.getHandleByName( rPropertyName
);
375 if( nHandle
== -1 ) {
376 // property not known throw exception
377 throw UnknownPropertyException();
380 sal_Int16 nAttributes
;
381 rPH
.fillPropertyMembersByHandle( nullptr, &nAttributes
, nHandle
);
382 if( !(nAttributes
& PropertyAttribute::CONSTRAINED
) )
384 OSL_FAIL( "addVetoableChangeListener, and property is not constrained" );
385 // silent ignore this
388 // add the vetoable listener to the helper container
389 aVetoableLC
.addInterface( nHandle
, rxListener
);
392 // add the vetoable listener to the helper container
393 rBHelper
.aLC
.addInterface(
394 getVetoableTypeIdentifier( ),
401 void OPropertySetHelper::removeVetoableChangeListener(
402 const OUString
& rPropertyName
,
403 const Reference
< XVetoableChangeListener
> & rxListener
)
405 MutexGuard
aGuard( rBHelper
.rMutex
);
406 OSL_ENSURE( !rBHelper
.bDisposed
, "object is disposed" );
407 // all listeners are automatically released in a dispose call
408 if( !rBHelper
.bInDispose
&& !rBHelper
.bDisposed
)
410 if( !rPropertyName
.isEmpty() )
413 IPropertyArrayHelper
& rPH
= getInfoHelper();
414 // map the name to the handle
415 sal_Int32 nHandle
= rPH
.getHandleByName( rPropertyName
);
416 if( nHandle
== -1 ) {
417 // property not known throw exception
418 throw UnknownPropertyException();
420 // remove the vetoable listener to the helper container
421 aVetoableLC
.removeInterface( nHandle
, rxListener
);
424 // add the vetoable listener to the helper container
425 rBHelper
.aLC
.removeInterface(
426 getVetoableTypeIdentifier( ),
432 void OPropertySetHelper::setDependentFastPropertyValue( sal_Int32 i_handle
, const css::uno::Any
& i_value
)
434 //OSL_PRECOND( rBHelper.rMutex.isAcquired(), "OPropertySetHelper::setDependentFastPropertyValue: to be called with a locked mutex only!" );
435 // there is no such thing as Mutex.isAcquired, sadly ...
437 sal_Int16
nAttributes(0);
438 IPropertyArrayHelper
& rInfo
= getInfoHelper();
439 if ( !rInfo
.fillPropertyMembersByHandle( nullptr, &nAttributes
, i_handle
) )
441 throw UnknownPropertyException();
443 // no need to check for READONLY-ness of the property. The method is intended to be called internally, which
444 // implies it might be invoked for properties which are read-only to the instance's clients, but well allowed
445 // to change their value.
447 Any aConverted
, aOld
;
448 bool bChanged
= convertFastPropertyValue( aConverted
, aOld
, i_handle
, i_value
);
452 // don't fire vetoable events. This method is called with our mutex locked, so calling into listeners would not be
453 // a good idea. The caller is responsible for not invoking this for constrained properties.
454 OSL_ENSURE( ( nAttributes
& PropertyAttribute::CONSTRAINED
) == 0,
455 "OPropertySetHelper::setDependentFastPropertyValue: not to be used for constrained properties!" );
457 // actually set the new value
460 setFastPropertyValue_NoBroadcast( i_handle
, aConverted
);
462 catch (const UnknownPropertyException
& ) { throw; /* allowed to leave */ }
463 catch (const PropertyVetoException
& ) { throw; /* allowed to leave */ }
464 catch (const IllegalArgumentException
& ) { throw; /* allowed to leave */ }
465 catch (const WrappedTargetException
& ) { throw; /* allowed to leave */ }
466 catch (const RuntimeException
& ) { throw; /* allowed to leave */ }
467 catch (const Exception
& )
469 // not allowed to leave this method
470 WrappedTargetException aWrapped
;
471 aWrapped
.TargetException
= ::cppu::getCaughtException();
472 aWrapped
.Context
= static_cast< XPropertySet
* >( this );
476 // remember the handle/values, for the events to be fired later
477 m_pReserved
->m_handles
.push_back( i_handle
);
478 m_pReserved
->m_newValues
.push_back( aConverted
); // TODO: setFastPropertyValue notifies the unconverted value here ...?
479 m_pReserved
->m_oldValues
.push_back( aOld
);
483 void OPropertySetHelper::setFastPropertyValue( sal_Int32 nHandle
, const Any
& rValue
)
485 OSL_ENSURE( !rBHelper
.bInDispose
, "do not setFastPropertyValue in the dispose call" );
486 OSL_ENSURE( !rBHelper
.bDisposed
, "object is disposed" );
488 IPropertyArrayHelper
& rInfo
= getInfoHelper();
489 sal_Int16 nAttributes
;
490 if( !rInfo
.fillPropertyMembersByHandle( nullptr, &nAttributes
, nHandle
) ) {
492 throw UnknownPropertyException();
494 if( nAttributes
& PropertyAttribute::READONLY
)
495 throw PropertyVetoException();
500 // Will the property change?
503 MutexGuard
aGuard( rBHelper
.rMutex
);
504 bChanged
= convertFastPropertyValue( aConvertedVal
, aOldVal
, nHandle
, rValue
);
505 // release guard to fire events
509 // Is it a constrained property?
510 if( nAttributes
& PropertyAttribute::CONSTRAINED
)
512 // In aValue is the converted rValue
513 // fire a constrained event
514 // second parameter NULL means constrained
515 fire( &nHandle
, &rValue
, &aOldVal
, 1, true );
519 MutexGuard
aGuard( rBHelper
.rMutex
);
522 // set the property to the new value
523 setFastPropertyValue_NoBroadcast( nHandle
, aConvertedVal
);
525 catch (const css::beans::UnknownPropertyException
& ) { throw; /* allowed to leave */ }
526 catch (const css::beans::PropertyVetoException
& ) { throw; /* allowed to leave */ }
527 catch (const css::lang::IllegalArgumentException
& ) { throw; /* allowed to leave */ }
528 catch (const css::lang::WrappedTargetException
& ) { throw; /* allowed to leave */ }
529 catch (const css::uno::RuntimeException
& ) { throw; /* allowed to leave */ }
530 catch (const css::uno::Exception
& e
)
532 // not allowed to leave this method
533 css::lang::WrappedTargetException aWrap
;
534 aWrap
.Context
= static_cast< css::beans::XPropertySet
* >( this );
535 aWrap
.TargetException
<<= e
;
540 // release guard to fire events
542 // file a change event, if the value changed
543 impl_fireAll( &nHandle
, &rValue
, &aOldVal
, 1 );
548 Any
OPropertySetHelper::getFastPropertyValue( sal_Int32 nHandle
)
551 IPropertyArrayHelper
& rInfo
= getInfoHelper();
552 if( !rInfo
.fillPropertyMembersByHandle( nullptr, nullptr, nHandle
) )
554 throw UnknownPropertyException();
557 MutexGuard
aGuard( rBHelper
.rMutex
);
558 getFastPropertyValue( aRet
, nHandle
);
563 void OPropertySetHelper::impl_fireAll( sal_Int32
* i_handles
, const Any
* i_newValues
, const Any
* i_oldValues
, sal_Int32 i_count
)
565 ClearableMutexGuard
aGuard( rBHelper
.rMutex
);
566 if ( m_pReserved
->m_handles
.empty() )
569 fire( i_handles
, i_newValues
, i_oldValues
, i_count
, false );
573 const size_t additionalEvents
= m_pReserved
->m_handles
.size();
574 OSL_ENSURE( additionalEvents
== m_pReserved
->m_newValues
.size()
575 && additionalEvents
== m_pReserved
->m_oldValues
.size(),
576 "OPropertySetHelper::impl_fireAll: inconsistency!" );
578 std::vector
< sal_Int32
> allHandles( additionalEvents
+ i_count
);
579 std::copy( m_pReserved
->m_handles
.begin(), m_pReserved
->m_handles
.end(), allHandles
.begin() );
580 std::copy( i_handles
, i_handles
+ i_count
, allHandles
.begin() + additionalEvents
);
582 std::vector
< Any
> allNewValues( additionalEvents
+ i_count
);
583 std::copy( m_pReserved
->m_newValues
.begin(), m_pReserved
->m_newValues
.end(), allNewValues
.begin() );
584 std::copy( i_newValues
, i_newValues
+ i_count
, allNewValues
.begin() + additionalEvents
);
586 std::vector
< Any
> allOldValues( additionalEvents
+ i_count
);
587 std::copy( m_pReserved
->m_oldValues
.begin(), m_pReserved
->m_oldValues
.end(), allOldValues
.begin() );
588 std::copy( i_oldValues
, i_oldValues
+ i_count
, allOldValues
.begin() + additionalEvents
);
590 m_pReserved
->m_handles
.clear();
591 m_pReserved
->m_newValues
.clear();
592 m_pReserved
->m_oldValues
.clear();
595 fire( &allHandles
[0], &allNewValues
[0], &allOldValues
[0], additionalEvents
+ i_count
, false );
599 void OPropertySetHelper::fire
601 sal_Int32
* pnHandles
,
602 const Any
* pNewValues
,
603 const Any
* pOldValues
,
604 sal_Int32 nHandles
, // These is the Count of the array
608 if (! m_pReserved
->m_bFireEvents
)
611 if (m_pReserved
->m_pFireEvents
) {
612 m_pReserved
->m_pFireEvents
->fireEvents(
613 pnHandles
, nHandles
, bVetoable
,
614 m_pReserved
->m_bIgnoreRuntimeExceptionsWhileFiring
);
617 // Only fire, if one or more properties changed
620 // create the event sequence of all changed properties
621 Sequence
< PropertyChangeEvent
> aEvts( nHandles
);
622 PropertyChangeEvent
* pEvts
= aEvts
.getArray();
623 Reference
< XInterface
> xSource( static_cast<XPropertySet
*>(this), UNO_QUERY
);
625 sal_Int32 nChangesLen
= 0;
626 // Loop over all changed properties to fill the event struct
627 for( i
= 0; i
< nHandles
; i
++ )
629 // Vetoable fire and constrained attribute set or
630 // Change fire and Changed and bound attribute set
631 IPropertyArrayHelper
& rInfo
= getInfoHelper();
632 sal_Int16 nAttributes
;
634 rInfo
.fillPropertyMembersByHandle( &aPropName
, &nAttributes
, pnHandles
[i
] );
637 (bVetoable
&& (nAttributes
& PropertyAttribute::CONSTRAINED
)) ||
638 (!bVetoable
&& (nAttributes
& PropertyAttribute::BOUND
))
641 pEvts
[nChangesLen
].Source
= xSource
;
642 pEvts
[nChangesLen
].PropertyName
= aPropName
;
643 pEvts
[nChangesLen
].PropertyHandle
= pnHandles
[i
];
644 pEvts
[nChangesLen
].OldValue
= pOldValues
[i
];
645 pEvts
[nChangesLen
].NewValue
= pNewValues
[i
];
650 bool bIgnoreRuntimeExceptionsWhileFiring
=
651 m_pReserved
->m_bIgnoreRuntimeExceptionsWhileFiring
;
653 // fire the events for all changed properties
654 for( i
= 0; i
< nChangesLen
; i
++ )
656 // get the listener container for the property name
657 OInterfaceContainerHelper
* pLC
;
658 if( bVetoable
) // fire change Events?
659 pLC
= aVetoableLC
.getContainer( pEvts
[i
].PropertyHandle
);
661 pLC
= aBoundLC
.getContainer( pEvts
[i
].PropertyHandle
);
664 // Iterate over all listeners and send events
665 OInterfaceIteratorHelper
aIt( *pLC
);
666 while( aIt
.hasMoreElements() )
668 XInterface
* pL
= aIt
.next();
673 if( bVetoable
) // fire change Events?
675 static_cast<XVetoableChangeListener
*>(pL
)->vetoableChange(
680 static_cast<XPropertyChangeListener
*>(pL
)->propertyChange(
684 catch (DisposedException
& exc
)
686 OSL_ENSURE( exc
.Context
.is(),
687 "DisposedException without Context!" );
688 if (exc
.Context
== pL
)
694 catch (RuntimeException
& exc
)
696 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc
);
697 if (! bIgnoreRuntimeExceptionsWhileFiring
)
702 // broadcast to all listeners with "" property name
704 // fire change Events?
705 pLC
= rBHelper
.aLC
.getContainer(
706 getVetoableTypeIdentifier()
710 pLC
= rBHelper
.aLC
.getContainer(
711 getPropertyTypeIdentifier( )
716 // Iterate over all listeners and send events.
717 OInterfaceIteratorHelper
aIt( *pLC
);
718 while( aIt
.hasMoreElements() )
720 XInterface
* pL
= aIt
.next();
725 if( bVetoable
) // fire change Events?
727 static_cast<XVetoableChangeListener
*>(pL
)->vetoableChange(
732 static_cast<XPropertyChangeListener
*>(pL
)->propertyChange(
736 catch (DisposedException
& exc
)
738 OSL_ENSURE( exc
.Context
.is(),
739 "DisposedException without Context!" );
740 if (exc
.Context
== pL
)
746 catch (RuntimeException
& exc
)
748 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc
);
749 if (! bIgnoreRuntimeExceptionsWhileFiring
)
756 // reduce array to changed properties
757 aEvts
.realloc( nChangesLen
);
761 OInterfaceContainerHelper
* pCont
= nullptr;
762 pCont
= rBHelper
.aLC
.getContainer(
763 getPropertiesTypeIdentifier( )
767 // Here is a Bug, unbound properties are also fired
768 OInterfaceIteratorHelper
aIt( *pCont
);
769 while( aIt
.hasMoreElements() )
771 XPropertiesChangeListener
* pL
=
772 static_cast<XPropertiesChangeListener
*>(aIt
.next());
777 // fire the hole event sequence to the
778 // XPropertiesChangeListener's
779 pL
->propertiesChange( aEvts
);
781 catch (DisposedException
& exc
)
783 OSL_ENSURE( exc
.Context
.is(),
784 "DisposedException without Context!" );
785 if (exc
.Context
== pL
)
791 catch (RuntimeException
& exc
)
793 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc
);
794 if (! bIgnoreRuntimeExceptionsWhileFiring
)
803 // OPropertySetHelper
804 void OPropertySetHelper::setFastPropertyValues(
806 sal_Int32
* pHandles
,
808 sal_Int32 nHitCount
)
810 OSL_ENSURE( !rBHelper
.bInDispose
, "do not getFastPropertyValue in the dispose call" );
811 OSL_ENSURE( !rBHelper
.bDisposed
, "object is disposed" );
814 IPropertyArrayHelper
& rPH
= getInfoHelper();
816 std::unique_ptr
<Any
[]> pConvertedValues(new Any
[ nHitCount
]);
817 std::unique_ptr
<Any
[]> pOldValues(new Any
[ nHitCount
]);
822 // must lock the mutex outside the loop. So all values are consistent.
823 MutexGuard
aGuard( rBHelper
.rMutex
);
824 for( i
= 0; i
< nSeqLen
; i
++ )
826 if( pHandles
[i
] != -1 )
828 sal_Int16 nAttributes
;
829 rPH
.fillPropertyMembersByHandle( nullptr, &nAttributes
, pHandles
[i
] );
830 if( nAttributes
& PropertyAttribute::READONLY
) {
831 throw PropertyVetoException();
833 // Will the property change?
834 if( convertFastPropertyValue( pConvertedValues
[ n
], pOldValues
[n
],
835 pHandles
[i
], pValues
[i
] ) )
837 // only increment if the property really change
838 pHandles
[n
] = pHandles
[i
];
843 // release guard to fire events
846 // fire vetoable events
847 fire( pHandles
, pConvertedValues
.get(), pOldValues
.get(), n
, true );
850 // must lock the mutex outside the loop.
851 MutexGuard
aGuard( rBHelper
.rMutex
);
852 // Loop over all changed properties
853 for( i
= 0; i
< n
; i
++ )
855 // Will the property change?
856 setFastPropertyValue_NoBroadcast( pHandles
[i
], pConvertedValues
[i
] );
858 // release guard to fire events
861 // fire change events
862 impl_fireAll( pHandles
, pConvertedValues
.get(), pOldValues
.get(), n
);
867 * The sequence may be contain not known properties. The implementation
868 * must ignore these properties.
870 void OPropertySetHelper::setPropertyValues(
871 const Sequence
<OUString
>& rPropertyNames
,
872 const Sequence
<Any
>& rValues
)
874 sal_Int32 nSeqLen
= rPropertyNames
.getLength();
875 std::unique_ptr
<sal_Int32
[]> pHandles(new sal_Int32
[ nSeqLen
]);
877 IPropertyArrayHelper
& rPH
= getInfoHelper();
878 // fill the handle array
879 sal_Int32 nHitCount
= rPH
.fillHandles( pHandles
.get(), rPropertyNames
);
881 setFastPropertyValues( nSeqLen
, pHandles
.get(), rValues
.getConstArray(), nHitCount
);
885 Sequence
<Any
> OPropertySetHelper::getPropertyValues( const Sequence
<OUString
>& rPropertyNames
)
887 sal_Int32 nSeqLen
= rPropertyNames
.getLength();
888 std::unique_ptr
<sal_Int32
[]> pHandles(new sal_Int32
[ nSeqLen
]);
889 Sequence
< Any
> aValues( nSeqLen
);
892 IPropertyArrayHelper
& rPH
= getInfoHelper();
893 // fill the handle array
894 rPH
.fillHandles( pHandles
.get(), rPropertyNames
);
896 Any
* pValues
= aValues
.getArray();
898 MutexGuard
aGuard( rBHelper
.rMutex
);
899 // fill the sequence with the values
900 for( sal_Int32 i
= 0; i
< nSeqLen
; i
++ )
901 getFastPropertyValue( pValues
[i
], pHandles
[i
] );
907 void OPropertySetHelper::addPropertiesChangeListener(
908 const Sequence
<OUString
> & ,
909 const Reference
< XPropertiesChangeListener
> & rListener
)
911 rBHelper
.addListener( cppu::UnoType
<decltype(rListener
)>::get(), rListener
);
915 void OPropertySetHelper::removePropertiesChangeListener(
916 const Reference
< XPropertiesChangeListener
> & rListener
)
918 rBHelper
.removeListener( cppu::UnoType
<decltype(rListener
)>::get(), rListener
);
922 void OPropertySetHelper::firePropertiesChangeEvent(
923 const Sequence
<OUString
>& rPropertyNames
,
924 const Reference
< XPropertiesChangeListener
>& rListener
)
926 sal_Int32 nLen
= rPropertyNames
.getLength();
927 std::unique_ptr
<sal_Int32
[]> pHandles(new sal_Int32
[nLen
]);
928 IPropertyArrayHelper
& rPH
= getInfoHelper();
929 rPH
.fillHandles( pHandles
.get(), rPropertyNames
);
930 const OUString
* pNames
= rPropertyNames
.getConstArray();
932 // get the count of matching properties
933 sal_Int32 nFireLen
= 0;
935 for( i
= 0; i
< nLen
; i
++ )
936 if( pHandles
[i
] != -1 )
939 Sequence
<PropertyChangeEvent
> aChanges( nFireLen
);
940 PropertyChangeEvent
* pChanges
= aChanges
.getArray();
943 // must lock the mutex outside the loop. So all values are consistent.
944 MutexGuard
aGuard( rBHelper
.rMutex
);
945 Reference
< XInterface
> xSource( static_cast<XPropertySet
*>(this), UNO_QUERY
);
946 sal_Int32 nFirePos
= 0;
947 for( i
= 0; i
< nLen
; i
++ )
949 if( pHandles
[i
] != -1 )
951 pChanges
[nFirePos
].Source
= xSource
;
952 pChanges
[nFirePos
].PropertyName
= pNames
[i
];
953 pChanges
[nFirePos
].PropertyHandle
= pHandles
[i
];
954 getFastPropertyValue( pChanges
[nFirePos
].OldValue
, pHandles
[i
] );
955 pChanges
[nFirePos
].NewValue
= pChanges
[nFirePos
].OldValue
;
959 // release guard to fire events
962 rListener
->propertiesChange( aChanges
);
965 void OPropertySetHelper2::enableChangeListenerNotification( sal_Bool bEnable
)
967 m_pReserved
->m_bFireEvents
= bEnable
;
972 static int compare_Property_Impl( const void *arg1
, const void *arg2
)
975 return static_cast<Property
const *>(arg1
)->Name
.compareTo( static_cast<Property
const *>(arg2
)->Name
);
980 void OPropertyArrayHelper::init( sal_Bool bSorted
)
982 sal_Int32 i
, nElements
= aInfos
.getLength();
983 const Property
* pProperties
= aInfos
.getConstArray();
985 for( i
= 1; i
< nElements
; i
++ )
987 if( pProperties
[i
-1].Name
>= pProperties
[i
].Name
)
990 OSL_FAIL( "Property array is not sorted" );
993 qsort( aInfos
.getArray(), nElements
, sizeof( Property
),
994 compare_Property_Impl
);
998 // may be that the array is resorted
999 pProperties
= aInfos
.getConstArray();
1000 for( i
= 0; i
< nElements
; i
++ )
1001 if( pProperties
[i
].Handle
!= i
)
1003 // The handle is the index
1004 bRightOrdered
= true;
1007 OPropertyArrayHelper::OPropertyArrayHelper(
1011 : m_pReserved(nullptr)
1012 , aInfos(pProps
, nEle
)
1013 , bRightOrdered( false )
1018 OPropertyArrayHelper::OPropertyArrayHelper(
1019 const Sequence
< Property
> & aProps
,
1021 : m_pReserved(nullptr)
1023 , bRightOrdered( false )
1029 sal_Int32
OPropertyArrayHelper::getCount() const
1031 return aInfos
.getLength();
1035 sal_Bool
OPropertyArrayHelper::fillPropertyMembersByHandle
1037 OUString
* pPropName
,
1038 sal_Int16
* pAttributes
,
1042 const Property
* pProperties
= aInfos
.getConstArray();
1043 sal_Int32 nElements
= aInfos
.getLength();
1047 if( nHandle
< 0 || nHandle
>= nElements
)
1050 *pPropName
= pProperties
[ nHandle
].Name
;
1052 *pAttributes
= pProperties
[ nHandle
].Attributes
;
1055 // normally the array is sorted
1056 for( sal_Int32 i
= 0; i
< nElements
; i
++ )
1058 if( pProperties
[i
].Handle
== nHandle
)
1061 *pPropName
= pProperties
[ i
].Name
;
1063 *pAttributes
= pProperties
[ i
].Attributes
;
1071 Sequence
< Property
> OPropertyArrayHelper::getProperties()
1077 Property
OPropertyArrayHelper::getPropertyByName(const OUString
& aPropertyName
)
1080 pR
= static_cast<Property
*>(bsearch( &aPropertyName
, aInfos
.getConstArray(), aInfos
.getLength(),
1082 compare_OUString_Property_Impl
));
1084 throw UnknownPropertyException();
1090 sal_Bool
OPropertyArrayHelper::hasPropertyByName(const OUString
& aPropertyName
)
1093 pR
= static_cast<Property
*>(bsearch( &aPropertyName
, aInfos
.getConstArray(), aInfos
.getLength(),
1095 compare_OUString_Property_Impl
));
1096 return pR
!= nullptr;
1100 sal_Int32
OPropertyArrayHelper::getHandleByName( const OUString
& rPropName
)
1103 pR
= static_cast<Property
*>(bsearch( &rPropName
, aInfos
.getConstArray(), aInfos
.getLength(),
1105 compare_OUString_Property_Impl
));
1106 return pR
? pR
->Handle
: -1;
1110 sal_Int32
OPropertyArrayHelper::fillHandles( sal_Int32
* pHandles
, const Sequence
< OUString
> & rPropNames
)
1112 sal_Int32 nHitCount
= 0;
1113 const OUString
* pReqProps
= rPropNames
.getConstArray();
1114 sal_Int32 nReqLen
= rPropNames
.getLength();
1115 const Property
* pCur
= aInfos
.getConstArray();
1116 const Property
* pEnd
= pCur
+ aInfos
.getLength();
1118 for( sal_Int32 i
= 0; i
< nReqLen
; i
++ )
1120 // Calculate logarithm
1121 sal_Int32 n
= static_cast<sal_Int32
>(pEnd
- pCur
);
1129 // Number of properties to search for * Log2 of the number of remaining
1130 // properties to search in.
1131 if( (nReqLen
- i
) * nLog
>= pEnd
- pCur
)
1133 // linear search is better
1134 while( pCur
< pEnd
&& pReqProps
[i
] > pCur
->Name
)
1138 if( pCur
< pEnd
&& pReqProps
[i
] == pCur
->Name
)
1140 pHandles
[i
] = pCur
->Handle
;
1148 // binary search is better
1149 sal_Int32 nCompVal
= 1;
1150 const Property
* pOldEnd
= pEnd
--;
1151 const Property
* pMid
= pCur
;
1153 while( nCompVal
!= 0 && pCur
<= pEnd
)
1155 pMid
= (pEnd
- pCur
) / 2 + pCur
;
1157 nCompVal
= pReqProps
[i
].compareTo( pMid
->Name
);
1167 pHandles
[i
] = pMid
->Handle
;
1171 else if( nCompVal
> 0 )
1187 } // end namespace cppu
1190 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */