nss: makefile bitrot: no need for android spcial case anymore
[LibreOffice.git] / cppuhelper / source / propshlp.cxx
blob3af4cda49bb77683767c68200709e4ee68e0e817
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 namespace {
72 class OPropertySetHelperInfo_Impl
73 : public WeakImplHelper< css::beans::XPropertySetInfo >
75 Sequence < Property > aInfos;
77 public:
78 explicit OPropertySetHelperInfo_Impl( IPropertyArrayHelper & rHelper_ );
80 // XPropertySetInfo-methods
81 virtual Sequence< Property > SAL_CALL getProperties() override;
82 virtual Property SAL_CALL getPropertyByName(const OUString& PropertyName) override;
83 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(PropertyName);
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;
135 class OPropertySetHelper::Impl {
137 public:
138 Impl( bool i_bIgnoreRuntimeExceptionsWhileFiring,
139 IEventNotificationHook *i_pFireEvents
141 :m_bIgnoreRuntimeExceptionsWhileFiring( i_bIgnoreRuntimeExceptionsWhileFiring )
142 ,m_bFireEvents(true)
143 ,m_pFireEvents( i_pFireEvents )
147 bool m_bIgnoreRuntimeExceptionsWhileFiring;
148 bool m_bFireEvents;
149 class IEventNotificationHook * const m_pFireEvents;
151 std::vector< sal_Int32 > m_handles;
152 std::vector< Any > m_newValues;
153 std::vector< Any > m_oldValues;
158 OPropertySetHelper::OPropertySetHelper(
159 OBroadcastHelper & rBHelper_ )
160 : rBHelper( rBHelper_ ),
161 aBoundLC( rBHelper_.rMutex ),
162 aVetoableLC( rBHelper_.rMutex ),
163 m_pReserved( new Impl(false, nullptr) )
167 OPropertySetHelper::OPropertySetHelper(
168 OBroadcastHelper & rBHelper_, bool bIgnoreRuntimeExceptionsWhileFiring )
169 : rBHelper( rBHelper_ ),
170 aBoundLC( rBHelper_.rMutex ),
171 aVetoableLC( rBHelper_.rMutex ),
172 m_pReserved( new Impl( bIgnoreRuntimeExceptionsWhileFiring, nullptr ) )
176 OPropertySetHelper::OPropertySetHelper(
177 OBroadcastHelper & rBHelper_, IEventNotificationHook * i_pFireEvents,
178 bool bIgnoreRuntimeExceptionsWhileFiring)
179 : rBHelper( rBHelper_ ),
180 aBoundLC( rBHelper_.rMutex ),
181 aVetoableLC( rBHelper_.rMutex ),
182 m_pReserved(
183 new Impl( bIgnoreRuntimeExceptionsWhileFiring, i_pFireEvents) )
187 OPropertySetHelper2::OPropertySetHelper2(
188 OBroadcastHelper & irBHelper,
189 IEventNotificationHook *i_pFireEvents,
190 bool bIgnoreRuntimeExceptionsWhileFiring)
191 :OPropertySetHelper( irBHelper, i_pFireEvents, bIgnoreRuntimeExceptionsWhileFiring )
196 * You must call disposing before.
198 OPropertySetHelper::~OPropertySetHelper()
200 delete m_pReserved;
202 OPropertySetHelper2::~OPropertySetHelper2()
206 // XInterface
207 Any OPropertySetHelper::queryInterface( const css::uno::Type & rType )
209 return ::cppu::queryInterface(
210 rType,
211 static_cast< XPropertySet * >( this ),
212 static_cast< XMultiPropertySet * >( this ),
213 static_cast< XFastPropertySet * >( this ) );
216 Any OPropertySetHelper2::queryInterface( const css::uno::Type & rType )
218 Any cnd(cppu::queryInterface(rType, static_cast< XPropertySetOption * >(this)));
219 if ( cnd.hasValue() )
220 return cnd;
221 return OPropertySetHelper::queryInterface(rType);
225 * called from the derivee's XTypeProvider::getTypes implementation
227 css::uno::Sequence< css::uno::Type > OPropertySetHelper::getTypes()
229 return {
230 UnoType<css::beans::XPropertySet>::get(),
231 UnoType<css::beans::XMultiPropertySet>::get(),
232 UnoType<css::beans::XFastPropertySet>::get()};
235 // ComponentHelper
236 void OPropertySetHelper::disposing()
238 // Create an event with this as sender
239 Reference < XPropertySet > rSource = this;
240 EventObject aEvt;
241 aEvt.Source = rSource;
243 // inform all listeners to release this object
244 // The listener containers are automatically cleared
245 aBoundLC.disposeAndClear( aEvt );
246 aVetoableLC.disposeAndClear( aEvt );
249 Reference < XPropertySetInfo > OPropertySetHelper::createPropertySetInfo(
250 IPropertyArrayHelper & rProperties )
252 return new OPropertySetHelperInfo_Impl(rProperties);
255 // XPropertySet
256 void OPropertySetHelper::setPropertyValue(
257 const OUString& rPropertyName, const Any& rValue )
259 // get the map table
260 IPropertyArrayHelper & rPH = getInfoHelper();
261 // map the name to the handle
262 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
263 // call the method of the XFastPropertySet interface
264 setFastPropertyValue( nHandle, rValue );
267 // XPropertySet
268 Any OPropertySetHelper::getPropertyValue(
269 const OUString& rPropertyName )
271 // get the map table
272 IPropertyArrayHelper & rPH = getInfoHelper();
273 // map the name to the handle
274 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
275 // call the method of the XFastPropertySet interface
276 return getFastPropertyValue( nHandle );
279 // XPropertySet
280 void OPropertySetHelper::addPropertyChangeListener(
281 const OUString& rPropertyName,
282 const Reference < XPropertyChangeListener > & rxListener )
284 MutexGuard aGuard( rBHelper.rMutex );
285 OSL_ENSURE( !rBHelper.bInDispose, "do not addPropertyChangeListener in the dispose call" );
286 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
287 if( rBHelper.bInDispose || rBHelper.bDisposed )
288 return;
290 // only add listeners if you are not disposed
291 // a listener with no name means all properties
292 if( !rPropertyName.isEmpty() )
294 // get the map table
295 IPropertyArrayHelper & rPH = getInfoHelper();
296 // map the name to the handle
297 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
298 if( nHandle == -1 ) {
299 // property not known throw exception
300 throw UnknownPropertyException(rPropertyName);
303 sal_Int16 nAttributes;
304 rPH.fillPropertyMembersByHandle( nullptr, &nAttributes, nHandle );
305 if( !(nAttributes & css::beans::PropertyAttribute::BOUND) )
307 OSL_FAIL( "add listener to an unbound property" );
308 // silent ignore this
309 return;
311 // add the change listener to the helper container
313 aBoundLC.addInterface( nHandle, rxListener );
315 else
316 // add the change listener to the helper container
317 rBHelper.aLC.addInterface(
318 getPropertyTypeIdentifier( ),
319 rxListener
324 // XPropertySet
325 void OPropertySetHelper::removePropertyChangeListener(
326 const OUString& rPropertyName,
327 const Reference < XPropertyChangeListener >& rxListener )
329 MutexGuard aGuard( rBHelper.rMutex );
330 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
331 // all listeners are automatically released in a dispose call
332 if( rBHelper.bInDispose || rBHelper.bDisposed )
333 return;
335 if( !rPropertyName.isEmpty() )
337 // get the map table
338 IPropertyArrayHelper & rPH = getInfoHelper();
339 // map the name to the handle
340 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
341 if( nHandle == -1 )
342 // property not known throw exception
343 throw UnknownPropertyException(rPropertyName);
344 aBoundLC.removeInterface( nHandle, rxListener );
346 else {
347 // remove the change listener to the helper container
348 rBHelper.aLC.removeInterface(
349 getPropertyTypeIdentifier( ),
350 rxListener
355 // XPropertySet
356 void OPropertySetHelper::addVetoableChangeListener(
357 const OUString& rPropertyName,
358 const Reference< XVetoableChangeListener > & rxListener )
360 MutexGuard aGuard( rBHelper.rMutex );
361 OSL_ENSURE( !rBHelper.bInDispose, "do not addVetoableChangeListener in the dispose call" );
362 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
363 if( rBHelper.bInDispose || rBHelper.bDisposed )
364 return;
366 // only add listeners if you are not disposed
367 // a listener with no name means all properties
368 if( !rPropertyName.isEmpty() )
370 // get the map table
371 IPropertyArrayHelper & rPH = getInfoHelper();
372 // map the name to the handle
373 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
374 if( nHandle == -1 ) {
375 // property not known throw exception
376 throw UnknownPropertyException(rPropertyName);
379 sal_Int16 nAttributes;
380 rPH.fillPropertyMembersByHandle( nullptr, &nAttributes, nHandle );
381 if( !(nAttributes & PropertyAttribute::CONSTRAINED) )
383 OSL_FAIL( "addVetoableChangeListener, and property is not constrained" );
384 // silent ignore this
385 return;
387 // add the vetoable listener to the helper container
388 aVetoableLC.addInterface( nHandle, rxListener );
390 else
391 // add the vetoable listener to the helper container
392 rBHelper.aLC.addInterface(
393 getVetoableTypeIdentifier( ),
394 rxListener
398 // XPropertySet
399 void OPropertySetHelper::removeVetoableChangeListener(
400 const OUString& rPropertyName,
401 const Reference < XVetoableChangeListener > & rxListener )
403 MutexGuard aGuard( rBHelper.rMutex );
404 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
405 // all listeners are automatically released in a dispose call
406 if( rBHelper.bInDispose || rBHelper.bDisposed )
407 return;
409 if( !rPropertyName.isEmpty() )
411 // get the map table
412 IPropertyArrayHelper & rPH = getInfoHelper();
413 // map the name to the handle
414 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
415 if( nHandle == -1 ) {
416 // property not known throw exception
417 throw UnknownPropertyException(rPropertyName);
419 // remove the vetoable listener to the helper container
420 aVetoableLC.removeInterface( nHandle, rxListener );
422 else
423 // add the vetoable listener to the helper container
424 rBHelper.aLC.removeInterface(
425 getVetoableTypeIdentifier( ),
426 rxListener
430 void OPropertySetHelper::setDependentFastPropertyValue( sal_Int32 i_handle, const css::uno::Any& i_value )
432 //OSL_PRECOND( rBHelper.rMutex.isAcquired(), "OPropertySetHelper::setDependentFastPropertyValue: to be called with a locked mutex only!" );
433 // there is no such thing as Mutex.isAcquired, sadly ...
435 sal_Int16 nAttributes(0);
436 IPropertyArrayHelper& rInfo = getInfoHelper();
437 if ( !rInfo.fillPropertyMembersByHandle( nullptr, &nAttributes, i_handle ) )
438 // unknown property
439 throw UnknownPropertyException(OUString::number(i_handle));
441 // no need to check for READONLY-ness of the property. The method is intended to be called internally, which
442 // implies it might be invoked for properties which are read-only to the instance's clients, but well allowed
443 // to change their value.
445 Any aConverted, aOld;
446 bool bChanged = convertFastPropertyValue( aConverted, aOld, i_handle, i_value );
447 if ( !bChanged )
448 return;
450 // don't fire vetoable events. This method is called with our mutex locked, so calling into listeners would not be
451 // a good idea. The caller is responsible for not invoking this for constrained properties.
452 OSL_ENSURE( ( nAttributes & PropertyAttribute::CONSTRAINED ) == 0,
453 "OPropertySetHelper::setDependentFastPropertyValue: not to be used for constrained properties!" );
455 // actually set the new value
458 setFastPropertyValue_NoBroadcast( i_handle, aConverted );
460 catch (const UnknownPropertyException& ) { throw; /* allowed to leave */ }
461 catch (const PropertyVetoException& ) { throw; /* allowed to leave */ }
462 catch (const IllegalArgumentException& ) { throw; /* allowed to leave */ }
463 catch (const WrappedTargetException& ) { throw; /* allowed to leave */ }
464 catch (const RuntimeException& ) { throw; /* allowed to leave */ }
465 catch (const Exception& )
467 // not allowed to leave this method
468 WrappedTargetException aWrapped;
469 aWrapped.TargetException = ::cppu::getCaughtException();
470 aWrapped.Context = static_cast< XPropertySet* >( this );
471 throw aWrapped;
474 // remember the handle/values, for the events to be fired later
475 m_pReserved->m_handles.push_back( i_handle );
476 m_pReserved->m_newValues.push_back( aConverted ); // TODO: setFastPropertyValue notifies the unconverted value here ...?
477 m_pReserved->m_oldValues.push_back( aOld );
480 // XFastPropertySet
481 void OPropertySetHelper::setFastPropertyValue( sal_Int32 nHandle, const Any& rValue )
483 OSL_ENSURE( !rBHelper.bInDispose, "do not setFastPropertyValue in the dispose call" );
484 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
486 IPropertyArrayHelper & rInfo = getInfoHelper();
487 sal_Int16 nAttributes;
488 if( !rInfo.fillPropertyMembersByHandle( nullptr, &nAttributes, nHandle ) ) {
489 // unknown property
490 throw UnknownPropertyException(OUString::number(nHandle));
492 if( nAttributes & PropertyAttribute::READONLY )
493 throw PropertyVetoException();
495 Any aConvertedVal;
496 Any aOldVal;
498 // Will the property change?
499 bool bChanged;
501 MutexGuard aGuard( rBHelper.rMutex );
502 bChanged = convertFastPropertyValue( aConvertedVal, aOldVal, nHandle, rValue );
503 // release guard to fire events
505 if( !bChanged )
506 return;
508 // Is it a constrained property?
509 if( nAttributes & PropertyAttribute::CONSTRAINED )
511 // In aValue is the converted rValue
512 // fire a constrained event
513 // second parameter NULL means constrained
514 fire( &nHandle, &rValue, &aOldVal, 1, true );
518 MutexGuard aGuard( rBHelper.rMutex );
521 // set the property to the new value
522 setFastPropertyValue_NoBroadcast( nHandle, aConvertedVal );
524 catch (const css::beans::UnknownPropertyException& ) { throw; /* allowed to leave */ }
525 catch (const css::beans::PropertyVetoException& ) { throw; /* allowed to leave */ }
526 catch (const css::lang::IllegalArgumentException& ) { throw; /* allowed to leave */ }
527 catch (const css::lang::WrappedTargetException& ) { throw; /* allowed to leave */ }
528 catch (const css::uno::RuntimeException& ) { throw; /* allowed to leave */ }
529 catch (const css::uno::Exception& e )
531 // not allowed to leave this method
532 css::lang::WrappedTargetException aWrap;
533 aWrap.Context = static_cast< css::beans::XPropertySet* >( this );
534 aWrap.TargetException <<= e;
536 throw aWrap;
539 // release guard to fire events
541 // file a change event, if the value changed
542 impl_fireAll( &nHandle, &rValue, &aOldVal, 1 );
545 // XFastPropertySet
546 Any OPropertySetHelper::getFastPropertyValue( sal_Int32 nHandle )
549 IPropertyArrayHelper & rInfo = getInfoHelper();
550 if( !rInfo.fillPropertyMembersByHandle( nullptr, nullptr, nHandle ) )
551 // unknown property
552 throw UnknownPropertyException(OUString::number(nHandle));
554 Any aRet;
555 MutexGuard aGuard( rBHelper.rMutex );
556 getFastPropertyValue( aRet, nHandle );
557 return aRet;
561 void OPropertySetHelper::impl_fireAll( sal_Int32* i_handles, const Any* i_newValues, const Any* i_oldValues, sal_Int32 i_count )
563 ClearableMutexGuard aGuard( rBHelper.rMutex );
564 if ( m_pReserved->m_handles.empty() )
566 aGuard.clear();
567 fire( i_handles, i_newValues, i_oldValues, i_count, false );
568 return;
571 const size_t additionalEvents = m_pReserved->m_handles.size();
572 OSL_ENSURE( additionalEvents == m_pReserved->m_newValues.size()
573 && additionalEvents == m_pReserved->m_oldValues.size(),
574 "OPropertySetHelper::impl_fireAll: inconsistency!" );
576 std::vector< sal_Int32 > allHandles( additionalEvents + i_count );
577 std::copy( m_pReserved->m_handles.begin(), m_pReserved->m_handles.end(), allHandles.begin() );
578 std::copy( i_handles, i_handles + i_count, allHandles.begin() + additionalEvents );
580 std::vector< Any > allNewValues( additionalEvents + i_count );
581 std::copy( m_pReserved->m_newValues.begin(), m_pReserved->m_newValues.end(), allNewValues.begin() );
582 std::copy( i_newValues, i_newValues + i_count, allNewValues.begin() + additionalEvents );
584 std::vector< Any > allOldValues( additionalEvents + i_count );
585 std::copy( m_pReserved->m_oldValues.begin(), m_pReserved->m_oldValues.end(), allOldValues.begin() );
586 std::copy( i_oldValues, i_oldValues + i_count, allOldValues.begin() + additionalEvents );
588 m_pReserved->m_handles.clear();
589 m_pReserved->m_newValues.clear();
590 m_pReserved->m_oldValues.clear();
592 aGuard.clear();
593 fire( allHandles.data(), allNewValues.data(), allOldValues.data(), additionalEvents + i_count, false );
597 void OPropertySetHelper::fire
599 sal_Int32 * pnHandles,
600 const Any * pNewValues,
601 const Any * pOldValues,
602 sal_Int32 nHandles, // This is the Count of the array
603 sal_Bool bVetoable
606 if (! m_pReserved->m_bFireEvents)
607 return;
609 if (m_pReserved->m_pFireEvents) {
610 m_pReserved->m_pFireEvents->fireEvents(
611 pnHandles, nHandles, bVetoable,
612 m_pReserved->m_bIgnoreRuntimeExceptionsWhileFiring);
615 // Only fire, if one or more properties changed
616 if( !nHandles )
617 return;
619 // create the event sequence of all changed properties
620 Sequence< PropertyChangeEvent > aEvts( nHandles );
621 PropertyChangeEvent * pEvts = aEvts.getArray();
622 Reference < XInterface > xSource( static_cast<XPropertySet *>(this), UNO_QUERY );
623 sal_Int32 i;
624 sal_Int32 nChangesLen = 0;
625 // Loop over all changed properties to fill the event struct
626 for( i = 0; i < nHandles; i++ )
628 // Vetoable fire and constrained attribute set or
629 // Change fire and Changed and bound attribute set
630 IPropertyArrayHelper & rInfo = getInfoHelper();
631 sal_Int16 nAttributes;
632 OUString aPropName;
633 rInfo.fillPropertyMembersByHandle( &aPropName, &nAttributes, pnHandles[i] );
636 (bVetoable && (nAttributes & PropertyAttribute::CONSTRAINED)) ||
637 (!bVetoable && (nAttributes & PropertyAttribute::BOUND))
640 pEvts[nChangesLen].Source = xSource;
641 pEvts[nChangesLen].PropertyName = aPropName;
642 pEvts[nChangesLen].PropertyHandle = pnHandles[i];
643 pEvts[nChangesLen].OldValue = pOldValues[i];
644 pEvts[nChangesLen].NewValue = pNewValues[i];
645 nChangesLen++;
649 bool bIgnoreRuntimeExceptionsWhileFiring =
650 m_pReserved->m_bIgnoreRuntimeExceptionsWhileFiring;
652 // fire the events for all changed properties
653 for( i = 0; i < nChangesLen; i++ )
655 // get the listener container for the property name
656 OInterfaceContainerHelper * pLC;
657 if( bVetoable ) // fire change Events?
658 pLC = aVetoableLC.getContainer( pEvts[i].PropertyHandle );
659 else
660 pLC = aBoundLC.getContainer( pEvts[i].PropertyHandle );
661 if( pLC )
663 // Iterate over all listeners and send events
664 OInterfaceIteratorHelper aIt( *pLC);
665 while( aIt.hasMoreElements() )
667 XInterface * pL = aIt.next();
672 if( bVetoable ) // fire change Events?
674 static_cast<XVetoableChangeListener *>(pL)->vetoableChange(
675 pEvts[i] );
677 else
679 static_cast<XPropertyChangeListener *>(pL)->propertyChange(
680 pEvts[i] );
683 catch (DisposedException & exc)
685 OSL_ENSURE( exc.Context.is(),
686 "DisposedException without Context!" );
687 if (exc.Context == pL)
688 aIt.remove();
689 else
690 throw;
693 catch (RuntimeException & exc)
695 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
696 if (! bIgnoreRuntimeExceptionsWhileFiring)
697 throw;
701 // broadcast to all listeners with "" property name
702 if( bVetoable ){
703 // fire change Events?
704 pLC = rBHelper.aLC.getContainer(
705 getVetoableTypeIdentifier()
708 else {
709 pLC = rBHelper.aLC.getContainer(
710 getPropertyTypeIdentifier( )
713 if( pLC )
715 // Iterate over all listeners and send events.
716 OInterfaceIteratorHelper aIt( *pLC);
717 while( aIt.hasMoreElements() )
719 XInterface * pL = aIt.next();
724 if( bVetoable ) // fire change Events?
726 static_cast<XVetoableChangeListener *>(pL)->vetoableChange(
727 pEvts[i] );
729 else
731 static_cast<XPropertyChangeListener *>(pL)->propertyChange(
732 pEvts[i] );
735 catch (DisposedException & exc)
737 OSL_ENSURE( exc.Context.is(),
738 "DisposedException without Context!" );
739 if (exc.Context == pL)
740 aIt.remove();
741 else
742 throw;
745 catch (RuntimeException & exc)
747 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
748 if (! bIgnoreRuntimeExceptionsWhileFiring)
749 throw;
755 // reduce array to changed properties
756 aEvts.realloc( nChangesLen );
758 if( bVetoable )
759 return;
761 auto pCont = rBHelper.aLC.getContainer(getPropertiesTypeIdentifier());
762 if (!pCont)
763 return;
765 // Here is a Bug, unbound properties are also fired
766 OInterfaceIteratorHelper aIt( *pCont );
767 while( aIt.hasMoreElements() )
769 XPropertiesChangeListener * pL =
770 static_cast<XPropertiesChangeListener *>(aIt.next());
775 // fire the whole event sequence to the
776 // XPropertiesChangeListener's
777 pL->propertiesChange( aEvts );
779 catch (DisposedException & exc)
781 OSL_ENSURE( exc.Context.is(),
782 "DisposedException without Context!" );
783 if (exc.Context == pL)
784 aIt.remove();
785 else
786 throw;
789 catch (RuntimeException & exc)
791 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
792 if (! bIgnoreRuntimeExceptionsWhileFiring)
793 throw;
798 // OPropertySetHelper
799 void OPropertySetHelper::setFastPropertyValues(
800 sal_Int32 nSeqLen,
801 sal_Int32 * pHandles,
802 const Any * pValues,
803 sal_Int32 nHitCount )
805 OSL_ENSURE( !rBHelper.bInDispose, "do not getFastPropertyValue in the dispose call" );
806 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
808 // get the map table
809 IPropertyArrayHelper & rPH = getInfoHelper();
811 std::unique_ptr<Any[]> pConvertedValues(new Any[ nHitCount ]);
812 std::unique_ptr<Any[]> pOldValues(new Any[ nHitCount ]);
813 sal_Int32 n = 0;
814 sal_Int32 i;
817 // must lock the mutex outside the loop. So all values are consistent.
818 MutexGuard aGuard( rBHelper.rMutex );
819 for( i = 0; i < nSeqLen; i++ )
821 if( pHandles[i] != -1 )
823 sal_Int16 nAttributes;
824 rPH.fillPropertyMembersByHandle( nullptr, &nAttributes, pHandles[i] );
825 if( nAttributes & PropertyAttribute::READONLY ) {
826 throw PropertyVetoException();
828 // Will the property change?
829 if( convertFastPropertyValue( pConvertedValues[ n ], pOldValues[n],
830 pHandles[i], pValues[i] ) )
832 // only increment if the property really change
833 pHandles[n] = pHandles[i];
834 n++;
838 // release guard to fire events
841 // fire vetoable events
842 fire( pHandles, pConvertedValues.get(), pOldValues.get(), n, true );
845 // must lock the mutex outside the loop.
846 MutexGuard aGuard( rBHelper.rMutex );
847 // Loop over all changed properties
848 for( i = 0; i < n; i++ )
850 // Will the property change?
851 setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
853 // release guard to fire events
856 // fire change events
857 impl_fireAll( pHandles, pConvertedValues.get(), pOldValues.get(), n );
860 // XMultiPropertySet
862 * The sequence may be contain not known properties. The implementation
863 * must ignore these properties.
865 void OPropertySetHelper::setPropertyValues(
866 const Sequence<OUString>& rPropertyNames,
867 const Sequence<Any>& rValues )
869 sal_Int32 nSeqLen = rPropertyNames.getLength();
870 std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[ nSeqLen ]);
871 // get the map table
872 IPropertyArrayHelper & rPH = getInfoHelper();
873 // fill the handle array
874 sal_Int32 nHitCount = rPH.fillHandles( pHandles.get(), rPropertyNames );
875 if( nHitCount != 0 )
876 setFastPropertyValues( nSeqLen, pHandles.get(), rValues.getConstArray(), nHitCount );
879 // XMultiPropertySet
880 Sequence<Any> OPropertySetHelper::getPropertyValues( const Sequence<OUString>& rPropertyNames )
882 sal_Int32 nSeqLen = rPropertyNames.getLength();
883 std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[ nSeqLen ]);
884 Sequence< Any > aValues( nSeqLen );
886 // get the map table
887 IPropertyArrayHelper & rPH = getInfoHelper();
888 // fill the handle array
889 rPH.fillHandles( pHandles.get(), rPropertyNames );
891 Any * pValues = aValues.getArray();
893 MutexGuard aGuard( rBHelper.rMutex );
894 // fill the sequence with the values
895 for( sal_Int32 i = 0; i < nSeqLen; i++ )
896 getFastPropertyValue( pValues[i], pHandles[i] );
898 return aValues;
901 // XMultiPropertySet
902 void OPropertySetHelper::addPropertiesChangeListener(
903 const Sequence<OUString> & ,
904 const Reference < XPropertiesChangeListener > & rListener )
906 rBHelper.addListener( cppu::UnoType<decltype(rListener)>::get(), rListener );
909 // XMultiPropertySet
910 void OPropertySetHelper::removePropertiesChangeListener(
911 const Reference < XPropertiesChangeListener > & rListener )
913 rBHelper.removeListener( cppu::UnoType<decltype(rListener)>::get(), rListener );
916 // XMultiPropertySet
917 void OPropertySetHelper::firePropertiesChangeEvent(
918 const Sequence<OUString>& rPropertyNames,
919 const Reference < XPropertiesChangeListener >& rListener )
921 sal_Int32 nLen = rPropertyNames.getLength();
922 std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nLen]);
923 IPropertyArrayHelper & rPH = getInfoHelper();
924 rPH.fillHandles( pHandles.get(), rPropertyNames );
925 const OUString* pNames = rPropertyNames.getConstArray();
927 // get the count of matching properties
928 sal_Int32 nFireLen = 0;
929 sal_Int32 i;
930 for( i = 0; i < nLen; i++ )
931 if( pHandles[i] != -1 )
932 nFireLen++;
934 Sequence<PropertyChangeEvent> aChanges( nFireLen );
935 PropertyChangeEvent* pChanges = aChanges.getArray();
938 // must lock the mutex outside the loop. So all values are consistent.
939 MutexGuard aGuard( rBHelper.rMutex );
940 Reference < XInterface > xSource( static_cast<XPropertySet *>(this), UNO_QUERY );
941 sal_Int32 nFirePos = 0;
942 for( i = 0; i < nLen; i++ )
944 if( pHandles[i] != -1 )
946 pChanges[nFirePos].Source = xSource;
947 pChanges[nFirePos].PropertyName = pNames[i];
948 pChanges[nFirePos].PropertyHandle = pHandles[i];
949 getFastPropertyValue( pChanges[nFirePos].OldValue, pHandles[i] );
950 pChanges[nFirePos].NewValue = pChanges[nFirePos].OldValue;
951 nFirePos++;
954 // release guard to fire events
956 if( nFireLen )
957 rListener->propertiesChange( aChanges );
960 void OPropertySetHelper2::enableChangeListenerNotification( sal_Bool bEnable )
962 m_pReserved->m_bFireEvents = bEnable;
965 extern "C" {
967 static int compare_Property_Impl( const void *arg1, const void *arg2 )
968 SAL_THROW_EXTERN_C()
970 return static_cast<Property const *>(arg1)->Name.compareTo( static_cast<Property const *>(arg2)->Name );
975 void OPropertyArrayHelper::init( sal_Bool bSorted )
977 sal_Int32 i, nElements = aInfos.getLength();
978 const Property* pProperties = aInfos.getConstArray();
980 for( i = 1; i < nElements; i++ )
982 if( pProperties[i-1].Name > pProperties[i].Name )
984 if (bSorted) {
985 OSL_FAIL( "Property array is not sorted" );
987 // not sorted
988 qsort( aInfos.getArray(), nElements, sizeof( Property ),
989 compare_Property_Impl );
990 pProperties = aInfos.getConstArray();
991 break;
994 for( i = 0; i < nElements; i++ )
995 if( pProperties[i].Handle != i )
996 return;
997 // The handle is the index
998 bRightOrdered = true;
1001 OPropertyArrayHelper::OPropertyArrayHelper(
1002 Property * pProps,
1003 sal_Int32 nEle,
1004 sal_Bool bSorted )
1005 : m_pReserved(nullptr)
1006 , aInfos(pProps, nEle)
1007 , bRightOrdered( false )
1009 init( bSorted );
1012 OPropertyArrayHelper::OPropertyArrayHelper(
1013 const Sequence< Property > & aProps,
1014 sal_Bool bSorted )
1015 : m_pReserved(nullptr)
1016 , aInfos(aProps)
1017 , bRightOrdered( false )
1019 init( bSorted );
1023 sal_Int32 OPropertyArrayHelper::getCount() const
1025 return aInfos.getLength();
1029 sal_Bool OPropertyArrayHelper::fillPropertyMembersByHandle
1031 OUString * pPropName,
1032 sal_Int16 * pAttributes,
1033 sal_Int32 nHandle
1036 const Property* pProperties = aInfos.getConstArray();
1037 sal_Int32 nElements = aInfos.getLength();
1039 if( bRightOrdered )
1041 if( nHandle < 0 || nHandle >= nElements )
1042 return false;
1043 if( pPropName )
1044 *pPropName = pProperties[ nHandle ].Name;
1045 if( pAttributes )
1046 *pAttributes = pProperties[ nHandle ].Attributes;
1047 return true;
1049 // normally the array is sorted
1050 for( sal_Int32 i = 0; i < nElements; i++ )
1052 if( pProperties[i].Handle == nHandle )
1054 if( pPropName )
1055 *pPropName = pProperties[ i ].Name;
1056 if( pAttributes )
1057 *pAttributes = pProperties[ i ].Attributes;
1058 return true;
1061 return false;
1065 Sequence< Property > OPropertyArrayHelper::getProperties()
1067 return aInfos;
1071 Property OPropertyArrayHelper::getPropertyByName(const OUString& aPropertyName)
1073 Property * pR;
1074 pR = static_cast<Property *>(bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(),
1075 sizeof( Property ),
1076 compare_OUString_Property_Impl ));
1077 if( !pR ) {
1078 throw UnknownPropertyException(aPropertyName);
1080 return *pR;
1084 sal_Bool OPropertyArrayHelper::hasPropertyByName(const OUString& aPropertyName)
1086 Property * pR;
1087 pR = static_cast<Property *>(bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(),
1088 sizeof( Property ),
1089 compare_OUString_Property_Impl ));
1090 return pR != nullptr;
1094 sal_Int32 OPropertyArrayHelper::getHandleByName( const OUString & rPropName )
1096 Property * pR;
1097 pR = static_cast<Property *>(bsearch( &rPropName, aInfos.getConstArray(), aInfos.getLength(),
1098 sizeof( Property ),
1099 compare_OUString_Property_Impl ));
1100 return pR ? pR->Handle : -1;
1104 sal_Int32 OPropertyArrayHelper::fillHandles( sal_Int32 * pHandles, const Sequence< OUString > & rPropNames )
1106 sal_Int32 nHitCount = 0;
1107 const OUString * pReqProps = rPropNames.getConstArray();
1108 sal_Int32 nReqLen = rPropNames.getLength();
1109 const Property * pCur = aInfos.getConstArray();
1110 const Property * pEnd = pCur + aInfos.getLength();
1112 for( sal_Int32 i = 0; i < nReqLen; i++ )
1114 // Calculate logarithm
1115 sal_Int32 n = static_cast<sal_Int32>(pEnd - pCur);
1116 sal_Int32 nLog = 0;
1117 while( n )
1119 nLog += 1;
1120 n = n >> 1;
1123 // Number of properties to search for * Log2 of the number of remaining
1124 // properties to search in.
1125 if( (nReqLen - i) * nLog >= pEnd - pCur )
1127 // linear search is better
1128 while( pCur < pEnd && pReqProps[i] > pCur->Name )
1130 pCur++;
1132 if( pCur < pEnd && pReqProps[i] == pCur->Name )
1134 pHandles[i] = pCur->Handle;
1135 nHitCount++;
1137 else
1138 pHandles[i] = -1;
1140 else
1142 // binary search is better
1143 sal_Int32 nCompVal = 1;
1144 const Property * pOldEnd = pEnd--;
1145 const Property * pMid = pCur;
1147 while( nCompVal != 0 && pCur <= pEnd )
1149 pMid = (pEnd - pCur) / 2 + pCur;
1151 nCompVal = pReqProps[i].compareTo( pMid->Name );
1153 if( nCompVal > 0 )
1154 pCur = pMid + 1;
1155 else
1156 pEnd = pMid - 1;
1159 if( nCompVal == 0 )
1161 pHandles[i] = pMid->Handle;
1162 nHitCount++;
1163 pCur = pMid +1;
1165 else if( nCompVal > 0 )
1167 pHandles[i] = -1;
1168 pCur = pMid +1;
1170 else
1172 pHandles[i] = -1;
1173 pCur = pMid;
1175 pEnd = pOldEnd;
1178 return nHitCount;
1181 } // end namespace cppu
1184 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */