Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / cppuhelper / source / propshlp.cxx
blob3f39522b008ce09b1f26f93fb631b071b54d7d14
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/propshlp.hxx>
25 #include <cppuhelper/exc_hlp.hxx>
26 #include <com/sun/star/beans/PropertyAttribute.hpp>
27 #include <com/sun/star/lang/DisposedException.hpp>
28 #include <memory>
29 #include <sal/log.hxx>
31 using namespace osl;
32 using namespace com::sun::star::uno;
33 using namespace com::sun::star::beans;
34 using namespace com::sun::star::lang;
35 using namespace cppu;
37 namespace cppu {
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();
56 extern "C" {
58 static int compare_OUString_Property_Impl( const void *arg1, const void *arg2 )
59 SAL_THROW_EXTERN_C()
61 return static_cast<OUString const *>(arg1)->compareTo( static_cast<Property const *>(arg2)->Name );
66 /**
67 * The class which implements the PropertySetInfo interface.
70 class OPropertySetHelperInfo_Impl
71 : public WeakImplHelper< css::beans::XPropertySetInfo >
73 Sequence < Property > aInfos;
75 public:
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;
85 /**
86 * Create an object that implements XPropertySetInfo IPropertyArrayHelper.
88 OPropertySetHelperInfo_Impl::OPropertySetHelperInfo_Impl(
89 IPropertyArrayHelper & rHelper_ )
90 :aInfos( rHelper_.getProperties() )
94 /**
95 * Return the sequence of properties, which are provided through the constructor.
97 Sequence< Property > OPropertySetHelperInfo_Impl::getProperties()
99 return aInfos;
103 * Return the sequence of properties, which are provided through the constructor.
105 Property OPropertySetHelperInfo_Impl::getPropertyByName( const OUString & PropertyName )
107 Property * pR;
108 pR = static_cast<Property *>(bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(),
109 sizeof( Property ),
110 compare_OUString_Property_Impl ));
111 if( !pR ) {
112 throw UnknownPropertyException(PropertyName);
115 return *pR;
119 * Return the sequence of properties, which are provided through the constructor.
121 sal_Bool OPropertySetHelperInfo_Impl::hasPropertyByName( const OUString & PropertyName )
123 Property * pR;
124 pR = static_cast<Property *>(bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(),
125 sizeof( Property ),
126 compare_OUString_Property_Impl ));
127 return pR != nullptr;
131 // class PropertySetHelper_Impl
133 class OPropertySetHelper::Impl {
135 public:
136 Impl( bool i_bIgnoreRuntimeExceptionsWhileFiring,
137 IEventNotificationHook *i_pFireEvents
139 :m_bIgnoreRuntimeExceptionsWhileFiring( i_bIgnoreRuntimeExceptionsWhileFiring )
140 ,m_bFireEvents(true)
141 ,m_pFireEvents( i_pFireEvents )
145 bool m_bIgnoreRuntimeExceptionsWhileFiring;
146 bool m_bFireEvents;
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 ),
181 m_pReserved(
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()
199 delete m_pReserved;
201 OPropertySetHelper2::~OPropertySetHelper2()
205 // XInterface
206 Any OPropertySetHelper::queryInterface( const css::uno::Type & rType )
208 return ::cppu::queryInterface(
209 rType,
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() )
219 return cnd;
220 return OPropertySetHelper::queryInterface(rType);
224 * called from the derivee's XTypeProvider::getTypes implementation
226 css::uno::Sequence< css::uno::Type > OPropertySetHelper::getTypes()
228 return {
229 UnoType<css::beans::XPropertySet>::get(),
230 UnoType<css::beans::XMultiPropertySet>::get(),
231 UnoType<css::beans::XFastPropertySet>::get()};
234 // ComponentHelper
235 void OPropertySetHelper::disposing()
237 // Create an event with this as sender
238 Reference < XPropertySet > rSource = this;
239 EventObject aEvt;
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);
254 // XPropertySet
255 void OPropertySetHelper::setPropertyValue(
256 const OUString& rPropertyName, const Any& rValue )
258 // get the map table
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 );
266 // XPropertySet
267 Any OPropertySetHelper::getPropertyValue(
268 const OUString& rPropertyName )
270 // get the map table
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 );
278 // XPropertySet
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() )
292 // get the map table
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
307 return;
309 // add the change listener to the helper container
311 aBoundLC.addInterface( nHandle, rxListener );
313 else
314 // add the change listener to the helper container
315 rBHelper.aLC.addInterface(
316 getPropertyTypeIdentifier( ),
317 rxListener
323 // XPropertySet
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() )
335 // get the map table
336 IPropertyArrayHelper & rPH = getInfoHelper();
337 // map the name to the handle
338 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
339 if( nHandle == -1 )
340 // property not known throw exception
341 throw UnknownPropertyException(rPropertyName);
342 aBoundLC.removeInterface( nHandle, rxListener );
344 else {
345 // remove the change listener to the helper container
346 rBHelper.aLC.removeInterface(
347 getPropertyTypeIdentifier( ),
348 rxListener
354 // XPropertySet
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() )
368 // get the map table
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
383 return;
385 // add the vetoable listener to the helper container
386 aVetoableLC.addInterface( nHandle, rxListener );
388 else
389 // add the vetoable listener to the helper container
390 rBHelper.aLC.addInterface(
391 getVetoableTypeIdentifier( ),
392 rxListener
397 // XPropertySet
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() )
409 // get the map table
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 );
420 else
421 // add the vetoable listener to the helper container
422 rBHelper.aLC.removeInterface(
423 getVetoableTypeIdentifier( ),
424 rxListener
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 ) )
437 // unknown property
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 );
446 if ( !bChanged )
447 return;
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 );
470 throw aWrapped;
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 );
479 // XFastPropertySet
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 ) ) {
488 // unknown property
489 throw UnknownPropertyException(OUString::number(nHandle));
491 if( nAttributes & PropertyAttribute::READONLY )
492 throw PropertyVetoException();
494 Any aConvertedVal;
495 Any aOldVal;
497 // Will the property change?
498 bool bChanged;
500 MutexGuard aGuard( rBHelper.rMutex );
501 bChanged = convertFastPropertyValue( aConvertedVal, aOldVal, nHandle, rValue );
502 // release guard to fire events
504 if( bChanged )
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;
534 throw aWrap;
537 // release guard to fire events
539 // file a change event, if the value changed
540 impl_fireAll( &nHandle, &rValue, &aOldVal, 1 );
544 // XFastPropertySet
545 Any OPropertySetHelper::getFastPropertyValue( sal_Int32 nHandle )
548 IPropertyArrayHelper & rInfo = getInfoHelper();
549 if( !rInfo.fillPropertyMembersByHandle( nullptr, nullptr, nHandle ) )
550 // unknown property
551 throw UnknownPropertyException(OUString::number(nHandle));
553 Any aRet;
554 MutexGuard aGuard( rBHelper.rMutex );
555 getFastPropertyValue( aRet, nHandle );
556 return aRet;
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() )
565 aGuard.clear();
566 fire( i_handles, i_newValues, i_oldValues, i_count, false );
567 return;
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();
591 aGuard.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
602 sal_Bool bVetoable
605 if (! m_pReserved->m_bFireEvents)
606 return;
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
615 if( nHandles )
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 );
621 sal_Int32 i;
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;
630 OUString aPropName;
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];
643 nChangesLen++;
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 );
657 else
658 pLC = aBoundLC.getContainer( pEvts[i].PropertyHandle );
659 if( pLC )
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(
673 pEvts[i] );
675 else
677 static_cast<XPropertyChangeListener *>(pL)->propertyChange(
678 pEvts[i] );
681 catch (DisposedException & exc)
683 OSL_ENSURE( exc.Context.is(),
684 "DisposedException without Context!" );
685 if (exc.Context == pL)
686 aIt.remove();
687 else
688 throw;
691 catch (RuntimeException & exc)
693 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
694 if (! bIgnoreRuntimeExceptionsWhileFiring)
695 throw;
699 // broadcast to all listeners with "" property name
700 if( bVetoable ){
701 // fire change Events?
702 pLC = rBHelper.aLC.getContainer(
703 getVetoableTypeIdentifier()
706 else {
707 pLC = rBHelper.aLC.getContainer(
708 getPropertyTypeIdentifier( )
711 if( pLC )
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(
725 pEvts[i] );
727 else
729 static_cast<XPropertyChangeListener *>(pL)->propertyChange(
730 pEvts[i] );
733 catch (DisposedException & exc)
735 OSL_ENSURE( exc.Context.is(),
736 "DisposedException without Context!" );
737 if (exc.Context == pL)
738 aIt.remove();
739 else
740 throw;
743 catch (RuntimeException & exc)
745 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
746 if (! bIgnoreRuntimeExceptionsWhileFiring)
747 throw;
753 // reduce array to changed properties
754 aEvts.realloc( nChangesLen );
756 if( !bVetoable )
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)
779 aIt.remove();
780 else
781 throw;
784 catch (RuntimeException & exc)
786 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
787 if (! bIgnoreRuntimeExceptionsWhileFiring)
788 throw;
796 // OPropertySetHelper
797 void OPropertySetHelper::setFastPropertyValues(
798 sal_Int32 nSeqLen,
799 sal_Int32 * pHandles,
800 const Any * pValues,
801 sal_Int32 nHitCount )
803 OSL_ENSURE( !rBHelper.bInDispose, "do not getFastPropertyValue in the dispose call" );
804 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
806 // get the map table
807 IPropertyArrayHelper & rPH = getInfoHelper();
809 std::unique_ptr<Any[]> pConvertedValues(new Any[ nHitCount ]);
810 std::unique_ptr<Any[]> pOldValues(new Any[ nHitCount ]);
811 sal_Int32 n = 0;
812 sal_Int32 i;
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];
832 n++;
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 );
858 // XMultiPropertySet
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 ]);
869 // get the map table
870 IPropertyArrayHelper & rPH = getInfoHelper();
871 // fill the handle array
872 sal_Int32 nHitCount = rPH.fillHandles( pHandles.get(), rPropertyNames );
873 if( nHitCount != 0 )
874 setFastPropertyValues( nSeqLen, pHandles.get(), rValues.getConstArray(), nHitCount );
877 // XMultiPropertySet
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 );
884 // get the map table
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] );
896 return aValues;
899 // XMultiPropertySet
900 void OPropertySetHelper::addPropertiesChangeListener(
901 const Sequence<OUString> & ,
902 const Reference < XPropertiesChangeListener > & rListener )
904 rBHelper.addListener( cppu::UnoType<decltype(rListener)>::get(), rListener );
907 // XMultiPropertySet
908 void OPropertySetHelper::removePropertiesChangeListener(
909 const Reference < XPropertiesChangeListener > & rListener )
911 rBHelper.removeListener( cppu::UnoType<decltype(rListener)>::get(), rListener );
914 // XMultiPropertySet
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;
927 sal_Int32 i;
928 for( i = 0; i < nLen; i++ )
929 if( pHandles[i] != -1 )
930 nFireLen++;
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;
949 nFirePos++;
952 // release guard to fire events
954 if( nFireLen )
955 rListener->propertiesChange( aChanges );
958 void OPropertySetHelper2::enableChangeListenerNotification( sal_Bool bEnable )
960 m_pReserved->m_bFireEvents = bEnable;
963 extern "C" {
965 static int compare_Property_Impl( const void *arg1, const void *arg2 )
966 SAL_THROW_EXTERN_C()
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 )
982 if (bSorted) {
983 OSL_FAIL( "Property array is not sorted" );
985 // not sorted
986 qsort( aInfos.getArray(), nElements, sizeof( Property ),
987 compare_Property_Impl );
988 pProperties = aInfos.getConstArray();
989 break;
992 for( i = 0; i < nElements; i++ )
993 if( pProperties[i].Handle != i )
994 return;
995 // The handle is the index
996 bRightOrdered = true;
999 OPropertyArrayHelper::OPropertyArrayHelper(
1000 Property * pProps,
1001 sal_Int32 nEle,
1002 sal_Bool bSorted )
1003 : m_pReserved(nullptr)
1004 , aInfos(pProps, nEle)
1005 , bRightOrdered( false )
1007 init( bSorted );
1010 OPropertyArrayHelper::OPropertyArrayHelper(
1011 const Sequence< Property > & aProps,
1012 sal_Bool bSorted )
1013 : m_pReserved(nullptr)
1014 , aInfos(aProps)
1015 , bRightOrdered( false )
1017 init( bSorted );
1021 sal_Int32 OPropertyArrayHelper::getCount() const
1023 return aInfos.getLength();
1027 sal_Bool OPropertyArrayHelper::fillPropertyMembersByHandle
1029 OUString * pPropName,
1030 sal_Int16 * pAttributes,
1031 sal_Int32 nHandle
1034 const Property* pProperties = aInfos.getConstArray();
1035 sal_Int32 nElements = aInfos.getLength();
1037 if( bRightOrdered )
1039 if( nHandle < 0 || nHandle >= nElements )
1040 return false;
1041 if( pPropName )
1042 *pPropName = pProperties[ nHandle ].Name;
1043 if( pAttributes )
1044 *pAttributes = pProperties[ nHandle ].Attributes;
1045 return true;
1047 // normally the array is sorted
1048 for( sal_Int32 i = 0; i < nElements; i++ )
1050 if( pProperties[i].Handle == nHandle )
1052 if( pPropName )
1053 *pPropName = pProperties[ i ].Name;
1054 if( pAttributes )
1055 *pAttributes = pProperties[ i ].Attributes;
1056 return true;
1059 return false;
1063 Sequence< Property > OPropertyArrayHelper::getProperties()
1065 return aInfos;
1069 Property OPropertyArrayHelper::getPropertyByName(const OUString& aPropertyName)
1071 Property * pR;
1072 pR = static_cast<Property *>(bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(),
1073 sizeof( Property ),
1074 compare_OUString_Property_Impl ));
1075 if( !pR ) {
1076 throw UnknownPropertyException(aPropertyName);
1078 return *pR;
1082 sal_Bool OPropertyArrayHelper::hasPropertyByName(const OUString& aPropertyName)
1084 Property * pR;
1085 pR = static_cast<Property *>(bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(),
1086 sizeof( Property ),
1087 compare_OUString_Property_Impl ));
1088 return pR != nullptr;
1092 sal_Int32 OPropertyArrayHelper::getHandleByName( const OUString & rPropName )
1094 Property * pR;
1095 pR = static_cast<Property *>(bsearch( &rPropName, aInfos.getConstArray(), aInfos.getLength(),
1096 sizeof( Property ),
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);
1114 sal_Int32 nLog = 0;
1115 while( n )
1117 nLog += 1;
1118 n = n >> 1;
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 )
1128 pCur++;
1130 if( pCur < pEnd && pReqProps[i] == pCur->Name )
1132 pHandles[i] = pCur->Handle;
1133 nHitCount++;
1135 else
1136 pHandles[i] = -1;
1138 else
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 );
1151 if( nCompVal > 0 )
1152 pCur = pMid + 1;
1153 else
1154 pEnd = pMid - 1;
1157 if( nCompVal == 0 )
1159 pHandles[i] = pMid->Handle;
1160 nHitCount++;
1161 pCur = pMid +1;
1163 else if( nCompVal > 0 )
1165 pHandles[i] = -1;
1166 pCur = pMid +1;
1168 else
1170 pHandles[i] = -1;
1171 pCur = pMid;
1173 pEnd = pOldEnd;
1176 return nHitCount;
1179 } // end namespace cppu
1182 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */