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/propshlp.hxx>
25 #include <cppuhelper/exc_hlp.hxx>
26 #include <com/sun/star/beans/PropertyAttribute.hpp>
27 #include <com/sun/star/lang/DisposedException.hpp>
29 #include <sal/log.hxx>
32 using namespace com::sun::star::uno
;
33 using namespace com::sun::star::beans
;
34 using namespace com::sun::star::lang
;
39 IPropertyArrayHelper::~IPropertyArrayHelper()
43 static const css::uno::Type
& getPropertyTypeIdentifier( )
45 return cppu::UnoType
<XPropertyChangeListener
>::get();
47 static const css::uno::Type
& getPropertiesTypeIdentifier()
49 return cppu::UnoType
<XPropertiesChangeListener
>::get();
51 static const css::uno::Type
& getVetoableTypeIdentifier()
53 return cppu::UnoType
<XVetoableChangeListener
>::get();
58 static int compare_OUString_Property_Impl( const void *arg1
, const void *arg2
)
61 return static_cast<OUString
const *>(arg1
)->compareTo( static_cast<Property
const *>(arg2
)->Name
);
67 * The class which implements the PropertySetInfo interface.
70 class OPropertySetHelperInfo_Impl
71 : public WeakImplHelper
< css::beans::XPropertySetInfo
>
73 Sequence
< Property
> aInfos
;
76 explicit OPropertySetHelperInfo_Impl( IPropertyArrayHelper
& rHelper_
);
78 // XPropertySetInfo-methods
79 virtual Sequence
< Property
> SAL_CALL
getProperties() override
;
80 virtual Property SAL_CALL
getPropertyByName(const OUString
& PropertyName
) override
;
81 virtual sal_Bool SAL_CALL
hasPropertyByName(const OUString
& PropertyName
) override
;
86 * Create an object that implements XPropertySetInfo IPropertyArrayHelper.
88 OPropertySetHelperInfo_Impl::OPropertySetHelperInfo_Impl(
89 IPropertyArrayHelper
& rHelper_
)
90 :aInfos( rHelper_
.getProperties() )
95 * Return the sequence of properties, which are provided through the constructor.
97 Sequence
< Property
> OPropertySetHelperInfo_Impl::getProperties()
103 * Return the sequence of properties, which are provided through the constructor.
105 Property
OPropertySetHelperInfo_Impl::getPropertyByName( const OUString
& PropertyName
)
108 pR
= static_cast<Property
*>(bsearch( &PropertyName
, aInfos
.getConstArray(), aInfos
.getLength(),
110 compare_OUString_Property_Impl
));
112 throw UnknownPropertyException(PropertyName
);
119 * Return the sequence of properties, which are provided through the constructor.
121 sal_Bool
OPropertySetHelperInfo_Impl::hasPropertyByName( const OUString
& PropertyName
)
124 pR
= static_cast<Property
*>(bsearch( &PropertyName
, aInfos
.getConstArray(), aInfos
.getLength(),
126 compare_OUString_Property_Impl
));
127 return pR
!= nullptr;
131 // class PropertySetHelper_Impl
133 class OPropertySetHelper::Impl
{
136 Impl( bool i_bIgnoreRuntimeExceptionsWhileFiring
,
137 IEventNotificationHook
*i_pFireEvents
139 :m_bIgnoreRuntimeExceptionsWhileFiring( i_bIgnoreRuntimeExceptionsWhileFiring
)
141 ,m_pFireEvents( i_pFireEvents
)
145 bool m_bIgnoreRuntimeExceptionsWhileFiring
;
147 class IEventNotificationHook
* const m_pFireEvents
;
149 std::vector
< sal_Int32
> m_handles
;
150 std::vector
< Any
> m_newValues
;
151 std::vector
< Any
> m_oldValues
;
155 // class PropertySetHelper
157 OPropertySetHelper::OPropertySetHelper(
158 OBroadcastHelper
& rBHelper_
)
159 : rBHelper( rBHelper_
),
160 aBoundLC( rBHelper_
.rMutex
),
161 aVetoableLC( rBHelper_
.rMutex
),
162 m_pReserved( new Impl(false, nullptr) )
166 OPropertySetHelper::OPropertySetHelper(
167 OBroadcastHelper
& rBHelper_
, bool bIgnoreRuntimeExceptionsWhileFiring
)
168 : rBHelper( rBHelper_
),
169 aBoundLC( rBHelper_
.rMutex
),
170 aVetoableLC( rBHelper_
.rMutex
),
171 m_pReserved( new Impl( bIgnoreRuntimeExceptionsWhileFiring
, nullptr ) )
175 OPropertySetHelper::OPropertySetHelper(
176 OBroadcastHelper
& rBHelper_
, IEventNotificationHook
* i_pFireEvents
,
177 bool bIgnoreRuntimeExceptionsWhileFiring
)
178 : rBHelper( rBHelper_
),
179 aBoundLC( rBHelper_
.rMutex
),
180 aVetoableLC( rBHelper_
.rMutex
),
182 new Impl( bIgnoreRuntimeExceptionsWhileFiring
, i_pFireEvents
) )
186 OPropertySetHelper2::OPropertySetHelper2(
187 OBroadcastHelper
& irBHelper
,
188 IEventNotificationHook
*i_pFireEvents
,
189 bool bIgnoreRuntimeExceptionsWhileFiring
)
190 :OPropertySetHelper( irBHelper
, i_pFireEvents
, bIgnoreRuntimeExceptionsWhileFiring
)
195 * You must call disposing before.
197 OPropertySetHelper::~OPropertySetHelper()
201 OPropertySetHelper2::~OPropertySetHelper2()
206 Any
OPropertySetHelper::queryInterface( const css::uno::Type
& rType
)
208 return ::cppu::queryInterface(
210 static_cast< XPropertySet
* >( this ),
211 static_cast< XMultiPropertySet
* >( this ),
212 static_cast< XFastPropertySet
* >( this ) );
215 Any
OPropertySetHelper2::queryInterface( const css::uno::Type
& rType
)
217 Any
cnd(cppu::queryInterface(rType
, static_cast< XPropertySetOption
* >(this)));
218 if ( cnd
.hasValue() )
220 return OPropertySetHelper::queryInterface(rType
);
224 * called from the derivee's XTypeProvider::getTypes implementation
226 css::uno::Sequence
< css::uno::Type
> OPropertySetHelper::getTypes()
229 UnoType
<css::beans::XPropertySet
>::get(),
230 UnoType
<css::beans::XMultiPropertySet
>::get(),
231 UnoType
<css::beans::XFastPropertySet
>::get()};
235 void OPropertySetHelper::disposing()
237 // Create an event with this as sender
238 Reference
< XPropertySet
> rSource
= this;
240 aEvt
.Source
= rSource
;
242 // inform all listeners to release this object
243 // The listener containers are automatically cleared
244 aBoundLC
.disposeAndClear( aEvt
);
245 aVetoableLC
.disposeAndClear( aEvt
);
248 Reference
< XPropertySetInfo
> OPropertySetHelper::createPropertySetInfo(
249 IPropertyArrayHelper
& rProperties
)
251 return new OPropertySetHelperInfo_Impl(rProperties
);
255 void OPropertySetHelper::setPropertyValue(
256 const OUString
& rPropertyName
, const Any
& rValue
)
259 IPropertyArrayHelper
& rPH
= getInfoHelper();
260 // map the name to the handle
261 sal_Int32 nHandle
= rPH
.getHandleByName( rPropertyName
);
262 // call the method of the XFastPropertySet interface
263 setFastPropertyValue( nHandle
, rValue
);
267 Any
OPropertySetHelper::getPropertyValue(
268 const OUString
& rPropertyName
)
271 IPropertyArrayHelper
& rPH
= getInfoHelper();
272 // map the name to the handle
273 sal_Int32 nHandle
= rPH
.getHandleByName( rPropertyName
);
274 // call the method of the XFastPropertySet interface
275 return getFastPropertyValue( nHandle
);
279 void OPropertySetHelper::addPropertyChangeListener(
280 const OUString
& rPropertyName
,
281 const Reference
< XPropertyChangeListener
> & rxListener
)
283 MutexGuard
aGuard( rBHelper
.rMutex
);
284 OSL_ENSURE( !rBHelper
.bInDispose
, "do not addPropertyChangeListener in the dispose call" );
285 OSL_ENSURE( !rBHelper
.bDisposed
, "object is disposed" );
286 if( !rBHelper
.bInDispose
&& !rBHelper
.bDisposed
)
288 // only add listeners if you are not disposed
289 // a listener with no name means all properties
290 if( !rPropertyName
.isEmpty() )
293 IPropertyArrayHelper
& rPH
= getInfoHelper();
294 // map the name to the handle
295 sal_Int32 nHandle
= rPH
.getHandleByName( rPropertyName
);
296 if( nHandle
== -1 ) {
297 // property not known throw exception
298 throw UnknownPropertyException(rPropertyName
);
301 sal_Int16 nAttributes
;
302 rPH
.fillPropertyMembersByHandle( nullptr, &nAttributes
, nHandle
);
303 if( !(nAttributes
& css::beans::PropertyAttribute::BOUND
) )
305 OSL_FAIL( "add listener to an unbound property" );
306 // silent ignore this
309 // add the change listener to the helper container
311 aBoundLC
.addInterface( nHandle
, rxListener
);
314 // add the change listener to the helper container
315 rBHelper
.aLC
.addInterface(
316 getPropertyTypeIdentifier( ),
324 void OPropertySetHelper::removePropertyChangeListener(
325 const OUString
& rPropertyName
,
326 const Reference
< XPropertyChangeListener
>& rxListener
)
328 MutexGuard
aGuard( rBHelper
.rMutex
);
329 OSL_ENSURE( !rBHelper
.bDisposed
, "object is disposed" );
330 // all listeners are automatically released in a dispose call
331 if( !rBHelper
.bInDispose
&& !rBHelper
.bDisposed
)
333 if( !rPropertyName
.isEmpty() )
336 IPropertyArrayHelper
& rPH
= getInfoHelper();
337 // map the name to the handle
338 sal_Int32 nHandle
= rPH
.getHandleByName( rPropertyName
);
340 // property not known throw exception
341 throw UnknownPropertyException(rPropertyName
);
342 aBoundLC
.removeInterface( nHandle
, rxListener
);
345 // remove the change listener to the helper container
346 rBHelper
.aLC
.removeInterface(
347 getPropertyTypeIdentifier( ),
355 void OPropertySetHelper::addVetoableChangeListener(
356 const OUString
& rPropertyName
,
357 const Reference
< XVetoableChangeListener
> & rxListener
)
359 MutexGuard
aGuard( rBHelper
.rMutex
);
360 OSL_ENSURE( !rBHelper
.bInDispose
, "do not addVetoableChangeListener in the dispose call" );
361 OSL_ENSURE( !rBHelper
.bDisposed
, "object is disposed" );
362 if( !rBHelper
.bInDispose
&& !rBHelper
.bDisposed
)
364 // only add listeners if you are not disposed
365 // a listener with no name means all properties
366 if( !rPropertyName
.isEmpty() )
369 IPropertyArrayHelper
& rPH
= getInfoHelper();
370 // map the name to the handle
371 sal_Int32 nHandle
= rPH
.getHandleByName( rPropertyName
);
372 if( nHandle
== -1 ) {
373 // property not known throw exception
374 throw UnknownPropertyException(rPropertyName
);
377 sal_Int16 nAttributes
;
378 rPH
.fillPropertyMembersByHandle( nullptr, &nAttributes
, nHandle
);
379 if( !(nAttributes
& PropertyAttribute::CONSTRAINED
) )
381 OSL_FAIL( "addVetoableChangeListener, and property is not constrained" );
382 // silent ignore this
385 // add the vetoable listener to the helper container
386 aVetoableLC
.addInterface( nHandle
, rxListener
);
389 // add the vetoable listener to the helper container
390 rBHelper
.aLC
.addInterface(
391 getVetoableTypeIdentifier( ),
398 void OPropertySetHelper::removeVetoableChangeListener(
399 const OUString
& rPropertyName
,
400 const Reference
< XVetoableChangeListener
> & rxListener
)
402 MutexGuard
aGuard( rBHelper
.rMutex
);
403 OSL_ENSURE( !rBHelper
.bDisposed
, "object is disposed" );
404 // all listeners are automatically released in a dispose call
405 if( !rBHelper
.bInDispose
&& !rBHelper
.bDisposed
)
407 if( !rPropertyName
.isEmpty() )
410 IPropertyArrayHelper
& rPH
= getInfoHelper();
411 // map the name to the handle
412 sal_Int32 nHandle
= rPH
.getHandleByName( rPropertyName
);
413 if( nHandle
== -1 ) {
414 // property not known throw exception
415 throw UnknownPropertyException(rPropertyName
);
417 // remove the vetoable listener to the helper container
418 aVetoableLC
.removeInterface( nHandle
, rxListener
);
421 // add the vetoable listener to the helper container
422 rBHelper
.aLC
.removeInterface(
423 getVetoableTypeIdentifier( ),
429 void OPropertySetHelper::setDependentFastPropertyValue( sal_Int32 i_handle
, const css::uno::Any
& i_value
)
431 //OSL_PRECOND( rBHelper.rMutex.isAcquired(), "OPropertySetHelper::setDependentFastPropertyValue: to be called with a locked mutex only!" );
432 // there is no such thing as Mutex.isAcquired, sadly ...
434 sal_Int16
nAttributes(0);
435 IPropertyArrayHelper
& rInfo
= getInfoHelper();
436 if ( !rInfo
.fillPropertyMembersByHandle( nullptr, &nAttributes
, i_handle
) )
438 throw UnknownPropertyException(OUString::number(i_handle
));
440 // no need to check for READONLY-ness of the property. The method is intended to be called internally, which
441 // implies it might be invoked for properties which are read-only to the instance's clients, but well allowed
442 // to change their value.
444 Any aConverted
, aOld
;
445 bool bChanged
= convertFastPropertyValue( aConverted
, aOld
, i_handle
, i_value
);
449 // don't fire vetoable events. This method is called with our mutex locked, so calling into listeners would not be
450 // a good idea. The caller is responsible for not invoking this for constrained properties.
451 OSL_ENSURE( ( nAttributes
& PropertyAttribute::CONSTRAINED
) == 0,
452 "OPropertySetHelper::setDependentFastPropertyValue: not to be used for constrained properties!" );
454 // actually set the new value
457 setFastPropertyValue_NoBroadcast( i_handle
, aConverted
);
459 catch (const UnknownPropertyException
& ) { throw; /* allowed to leave */ }
460 catch (const PropertyVetoException
& ) { throw; /* allowed to leave */ }
461 catch (const IllegalArgumentException
& ) { throw; /* allowed to leave */ }
462 catch (const WrappedTargetException
& ) { throw; /* allowed to leave */ }
463 catch (const RuntimeException
& ) { throw; /* allowed to leave */ }
464 catch (const Exception
& )
466 // not allowed to leave this method
467 WrappedTargetException aWrapped
;
468 aWrapped
.TargetException
= ::cppu::getCaughtException();
469 aWrapped
.Context
= static_cast< XPropertySet
* >( this );
473 // remember the handle/values, for the events to be fired later
474 m_pReserved
->m_handles
.push_back( i_handle
);
475 m_pReserved
->m_newValues
.push_back( aConverted
); // TODO: setFastPropertyValue notifies the unconverted value here ...?
476 m_pReserved
->m_oldValues
.push_back( aOld
);
480 void OPropertySetHelper::setFastPropertyValue( sal_Int32 nHandle
, const Any
& rValue
)
482 OSL_ENSURE( !rBHelper
.bInDispose
, "do not setFastPropertyValue in the dispose call" );
483 OSL_ENSURE( !rBHelper
.bDisposed
, "object is disposed" );
485 IPropertyArrayHelper
& rInfo
= getInfoHelper();
486 sal_Int16 nAttributes
;
487 if( !rInfo
.fillPropertyMembersByHandle( nullptr, &nAttributes
, nHandle
) ) {
489 throw UnknownPropertyException(OUString::number(nHandle
));
491 if( nAttributes
& PropertyAttribute::READONLY
)
492 throw PropertyVetoException();
497 // Will the property change?
500 MutexGuard
aGuard( rBHelper
.rMutex
);
501 bChanged
= convertFastPropertyValue( aConvertedVal
, aOldVal
, nHandle
, rValue
);
502 // release guard to fire events
506 // Is it a constrained property?
507 if( nAttributes
& PropertyAttribute::CONSTRAINED
)
509 // In aValue is the converted rValue
510 // fire a constrained event
511 // second parameter NULL means constrained
512 fire( &nHandle
, &rValue
, &aOldVal
, 1, true );
516 MutexGuard
aGuard( rBHelper
.rMutex
);
519 // set the property to the new value
520 setFastPropertyValue_NoBroadcast( nHandle
, aConvertedVal
);
522 catch (const css::beans::UnknownPropertyException
& ) { throw; /* allowed to leave */ }
523 catch (const css::beans::PropertyVetoException
& ) { throw; /* allowed to leave */ }
524 catch (const css::lang::IllegalArgumentException
& ) { throw; /* allowed to leave */ }
525 catch (const css::lang::WrappedTargetException
& ) { throw; /* allowed to leave */ }
526 catch (const css::uno::RuntimeException
& ) { throw; /* allowed to leave */ }
527 catch (const css::uno::Exception
& e
)
529 // not allowed to leave this method
530 css::lang::WrappedTargetException aWrap
;
531 aWrap
.Context
= static_cast< css::beans::XPropertySet
* >( this );
532 aWrap
.TargetException
<<= e
;
537 // release guard to fire events
539 // file a change event, if the value changed
540 impl_fireAll( &nHandle
, &rValue
, &aOldVal
, 1 );
545 Any
OPropertySetHelper::getFastPropertyValue( sal_Int32 nHandle
)
548 IPropertyArrayHelper
& rInfo
= getInfoHelper();
549 if( !rInfo
.fillPropertyMembersByHandle( nullptr, nullptr, nHandle
) )
551 throw UnknownPropertyException(OUString::number(nHandle
));
554 MutexGuard
aGuard( rBHelper
.rMutex
);
555 getFastPropertyValue( aRet
, nHandle
);
560 void OPropertySetHelper::impl_fireAll( sal_Int32
* i_handles
, const Any
* i_newValues
, const Any
* i_oldValues
, sal_Int32 i_count
)
562 ClearableMutexGuard
aGuard( rBHelper
.rMutex
);
563 if ( m_pReserved
->m_handles
.empty() )
566 fire( i_handles
, i_newValues
, i_oldValues
, i_count
, false );
570 const size_t additionalEvents
= m_pReserved
->m_handles
.size();
571 OSL_ENSURE( additionalEvents
== m_pReserved
->m_newValues
.size()
572 && additionalEvents
== m_pReserved
->m_oldValues
.size(),
573 "OPropertySetHelper::impl_fireAll: inconsistency!" );
575 std::vector
< sal_Int32
> allHandles( additionalEvents
+ i_count
);
576 std::copy( m_pReserved
->m_handles
.begin(), m_pReserved
->m_handles
.end(), allHandles
.begin() );
577 std::copy( i_handles
, i_handles
+ i_count
, allHandles
.begin() + additionalEvents
);
579 std::vector
< Any
> allNewValues( additionalEvents
+ i_count
);
580 std::copy( m_pReserved
->m_newValues
.begin(), m_pReserved
->m_newValues
.end(), allNewValues
.begin() );
581 std::copy( i_newValues
, i_newValues
+ i_count
, allNewValues
.begin() + additionalEvents
);
583 std::vector
< Any
> allOldValues( additionalEvents
+ i_count
);
584 std::copy( m_pReserved
->m_oldValues
.begin(), m_pReserved
->m_oldValues
.end(), allOldValues
.begin() );
585 std::copy( i_oldValues
, i_oldValues
+ i_count
, allOldValues
.begin() + additionalEvents
);
587 m_pReserved
->m_handles
.clear();
588 m_pReserved
->m_newValues
.clear();
589 m_pReserved
->m_oldValues
.clear();
592 fire( allHandles
.data(), allNewValues
.data(), allOldValues
.data(), additionalEvents
+ i_count
, false );
596 void OPropertySetHelper::fire
598 sal_Int32
* pnHandles
,
599 const Any
* pNewValues
,
600 const Any
* pOldValues
,
601 sal_Int32 nHandles
, // This is the Count of the array
605 if (! m_pReserved
->m_bFireEvents
)
608 if (m_pReserved
->m_pFireEvents
) {
609 m_pReserved
->m_pFireEvents
->fireEvents(
610 pnHandles
, nHandles
, bVetoable
,
611 m_pReserved
->m_bIgnoreRuntimeExceptionsWhileFiring
);
614 // Only fire, if one or more properties changed
617 // create the event sequence of all changed properties
618 Sequence
< PropertyChangeEvent
> aEvts( nHandles
);
619 PropertyChangeEvent
* pEvts
= aEvts
.getArray();
620 Reference
< XInterface
> xSource( static_cast<XPropertySet
*>(this), UNO_QUERY
);
622 sal_Int32 nChangesLen
= 0;
623 // Loop over all changed properties to fill the event struct
624 for( i
= 0; i
< nHandles
; i
++ )
626 // Vetoable fire and constrained attribute set or
627 // Change fire and Changed and bound attribute set
628 IPropertyArrayHelper
& rInfo
= getInfoHelper();
629 sal_Int16 nAttributes
;
631 rInfo
.fillPropertyMembersByHandle( &aPropName
, &nAttributes
, pnHandles
[i
] );
634 (bVetoable
&& (nAttributes
& PropertyAttribute::CONSTRAINED
)) ||
635 (!bVetoable
&& (nAttributes
& PropertyAttribute::BOUND
))
638 pEvts
[nChangesLen
].Source
= xSource
;
639 pEvts
[nChangesLen
].PropertyName
= aPropName
;
640 pEvts
[nChangesLen
].PropertyHandle
= pnHandles
[i
];
641 pEvts
[nChangesLen
].OldValue
= pOldValues
[i
];
642 pEvts
[nChangesLen
].NewValue
= pNewValues
[i
];
647 bool bIgnoreRuntimeExceptionsWhileFiring
=
648 m_pReserved
->m_bIgnoreRuntimeExceptionsWhileFiring
;
650 // fire the events for all changed properties
651 for( i
= 0; i
< nChangesLen
; i
++ )
653 // get the listener container for the property name
654 OInterfaceContainerHelper
* pLC
;
655 if( bVetoable
) // fire change Events?
656 pLC
= aVetoableLC
.getContainer( pEvts
[i
].PropertyHandle
);
658 pLC
= aBoundLC
.getContainer( pEvts
[i
].PropertyHandle
);
661 // Iterate over all listeners and send events
662 OInterfaceIteratorHelper
aIt( *pLC
);
663 while( aIt
.hasMoreElements() )
665 XInterface
* pL
= aIt
.next();
670 if( bVetoable
) // fire change Events?
672 static_cast<XVetoableChangeListener
*>(pL
)->vetoableChange(
677 static_cast<XPropertyChangeListener
*>(pL
)->propertyChange(
681 catch (DisposedException
& exc
)
683 OSL_ENSURE( exc
.Context
.is(),
684 "DisposedException without Context!" );
685 if (exc
.Context
== pL
)
691 catch (RuntimeException
& exc
)
693 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc
);
694 if (! bIgnoreRuntimeExceptionsWhileFiring
)
699 // broadcast to all listeners with "" property name
701 // fire change Events?
702 pLC
= rBHelper
.aLC
.getContainer(
703 getVetoableTypeIdentifier()
707 pLC
= rBHelper
.aLC
.getContainer(
708 getPropertyTypeIdentifier( )
713 // Iterate over all listeners and send events.
714 OInterfaceIteratorHelper
aIt( *pLC
);
715 while( aIt
.hasMoreElements() )
717 XInterface
* pL
= aIt
.next();
722 if( bVetoable
) // fire change Events?
724 static_cast<XVetoableChangeListener
*>(pL
)->vetoableChange(
729 static_cast<XPropertyChangeListener
*>(pL
)->propertyChange(
733 catch (DisposedException
& exc
)
735 OSL_ENSURE( exc
.Context
.is(),
736 "DisposedException without Context!" );
737 if (exc
.Context
== pL
)
743 catch (RuntimeException
& exc
)
745 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc
);
746 if (! bIgnoreRuntimeExceptionsWhileFiring
)
753 // reduce array to changed properties
754 aEvts
.realloc( nChangesLen
);
758 if (auto pCont
= rBHelper
.aLC
.getContainer(getPropertiesTypeIdentifier()))
760 // Here is a Bug, unbound properties are also fired
761 OInterfaceIteratorHelper
aIt( *pCont
);
762 while( aIt
.hasMoreElements() )
764 XPropertiesChangeListener
* pL
=
765 static_cast<XPropertiesChangeListener
*>(aIt
.next());
770 // fire the hole event sequence to the
771 // XPropertiesChangeListener's
772 pL
->propertiesChange( aEvts
);
774 catch (DisposedException
& exc
)
776 OSL_ENSURE( exc
.Context
.is(),
777 "DisposedException without Context!" );
778 if (exc
.Context
== pL
)
784 catch (RuntimeException
& exc
)
786 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc
);
787 if (! bIgnoreRuntimeExceptionsWhileFiring
)
796 // OPropertySetHelper
797 void OPropertySetHelper::setFastPropertyValues(
799 sal_Int32
* pHandles
,
801 sal_Int32 nHitCount
)
803 OSL_ENSURE( !rBHelper
.bInDispose
, "do not getFastPropertyValue in the dispose call" );
804 OSL_ENSURE( !rBHelper
.bDisposed
, "object is disposed" );
807 IPropertyArrayHelper
& rPH
= getInfoHelper();
809 std::unique_ptr
<Any
[]> pConvertedValues(new Any
[ nHitCount
]);
810 std::unique_ptr
<Any
[]> pOldValues(new Any
[ nHitCount
]);
815 // must lock the mutex outside the loop. So all values are consistent.
816 MutexGuard
aGuard( rBHelper
.rMutex
);
817 for( i
= 0; i
< nSeqLen
; i
++ )
819 if( pHandles
[i
] != -1 )
821 sal_Int16 nAttributes
;
822 rPH
.fillPropertyMembersByHandle( nullptr, &nAttributes
, pHandles
[i
] );
823 if( nAttributes
& PropertyAttribute::READONLY
) {
824 throw PropertyVetoException();
826 // Will the property change?
827 if( convertFastPropertyValue( pConvertedValues
[ n
], pOldValues
[n
],
828 pHandles
[i
], pValues
[i
] ) )
830 // only increment if the property really change
831 pHandles
[n
] = pHandles
[i
];
836 // release guard to fire events
839 // fire vetoable events
840 fire( pHandles
, pConvertedValues
.get(), pOldValues
.get(), n
, true );
843 // must lock the mutex outside the loop.
844 MutexGuard
aGuard( rBHelper
.rMutex
);
845 // Loop over all changed properties
846 for( i
= 0; i
< n
; i
++ )
848 // Will the property change?
849 setFastPropertyValue_NoBroadcast( pHandles
[i
], pConvertedValues
[i
] );
851 // release guard to fire events
854 // fire change events
855 impl_fireAll( pHandles
, pConvertedValues
.get(), pOldValues
.get(), n
);
860 * The sequence may be contain not known properties. The implementation
861 * must ignore these properties.
863 void OPropertySetHelper::setPropertyValues(
864 const Sequence
<OUString
>& rPropertyNames
,
865 const Sequence
<Any
>& rValues
)
867 sal_Int32 nSeqLen
= rPropertyNames
.getLength();
868 std::unique_ptr
<sal_Int32
[]> pHandles(new sal_Int32
[ nSeqLen
]);
870 IPropertyArrayHelper
& rPH
= getInfoHelper();
871 // fill the handle array
872 sal_Int32 nHitCount
= rPH
.fillHandles( pHandles
.get(), rPropertyNames
);
874 setFastPropertyValues( nSeqLen
, pHandles
.get(), rValues
.getConstArray(), nHitCount
);
878 Sequence
<Any
> OPropertySetHelper::getPropertyValues( const Sequence
<OUString
>& rPropertyNames
)
880 sal_Int32 nSeqLen
= rPropertyNames
.getLength();
881 std::unique_ptr
<sal_Int32
[]> pHandles(new sal_Int32
[ nSeqLen
]);
882 Sequence
< Any
> aValues( nSeqLen
);
885 IPropertyArrayHelper
& rPH
= getInfoHelper();
886 // fill the handle array
887 rPH
.fillHandles( pHandles
.get(), rPropertyNames
);
889 Any
* pValues
= aValues
.getArray();
891 MutexGuard
aGuard( rBHelper
.rMutex
);
892 // fill the sequence with the values
893 for( sal_Int32 i
= 0; i
< nSeqLen
; i
++ )
894 getFastPropertyValue( pValues
[i
], pHandles
[i
] );
900 void OPropertySetHelper::addPropertiesChangeListener(
901 const Sequence
<OUString
> & ,
902 const Reference
< XPropertiesChangeListener
> & rListener
)
904 rBHelper
.addListener( cppu::UnoType
<decltype(rListener
)>::get(), rListener
);
908 void OPropertySetHelper::removePropertiesChangeListener(
909 const Reference
< XPropertiesChangeListener
> & rListener
)
911 rBHelper
.removeListener( cppu::UnoType
<decltype(rListener
)>::get(), rListener
);
915 void OPropertySetHelper::firePropertiesChangeEvent(
916 const Sequence
<OUString
>& rPropertyNames
,
917 const Reference
< XPropertiesChangeListener
>& rListener
)
919 sal_Int32 nLen
= rPropertyNames
.getLength();
920 std::unique_ptr
<sal_Int32
[]> pHandles(new sal_Int32
[nLen
]);
921 IPropertyArrayHelper
& rPH
= getInfoHelper();
922 rPH
.fillHandles( pHandles
.get(), rPropertyNames
);
923 const OUString
* pNames
= rPropertyNames
.getConstArray();
925 // get the count of matching properties
926 sal_Int32 nFireLen
= 0;
928 for( i
= 0; i
< nLen
; i
++ )
929 if( pHandles
[i
] != -1 )
932 Sequence
<PropertyChangeEvent
> aChanges( nFireLen
);
933 PropertyChangeEvent
* pChanges
= aChanges
.getArray();
936 // must lock the mutex outside the loop. So all values are consistent.
937 MutexGuard
aGuard( rBHelper
.rMutex
);
938 Reference
< XInterface
> xSource( static_cast<XPropertySet
*>(this), UNO_QUERY
);
939 sal_Int32 nFirePos
= 0;
940 for( i
= 0; i
< nLen
; i
++ )
942 if( pHandles
[i
] != -1 )
944 pChanges
[nFirePos
].Source
= xSource
;
945 pChanges
[nFirePos
].PropertyName
= pNames
[i
];
946 pChanges
[nFirePos
].PropertyHandle
= pHandles
[i
];
947 getFastPropertyValue( pChanges
[nFirePos
].OldValue
, pHandles
[i
] );
948 pChanges
[nFirePos
].NewValue
= pChanges
[nFirePos
].OldValue
;
952 // release guard to fire events
955 rListener
->propertiesChange( aChanges
);
958 void OPropertySetHelper2::enableChangeListenerNotification( sal_Bool bEnable
)
960 m_pReserved
->m_bFireEvents
= bEnable
;
965 static int compare_Property_Impl( const void *arg1
, const void *arg2
)
968 return static_cast<Property
const *>(arg1
)->Name
.compareTo( static_cast<Property
const *>(arg2
)->Name
);
973 void OPropertyArrayHelper::init( sal_Bool bSorted
)
975 sal_Int32 i
, nElements
= aInfos
.getLength();
976 const Property
* pProperties
= aInfos
.getConstArray();
978 for( i
= 1; i
< nElements
; i
++ )
980 if( pProperties
[i
-1].Name
> pProperties
[i
].Name
)
983 OSL_FAIL( "Property array is not sorted" );
986 qsort( aInfos
.getArray(), nElements
, sizeof( Property
),
987 compare_Property_Impl
);
988 pProperties
= aInfos
.getConstArray();
992 for( i
= 0; i
< nElements
; i
++ )
993 if( pProperties
[i
].Handle
!= i
)
995 // The handle is the index
996 bRightOrdered
= true;
999 OPropertyArrayHelper::OPropertyArrayHelper(
1003 : m_pReserved(nullptr)
1004 , aInfos(pProps
, nEle
)
1005 , bRightOrdered( false )
1010 OPropertyArrayHelper::OPropertyArrayHelper(
1011 const Sequence
< Property
> & aProps
,
1013 : m_pReserved(nullptr)
1015 , bRightOrdered( false )
1021 sal_Int32
OPropertyArrayHelper::getCount() const
1023 return aInfos
.getLength();
1027 sal_Bool
OPropertyArrayHelper::fillPropertyMembersByHandle
1029 OUString
* pPropName
,
1030 sal_Int16
* pAttributes
,
1034 const Property
* pProperties
= aInfos
.getConstArray();
1035 sal_Int32 nElements
= aInfos
.getLength();
1039 if( nHandle
< 0 || nHandle
>= nElements
)
1042 *pPropName
= pProperties
[ nHandle
].Name
;
1044 *pAttributes
= pProperties
[ nHandle
].Attributes
;
1047 // normally the array is sorted
1048 for( sal_Int32 i
= 0; i
< nElements
; i
++ )
1050 if( pProperties
[i
].Handle
== nHandle
)
1053 *pPropName
= pProperties
[ i
].Name
;
1055 *pAttributes
= pProperties
[ i
].Attributes
;
1063 Sequence
< Property
> OPropertyArrayHelper::getProperties()
1069 Property
OPropertyArrayHelper::getPropertyByName(const OUString
& aPropertyName
)
1072 pR
= static_cast<Property
*>(bsearch( &aPropertyName
, aInfos
.getConstArray(), aInfos
.getLength(),
1074 compare_OUString_Property_Impl
));
1076 throw UnknownPropertyException(aPropertyName
);
1082 sal_Bool
OPropertyArrayHelper::hasPropertyByName(const OUString
& aPropertyName
)
1085 pR
= static_cast<Property
*>(bsearch( &aPropertyName
, aInfos
.getConstArray(), aInfos
.getLength(),
1087 compare_OUString_Property_Impl
));
1088 return pR
!= nullptr;
1092 sal_Int32
OPropertyArrayHelper::getHandleByName( const OUString
& rPropName
)
1095 pR
= static_cast<Property
*>(bsearch( &rPropName
, aInfos
.getConstArray(), aInfos
.getLength(),
1097 compare_OUString_Property_Impl
));
1098 return pR
? pR
->Handle
: -1;
1102 sal_Int32
OPropertyArrayHelper::fillHandles( sal_Int32
* pHandles
, const Sequence
< OUString
> & rPropNames
)
1104 sal_Int32 nHitCount
= 0;
1105 const OUString
* pReqProps
= rPropNames
.getConstArray();
1106 sal_Int32 nReqLen
= rPropNames
.getLength();
1107 const Property
* pCur
= aInfos
.getConstArray();
1108 const Property
* pEnd
= pCur
+ aInfos
.getLength();
1110 for( sal_Int32 i
= 0; i
< nReqLen
; i
++ )
1112 // Calculate logarithm
1113 sal_Int32 n
= static_cast<sal_Int32
>(pEnd
- pCur
);
1121 // Number of properties to search for * Log2 of the number of remaining
1122 // properties to search in.
1123 if( (nReqLen
- i
) * nLog
>= pEnd
- pCur
)
1125 // linear search is better
1126 while( pCur
< pEnd
&& pReqProps
[i
] > pCur
->Name
)
1130 if( pCur
< pEnd
&& pReqProps
[i
] == pCur
->Name
)
1132 pHandles
[i
] = pCur
->Handle
;
1140 // binary search is better
1141 sal_Int32 nCompVal
= 1;
1142 const Property
* pOldEnd
= pEnd
--;
1143 const Property
* pMid
= pCur
;
1145 while( nCompVal
!= 0 && pCur
<= pEnd
)
1147 pMid
= (pEnd
- pCur
) / 2 + pCur
;
1149 nCompVal
= pReqProps
[i
].compareTo( pMid
->Name
);
1159 pHandles
[i
] = pMid
->Handle
;
1163 else if( nCompVal
> 0 )
1179 } // end namespace cppu
1182 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */