LibreOffice Module cppuhelper (master) 1
propshlp.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21#include <osl/diagnose.h>
26#include <com/sun/star/beans/PropertyAttribute.hpp>
27#include <com/sun/star/lang/DisposedException.hpp>
28#include <com/sun/star/lang/IllegalArgumentException.hpp>
29#include <memory>
30#include <sal/log.hxx>
31
32using namespace osl;
33using namespace com::sun::star::uno;
34using namespace com::sun::star::beans;
35using namespace com::sun::star::lang;
36using namespace cppu;
37
38namespace cppu {
39
41{
42}
43
44static const css::uno::Type & getPropertyTypeIdentifier( )
45{
47}
48static const css::uno::Type & getPropertiesTypeIdentifier()
49{
51}
52static const css::uno::Type & getVetoableTypeIdentifier()
53{
55}
56
57extern "C" {
58
59static int compare_OUString_Property_Impl( const void *arg1, const void *arg2 )
61{
62 return static_cast<OUString const *>(arg1)->compareTo( static_cast<Property const *>(arg2)->Name );
63}
64
65}
66
71namespace {
72
73class OPropertySetHelperInfo_Impl
74 : public WeakImplHelper< css::beans::XPropertySetInfo >
75{
77
78public:
79 explicit OPropertySetHelperInfo_Impl( IPropertyArrayHelper & rHelper_ );
80
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;
85};
86
87}
88
92OPropertySetHelperInfo_Impl::OPropertySetHelperInfo_Impl(
93 IPropertyArrayHelper & rHelper_ )
94 :aInfos( rHelper_.getProperties() )
95{
96}
97
101Sequence< Property > OPropertySetHelperInfo_Impl::getProperties()
102{
103 return aInfos;
104}
105
109Property OPropertySetHelperInfo_Impl::getPropertyByName( const OUString & PropertyName )
110{
111 Property * pR;
112 pR = static_cast<Property *>(bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(),
113 sizeof( Property ),
114 compare_OUString_Property_Impl ));
115 if( !pR ) {
116 throw UnknownPropertyException(PropertyName);
117 }
118
119 return *pR;
120}
121
125sal_Bool OPropertySetHelperInfo_Impl::hasPropertyByName( const OUString & PropertyName )
126{
127 Property * pR;
128 pR = static_cast<Property *>(bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(),
129 sizeof( Property ),
130 compare_OUString_Property_Impl ));
131 return pR != nullptr;
132}
133
134
135
137
138public:
139 Impl( bool i_bIgnoreRuntimeExceptionsWhileFiring,
140 IEventNotificationHook *i_pFireEvents
141 )
142 :m_bIgnoreRuntimeExceptionsWhileFiring( i_bIgnoreRuntimeExceptionsWhileFiring )
143 ,m_bFireEvents(true)
144 ,m_pFireEvents( i_pFireEvents )
145 {
146 }
147
151
152 std::vector< sal_Int32 > m_handles;
153 std::vector< Any > m_newValues;
154 std::vector< Any > m_oldValues;
155};
156
157
158
159OPropertySetHelper::OPropertySetHelper(
160 OBroadcastHelper & rBHelper_ )
161 : rBHelper( rBHelper_ ),
162 aBoundLC( rBHelper_.rMutex ),
163 aVetoableLC( rBHelper_.rMutex ),
164 m_pReserved( new Impl(false, nullptr) )
165{
166}
167
169 OBroadcastHelper & rBHelper_, bool bIgnoreRuntimeExceptionsWhileFiring )
170 : rBHelper( rBHelper_ ),
171 aBoundLC( rBHelper_.rMutex ),
172 aVetoableLC( rBHelper_.rMutex ),
173 m_pReserved( new Impl( bIgnoreRuntimeExceptionsWhileFiring, nullptr ) )
174{
175}
176
178 OBroadcastHelper & rBHelper_, IEventNotificationHook * i_pFireEvents,
179 bool bIgnoreRuntimeExceptionsWhileFiring)
180 : rBHelper( rBHelper_ ),
181 aBoundLC( rBHelper_.rMutex ),
182 aVetoableLC( rBHelper_.rMutex ),
183 m_pReserved(
184 new Impl( bIgnoreRuntimeExceptionsWhileFiring, i_pFireEvents) )
185{
186}
187
189 OBroadcastHelper & irBHelper,
190 IEventNotificationHook *i_pFireEvents,
191 bool bIgnoreRuntimeExceptionsWhileFiring)
192 :OPropertySetHelper( irBHelper, i_pFireEvents, bIgnoreRuntimeExceptionsWhileFiring )
193{
194}
195
200{
201 delete m_pReserved;
202}
204{
205}
206
207// XInterface
208Any OPropertySetHelper::queryInterface( const css::uno::Type & rType )
209{
211 rType,
212 static_cast< XPropertySet * >( this ),
213 static_cast< XMultiPropertySet * >( this ),
214 static_cast< XFastPropertySet * >( this ) );
215}
216
217Any OPropertySetHelper2::queryInterface( const css::uno::Type & rType )
218{
219 Any cnd(cppu::queryInterface(rType, static_cast< XPropertySetOption * >(this)));
220 if ( cnd.hasValue() )
221 return cnd;
223}
224
228css::uno::Sequence< css::uno::Type > OPropertySetHelper::getTypes()
229{
230 return {
234}
235
236// ComponentHelper
238{
239 // Create an event with this as sender
240 Reference < XPropertySet > rSource = this;
241 EventObject aEvt;
242 aEvt.Source = rSource;
243
244 // inform all listeners to release this object
245 // The listener containers are automatically cleared
248}
249
251 IPropertyArrayHelper & rProperties )
252{
253 return new OPropertySetHelperInfo_Impl(rProperties);
254}
255
256// XPropertySet
258 const OUString& rPropertyName, const Any& rValue )
259{
260 // get the map table
262 // map the name to the handle
263 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
264 // call the method of the XFastPropertySet interface
265 setFastPropertyValue( nHandle, rValue );
266}
267
268// XPropertySet
270 const OUString& rPropertyName )
271{
272 // get the map table
274 // map the name to the handle
275 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName );
276 // call the method of the XFastPropertySet interface
277 return getFastPropertyValue( nHandle );
278}
279
280// XPropertySet
282 const OUString& rPropertyName,
283 const Reference < XPropertyChangeListener > & rxListener )
284{
285 MutexGuard aGuard( rBHelper.rMutex );
286 OSL_ENSURE( !rBHelper.bInDispose, "do not addPropertyChangeListener in the dispose call" );
287 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
289 return;
290
291 // only add listeners if you are not disposed
292 // a listener with no name means all properties
293 if( !rPropertyName.isEmpty() )
294 {
295 // get the map table
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(rPropertyName);
302 }
303
304 sal_Int16 nAttributes;
305 rPH.fillPropertyMembersByHandle( nullptr, &nAttributes, nHandle );
306 if( !(nAttributes & css::beans::PropertyAttribute::BOUND) )
307 {
308 OSL_FAIL( "add listener to an unbound property" );
309 // silent ignore this
310 return;
311 }
312 // add the change listener to the helper container
313
314 aBoundLC.addInterface( nHandle, rxListener );
315 }
316 else
317 // add the change listener to the helper container
318 rBHelper.aLC.addInterface(
320 rxListener
321 );
322}
323
324
325// XPropertySet
327 const OUString& rPropertyName,
328 const Reference < XPropertyChangeListener >& rxListener )
329{
330 MutexGuard aGuard( rBHelper.rMutex );
331 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
332 // all listeners are automatically released in a dispose call
334 return;
335
336 if( !rPropertyName.isEmpty() )
337 {
338 // get the map table
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(rPropertyName);
345 aBoundLC.removeInterface( nHandle, rxListener );
346 }
347 else {
348 // remove the change listener to the helper container
349 rBHelper.aLC.removeInterface(
351 rxListener
352 );
353 }
354}
355
356// XPropertySet
358 const OUString& rPropertyName,
359 const Reference< XVetoableChangeListener > & rxListener )
360{
361 MutexGuard aGuard( rBHelper.rMutex );
362 OSL_ENSURE( !rBHelper.bInDispose, "do not addVetoableChangeListener in the dispose call" );
363 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
365 return;
366
367 // only add listeners if you are not disposed
368 // a listener with no name means all properties
369 if( !rPropertyName.isEmpty() )
370 {
371 // get the map table
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(rPropertyName);
378 }
379
380 sal_Int16 nAttributes;
381 rPH.fillPropertyMembersByHandle( nullptr, &nAttributes, nHandle );
382 if( !(nAttributes & PropertyAttribute::CONSTRAINED) )
383 {
384 OSL_FAIL( "addVetoableChangeListener, and property is not constrained" );
385 // silent ignore this
386 return;
387 }
388 // add the vetoable listener to the helper container
389 aVetoableLC.addInterface( nHandle, rxListener );
390 }
391 else
392 // add the vetoable listener to the helper container
393 rBHelper.aLC.addInterface(
395 rxListener
396 );
397}
398
399// XPropertySet
401 const OUString& rPropertyName,
402 const Reference < XVetoableChangeListener > & rxListener )
403{
404 MutexGuard aGuard( rBHelper.rMutex );
405 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
406 // all listeners are automatically released in a dispose call
408 return;
409
410 if( !rPropertyName.isEmpty() )
411 {
412 // get the map table
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(rPropertyName);
419 }
420 // remove the vetoable listener to the helper container
421 aVetoableLC.removeInterface( nHandle, rxListener );
422 }
423 else
424 // add the vetoable listener to the helper container
425 rBHelper.aLC.removeInterface(
427 rxListener
428 );
429}
430
431void OPropertySetHelper::setDependentFastPropertyValue( sal_Int32 i_handle, const css::uno::Any& i_value )
432{
433 //OSL_PRECOND( rBHelper.rMutex.isAcquired(), "OPropertySetHelper::setDependentFastPropertyValue: to be called with a locked mutex only!" );
434 // there is no such thing as Mutex.isAcquired, sadly ...
435
436 sal_Int16 nAttributes(0);
438 if ( !rInfo.fillPropertyMembersByHandle( nullptr, &nAttributes, i_handle ) )
439 // unknown property
440 throw UnknownPropertyException(OUString::number(i_handle));
441
442 // no need to check for READONLY-ness of the property. The method is intended to be called internally, which
443 // implies it might be invoked for properties which are read-only to the instance's clients, but well allowed
444 // to change their value.
445
446 Any aConverted, aOld;
447 bool bChanged = convertFastPropertyValue( aConverted, aOld, i_handle, i_value );
448 if ( !bChanged )
449 return;
450
451 // don't fire vetoable events. This method is called with our mutex locked, so calling into listeners would not be
452 // a good idea. The caller is responsible for not invoking this for constrained properties.
453 OSL_ENSURE( ( nAttributes & PropertyAttribute::CONSTRAINED ) == 0,
454 "OPropertySetHelper::setDependentFastPropertyValue: not to be used for constrained properties!" );
455
456 // actually set the new value
457 try
458 {
459 setFastPropertyValue_NoBroadcast( i_handle, aConverted );
460 }
461 catch (const UnknownPropertyException& ) { throw; /* allowed to leave */ }
462 catch (const PropertyVetoException& ) { throw; /* allowed to leave */ }
463 catch (const IllegalArgumentException& ) { throw; /* allowed to leave */ }
464 catch (const WrappedTargetException& ) { throw; /* allowed to leave */ }
465 catch (const RuntimeException& ) { throw; /* allowed to leave */ }
466 catch (const Exception& )
467 {
468 // not allowed to leave this method
469 WrappedTargetException aWrapped;
470 aWrapped.TargetException = ::cppu::getCaughtException();
471 aWrapped.Context = static_cast< XPropertySet* >( this );
472 throw aWrapped;
473 }
474
475 // remember the handle/values, for the events to be fired later
476 m_pReserved->m_handles.push_back( i_handle );
477 m_pReserved->m_newValues.push_back( aConverted ); // TODO: setFastPropertyValue notifies the unconverted value here ...?
478 m_pReserved->m_oldValues.push_back( aOld );
479}
480
481// XFastPropertySet
482void OPropertySetHelper::setFastPropertyValue( sal_Int32 nHandle, const Any& rValue )
483{
484 OSL_ENSURE( !rBHelper.bInDispose, "do not setFastPropertyValue in the dispose call" );
485 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
486
488 sal_Int16 nAttributes;
489 if( !rInfo.fillPropertyMembersByHandle( nullptr, &nAttributes, nHandle ) ) {
490 // unknown property
491 throw UnknownPropertyException(OUString::number(nHandle));
492 }
493 if( nAttributes & PropertyAttribute::READONLY )
494 throw PropertyVetoException();
495
496 Any aConvertedVal;
497 Any aOldVal;
498
499 // Will the property change?
500 bool bChanged;
501 {
502 MutexGuard aGuard( rBHelper.rMutex );
503 bChanged = convertFastPropertyValue( aConvertedVal, aOldVal, nHandle, rValue );
504 // release guard to fire events
505 }
506 if( !bChanged )
507 return;
508
509 // Is it a constrained property?
510 if( nAttributes & PropertyAttribute::CONSTRAINED )
511 {
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 );
516 }
517
518 {
519 MutexGuard aGuard( rBHelper.rMutex );
520 try
521 {
522 // set the property to the new value
523 setFastPropertyValue_NoBroadcast( nHandle, aConvertedVal );
524 }
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 )
531 {
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;
536
537 throw aWrap;
538 }
539
540 // release guard to fire events
541 }
542 // file a change event, if the value changed
543 impl_fireAll( &nHandle, &rValue, &aOldVal, 1 );
544}
545
546// XFastPropertySet
548
549{
551 if( !rInfo.fillPropertyMembersByHandle( nullptr, nullptr, nHandle ) )
552 // unknown property
553 throw UnknownPropertyException(OUString::number(nHandle));
554
555 Any aRet;
556 MutexGuard aGuard( rBHelper.rMutex );
558 return aRet;
559}
560
561
562void OPropertySetHelper::impl_fireAll( sal_Int32* i_handles, const Any* i_newValues, const Any* i_oldValues, sal_Int32 i_count )
563{
564 ClearableMutexGuard aGuard( rBHelper.rMutex );
565 if ( m_pReserved->m_handles.empty() )
566 {
567 aGuard.clear();
568 fire( i_handles, i_newValues, i_oldValues, i_count, false );
569 return;
570 }
571
572 const size_t additionalEvents = m_pReserved->m_handles.size();
573 OSL_ENSURE( additionalEvents == m_pReserved->m_newValues.size()
574 && additionalEvents == m_pReserved->m_oldValues.size(),
575 "OPropertySetHelper::impl_fireAll: inconsistency!" );
576
577 std::vector< sal_Int32 > allHandles( additionalEvents + i_count );
578 std::copy( m_pReserved->m_handles.begin(), m_pReserved->m_handles.end(), allHandles.begin() );
579 std::copy( i_handles, i_handles + i_count, allHandles.begin() + additionalEvents );
580
581 std::vector< Any > allNewValues( additionalEvents + i_count );
582 std::copy( m_pReserved->m_newValues.begin(), m_pReserved->m_newValues.end(), allNewValues.begin() );
583 std::copy( i_newValues, i_newValues + i_count, allNewValues.begin() + additionalEvents );
584
585 std::vector< Any > allOldValues( additionalEvents + i_count );
586 std::copy( m_pReserved->m_oldValues.begin(), m_pReserved->m_oldValues.end(), allOldValues.begin() );
587 std::copy( i_oldValues, i_oldValues + i_count, allOldValues.begin() + additionalEvents );
588
589 m_pReserved->m_handles.clear();
590 m_pReserved->m_newValues.clear();
591 m_pReserved->m_oldValues.clear();
592
593 aGuard.clear();
594 fire( allHandles.data(), allNewValues.data(), allOldValues.data(), additionalEvents + i_count, false );
595}
596
597
599(
600 sal_Int32 * pnHandles,
601 const Any * pNewValues,
602 const Any * pOldValues,
603 sal_Int32 nHandles, // This is the Count of the array
604 sal_Bool bVetoable
605)
606{
608 return;
609
612 pnHandles, nHandles, bVetoable,
614 }
615
616 // Only fire, if one or more properties changed
617 if( !nHandles )
618 return;
619
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++ )
628 {
629 // Vetoable fire and constrained attribute set or
630 // Change fire and Changed and bound attribute set
632 sal_Int16 nAttributes;
633 OUString aPropName;
634 rInfo.fillPropertyMembersByHandle( &aPropName, &nAttributes, pnHandles[i] );
635
636 if(
637 (bVetoable && (nAttributes & PropertyAttribute::CONSTRAINED)) ||
638 (!bVetoable && (nAttributes & PropertyAttribute::BOUND))
639 )
640 {
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++;
647 }
648 }
649
650 bool bIgnoreRuntimeExceptionsWhileFiring =
652
653 // fire the events for all changed properties
654 for( i = 0; i < nChangesLen; i++ )
655 {
656 // get the listener container for the property name
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 )
663 {
664 // Iterate over all listeners and send events
665 OInterfaceIteratorHelper aIt( *pLC);
666 while( aIt.hasMoreElements() )
667 {
668 XInterface * pL = aIt.next();
669 try
670 {
671 try
672 {
673 if( bVetoable ) // fire change Events?
674 {
675 static_cast<XVetoableChangeListener *>(pL)->vetoableChange(
676 pEvts[i] );
677 }
678 else
679 {
680 static_cast<XPropertyChangeListener *>(pL)->propertyChange(
681 pEvts[i] );
682 }
683 }
684 catch (DisposedException & exc)
685 {
686 OSL_ENSURE( exc.Context.is(),
687 "DisposedException without Context!" );
688 if (exc.Context == pL)
689 aIt.remove();
690 else
691 throw;
692 }
693 }
694 catch (RuntimeException & exc)
695 {
696 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
697 if (! bIgnoreRuntimeExceptionsWhileFiring)
698 throw;
699 }
700 }
701 }
702 // broadcast to all listeners with "" property name
703 if( bVetoable ){
704 // fire change Events?
705 pLC = rBHelper.aLC.getContainer(
707 );
708 }
709 else {
710 pLC = rBHelper.aLC.getContainer(
712 );
713 }
714 if( pLC )
715 {
716 // Iterate over all listeners and send events.
717 OInterfaceIteratorHelper aIt( *pLC);
718 while( aIt.hasMoreElements() )
719 {
720 XInterface * pL = aIt.next();
721 try
722 {
723 try
724 {
725 if( bVetoable ) // fire change Events?
726 {
727 static_cast<XVetoableChangeListener *>(pL)->vetoableChange(
728 pEvts[i] );
729 }
730 else
731 {
732 static_cast<XPropertyChangeListener *>(pL)->propertyChange(
733 pEvts[i] );
734 }
735 }
736 catch (DisposedException & exc)
737 {
738 OSL_ENSURE( exc.Context.is(),
739 "DisposedException without Context!" );
740 if (exc.Context == pL)
741 aIt.remove();
742 else
743 throw;
744 }
745 }
746 catch (RuntimeException & exc)
747 {
748 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
749 if (! bIgnoreRuntimeExceptionsWhileFiring)
750 throw;
751 }
752 }
753 }
754 }
755
756 // reduce array to changed properties
757 aEvts.realloc( nChangesLen );
758
759 if( bVetoable )
760 return;
761
762 auto pCont = rBHelper.aLC.getContainer(getPropertiesTypeIdentifier());
763 if (!pCont)
764 return;
765
766 // Here is a Bug, unbound properties are also fired
767 OInterfaceIteratorHelper aIt( *pCont );
768 while( aIt.hasMoreElements() )
769 {
770 XPropertiesChangeListener * pL =
771 static_cast<XPropertiesChangeListener *>(aIt.next());
772 try
773 {
774 try
775 {
776 // fire the whole event sequence to the
777 // XPropertiesChangeListener's
778 pL->propertiesChange( aEvts );
779 }
780 catch (DisposedException & exc)
781 {
782 OSL_ENSURE( exc.Context.is(),
783 "DisposedException without Context!" );
784 if (exc.Context == pL)
785 aIt.remove();
786 else
787 throw;
788 }
789 }
790 catch (RuntimeException & exc)
791 {
792 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
793 if (! bIgnoreRuntimeExceptionsWhileFiring)
794 throw;
795 }
796 }
797}
798
799// OPropertySetHelper
801 sal_Int32 nSeqLen,
802 sal_Int32 * pHandles,
803 const Any * pValues,
804 sal_Int32 nHitCount )
805{
806 OSL_ENSURE( !rBHelper.bInDispose, "do not getFastPropertyValue in the dispose call" );
807 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
808
809 // get the map table
811
812 std::unique_ptr<Any[]> pConvertedValues(new Any[ nHitCount ]);
813 std::unique_ptr<Any[]> pOldValues(new Any[ nHitCount ]);
814 sal_Int32 n = 0;
815 sal_Int32 i;
816
817 {
818 // must lock the mutex outside the loop. So all values are consistent.
819 MutexGuard aGuard( rBHelper.rMutex );
820 for( i = 0; i < nSeqLen; i++ )
821 {
822 if( pHandles[i] != -1 )
823 {
824 sal_Int16 nAttributes;
825 rPH.fillPropertyMembersByHandle( nullptr, &nAttributes, pHandles[i] );
826 if( nAttributes & PropertyAttribute::READONLY ) {
827 throw PropertyVetoException();
828 }
829 // Will the property change?
830 if( convertFastPropertyValue( pConvertedValues[ n ], pOldValues[n],
831 pHandles[i], pValues[i] ) )
832 {
833 // only increment if the property really change
834 pHandles[n] = pHandles[i];
835 n++;
836 }
837 }
838 }
839 // release guard to fire events
840 }
841
842 // fire vetoable events
843 fire( pHandles, pConvertedValues.get(), pOldValues.get(), n, true );
844
845 {
846 // must lock the mutex outside the loop.
847 MutexGuard aGuard( rBHelper.rMutex );
848 // Loop over all changed properties
849 for( i = 0; i < n; i++ )
850 {
851 // Will the property change?
852 setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
853 }
854 // release guard to fire events
855 }
856
857 // fire change events
858 impl_fireAll( pHandles, pConvertedValues.get(), pOldValues.get(), n );
859}
860
861// XMultiPropertySet
867 const Sequence<OUString>& rPropertyNames,
868 const Sequence<Any>& rValues )
869{
870 sal_Int32 nSeqLen = rPropertyNames.getLength();
871 if (nSeqLen != rValues.getLength())
872 throw IllegalArgumentException("lengths do not match", static_cast<XPropertySet*>(this),
873 -1);
874 std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[ nSeqLen ]);
875 // get the map table
877 // fill the handle array
878 sal_Int32 nHitCount = rPH.fillHandles( pHandles.get(), rPropertyNames );
879 if( nHitCount != 0 )
880 setFastPropertyValues( nSeqLen, pHandles.get(), rValues.getConstArray(), nHitCount );
881}
882
883// XMultiPropertySet
885{
886 sal_Int32 nSeqLen = rPropertyNames.getLength();
887 std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[ nSeqLen ]);
888 Sequence< Any > aValues( nSeqLen );
889
890 // get the map table
892 // fill the handle array
893 rPH.fillHandles( pHandles.get(), rPropertyNames );
894
895 Any * pValues = aValues.getArray();
896
897 MutexGuard aGuard( rBHelper.rMutex );
898 // fill the sequence with the values
899 for( sal_Int32 i = 0; i < nSeqLen; i++ )
900 getFastPropertyValue( pValues[i], pHandles[i] );
901
902 return aValues;
903}
904
905// XMultiPropertySet
907 const Sequence<OUString> & ,
909{
910 rBHelper.addListener( cppu::UnoType<decltype(rListener)>::get(), rListener );
911}
912
913// XMultiPropertySet
916{
917 rBHelper.removeListener( cppu::UnoType<decltype(rListener)>::get(), rListener );
918}
919
920// XMultiPropertySet
922 const Sequence<OUString>& rPropertyNames,
924{
925 sal_Int32 nLen = rPropertyNames.getLength();
926 std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nLen]);
928 rPH.fillHandles( pHandles.get(), rPropertyNames );
929 const OUString* pNames = rPropertyNames.getConstArray();
930
931 // get the count of matching properties
932 sal_Int32 nFireLen = 0;
933 sal_Int32 i;
934 for( i = 0; i < nLen; i++ )
935 if( pHandles[i] != -1 )
936 nFireLen++;
937
938 Sequence<PropertyChangeEvent> aChanges( nFireLen );
939 PropertyChangeEvent* pChanges = aChanges.getArray();
940
941 {
942 // must lock the mutex outside the loop. So all values are consistent.
943 MutexGuard aGuard( rBHelper.rMutex );
944 Reference < XInterface > xSource( static_cast<XPropertySet *>(this), UNO_QUERY );
945 sal_Int32 nFirePos = 0;
946 for( i = 0; i < nLen; i++ )
947 {
948 if( pHandles[i] != -1 )
949 {
950 pChanges[nFirePos].Source = xSource;
951 pChanges[nFirePos].PropertyName = pNames[i];
952 pChanges[nFirePos].PropertyHandle = pHandles[i];
953 getFastPropertyValue( pChanges[nFirePos].OldValue, pHandles[i] );
954 pChanges[nFirePos].NewValue = pChanges[nFirePos].OldValue;
955 nFirePos++;
956 }
957 }
958 // release guard to fire events
959 }
960 if( nFireLen )
961 rListener->propertiesChange( aChanges );
962}
963
965{
966 m_pReserved->m_bFireEvents = bEnable;
967}
968
969extern "C" {
970
971static int compare_Property_Impl( const void *arg1, const void *arg2 )
973{
974 return static_cast<Property const *>(arg1)->Name.compareTo( static_cast<Property const *>(arg2)->Name );
975}
976
977}
978
980{
981 sal_Int32 i, nElements = aInfos.getLength();
982 const Property* pProperties = aInfos.getConstArray();
983
984 for( i = 1; i < nElements; i++ )
985 {
986 if( pProperties[i-1].Name > pProperties[i].Name )
987 {
988 if (bSorted) {
989 OSL_FAIL( "Property array is not sorted" );
990 }
991 // not sorted
992 qsort( aInfos.getArray(), nElements, sizeof( Property ),
994 pProperties = aInfos.getConstArray();
995 break;
996 }
997 }
998 for( i = 0; i < nElements; i++ )
999 if( pProperties[i].Handle != i )
1000 return;
1001 // The handle is the index
1002 bRightOrdered = true;
1003}
1004
1006 Property * pProps,
1007 sal_Int32 nEle,
1008 sal_Bool bSorted )
1009 : m_pReserved(nullptr)
1010 , aInfos(pProps, nEle)
1011 , bRightOrdered( false )
1012{
1013 init( bSorted );
1014}
1015
1017 const Sequence< Property > & aProps,
1018 sal_Bool bSorted )
1019 : m_pReserved(nullptr)
1020 , aInfos(aProps)
1021 , bRightOrdered( false )
1022{
1023 init( bSorted );
1024}
1025
1026
1028{
1029 return aInfos.getLength();
1030}
1031
1032
1034(
1035 OUString * pPropName,
1036 sal_Int16 * pAttributes,
1037 sal_Int32 nHandle
1038)
1039{
1040 const Property* pProperties = aInfos.getConstArray();
1041 sal_Int32 nElements = aInfos.getLength();
1042
1043 if( bRightOrdered )
1044 {
1045 if( nHandle < 0 || nHandle >= nElements )
1046 return false;
1047 if( pPropName )
1048 *pPropName = pProperties[ nHandle ].Name;
1049 if( pAttributes )
1050 *pAttributes = pProperties[ nHandle ].Attributes;
1051 return true;
1052 }
1053 // normally the array is sorted
1054 for( sal_Int32 i = 0; i < nElements; i++ )
1055 {
1056 if( pProperties[i].Handle == nHandle )
1057 {
1058 if( pPropName )
1059 *pPropName = pProperties[ i ].Name;
1060 if( pAttributes )
1061 *pAttributes = pProperties[ i ].Attributes;
1062 return true;
1063 }
1064 }
1065 return false;
1066}
1067
1068
1070{
1071 return aInfos;
1072}
1073
1074
1076{
1077 Property * pR;
1078 pR = static_cast<Property *>(bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(),
1079 sizeof( Property ),
1081 if( !pR ) {
1082 throw UnknownPropertyException(aPropertyName);
1083 }
1084 return *pR;
1085}
1086
1087
1089{
1090 Property * pR;
1091 pR = static_cast<Property *>(bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(),
1092 sizeof( Property ),
1094 return pR != nullptr;
1095}
1096
1097
1098sal_Int32 OPropertyArrayHelper::getHandleByName( const OUString & rPropName )
1099{
1100 Property * pR;
1101 pR = static_cast<Property *>(bsearch( &rPropName, aInfos.getConstArray(), aInfos.getLength(),
1102 sizeof( Property ),
1104 return pR ? pR->Handle : -1;
1105}
1106
1107
1108sal_Int32 OPropertyArrayHelper::fillHandles( sal_Int32 * pHandles, const Sequence< OUString > & rPropNames )
1109{
1110 sal_Int32 nHitCount = 0;
1111 const OUString * pReqProps = rPropNames.getConstArray();
1112 sal_Int32 nReqLen = rPropNames.getLength();
1113 const Property * pCur = aInfos.getConstArray();
1114 const Property * pEnd = pCur + aInfos.getLength();
1115
1116 for( sal_Int32 i = 0; i < nReqLen; i++ )
1117 {
1118 // Calculate logarithm
1119 sal_Int32 n = static_cast<sal_Int32>(pEnd - pCur);
1120 sal_Int32 nLog = 0;
1121 while( n )
1122 {
1123 nLog += 1;
1124 n = n >> 1;
1125 }
1126
1127 // Number of properties to search for * Log2 of the number of remaining
1128 // properties to search in.
1129 if( (nReqLen - i) * nLog >= pEnd - pCur )
1130 {
1131 // linear search is better
1132 while( pCur < pEnd && pReqProps[i] > pCur->Name )
1133 {
1134 pCur++;
1135 }
1136 if( pCur < pEnd && pReqProps[i] == pCur->Name )
1137 {
1138 pHandles[i] = pCur->Handle;
1139 nHitCount++;
1140 }
1141 else
1142 pHandles[i] = -1;
1143 }
1144 else
1145 {
1146 // binary search is better
1147 sal_Int32 nCompVal = 1;
1148 const Property * pOldEnd = pEnd--;
1149 const Property * pMid = pCur;
1150
1151 while( nCompVal != 0 && pCur <= pEnd )
1152 {
1153 pMid = (pEnd - pCur) / 2 + pCur;
1154
1155 nCompVal = pReqProps[i].compareTo( pMid->Name );
1156
1157 if( nCompVal > 0 )
1158 pCur = pMid + 1;
1159 else
1160 pEnd = pMid - 1;
1161 }
1162
1163 if( nCompVal == 0 )
1164 {
1165 pHandles[i] = pMid->Handle;
1166 nHitCount++;
1167 pCur = pMid +1;
1168 }
1169 else if( nCompVal > 0 )
1170 {
1171 pHandles[i] = -1;
1172 pCur = pMid +1;
1173 }
1174 else
1175 {
1176 pHandles[i] = -1;
1177 pCur = pMid;
1178 }
1179 pEnd = pOldEnd;
1180 }
1181 }
1182 return nHitCount;
1183}
1184
1185} // end namespace cppu
1186
1187
1188/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const PropertyValue * pValues
An interface to extend event notification actions.
Definition: propshlp.hxx:309
virtual void fireEvents(sal_Int32 *pnHandles, sal_Int32 nCount, sal_Bool bVetoable, bool bIgnoreRuntimeExceptionsWhileFiring)=0
Method to be called by OPropertySetHelper::fire.
This interface is used by the OPropertyHelper, to access the property description.
Definition: propshlp.hxx:51
virtual sal_Bool SAL_CALL fillPropertyMembersByHandle(::rtl::OUString *pPropName, sal_Int16 *pAttributes, sal_Int32 nHandle)=0
Return the property members Name and Attribute from the handle nHandle.
virtual sal_Int32 SAL_CALL fillHandles(sal_Int32 *pHandles, const css::uno::Sequence< ::rtl::OUString > &rPropNames)=0
Fill the array with the handles of the properties.
virtual ~IPropertyArrayHelper()
Following the rule, the first virtual method implies a virtual destructor.
Definition: propshlp.cxx:40
virtual sal_Int32 SAL_CALL getHandleByName(const ::rtl::OUString &rPropertyName)=0
Return the handle of the property with the name rPropertyName.
A container of interfaces.
This is the iterator of an InterfaceContainerHelper.
sal_Int32 SAL_CALL addInterface(const sal_Int32 &rKey, const css::uno::Reference< css::uno::XInterface > &r)
Insert an element in the container specified with the key.
sal_Int32 SAL_CALL removeInterface(const sal_Int32 &rKey, const css::uno::Reference< css::uno::XInterface > &rxIFace)
Remove an element from the container specified with the key.
void SAL_CALL disposeAndClear(const css::lang::EventObject &rEvt)
Call disposing on all objects in the container that support XEventListener.
OInterfaceContainerHelper *SAL_CALL getContainer(const sal_Int32 &rKey) const
Return the container created under this key.
sal_Int32 SAL_CALL getCount() const
Return the number of properties.
Definition: propshlp.cxx:1027
OPropertyArrayHelper(css::beans::Property *pProps, sal_Int32 nElements, sal_Bool bSorted=true)
Create an object which supports the common property interfaces.
virtual css::beans::Property SAL_CALL getPropertyByName(const ::rtl::OUString &rPropertyName) SAL_OVERRIDE
Return the property with the name rPropertyName.
Definition: propshlp.cxx:1075
sal_Bool bRightOrdered
True, If the values of the handles are sorted in the same way as the names and the highest handle val...
Definition: propshlp.hxx:205
virtual sal_Bool SAL_CALL fillPropertyMembersByHandle(::rtl::OUString *pPropName, sal_Int16 *pAttributes, sal_Int32 nHandle) SAL_OVERRIDE
Return the property members Name and Attribute from the handle nHandle.
Definition: propshlp.cxx:1034
void init(sal_Bool bSorted)
Definition: propshlp.cxx:979
css::uno::Sequence< css::beans::Property > aInfos
The sequence generated from the pProperties array.
Definition: propshlp.hxx:199
virtual sal_Bool SAL_CALL hasPropertyByName(const ::rtl::OUString &rPropertyName) SAL_OVERRIDE
Return true if the property with the name rPropertyName exist, otherwise false.
Definition: propshlp.cxx:1088
virtual sal_Int32 SAL_CALL getHandleByName(const ::rtl::OUString &rPropertyName) SAL_OVERRIDE
Return the handle of the property with the name rPropertyName.
Definition: propshlp.cxx:1098
virtual sal_Int32 SAL_CALL fillHandles(sal_Int32 *pHandles, const css::uno::Sequence< ::rtl::OUString > &rPropNames) SAL_OVERRIDE
Fill the array with the handles of the properties.
Definition: propshlp.cxx:1108
virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties() SAL_OVERRIDE
Return the sequence of properties.
Definition: propshlp.cxx:1069
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) SAL_OVERRIDE
Only returns a reference to XMultiPropertySet, XFastPropertySet, XPropertySet and XEventListener.
Definition: propshlp.cxx:217
OPropertySetHelper2(OBroadcastHelper &rBHelper, IEventNotificationHook *i_pFireEvents=NULL, bool bIgnoreRuntimeExceptionsWhileFiring=false)
Constructor.
Definition: propshlp.cxx:188
virtual void SAL_CALL enableChangeListenerNotification(sal_Bool bEnable) SAL_OVERRIDE
Definition: propshlp.cxx:964
virtual ~OPropertySetHelper2()
You must call disposing before destruction.
Definition: propshlp.cxx:203
std::vector< Any > m_oldValues
Definition: propshlp.cxx:154
std::vector< sal_Int32 > m_handles
Definition: propshlp.cxx:152
class IEventNotificationHook *const m_pFireEvents
Definition: propshlp.cxx:150
Impl(bool i_bIgnoreRuntimeExceptionsWhileFiring, IEventNotificationHook *i_pFireEvents)
Definition: propshlp.cxx:139
std::vector< Any > m_newValues
Definition: propshlp.cxx:153
This abstract class maps the methods of the interfaces XMultiPropertySet, XFastPropertySet and XPrope...
Definition: propshlp.hxx:360
virtual void SAL_CALL addVetoableChangeListener(const ::rtl::OUString &aPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &aListener) SAL_OVERRIDE
Ignored if the property is not constrained.
virtual void SAL_CALL addPropertyChangeListener(const ::rtl::OUString &aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &aListener) SAL_OVERRIDE
Ignored if the property is not bound.
void setDependentFastPropertyValue(sal_Int32 i_handle, const css::uno::Any &i_value)
sets an dependent property's value
Definition: propshlp.cxx:431
void SAL_CALL setFastPropertyValues(sal_Int32 nSeqLen, sal_Int32 *pHandles, const css::uno::Any *pValues, sal_Int32 nHitCount)
Set multiple properties with the handles.
virtual void SAL_CALL removeVetoableChangeListener(const ::rtl::OUString &aPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &aListener) SAL_OVERRIDE
Ignored if the property is not constrained.
virtual void SAL_CALL setFastPropertyValue(sal_Int32 nHandle, const css::uno::Any &rValue) SAL_OVERRIDE
Throw UnknownPropertyException or PropertyVetoException if the property with the name rPropertyName d...
static css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL createPropertySetInfo(IPropertyArrayHelper &rProperties)
The property sequence is created in the call.
Definition: propshlp.cxx:250
virtual css::uno::Any SAL_CALL getFastPropertyValue(sal_Int32 nHandle) SAL_OVERRIDE
Definition: propshlp.cxx:547
Impl *const m_pReserved
reserved for future use.
Definition: propshlp.hxx:631
virtual void SAL_CALL setPropertyValue(const ::rtl::OUString &rPropertyName, const css::uno::Any &aValue) SAL_OVERRIDE
Throw UnknownPropertyException or PropertyVetoException if the property with the name rPropertyName d...
~OPropertySetHelper()
You must call disposing before destruction.
Definition: propshlp.cxx:199
virtual IPropertyArrayHelper &SAL_CALL getInfoHelper()=0
This abstract method must return the name to index table.
OMultiTypeInterfaceContainerHelperInt32 aBoundLC
Container for the XPropertyChangedListener.
Definition: propshlp.hxx:625
virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const css::uno::Any &rValue)=0
The same as setFastPropertyValue; nHandle is always valid.
virtual void SAL_CALL addPropertiesChangeListener(const css::uno::Sequence< ::rtl::OUString > &PropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener > &Listener) SAL_OVERRIDE
virtual css::uno::Any SAL_CALL getPropertyValue(const ::rtl::OUString &aPropertyName) SAL_OVERRIDE
Throw UnknownPropertyException if the property with the name rPropertyName does not exist.
void SAL_CALL disposing()
Send a disposing notification to the listeners in the containers aBoundLC and aVetoableLC.
Definition: propshlp.cxx:237
OBroadcastHelper & rBHelper
The common data of a broadcaster.
Definition: propshlp.hxx:621
OMultiTypeInterfaceContainerHelperInt32 aVetoableLC
Container for the XPropertyVetoableListener.
Definition: propshlp.hxx:629
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) SAL_OVERRIDE
Only returns a reference to XMultiPropertySet, XFastPropertySet, XPropertySet and XEventListener.
Definition: propshlp.cxx:208
virtual void SAL_CALL removePropertiesChangeListener(const css::uno::Reference< css::beans::XPropertiesChangeListener > &Listener) SAL_OVERRIDE
void impl_fireAll(sal_Int32 *i_handles, const css::uno::Any *i_newValues, const css::uno::Any *i_oldValues, sal_Int32 i_count)
notifies the given changes in property's values, plus all property changes collected during recent |s...
virtual sal_Bool SAL_CALL convertFastPropertyValue(css::uno::Any &rConvertedValue, css::uno::Any &rOldValue, sal_Int32 nHandle, const css::uno::Any &rValue)=0
Converted the value rValue and return the result in rConvertedValue and the old value in rOldValue.
OPropertySetHelper(OBroadcastHelper &rBHelper)
Definition: propshlp.cxx:159
void SAL_CALL fire(sal_Int32 *pnHandles, const css::uno::Any *pNewValues, const css::uno::Any *pOldValues, sal_Int32 nCount, sal_Bool bVetoable)
This method fire events to all registered property listeners.
virtual void SAL_CALL firePropertiesChangeEvent(const css::uno::Sequence< ::rtl::OUString > &PropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener > &Listener) SAL_OVERRIDE
virtual void SAL_CALL setPropertyValues(const css::uno::Sequence< ::rtl::OUString > &PropertyNames, const css::uno::Sequence< css::uno::Any > &Values) SAL_OVERRIDE
virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues(const css::uno::Sequence< ::rtl::OUString > &PropertyNames) SAL_OVERRIDE
virtual void SAL_CALL removePropertyChangeListener(const ::rtl::OUString &aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &aListener) SAL_OVERRIDE
Ignored if the property is not bound.
css::uno::Sequence< css::uno::Type > getTypes()
eases implementing XTypeProvider::getTypes, returns the types of XMultiPropertySet,...
Definition: propshlp.cxx:228
css::uno::Type const & get()
sal_Int32 nElements
sal_Int64 n
#define SAL_INFO(area, stream)
@ Exception
class SAL_NO_VTABLE XPropertySet
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType, Interface1 *p1)
Compares demanded type to given template argument types.
static int compare_Property_Impl(const void *arg1, const void *arg2) SAL_THROW_EXTERN_C()
Definition: propshlp.cxx:971
static const css::uno::Type & getPropertiesTypeIdentifier()
Definition: propshlp.cxx:48
static const css::uno::Type & getPropertyTypeIdentifier()
Definition: propshlp.cxx:44
static const css::uno::Type & getVetoableTypeIdentifier()
Definition: propshlp.cxx:52
static int compare_OUString_Property_Impl(const void *arg1, const void *arg2) SAL_THROW_EXTERN_C()
Definition: propshlp.cxx:59
Any SAL_CALL getCaughtException()
Use this function to get the dynamic type of a caught C++-UNO exception; completes the above function...
int i
OUString aPropName
Sequence< Property > aInfos
Definition: propshlp.cxx:76
sal_Int32 nHandle
sal_Int16 nAttributes
This struct contains the standard variables of a broadcaster.
void addListener(const keyType &key, const css::uno::Reference< css::uno::XInterface > &r)
adds a listener threadsafe.
container aLC
ListenerContainer class is thread safe.
::osl::Mutex & rMutex
The shared mutex.
sal_Bool bInDispose
In dispose call.
void removeListener(const keyType &key, const css::uno::Reference< css::uno::XInterface > &r)
removes a listener threadsafe
sal_Bool bDisposed
Dispose call ready.
OUString Name
unsigned char sal_Bool
#define SAL_THROW_EXTERN_C()