Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / cppuhelper / source / propshlp.cxx
blob6d1549d68e96ca8891953a5faee7c255b0cb37f3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <osl/diagnose.h>
22 #include <cppuhelper/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>
29 #include <memory>
30 #include <sal/log.hxx>
32 using namespace osl;
33 using namespace com::sun::star::uno;
34 using namespace com::sun::star::beans;
35 using namespace com::sun::star::lang;
36 using namespace cppu;
38 using ::rtl::OUString;
40 namespace cppu {
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();
59 extern "C" {
61 static int compare_OUString_Property_Impl( const void *arg1, const void *arg2 )
62 SAL_THROW_EXTERN_C()
64 return static_cast<OUString const *>(arg1)->compareTo( static_cast<Property const *>(arg2)->Name );
69 /**
70 * The class which implements the PropertySetInfo interface.
73 class OPropertySetHelperInfo_Impl
74 : public WeakImplHelper< css::beans::XPropertySetInfo >
76 Sequence < Property > aInfos;
78 public:
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;
88 /**
89 * Create an object that implements XPropertySetInfo IPropertyArrayHelper.
91 OPropertySetHelperInfo_Impl::OPropertySetHelperInfo_Impl(
92 IPropertyArrayHelper & rHelper_ )
93 :aInfos( rHelper_.getProperties() )
97 /**
98 * Return the sequence of properties, which are provided through the constructor.
100 Sequence< Property > OPropertySetHelperInfo_Impl::getProperties()
102 return aInfos;
106 * Return the sequence of properties, which are provided through the constructor.
108 Property OPropertySetHelperInfo_Impl::getPropertyByName( const OUString & PropertyName )
110 Property * pR;
111 pR = static_cast<Property *>(bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(),
112 sizeof( Property ),
113 compare_OUString_Property_Impl ));
114 if( !pR ) {
115 throw UnknownPropertyException();
118 return *pR;
122 * Return the sequence of properties, which are provided through the constructor.
124 sal_Bool OPropertySetHelperInfo_Impl::hasPropertyByName( const OUString & PropertyName )
126 Property * pR;
127 pR = static_cast<Property *>(bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(),
128 sizeof( Property ),
129 compare_OUString_Property_Impl ));
130 return pR != nullptr;
134 // class PropertySetHelper_Impl
136 class OPropertySetHelper::Impl {
138 public:
139 Impl( bool i_bIgnoreRuntimeExceptionsWhileFiring,
140 IEventNotificationHook *i_pFireEvents
142 :m_bIgnoreRuntimeExceptionsWhileFiring( i_bIgnoreRuntimeExceptionsWhileFiring )
143 ,m_bFireEvents(true)
144 ,m_pFireEvents( i_pFireEvents )
148 bool m_bIgnoreRuntimeExceptionsWhileFiring;
149 bool m_bFireEvents;
150 class IEventNotificationHook * const m_pFireEvents;
152 std::vector< sal_Int32 > m_handles;
153 std::vector< Any > m_newValues;
154 std::vector< Any > m_oldValues;
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 ),
184 m_pReserved(
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()
202 delete m_pReserved;
204 OPropertySetHelper2::~OPropertySetHelper2()
208 // XInterface
209 Any OPropertySetHelper::queryInterface( const css::uno::Type & rType )
211 return ::cppu::queryInterface(
212 rType,
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() )
222 return cnd;
223 return OPropertySetHelper::queryInterface(rType);
227 * called from the derivee's XTypeProvider::getTypes implementation
229 css::uno::Sequence< css::uno::Type > OPropertySetHelper::getTypes()
231 return {
232 UnoType<css::beans::XPropertySet>::get(),
233 UnoType<css::beans::XMultiPropertySet>::get(),
234 UnoType<css::beans::XFastPropertySet>::get()};
237 // ComponentHelper
238 void OPropertySetHelper::disposing()
240 // Create an event with this as sender
241 Reference < XPropertySet > rSource( static_cast< XPropertySet * >(this), UNO_QUERY );
242 EventObject aEvt;
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 ) );
257 // XPropertySet
258 void OPropertySetHelper::setPropertyValue(
259 const OUString& rPropertyName, const Any& rValue )
261 // get the map table
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 );
269 // XPropertySet
270 Any OPropertySetHelper::getPropertyValue(
271 const OUString& rPropertyName )
273 // get the map table
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 );
281 // XPropertySet
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() )
295 // get the map table
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
310 return;
312 // add the change listener to the helper container
314 aBoundLC.addInterface( nHandle, rxListener );
316 else
317 // add the change listener to the helper container
318 rBHelper.aLC.addInterface(
319 getPropertyTypeIdentifier( ),
320 rxListener
326 // XPropertySet
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() )
338 // get the map table
339 IPropertyArrayHelper & rPH = getInfoHelper();
340 // map the name to the handle
341 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
342 if( nHandle == -1 )
343 // property not known throw exception
344 throw UnknownPropertyException();
345 aBoundLC.removeInterface( nHandle, rxListener );
347 else {
348 // remove the change listener to the helper container
349 rBHelper.aLC.removeInterface(
350 getPropertyTypeIdentifier( ),
351 rxListener
357 // XPropertySet
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() )
371 // get the map table
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
386 return;
388 // add the vetoable listener to the helper container
389 aVetoableLC.addInterface( nHandle, rxListener );
391 else
392 // add the vetoable listener to the helper container
393 rBHelper.aLC.addInterface(
394 getVetoableTypeIdentifier( ),
395 rxListener
400 // XPropertySet
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() )
412 // get the map table
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 );
423 else
424 // add the vetoable listener to the helper container
425 rBHelper.aLC.removeInterface(
426 getVetoableTypeIdentifier( ),
427 rxListener
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 ) )
440 // unknown property
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 );
449 if ( !bChanged )
450 return;
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 );
473 throw aWrapped;
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 );
482 // XFastPropertySet
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 ) ) {
491 // unknown property
492 throw UnknownPropertyException();
494 if( nAttributes & PropertyAttribute::READONLY )
495 throw PropertyVetoException();
497 Any aConvertedVal;
498 Any aOldVal;
500 // Will the property change?
501 bool bChanged;
503 MutexGuard aGuard( rBHelper.rMutex );
504 bChanged = convertFastPropertyValue( aConvertedVal, aOldVal, nHandle, rValue );
505 // release guard to fire events
507 if( bChanged )
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;
537 throw aWrap;
540 // release guard to fire events
542 // file a change event, if the value changed
543 impl_fireAll( &nHandle, &rValue, &aOldVal, 1 );
547 // XFastPropertySet
548 Any OPropertySetHelper::getFastPropertyValue( sal_Int32 nHandle )
551 IPropertyArrayHelper & rInfo = getInfoHelper();
552 if( !rInfo.fillPropertyMembersByHandle( nullptr, nullptr, nHandle ) )
553 // unknown property
554 throw UnknownPropertyException();
556 Any aRet;
557 MutexGuard aGuard( rBHelper.rMutex );
558 getFastPropertyValue( aRet, nHandle );
559 return aRet;
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() )
568 aGuard.clear();
569 fire( i_handles, i_newValues, i_oldValues, i_count, false );
570 return;
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();
594 aGuard.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
605 sal_Bool bVetoable
608 if (! m_pReserved->m_bFireEvents)
609 return;
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
618 if( nHandles )
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 );
624 sal_Int32 i;
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;
633 OUString aPropName;
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];
646 nChangesLen++;
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 );
660 else
661 pLC = aBoundLC.getContainer( pEvts[i].PropertyHandle );
662 if( pLC )
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(
676 pEvts[i] );
678 else
680 static_cast<XPropertyChangeListener *>(pL)->propertyChange(
681 pEvts[i] );
684 catch (DisposedException & exc)
686 OSL_ENSURE( exc.Context.is(),
687 "DisposedException without Context!" );
688 if (exc.Context == pL)
689 aIt.remove();
690 else
691 throw;
694 catch (RuntimeException & exc)
696 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
697 if (! bIgnoreRuntimeExceptionsWhileFiring)
698 throw;
702 // broadcast to all listeners with "" property name
703 if( bVetoable ){
704 // fire change Events?
705 pLC = rBHelper.aLC.getContainer(
706 getVetoableTypeIdentifier()
709 else {
710 pLC = rBHelper.aLC.getContainer(
711 getPropertyTypeIdentifier( )
714 if( pLC )
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(
728 pEvts[i] );
730 else
732 static_cast<XPropertyChangeListener *>(pL)->propertyChange(
733 pEvts[i] );
736 catch (DisposedException & exc)
738 OSL_ENSURE( exc.Context.is(),
739 "DisposedException without Context!" );
740 if (exc.Context == pL)
741 aIt.remove();
742 else
743 throw;
746 catch (RuntimeException & exc)
748 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
749 if (! bIgnoreRuntimeExceptionsWhileFiring)
750 throw;
756 // reduce array to changed properties
757 aEvts.realloc( nChangesLen );
759 if( !bVetoable )
761 OInterfaceContainerHelper * pCont = nullptr;
762 pCont = rBHelper.aLC.getContainer(
763 getPropertiesTypeIdentifier( )
765 if( pCont )
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)
786 aIt.remove();
787 else
788 throw;
791 catch (RuntimeException & exc)
793 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
794 if (! bIgnoreRuntimeExceptionsWhileFiring)
795 throw;
803 // OPropertySetHelper
804 void OPropertySetHelper::setFastPropertyValues(
805 sal_Int32 nSeqLen,
806 sal_Int32 * pHandles,
807 const Any * pValues,
808 sal_Int32 nHitCount )
810 OSL_ENSURE( !rBHelper.bInDispose, "do not getFastPropertyValue in the dispose call" );
811 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
813 // get the map table
814 IPropertyArrayHelper & rPH = getInfoHelper();
816 std::unique_ptr<Any[]> pConvertedValues(new Any[ nHitCount ]);
817 std::unique_ptr<Any[]> pOldValues(new Any[ nHitCount ]);
818 sal_Int32 n = 0;
819 sal_Int32 i;
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];
839 n++;
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 );
865 // XMultiPropertySet
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 ]);
876 // get the map table
877 IPropertyArrayHelper & rPH = getInfoHelper();
878 // fill the handle array
879 sal_Int32 nHitCount = rPH.fillHandles( pHandles.get(), rPropertyNames );
880 if( nHitCount != 0 )
881 setFastPropertyValues( nSeqLen, pHandles.get(), rValues.getConstArray(), nHitCount );
884 // XMultiPropertySet
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 );
891 // get the map table
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] );
903 return aValues;
906 // XMultiPropertySet
907 void OPropertySetHelper::addPropertiesChangeListener(
908 const Sequence<OUString> & ,
909 const Reference < XPropertiesChangeListener > & rListener )
911 rBHelper.addListener( cppu::UnoType<decltype(rListener)>::get(), rListener );
914 // XMultiPropertySet
915 void OPropertySetHelper::removePropertiesChangeListener(
916 const Reference < XPropertiesChangeListener > & rListener )
918 rBHelper.removeListener( cppu::UnoType<decltype(rListener)>::get(), rListener );
921 // XMultiPropertySet
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;
934 sal_Int32 i;
935 for( i = 0; i < nLen; i++ )
936 if( pHandles[i] != -1 )
937 nFireLen++;
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;
956 nFirePos++;
959 // release guard to fire events
961 if( nFireLen )
962 rListener->propertiesChange( aChanges );
965 void OPropertySetHelper2::enableChangeListenerNotification( sal_Bool bEnable )
967 m_pReserved->m_bFireEvents = bEnable;
970 extern "C" {
972 static int compare_Property_Impl( const void *arg1, const void *arg2 )
973 SAL_THROW_EXTERN_C()
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 )
989 if (bSorted) {
990 OSL_FAIL( "Property array is not sorted" );
992 // not sorted
993 qsort( aInfos.getArray(), nElements, sizeof( Property ),
994 compare_Property_Impl );
995 break;
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 )
1002 return;
1003 // The handle is the index
1004 bRightOrdered = true;
1007 OPropertyArrayHelper::OPropertyArrayHelper(
1008 Property * pProps,
1009 sal_Int32 nEle,
1010 sal_Bool bSorted )
1011 : m_pReserved(nullptr)
1012 , aInfos(pProps, nEle)
1013 , bRightOrdered( false )
1015 init( bSorted );
1018 OPropertyArrayHelper::OPropertyArrayHelper(
1019 const Sequence< Property > & aProps,
1020 sal_Bool bSorted )
1021 : m_pReserved(nullptr)
1022 , aInfos(aProps)
1023 , bRightOrdered( false )
1025 init( bSorted );
1029 sal_Int32 OPropertyArrayHelper::getCount() const
1031 return aInfos.getLength();
1035 sal_Bool OPropertyArrayHelper::fillPropertyMembersByHandle
1037 OUString * pPropName,
1038 sal_Int16 * pAttributes,
1039 sal_Int32 nHandle
1042 const Property* pProperties = aInfos.getConstArray();
1043 sal_Int32 nElements = aInfos.getLength();
1045 if( bRightOrdered )
1047 if( nHandle < 0 || nHandle >= nElements )
1048 return false;
1049 if( pPropName )
1050 *pPropName = pProperties[ nHandle ].Name;
1051 if( pAttributes )
1052 *pAttributes = pProperties[ nHandle ].Attributes;
1053 return true;
1055 // normally the array is sorted
1056 for( sal_Int32 i = 0; i < nElements; i++ )
1058 if( pProperties[i].Handle == nHandle )
1060 if( pPropName )
1061 *pPropName = pProperties[ i ].Name;
1062 if( pAttributes )
1063 *pAttributes = pProperties[ i ].Attributes;
1064 return true;
1067 return false;
1071 Sequence< Property > OPropertyArrayHelper::getProperties()
1073 return aInfos;
1077 Property OPropertyArrayHelper::getPropertyByName(const OUString& aPropertyName)
1079 Property * pR;
1080 pR = static_cast<Property *>(bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(),
1081 sizeof( Property ),
1082 compare_OUString_Property_Impl ));
1083 if( !pR ) {
1084 throw UnknownPropertyException();
1086 return *pR;
1090 sal_Bool OPropertyArrayHelper::hasPropertyByName(const OUString& aPropertyName)
1092 Property * pR;
1093 pR = static_cast<Property *>(bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(),
1094 sizeof( Property ),
1095 compare_OUString_Property_Impl ));
1096 return pR != nullptr;
1100 sal_Int32 OPropertyArrayHelper::getHandleByName( const OUString & rPropName )
1102 Property * pR;
1103 pR = static_cast<Property *>(bsearch( &rPropName, aInfos.getConstArray(), aInfos.getLength(),
1104 sizeof( Property ),
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);
1122 sal_Int32 nLog = 0;
1123 while( n )
1125 nLog += 1;
1126 n = n >> 1;
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 )
1136 pCur++;
1138 if( pCur < pEnd && pReqProps[i] == pCur->Name )
1140 pHandles[i] = pCur->Handle;
1141 nHitCount++;
1143 else
1144 pHandles[i] = -1;
1146 else
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 );
1159 if( nCompVal > 0 )
1160 pCur = pMid + 1;
1161 else
1162 pEnd = pMid - 1;
1165 if( nCompVal == 0 )
1167 pHandles[i] = pMid->Handle;
1168 nHitCount++;
1169 pCur = pMid +1;
1171 else if( nCompVal > 0 )
1173 pHandles[i] = -1;
1174 pCur = pMid +1;
1176 else
1178 pHandles[i] = -1;
1179 pCur = pMid;
1181 pEnd = pOldEnd;
1184 return nHitCount;
1187 } // end namespace cppu
1190 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */