1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_cppuhelper.hxx" 26 27 #include "osl/diagnose.h" 28 #include "cppuhelper/implbase1.hxx" 29 #include "cppuhelper/weak.hxx" 30 #include "cppuhelper/propshlp.hxx" 31 #include "cppuhelper/exc_hlp.hxx" 32 #include "com/sun/star/beans/PropertyAttribute.hpp" 33 #include "com/sun/star/lang/DisposedException.hpp" 34 35 36 using namespace osl; 37 using namespace com::sun::star::uno; 38 using namespace com::sun::star::beans; 39 using namespace com::sun::star::lang; 40 using namespace rtl; 41 using namespace cppu; 42 43 namespace cppu { 44 45 IPropertyArrayHelper::~IPropertyArrayHelper() 46 { 47 } 48 49 inline const ::com::sun::star::uno::Type & getPropertyTypeIdentifier( ) SAL_THROW( () ) 50 { 51 return ::getCppuType( (Reference< XPropertyChangeListener > *)0 ); 52 } 53 inline const ::com::sun::star::uno::Type & getPropertiesTypeIdentifier() SAL_THROW( () ) 54 { 55 return ::getCppuType( (Reference< XPropertiesChangeListener > *)0 ); 56 } 57 inline const ::com::sun::star::uno::Type & getVetoableTypeIdentifier() SAL_THROW( () ) 58 { 59 return ::getCppuType( (Reference< XVetoableChangeListener > *)0 ); 60 } 61 62 extern "C" { 63 64 static int compare_OUString_Property_Impl( const void *arg1, const void *arg2 ) 65 SAL_THROW_EXTERN_C() 66 { 67 return ((OUString *)arg1)->compareTo( ((Property *)arg2)->Name ); 68 } 69 70 } 71 72 /** 73 * The class which implements the PropertySetInfo interface. 74 */ 75 76 class OPropertySetHelperInfo_Impl 77 : public WeakImplHelper1< ::com::sun::star::beans::XPropertySetInfo > 78 { 79 Sequence < Property > aInfos; 80 81 public: 82 OPropertySetHelperInfo_Impl( IPropertyArrayHelper & rHelper_ ) SAL_THROW( () ); 83 84 // XPropertySetInfo-Methoden 85 virtual Sequence< Property > SAL_CALL getProperties(void); 86 virtual Property SAL_CALL getPropertyByName(const OUString& PropertyName); 87 virtual sal_Bool SAL_CALL hasPropertyByName(const OUString& PropertyName); 88 }; 89 90 91 /** 92 * Create an object that implements XPropertySetInfo IPropertyArrayHelper. 93 */ 94 OPropertySetHelperInfo_Impl::OPropertySetHelperInfo_Impl( 95 IPropertyArrayHelper & rHelper_ ) 96 SAL_THROW( () ) 97 :aInfos( rHelper_.getProperties() ) 98 { 99 } 100 101 /** 102 * Return the sequence of properties, which are provided throug the constructor. 103 */ 104 Sequence< Property > OPropertySetHelperInfo_Impl::getProperties(void) 105 106 { 107 return aInfos; 108 } 109 110 /** 111 * Return the sequence of properties, which are provided throug the constructor. 112 */ 113 Property OPropertySetHelperInfo_Impl::getPropertyByName( const OUString & PropertyName ) 114 { 115 Property * pR; 116 pR = (Property *)bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(), 117 sizeof( Property ), 118 compare_OUString_Property_Impl ); 119 if( !pR ) { 120 throw UnknownPropertyException(); 121 } 122 123 return *pR; 124 } 125 126 /** 127 * Return the sequence of properties, which are provided throug the constructor. 128 */ 129 sal_Bool OPropertySetHelperInfo_Impl::hasPropertyByName( const OUString & PropertyName ) 130 { 131 Property * pR; 132 pR = (Property *)bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(), 133 sizeof( Property ), 134 compare_OUString_Property_Impl ); 135 return pR != NULL; 136 } 137 138 // ---------------------------------------------------- 139 // class PropertySetHelper_Impl 140 // ---------------------------------------------------- 141 class OPropertySetHelper::Impl { 142 143 public: 144 Impl( bool i_bIgnoreRuntimeExceptionsWhileFiring, 145 IEventNotificationHook *i_pFireEvents 146 ) 147 :m_bIgnoreRuntimeExceptionsWhileFiring( i_bIgnoreRuntimeExceptionsWhileFiring ) 148 ,m_pFireEvents( i_pFireEvents ) 149 { 150 } 151 152 bool m_bIgnoreRuntimeExceptionsWhileFiring; 153 class IEventNotificationHook * const m_pFireEvents; 154 155 ::std::vector< sal_Int32 > m_handles; 156 ::std::vector< Any > m_newValues; 157 ::std::vector< Any > m_oldValues; 158 }; 159 160 161 // ---------------------------------------------------- 162 // class PropertySetHelper 163 // ---------------------------------------------------- 164 OPropertySetHelper::OPropertySetHelper( 165 OBroadcastHelper & rBHelper_ ) SAL_THROW( () ) 166 : rBHelper( rBHelper_ ), 167 aBoundLC( rBHelper_.rMutex ), 168 aVetoableLC( rBHelper_.rMutex ), 169 m_pReserved( new Impl(false, 0) ) 170 { 171 } 172 173 OPropertySetHelper::OPropertySetHelper( 174 OBroadcastHelper & rBHelper_, bool bIgnoreRuntimeExceptionsWhileFiring ) 175 : rBHelper( rBHelper_ ), 176 aBoundLC( rBHelper_.rMutex ), 177 aVetoableLC( rBHelper_.rMutex ), 178 m_pReserved( new Impl( bIgnoreRuntimeExceptionsWhileFiring, 0 ) ) 179 { 180 } 181 182 OPropertySetHelper::OPropertySetHelper( 183 OBroadcastHelper & rBHelper_, IEventNotificationHook * i_pFireEvents, 184 bool bIgnoreRuntimeExceptionsWhileFiring) 185 : rBHelper( rBHelper_ ), 186 aBoundLC( rBHelper_.rMutex ), 187 aVetoableLC( rBHelper_.rMutex ), 188 m_pReserved( 189 new Impl( bIgnoreRuntimeExceptionsWhileFiring, i_pFireEvents) ) 190 { 191 } 192 193 /** 194 * You must call disposing before. 195 */ 196 OPropertySetHelper::~OPropertySetHelper() SAL_THROW( () ) 197 { 198 } 199 200 /** 201 * These method is called from queryInterface, if no delegator is set. 202 * Otherwise this method is called from the delegator. 203 */ 204 // XAggregation 205 Any OPropertySetHelper::queryInterface( const ::com::sun::star::uno::Type & rType ) 206 { 207 return ::cppu::queryInterface( 208 rType, 209 static_cast< XPropertySet * >( this ), 210 static_cast< XMultiPropertySet * >( this ), 211 static_cast< XFastPropertySet * >( this ) ); 212 } 213 214 /** 215 * called from the derivee's XTypeProvider::getTypes implementation 216 */ 217 ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > OPropertySetHelper::getTypes() 218 { 219 Sequence< ::com::sun::star::uno::Type > aTypes( 3 ); 220 aTypes[ 0 ] = XPropertySet::static_type(); 221 aTypes[ 1 ] = XMultiPropertySet::static_type(); 222 aTypes[ 2 ] = XFastPropertySet::static_type(); 223 return aTypes; 224 } 225 226 // ComponentHelper 227 void OPropertySetHelper::disposing() SAL_THROW( () ) 228 { 229 // Create an event with this as sender 230 Reference < XPropertySet > rSource( SAL_STATIC_CAST( XPropertySet * , this ) , UNO_QUERY ); 231 EventObject aEvt; 232 aEvt.Source = rSource; 233 234 // inform all listeners to reelease this object 235 // The listener container are automatically cleared 236 aBoundLC.disposeAndClear( aEvt ); 237 aVetoableLC.disposeAndClear( aEvt ); 238 } 239 240 Reference < XPropertySetInfo > OPropertySetHelper::createPropertySetInfo( 241 IPropertyArrayHelper & rProperties ) SAL_THROW( () ) 242 { 243 return static_cast< XPropertySetInfo * >( new OPropertySetHelperInfo_Impl( rProperties ) ); 244 } 245 246 // XPropertySet 247 void OPropertySetHelper::setPropertyValue( 248 const OUString& rPropertyName, const Any& rValue ) 249 { 250 // get the map table 251 IPropertyArrayHelper & rPH = getInfoHelper(); 252 // map the name to the handle 253 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName ); 254 // call the method of the XFastPropertySet interface 255 setFastPropertyValue( nHandle, rValue ); 256 } 257 258 // XPropertySet 259 Any OPropertySetHelper::getPropertyValue( 260 const OUString& rPropertyName ) 261 { 262 // get the map table 263 IPropertyArrayHelper & rPH = getInfoHelper(); 264 // map the name to the handle 265 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName ); 266 // call the method of the XFastPropertySet interface 267 return getFastPropertyValue( nHandle ); 268 } 269 270 // XPropertySet 271 void OPropertySetHelper::addPropertyChangeListener( 272 const OUString& rPropertyName, 273 const Reference < XPropertyChangeListener > & rxListener ) 274 { 275 MutexGuard aGuard( rBHelper.rMutex ); 276 OSL_ENSURE( !rBHelper.bInDispose, "do not addPropertyChangeListener in the dispose call" ); 277 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); 278 if( !rBHelper.bInDispose && !rBHelper.bDisposed ) 279 { 280 // only add listeners if you are not disposed 281 // a listener with no name means all properties 282 if( rPropertyName.getLength() ) 283 { 284 // get the map table 285 IPropertyArrayHelper & rPH = getInfoHelper(); 286 // map the name to the handle 287 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName ); 288 if( nHandle == -1 ) { 289 // property not known throw exception 290 throw UnknownPropertyException() ; 291 } 292 293 sal_Int16 nAttributes; 294 rPH.fillPropertyMembersByHandle( NULL, &nAttributes, nHandle ); 295 if( !(nAttributes & ::com::sun::star::beans::PropertyAttribute::BOUND) ) 296 { 297 OSL_ENSURE( sal_False, "add listener to an unbound property" ); 298 // silent ignore this 299 return; 300 } 301 // add the change listener to the helper container 302 303 aBoundLC.addInterface( (sal_Int32)nHandle, rxListener ); 304 } 305 else 306 // add the change listener to the helper container 307 rBHelper.aLC.addInterface( 308 getPropertyTypeIdentifier( ), 309 rxListener 310 ); 311 } 312 } 313 314 315 // XPropertySet 316 void OPropertySetHelper::removePropertyChangeListener( 317 const OUString& rPropertyName, 318 const Reference < XPropertyChangeListener >& rxListener ) 319 { 320 MutexGuard aGuard( rBHelper.rMutex ); 321 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); 322 // all listeners are automatically released in a dispose call 323 if( !rBHelper.bInDispose && !rBHelper.bDisposed ) 324 { 325 if( rPropertyName.getLength() ) 326 { 327 // get the map table 328 IPropertyArrayHelper & rPH = getInfoHelper(); 329 // map the name to the handle 330 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName ); 331 if( nHandle == -1 ) 332 // property not known throw exception 333 throw UnknownPropertyException(); 334 aBoundLC.removeInterface( (sal_Int32)nHandle, rxListener ); 335 } 336 else { 337 // remove the change listener to the helper container 338 rBHelper.aLC.removeInterface( 339 getPropertyTypeIdentifier( ), 340 rxListener 341 ); 342 } 343 } 344 } 345 346 // XPropertySet 347 void OPropertySetHelper::addVetoableChangeListener( 348 const OUString& rPropertyName, 349 const Reference< XVetoableChangeListener > & rxListener ) 350 { 351 MutexGuard aGuard( rBHelper.rMutex ); 352 OSL_ENSURE( !rBHelper.bInDispose, "do not addVetoableChangeListener in the dispose call" ); 353 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); 354 if( !rBHelper.bInDispose && !rBHelper.bDisposed ) 355 { 356 // only add listeners if you are not disposed 357 // a listener with no name means all properties 358 if( rPropertyName.getLength() ) 359 { 360 // get the map table 361 IPropertyArrayHelper & rPH = getInfoHelper(); 362 // map the name to the handle 363 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName ); 364 if( nHandle == -1 ) { 365 // property not known throw exception 366 throw UnknownPropertyException(); 367 } 368 369 sal_Int16 nAttributes; 370 rPH.fillPropertyMembersByHandle( NULL, &nAttributes, nHandle ); 371 if( !(nAttributes & PropertyAttribute::CONSTRAINED) ) 372 { 373 OSL_ENSURE( sal_False, "addVetoableChangeListener, and property is not constrained" ); 374 // silent ignore this 375 return; 376 } 377 // add the vetoable listener to the helper container 378 aVetoableLC.addInterface( (sal_Int32)nHandle, rxListener ); 379 } 380 else 381 // add the vetoable listener to the helper container 382 rBHelper.aLC.addInterface( 383 getVetoableTypeIdentifier( ), 384 rxListener 385 ); 386 } 387 } 388 389 // XPropertySet 390 void OPropertySetHelper::removeVetoableChangeListener( 391 const OUString& rPropertyName, 392 const Reference < XVetoableChangeListener > & rxListener ) 393 { 394 MutexGuard aGuard( rBHelper.rMutex ); 395 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); 396 // all listeners are automatically released in a dispose call 397 if( !rBHelper.bInDispose && !rBHelper.bDisposed ) 398 { 399 if( rPropertyName.getLength() ) 400 { 401 // get the map table 402 IPropertyArrayHelper & rPH = getInfoHelper(); 403 // map the name to the handle 404 sal_Int32 nHandle = rPH.getHandleByName( rPropertyName ); 405 if( nHandle == -1 ) { 406 // property not known throw exception 407 throw UnknownPropertyException(); 408 } 409 // remove the vetoable listener to the helper container 410 aVetoableLC.removeInterface( (sal_Int32)nHandle, rxListener ); 411 } 412 else 413 // add the vetoable listener to the helper container 414 rBHelper.aLC.removeInterface( 415 getVetoableTypeIdentifier( ), 416 rxListener 417 ); 418 } 419 } 420 421 void OPropertySetHelper::setDependentFastPropertyValue( sal_Int32 i_handle, const ::com::sun::star::uno::Any& i_value ) 422 { 423 //OSL_PRECOND( rBHelper.rMutex.isAcquired(), "OPropertySetHelper::setDependentFastPropertyValue: to be called with a locked mutex only!" ); 424 // there is no such thing as Mutex.isAcquired, sadly ... 425 426 sal_Int16 nAttributes(0); 427 IPropertyArrayHelper& rInfo = getInfoHelper(); 428 if ( !rInfo.fillPropertyMembersByHandle( NULL, &nAttributes, i_handle ) ) 429 // unknown property 430 throw UnknownPropertyException(); 431 432 // no need to check for READONLY-ness of the property. The method is intended to be called internally, which 433 // implies it might be invoked for properties which are read-only to the instance's clients, but well allowed 434 // to change their value. 435 436 Any aConverted, aOld; 437 sal_Bool bChanged = convertFastPropertyValue( aConverted, aOld, i_handle, i_value ); 438 if ( !bChanged ) 439 return; 440 441 // don't fire vetoable events. This method is called with our mutex locked, so calling into listeners would not be 442 // a good idea. The caler is responsible for not invoking this for constrained properties. 443 OSL_ENSURE( ( nAttributes & PropertyAttribute::CONSTRAINED ) == 0, 444 "OPropertySetHelper::setDependentFastPropertyValue: not to be used for constrained properties!" ); 445 (void)nAttributes; 446 447 // actually set the new value 448 try 449 { 450 setFastPropertyValue_NoBroadcast( i_handle, aConverted ); 451 } 452 catch (const UnknownPropertyException& ) { throw; /* allowed to leave */ } 453 catch (const PropertyVetoException& ) { throw; /* allowed to leave */ } 454 catch (const IllegalArgumentException& ) { throw; /* allowed to leave */ } 455 catch (const WrappedTargetException& ) { throw; /* allowed to leave */ } 456 catch (const RuntimeException& ) { throw; /* allowed to leave */ } 457 catch (const Exception& ) 458 { 459 // not allowed to leave this method 460 WrappedTargetException aWrapped; 461 aWrapped.TargetException <<= ::cppu::getCaughtException(); 462 aWrapped.Context = static_cast< XPropertySet* >( this ); 463 throw aWrapped; 464 } 465 466 // remember the handle/values, for the events to be fired later 467 m_pReserved->m_handles.push_back( i_handle ); 468 m_pReserved->m_newValues.push_back( aConverted ); // TODO: setFastPropertyValue notifies the unconverted value here ...? 469 m_pReserved->m_oldValues.push_back( aOld ); 470 } 471 472 // XFastPropertySet 473 void OPropertySetHelper::setFastPropertyValue( sal_Int32 nHandle, const Any& rValue ) 474 { 475 OSL_ENSURE( !rBHelper.bInDispose, "do not setFastPropertyValue in the dispose call" ); 476 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); 477 478 IPropertyArrayHelper & rInfo = getInfoHelper(); 479 sal_Int16 nAttributes; 480 if( !rInfo.fillPropertyMembersByHandle( NULL, &nAttributes, nHandle ) ) { 481 // unknown property 482 throw UnknownPropertyException(); 483 } 484 if( nAttributes & PropertyAttribute::READONLY ) 485 throw PropertyVetoException(); 486 487 Any aConvertedVal; 488 Any aOldVal; 489 490 // Will the property change? 491 sal_Bool bChanged; 492 { 493 MutexGuard aGuard( rBHelper.rMutex ); 494 bChanged = convertFastPropertyValue( aConvertedVal, aOldVal, nHandle, rValue ); 495 // release guard to fire events 496 } 497 if( bChanged ) 498 { 499 // Is it a constrained property? 500 if( nAttributes & PropertyAttribute::CONSTRAINED ) 501 { 502 // In aValue is the converted rValue 503 // fire a constarined event 504 // second parameter NULL means constrained 505 fire( &nHandle, &rValue, &aOldVal, 1, sal_True ); 506 } 507 508 { 509 MutexGuard aGuard( rBHelper.rMutex ); 510 try 511 { 512 // set the property to the new value 513 setFastPropertyValue_NoBroadcast( nHandle, aConvertedVal ); 514 } 515 catch (const ::com::sun::star::beans::UnknownPropertyException& ) { throw; /* allowed to leave */ } 516 catch (const ::com::sun::star::beans::PropertyVetoException& ) { throw; /* allowed to leave */ } 517 catch (const ::com::sun::star::lang::IllegalArgumentException& ) { throw; /* allowed to leave */ } 518 catch (const ::com::sun::star::lang::WrappedTargetException& ) { throw; /* allowed to leave */ } 519 catch (const ::com::sun::star::uno::RuntimeException& ) { throw; /* allowed to leave */ } 520 catch (const ::com::sun::star::uno::Exception& e ) 521 { 522 // not allowed to leave this method 523 ::com::sun::star::lang::WrappedTargetException aWrap; 524 aWrap.Context = static_cast< ::com::sun::star::beans::XPropertySet* >( this ); 525 aWrap.TargetException <<= e; 526 527 throw ::com::sun::star::lang::WrappedTargetException( aWrap ); 528 } 529 530 // release guard to fire events 531 } 532 // file a change event, if the value changed 533 impl_fireAll( &nHandle, &rValue, &aOldVal, 1 ); 534 } 535 } 536 537 // XFastPropertySet 538 Any OPropertySetHelper::getFastPropertyValue( sal_Int32 nHandle ) 539 540 { 541 IPropertyArrayHelper & rInfo = getInfoHelper(); 542 if( !rInfo.fillPropertyMembersByHandle( NULL, NULL, nHandle ) ) 543 // unknown property 544 throw UnknownPropertyException(); 545 546 Any aRet; 547 MutexGuard aGuard( rBHelper.rMutex ); 548 getFastPropertyValue( aRet, nHandle ); 549 return aRet; 550 } 551 552 //-------------------------------------------------------------------------- 553 void OPropertySetHelper::impl_fireAll( sal_Int32* i_handles, const Any* i_newValues, const Any* i_oldValues, sal_Int32 i_count ) 554 { 555 ClearableMutexGuard aGuard( rBHelper.rMutex ); 556 if ( m_pReserved->m_handles.empty() ) 557 { 558 aGuard.clear(); 559 fire( i_handles, i_newValues, i_oldValues, i_count, sal_False ); 560 return; 561 } 562 563 const size_t additionalEvents = m_pReserved->m_handles.size(); 564 OSL_ENSURE( additionalEvents == m_pReserved->m_newValues.size() 565 && additionalEvents == m_pReserved->m_oldValues.size(), 566 "OPropertySetHelper::impl_fireAll: inconsistency!" ); 567 568 ::std::vector< sal_Int32 > allHandles( additionalEvents + i_count ); 569 ::std::copy( m_pReserved->m_handles.begin(), m_pReserved->m_handles.end(), allHandles.begin() ); 570 ::std::copy( i_handles, i_handles + i_count, allHandles.begin() + additionalEvents ); 571 572 ::std::vector< Any > allNewValues( additionalEvents + i_count ); 573 ::std::copy( m_pReserved->m_newValues.begin(), m_pReserved->m_newValues.end(), allNewValues.begin() ); 574 ::std::copy( i_newValues, i_newValues + i_count, allNewValues.begin() + additionalEvents ); 575 576 ::std::vector< Any > allOldValues( additionalEvents + i_count ); 577 ::std::copy( m_pReserved->m_oldValues.begin(), m_pReserved->m_oldValues.end(), allOldValues.begin() ); 578 ::std::copy( i_oldValues, i_oldValues + i_count, allOldValues.begin() + additionalEvents ); 579 580 m_pReserved->m_handles.clear(); 581 m_pReserved->m_newValues.clear(); 582 m_pReserved->m_oldValues.clear(); 583 584 aGuard.clear(); 585 fire( &allHandles[0], &allNewValues[0], &allOldValues[0], additionalEvents + i_count, sal_False ); 586 } 587 588 //-------------------------------------------------------------------------- 589 void OPropertySetHelper::fire 590 ( 591 sal_Int32 * pnHandles, 592 const Any * pNewValues, 593 const Any * pOldValues, 594 sal_Int32 nHandles, // These is the Count of the array 595 sal_Bool bVetoable 596 ) 597 { 598 OSL_ENSURE( m_pReserved.get(), "No OPropertySetHelper::Impl" ); 599 if (m_pReserved->m_pFireEvents) { 600 m_pReserved->m_pFireEvents->fireEvents( 601 pnHandles, nHandles, bVetoable, 602 m_pReserved->m_bIgnoreRuntimeExceptionsWhileFiring); 603 } 604 605 // Only fire, if one or more properties changed 606 if( nHandles ) 607 { 608 // create the event sequence of all changed properties 609 Sequence< PropertyChangeEvent > aEvts( nHandles ); 610 PropertyChangeEvent * pEvts = aEvts.getArray(); 611 Reference < XInterface > xSource( (XPropertySet *)this, UNO_QUERY ); 612 sal_Int32 i; 613 sal_Int32 nChangesLen = 0; 614 // Loop over all changed properties to fill the event struct 615 for( i = 0; i < nHandles; i++ ) 616 { 617 // Vetoable fire and constrained attribute set or 618 // Change fire and Changed and bound attribute set 619 IPropertyArrayHelper & rInfo = getInfoHelper(); 620 sal_Int16 nAttributes; 621 OUString aPropName; 622 rInfo.fillPropertyMembersByHandle( &aPropName, &nAttributes, pnHandles[i] ); 623 624 if( 625 (bVetoable && (nAttributes & PropertyAttribute::CONSTRAINED)) || 626 (!bVetoable && (nAttributes & PropertyAttribute::BOUND)) 627 ) 628 { 629 pEvts[nChangesLen].Source = xSource; 630 pEvts[nChangesLen].PropertyName = aPropName; 631 pEvts[nChangesLen].PropertyHandle = pnHandles[i]; 632 pEvts[nChangesLen].OldValue = pOldValues[i]; 633 pEvts[nChangesLen].NewValue = pNewValues[i]; 634 nChangesLen++; 635 } 636 } 637 638 bool bIgnoreRuntimeExceptionsWhileFiring = 639 m_pReserved->m_bIgnoreRuntimeExceptionsWhileFiring; 640 641 // fire the events for all changed properties 642 for( i = 0; i < nChangesLen; i++ ) 643 { 644 // get the listener container for the property name 645 OInterfaceContainerHelper * pLC; 646 if( bVetoable ) // fire change Events? 647 pLC = aVetoableLC.getContainer( pEvts[i].PropertyHandle ); 648 else 649 pLC = aBoundLC.getContainer( pEvts[i].PropertyHandle ); 650 if( pLC ) 651 { 652 // Ueber alle Listener iterieren und Events senden 653 OInterfaceIteratorHelper aIt( *pLC); 654 while( aIt.hasMoreElements() ) 655 { 656 XInterface * pL = aIt.next(); 657 try 658 { 659 try 660 { 661 if( bVetoable ) // fire change Events? 662 { 663 ((XVetoableChangeListener *)pL)->vetoableChange( 664 pEvts[i] ); 665 } 666 else 667 { 668 ((XPropertyChangeListener *)pL)->propertyChange( 669 pEvts[i] ); 670 } 671 } 672 catch (DisposedException & exc) 673 { 674 OSL_ENSURE( exc.Context.is(), 675 "DisposedException without Context!" ); 676 if (exc.Context == pL) 677 aIt.remove(); 678 else 679 throw; 680 } 681 } 682 catch (RuntimeException & exc) 683 { 684 OSL_TRACE( 685 OUStringToOString( 686 OUString( RTL_CONSTASCII_USTRINGPARAM( 687 "caught RuntimeException while " 688 "firing listeners: ") ) + 689 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); 690 if (! bIgnoreRuntimeExceptionsWhileFiring) 691 throw; 692 } 693 } 694 } 695 // broadcast to all listeners with "" property name 696 if( bVetoable ){ 697 // fire change Events? 698 pLC = rBHelper.aLC.getContainer( 699 getVetoableTypeIdentifier() 700 ); 701 } 702 else { 703 pLC = rBHelper.aLC.getContainer( 704 getPropertyTypeIdentifier( ) 705 ); 706 } 707 if( pLC ) 708 { 709 // Ueber alle Listener iterieren und Events senden 710 OInterfaceIteratorHelper aIt( *pLC); 711 while( aIt.hasMoreElements() ) 712 { 713 XInterface * pL = aIt.next(); 714 try 715 { 716 try 717 { 718 if( bVetoable ) // fire change Events? 719 { 720 ((XVetoableChangeListener *)pL)->vetoableChange( 721 pEvts[i] ); 722 } 723 else 724 { 725 ((XPropertyChangeListener *)pL)->propertyChange( 726 pEvts[i] ); 727 } 728 } 729 catch (DisposedException & exc) 730 { 731 OSL_ENSURE( exc.Context.is(), 732 "DisposedException without Context!" ); 733 if (exc.Context == pL) 734 aIt.remove(); 735 else 736 throw; 737 } 738 } 739 catch (RuntimeException & exc) 740 { 741 OSL_TRACE( 742 OUStringToOString( 743 OUString( RTL_CONSTASCII_USTRINGPARAM( 744 "caught RuntimeException while " 745 "firing listeners: ") ) + 746 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); 747 if (! bIgnoreRuntimeExceptionsWhileFiring) 748 throw; 749 } 750 } 751 } 752 } 753 754 // reduce array to changed properties 755 aEvts.realloc( nChangesLen ); 756 757 if( !bVetoable ) 758 { 759 OInterfaceContainerHelper * pCont = 0; 760 pCont = rBHelper.aLC.getContainer( 761 getPropertiesTypeIdentifier( ) 762 ); 763 if( pCont ) 764 { 765 // Here is a Bug, unbound properties are also fired 766 OInterfaceIteratorHelper aIt( *pCont ); 767 while( aIt.hasMoreElements() ) 768 { 769 XPropertiesChangeListener * pL = 770 (XPropertiesChangeListener *)aIt.next(); 771 try 772 { 773 try 774 { 775 // fire the hole event sequence to the 776 // XPropertiesChangeListener's 777 pL->propertiesChange( aEvts ); 778 } 779 catch (DisposedException & exc) 780 { 781 OSL_ENSURE( exc.Context.is(), 782 "DisposedException without Context!" ); 783 if (exc.Context == pL) 784 aIt.remove(); 785 else 786 throw; 787 } 788 } 789 catch (RuntimeException & exc) 790 { 791 OSL_TRACE( 792 OUStringToOString( 793 OUString( RTL_CONSTASCII_USTRINGPARAM( 794 "caught RuntimeException while " 795 "firing listeners: ") ) + 796 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); 797 if (! bIgnoreRuntimeExceptionsWhileFiring) 798 throw; 799 } 800 } 801 } 802 } 803 } 804 } 805 806 // OPropertySetHelper 807 void OPropertySetHelper::setFastPropertyValues( 808 sal_Int32 nSeqLen, 809 sal_Int32 * pHandles, 810 const Any * pValues, 811 sal_Int32 nHitCount ) 812 { 813 OSL_ENSURE( !rBHelper.bInDispose, "do not getFastPropertyValue in the dispose call" ); 814 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); 815 816 Any * pConvertedValues = NULL; 817 Any * pOldValues = NULL; 818 819 try 820 { 821 // get the map table 822 IPropertyArrayHelper & rPH = getInfoHelper(); 823 824 pConvertedValues = new Any[ nHitCount ]; 825 pOldValues = new Any[ nHitCount ]; 826 sal_Int32 n = 0; 827 sal_Int32 i; 828 829 { 830 // must lock the mutex outside the loop. So all values are consistent. 831 MutexGuard aGuard( rBHelper.rMutex ); 832 for( i = 0; i < nSeqLen; i++ ) 833 { 834 if( pHandles[i] != -1 ) 835 { 836 sal_Int16 nAttributes; 837 rPH.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] ); 838 if( nAttributes & PropertyAttribute::READONLY ) { 839 throw PropertyVetoException(); 840 } 841 // Will the property change? 842 if( convertFastPropertyValue( pConvertedValues[ n ], pOldValues[n], 843 pHandles[i], pValues[i] ) ) 844 { 845 // only increment if the property really change 846 pHandles[n] = pHandles[i]; 847 n++; 848 } 849 } 850 } 851 // release guard to fire events 852 } 853 854 // fire vetoable events 855 fire( pHandles, pConvertedValues, pOldValues, n, sal_True ); 856 857 { 858 // must lock the mutex outside the loop. 859 MutexGuard aGuard( rBHelper.rMutex ); 860 // Loop over all changed properties 861 for( i = 0; i < n; i++ ) 862 { 863 // Will the property change? 864 setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] ); 865 } 866 // release guard to fire events 867 } 868 869 // fire change events 870 impl_fireAll( pHandles, pConvertedValues, pOldValues, n ); 871 } 872 catch( ... ) 873 { 874 delete [] pOldValues; 875 delete [] pConvertedValues; 876 throw; 877 } 878 delete [] pOldValues; 879 delete [] pConvertedValues; 880 } 881 882 // XMultiPropertySet 883 /** 884 * The sequence may contain not known properties. The implementation 885 * must ignore these properties. 886 */ 887 void OPropertySetHelper::setPropertyValues( 888 const Sequence<OUString>& rPropertyNames, 889 const Sequence<Any>& rValues ) 890 { 891 sal_Int32 * pHandles = NULL; 892 try 893 { 894 sal_Int32 nSeqLen = rPropertyNames.getLength(); 895 pHandles = new sal_Int32[ nSeqLen ]; 896 // get the map table 897 IPropertyArrayHelper & rPH = getInfoHelper(); 898 // fill the handle array 899 sal_Int32 nHitCount = rPH.fillHandles( pHandles, rPropertyNames ); 900 if( nHitCount != 0 ) 901 setFastPropertyValues( nSeqLen, pHandles, rValues.getConstArray(), nHitCount ); 902 } 903 catch( ... ) 904 { 905 delete [] pHandles; 906 throw; 907 } 908 delete [] pHandles; 909 } 910 911 // XMultiPropertySet 912 Sequence<Any> OPropertySetHelper::getPropertyValues( const Sequence<OUString>& rPropertyNames ) 913 { 914 sal_Int32 nSeqLen = rPropertyNames.getLength(); 915 sal_Int32 * pHandles = new sal_Int32[ nSeqLen ]; 916 Sequence< Any > aValues( nSeqLen ); 917 918 // get the map table 919 IPropertyArrayHelper & rPH = getInfoHelper(); 920 // fill the handle array 921 rPH.fillHandles( pHandles, rPropertyNames ); 922 923 Any * pValues = aValues.getArray(); 924 925 MutexGuard aGuard( rBHelper.rMutex ); 926 // fill the sequence with the values 927 for( sal_Int32 i = 0; i < nSeqLen; i++ ) 928 getFastPropertyValue( pValues[i], pHandles[i] ); 929 930 delete [] pHandles; 931 return aValues; 932 } 933 934 // XMultiPropertySet 935 void OPropertySetHelper::addPropertiesChangeListener( 936 const Sequence<OUString> & , 937 const Reference < XPropertiesChangeListener > & rListener ) 938 { 939 rBHelper.addListener( getCppuType(&rListener) , rListener ); 940 } 941 942 // XMultiPropertySet 943 void OPropertySetHelper::removePropertiesChangeListener( 944 const Reference < XPropertiesChangeListener > & rListener ) 945 { 946 rBHelper.removeListener( getCppuType(&rListener) , rListener ); 947 } 948 949 // XMultiPropertySet 950 void OPropertySetHelper::firePropertiesChangeEvent( 951 const Sequence<OUString>& rPropertyNames, 952 const Reference < XPropertiesChangeListener >& rListener ) 953 { 954 sal_Int32 nLen = rPropertyNames.getLength(); 955 sal_Int32 * pHandles = new sal_Int32[nLen]; 956 IPropertyArrayHelper & rPH = getInfoHelper(); 957 rPH.fillHandles( pHandles, rPropertyNames ); 958 const OUString* pNames = rPropertyNames.getConstArray(); 959 960 // get the count of matching properties 961 sal_Int32 nFireLen = 0; 962 sal_Int32 i; 963 for( i = 0; i < nLen; i++ ) 964 if( pHandles[i] != -1 ) 965 nFireLen++; 966 967 Sequence<PropertyChangeEvent> aChanges( nFireLen ); 968 PropertyChangeEvent* pChanges = aChanges.getArray(); 969 970 sal_Int32 nFirePos = 0; 971 { 972 // must lock the mutex outside the loop. So all values are consistent. 973 MutexGuard aGuard( rBHelper.rMutex ); 974 Reference < XInterface > xSource( (XPropertySet *)this, UNO_QUERY ); 975 for( i = 0; i < nLen; i++ ) 976 { 977 if( pHandles[i] != -1 ) 978 { 979 pChanges[nFirePos].Source = xSource; 980 pChanges[nFirePos].PropertyName = pNames[i]; 981 pChanges[nFirePos].PropertyHandle = pHandles[i]; 982 getFastPropertyValue( pChanges[nFirePos].OldValue, pHandles[i] ); 983 pChanges[nFirePos].NewValue = pChanges[nFirePos].OldValue; 984 nFirePos++; 985 } 986 } 987 // release guard to fire events 988 } 989 if( nFireLen ) 990 rListener->propertiesChange( aChanges ); 991 992 delete [] pHandles; 993 } 994 995 #ifdef xdvnsdfln 996 // XPropertyState 997 PropertyState OPropertySetHelper::getPropertyState( const OUString& PropertyName ) 998 { 999 PropertyState aState; 1000 return aState; 1001 } 1002 1003 // XPropertyState 1004 Sequence< PropertyState > OPropertySetHelper::getPropertyStates( const Sequence< OUString >& PropertyNames ) 1005 { 1006 ULONG nNames = PropertyNames.getLength(); 1007 const OUString* pNames = PropertyNames.getConstArray(); 1008 1009 Sequence< PropertyState > aStates( nNames ); 1010 return aStates; 1011 1012 } 1013 1014 void OPropertySetHelper::setPropertyToDefault( const OUString& aPropertyName ) 1015 { 1016 setPropertyValue( aPropertyName, Any() ); 1017 } 1018 1019 Any OPropertySetHelper::getPropertyDefault( const OUString& aPropertyName ) const 1020 { 1021 return Any(); 1022 } 1023 1024 void OPropertySetHelper::addPropertyStateChangeListener( const OUString& aPropertyName, const XPropertyStateChangeListenerRef& Listener ) 1025 { 1026 } 1027 1028 void OPropertySetHelper::removePropertyStateChangeListener( const OUString& aPropertyName, const XPropertyStateChangeListenerRef& Listener ) 1029 { 1030 } 1031 #endif 1032 1033 //======================================================================== 1034 //== OPropertyArrayHelper ================================================ 1035 //======================================================================== 1036 1037 //======================================================================== 1038 1039 // static OUString makeOUString( sal_Char *p ) 1040 // { 1041 // sal_Int32 nLen = strlen(p); 1042 // sal_Unicode *pw = new sal_Unicode[nLen]; 1043 1044 // for( int i = 0 ; i < nLen ; i ++ ) { 1045 1046 // // Only ascii strings allowed with this helper ! 1047 // OSL_ASSERT( p[i] < 127 ); 1048 // pw[i] = p[i]; 1049 // } 1050 // OUString ow( pw , nLen ); 1051 // delete pw; 1052 // return ow; 1053 // } 1054 1055 extern "C" { 1056 1057 static int compare_Property_Impl( const void *arg1, const void *arg2 ) 1058 SAL_THROW_EXTERN_C() 1059 { 1060 return ((Property *)arg1)->Name.compareTo( ((Property *)arg2)->Name ); 1061 } 1062 1063 } 1064 1065 void OPropertyArrayHelper::init( sal_Bool bSorted ) SAL_THROW( () ) 1066 { 1067 sal_Int32 i, nElements = aInfos.getLength(); 1068 const Property* pProperties = aInfos.getConstArray(); 1069 1070 for( i = 1; i < nElements; i++ ) 1071 { 1072 if( pProperties[i-1].Name >= pProperties[i].Name ) 1073 { 1074 #ifndef OS2 // YD disabled, too many troubles with debug builds! 1075 if (bSorted) { 1076 OSL_ENSURE( false, "Property array is not sorted" ); 1077 } 1078 #endif 1079 // not sorted 1080 qsort( aInfos.getArray(), nElements, sizeof( Property ), 1081 compare_Property_Impl ); 1082 break; 1083 } 1084 } 1085 // may be that the array is resorted 1086 pProperties = aInfos.getConstArray(); 1087 for( i = 0; i < nElements; i++ ) 1088 if( pProperties[i].Handle != i ) 1089 return; 1090 // The handle is the index 1091 bRightOrdered = sal_True; 1092 } 1093 1094 OPropertyArrayHelper::OPropertyArrayHelper( 1095 Property * pProps, 1096 sal_Int32 nEle, 1097 sal_Bool bSorted ) 1098 SAL_THROW( () ) 1099 : aInfos(pProps, nEle) 1100 , bRightOrdered( sal_False ) 1101 { 1102 init( bSorted ); 1103 } 1104 1105 OPropertyArrayHelper::OPropertyArrayHelper( 1106 const Sequence< Property > & aProps, 1107 sal_Bool bSorted ) 1108 SAL_THROW( () ) 1109 : aInfos(aProps) 1110 , bRightOrdered( sal_False ) 1111 { 1112 init( bSorted ); 1113 } 1114 1115 //======================================================================== 1116 sal_Int32 OPropertyArrayHelper::getCount() const 1117 { 1118 return aInfos.getLength(); 1119 } 1120 1121 //======================================================================== 1122 sal_Bool OPropertyArrayHelper::fillPropertyMembersByHandle 1123 ( 1124 OUString * pPropName, 1125 sal_Int16 * pAttributes, 1126 sal_Int32 nHandle 1127 ) 1128 { 1129 const Property* pProperties = aInfos.getConstArray(); 1130 sal_Int32 nElements = aInfos.getLength(); 1131 1132 if( bRightOrdered ) 1133 { 1134 if( nHandle < 0 || nHandle >= nElements ) 1135 return sal_False; 1136 if( pPropName ) 1137 *pPropName = pProperties[ nHandle ].Name; 1138 if( pAttributes ) 1139 *pAttributes = pProperties[ nHandle ].Attributes; 1140 return sal_True; 1141 } 1142 else 1143 { 1144 // normally the array is sorted 1145 for( sal_Int32 i = 0; i < nElements; i++ ) 1146 { 1147 if( pProperties[i].Handle == nHandle ) 1148 { 1149 if( pPropName ) 1150 *pPropName = pProperties[ i ].Name; 1151 if( pAttributes ) 1152 *pAttributes = pProperties[ i ].Attributes; 1153 return sal_True; 1154 } 1155 } 1156 } 1157 return sal_False; 1158 } 1159 1160 //======================================================================== 1161 Sequence< Property > OPropertyArrayHelper::getProperties(void) 1162 { 1163 /*if( aInfos.getLength() != nElements ) 1164 { 1165 ((OPropertyArrayHelper *)this)->aInfos.realloc( nElements ); 1166 Property * pProps = ((OPropertyArrayHelper *)this)->aInfos.getArray(); 1167 for( sal_Int32 i = 0; i < nElements; i++ ) 1168 { 1169 pProps[i].Name = pProperties[i].Name; 1170 pProps[i].Handle = pProperties[i].Handle; 1171 pProps[i].Type = pProperties[i].Type; 1172 pProps[i].Attributes = pProperties[i].Attributes; 1173 } 1174 }*/ 1175 return aInfos; 1176 } 1177 1178 //======================================================================== 1179 Property OPropertyArrayHelper::getPropertyByName(const OUString& aPropertyName) 1180 { 1181 Property * pR; 1182 pR = (Property *)bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(), 1183 sizeof( Property ), 1184 compare_OUString_Property_Impl ); 1185 if( !pR ) { 1186 throw UnknownPropertyException(); 1187 } 1188 1189 /*Property aProp; 1190 aProp.Name = pR->Name; 1191 aProp.Handle = pR->Handle; 1192 aProp.Type = pR->Type; 1193 aProp.Attributes = pR->Attributes; 1194 return aProp;*/ 1195 return *pR; 1196 } 1197 1198 //======================================================================== 1199 sal_Bool OPropertyArrayHelper::hasPropertyByName(const OUString& aPropertyName) 1200 { 1201 Property * pR; 1202 pR = (Property *)bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(), 1203 sizeof( Property ), 1204 compare_OUString_Property_Impl ); 1205 return pR != NULL; 1206 } 1207 1208 //======================================================================== 1209 sal_Int32 OPropertyArrayHelper::getHandleByName( const OUString & rPropName ) 1210 { 1211 Property * pR; 1212 pR = (Property *)bsearch( &rPropName, aInfos.getConstArray(), aInfos.getLength(), 1213 sizeof( Property ), 1214 compare_OUString_Property_Impl ); 1215 return pR ? pR->Handle : -1; 1216 } 1217 1218 //======================================================================== 1219 sal_Int32 OPropertyArrayHelper::fillHandles( sal_Int32 * pHandles, const Sequence< OUString > & rPropNames ) 1220 { 1221 sal_Int32 nHitCount = 0; 1222 const OUString * pReqProps = rPropNames.getConstArray(); 1223 sal_Int32 nReqLen = rPropNames.getLength(); 1224 const Property * pCur = aInfos.getConstArray(); 1225 const Property * pEnd = pCur + aInfos.getLength(); 1226 1227 for( sal_Int32 i = 0; i < nReqLen; i++ ) 1228 { 1229 // Logarithmus ermitteln 1230 sal_Int32 n = (sal_Int32)(pEnd - pCur); 1231 sal_Int32 nLog = 0; 1232 while( n ) 1233 { 1234 nLog += 1; 1235 n = n >> 1; 1236 } 1237 1238 // Anzahl der noch zu suchenden Properties * dem Log2 der verbleibenden 1239 // zu dursuchenden Properties. 1240 if( (nReqLen - i) * nLog >= pEnd - pCur ) 1241 { 1242 // linear search is better 1243 while( pCur < pEnd && pReqProps[i] > pCur->Name ) 1244 { 1245 pCur++; 1246 } 1247 if( pCur < pEnd && pReqProps[i] == pCur->Name ) 1248 { 1249 pHandles[i] = pCur->Handle; 1250 nHitCount++; 1251 } 1252 else 1253 pHandles[i] = -1; 1254 } 1255 else 1256 { 1257 // binary search is better 1258 sal_Int32 nCompVal = 1; 1259 const Property * pOldEnd = pEnd--; 1260 const Property * pMid = pCur; 1261 1262 while( nCompVal != 0 && pCur <= pEnd ) 1263 { 1264 pMid = (pEnd - pCur) / 2 + pCur; 1265 1266 nCompVal = pReqProps[i].compareTo( pMid->Name ); 1267 1268 if( nCompVal > 0 ) 1269 pCur = pMid + 1; 1270 else 1271 pEnd = pMid - 1; 1272 } 1273 1274 if( nCompVal == 0 ) 1275 { 1276 pHandles[i] = pMid->Handle; 1277 nHitCount++; 1278 pCur = pMid +1; 1279 } 1280 else if( nCompVal > 0 ) 1281 { 1282 pHandles[i] = -1; 1283 pCur = pMid +1; 1284 } 1285 else 1286 { 1287 pHandles[i] = -1; 1288 pCur = pMid; 1289 } 1290 pEnd = pOldEnd; 1291 } 1292 } 1293 return nHitCount; 1294 } 1295 1296 } // end namespace cppu 1297