1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_comphelper.hxx" 30 #include "comphelper/propagg.hxx" 31 #include "comphelper/property.hxx" 32 #include <cppuhelper/queryinterface.hxx> 33 #include <osl/diagnose.h> 34 #include <com/sun/star/beans/PropertyAttribute.hpp> 35 36 #if OSL_DEBUG_LEVEL > 0 37 #include <typeinfo> 38 #include <rtl/strbuf.hxx> 39 #endif 40 41 #include <algorithm> 42 #include <set> 43 44 //......................................................................... 45 namespace comphelper 46 { 47 //......................................................................... 48 49 using namespace ::com::sun::star::uno; 50 using namespace ::com::sun::star::lang; 51 using namespace ::com::sun::star::beans; 52 53 using namespace internal; 54 55 //------------------------------------------------------------------------------ 56 namespace 57 { 58 const Property* lcl_findPropertyByName( const Sequence< Property >& _rProps, const ::rtl::OUString& _rName ) 59 { 60 sal_Int32 nLen = _rProps.getLength(); 61 const Property* pProperties = _rProps.getConstArray(); 62 const Property* pResult = ::std::lower_bound(pProperties, pProperties + nLen,_rName, ::comphelper::PropertyStringLessFunctor()); 63 if ( pResult && ( pResult == pProperties + nLen || pResult->Name != _rName) ) 64 pResult = NULL; 65 66 return pResult; 67 } 68 } 69 //================================================================== 70 //= OPropertyArrayAggregationHelper 71 //================================================================== 72 73 //------------------------------------------------------------------------------ 74 OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper( 75 const Sequence< Property >& _rProperties, const Sequence< Property >& _rAggProperties, 76 IPropertyInfoService* _pInfoService, sal_Int32 _nFirstAggregateId ) 77 :m_aProperties( _rProperties ) 78 { 79 sal_Int32 nDelegatorProps = _rProperties.getLength(); 80 sal_Int32 nAggregateProps = _rAggProperties.getLength(); 81 82 // make room for all properties 83 sal_Int32 nMergedProps = nDelegatorProps + nAggregateProps; 84 m_aProperties.realloc( nMergedProps ); 85 86 const Property* pAggregateProps = _rAggProperties.getConstArray(); 87 const Property* pDelegateProps = _rProperties.getConstArray(); 88 Property* pMergedProps = m_aProperties.getArray(); 89 90 // if properties are present both at the delegatee and the aggregate, then the former are supposed to win. 91 // So, we'll need an existence check. 92 ::std::set< ::rtl::OUString > aDelegatorProps; 93 94 // create the map for the delegator properties 95 sal_Int32 nMPLoop = 0; 96 for ( ; nMPLoop < nDelegatorProps; ++nMPLoop, ++pDelegateProps ) 97 { 98 m_aPropertyAccessors[ pDelegateProps->Handle ] = OPropertyAccessor( -1, nMPLoop, sal_False ); 99 OSL_ENSURE( aDelegatorProps.find( pDelegateProps->Name ) == aDelegatorProps.end(), 100 "OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper: duplicate delegatee property!" ); 101 aDelegatorProps.insert( pDelegateProps->Name ); 102 } 103 104 // create the map for the aggregate properties 105 sal_Int32 nAggregateHandle = _nFirstAggregateId; 106 pMergedProps += nDelegatorProps; 107 for ( ; nMPLoop < nMergedProps; ++pAggregateProps ) 108 { 109 // if the aggregate property is present at the delegatee already, ignore it 110 if ( aDelegatorProps.find( pAggregateProps->Name ) != aDelegatorProps.end() ) 111 { 112 --nMergedProps; 113 continue; 114 } 115 116 // next aggregate property - remember it 117 *pMergedProps = *pAggregateProps; 118 119 // determine the handle for the property which we will expose to the outside world 120 sal_Int32 nHandle = -1; 121 // ask the infor service first 122 if ( _pInfoService ) 123 nHandle = _pInfoService->getPreferedPropertyId( pMergedProps->Name ); 124 125 if ( -1 == nHandle ) 126 // no handle from the info service -> default 127 nHandle = nAggregateHandle++; 128 else 129 { // check if we alread have a property with the given handle 130 const Property* pPropsTilNow = m_aProperties.getConstArray(); 131 for ( sal_Int32 nCheck = 0; nCheck < nMPLoop; ++nCheck, ++pPropsTilNow ) 132 if ( pPropsTilNow->Handle == nHandle ) 133 { // conflicts -> use another one (which we don't check anymore, assuming _nFirstAggregateId was large enough) 134 nHandle = nAggregateHandle++; 135 break; 136 } 137 } 138 139 // remember the accessor for this property 140 m_aPropertyAccessors[ nHandle ] = OPropertyAccessor( pMergedProps->Handle, nMPLoop, sal_True ); 141 pMergedProps->Handle = nHandle; 142 143 ++nMPLoop; 144 ++pMergedProps; 145 } 146 m_aProperties.realloc( nMergedProps ); 147 pMergedProps = m_aProperties.getArray(); // reset, needed again below 148 149 // sortieren der Properties nach Namen 150 ::std::sort( pMergedProps, pMergedProps+nMergedProps, PropertyCompareByName()); 151 152 pMergedProps = m_aProperties.getArray(); 153 154 // Positionen in der Map abgleichen 155 for ( nMPLoop = 0; nMPLoop < nMergedProps; ++nMPLoop, ++pMergedProps ) 156 m_aPropertyAccessors[ pMergedProps->Handle ].nPos = nMPLoop; 157 } 158 159 //------------------------------------------------------------------ 160 OPropertyArrayAggregationHelper::PropertyOrigin OPropertyArrayAggregationHelper::classifyProperty( const ::rtl::OUString& _rName ) 161 { 162 PropertyOrigin eOrigin = UNKNOWN_PROPERTY; 163 // look up the name 164 const Property* pPropertyDescriptor = lcl_findPropertyByName( m_aProperties, _rName ); 165 if ( pPropertyDescriptor ) 166 { 167 // look up the handle for this name 168 ConstPropertyAccessorMapIterator aPos = m_aPropertyAccessors.find( pPropertyDescriptor->Handle ); 169 OSL_ENSURE( m_aPropertyAccessors.end() != aPos, "OPropertyArrayAggregationHelper::classifyProperty: should have this handle in my map!" ); 170 if ( m_aPropertyAccessors.end() != aPos ) 171 { 172 eOrigin = aPos->second.bAggregate ? AGGREGATE_PROPERTY : DELEGATOR_PROPERTY; 173 } 174 } 175 return eOrigin; 176 } 177 178 //------------------------------------------------------------------ 179 Property OPropertyArrayAggregationHelper::getPropertyByName( const ::rtl::OUString& _rPropertyName ) throw( UnknownPropertyException ) 180 { 181 const Property* pProperty = findPropertyByName( _rPropertyName ); 182 183 if ( !pProperty ) 184 throw UnknownPropertyException(); 185 186 return *pProperty; 187 } 188 189 //------------------------------------------------------------------------------ 190 sal_Bool OPropertyArrayAggregationHelper::hasPropertyByName(const ::rtl::OUString& _rPropertyName) 191 { 192 return NULL != findPropertyByName( _rPropertyName ); 193 } 194 195 //------------------------------------------------------------------------------ 196 const Property* OPropertyArrayAggregationHelper::findPropertyByName(const :: rtl::OUString& _rName ) const 197 { 198 return lcl_findPropertyByName( m_aProperties, _rName ); 199 } 200 201 //------------------------------------------------------------------------------ 202 sal_Int32 OPropertyArrayAggregationHelper::getHandleByName(const ::rtl::OUString& _rPropertyName) 203 { 204 const Property* pProperty = findPropertyByName( _rPropertyName ); 205 return pProperty ? pProperty->Handle : -1; 206 } 207 208 //------------------------------------------------------------------------------ 209 sal_Bool OPropertyArrayAggregationHelper::fillPropertyMembersByHandle( 210 ::rtl::OUString* _pPropName, sal_Int16* _pAttributes, sal_Int32 _nHandle) 211 { 212 ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle); 213 sal_Bool bRet = i != m_aPropertyAccessors.end(); 214 if (bRet) 215 { 216 const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos]; 217 if (_pPropName) 218 *_pPropName = rProperty.Name; 219 if (_pAttributes) 220 *_pAttributes = rProperty.Attributes; 221 } 222 return bRet; 223 } 224 225 //------------------------------------------------------------------------------ 226 sal_Bool OPropertyArrayAggregationHelper::getPropertyByHandle( sal_Int32 _nHandle, Property& _rProperty ) const 227 { 228 ConstPropertyAccessorMapIterator pos = m_aPropertyAccessors.find(_nHandle); 229 if ( pos != m_aPropertyAccessors.end() ) 230 { 231 _rProperty = m_aProperties[ pos->second.nPos ]; 232 return sal_True; 233 } 234 return sal_False; 235 } 236 237 //------------------------------------------------------------------------------ 238 sal_Bool OPropertyArrayAggregationHelper::fillAggregatePropertyInfoByHandle( 239 ::rtl::OUString* _pPropName, sal_Int32* _pOriginalHandle, sal_Int32 _nHandle) const 240 { 241 ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle); 242 sal_Bool bRet = i != m_aPropertyAccessors.end() && (*i).second.bAggregate; 243 if (bRet) 244 { 245 if (_pOriginalHandle) 246 *_pOriginalHandle = (*i).second.nOriginalHandle; 247 if (_pPropName) 248 { 249 OSL_ENSURE((*i).second.nPos < m_aProperties.getLength(),"Invalid index for sequence!"); 250 const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos]; 251 *_pPropName = rProperty.Name; 252 } 253 } 254 return bRet; 255 } 256 257 258 //------------------------------------------------------------------------------ 259 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property> OPropertyArrayAggregationHelper::getProperties() 260 { 261 return m_aProperties; 262 } 263 264 265 //------------------------------------------------------------------------------ 266 sal_Int32 OPropertyArrayAggregationHelper::fillHandles( 267 sal_Int32* _pHandles, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rPropNames ) 268 { 269 sal_Int32 nHitCount = 0; 270 const ::rtl::OUString* pReqProps = _rPropNames.getConstArray(); 271 sal_Int32 nReqLen = _rPropNames.getLength(); 272 273 #if OSL_DEBUG_LEVEL > 0 274 // assure that the sequence is sorted 275 { 276 const ::rtl::OUString* pLookup = _rPropNames.getConstArray(); 277 const ::rtl::OUString* pEnd = _rPropNames.getConstArray() + _rPropNames.getLength() - 1; 278 for (; pLookup < pEnd; ++pLookup) 279 { 280 const ::rtl::OUString* pCompare = pLookup + 1; 281 const ::rtl::OUString* pCompareEnd = pEnd + 1; 282 for (; pCompare < pCompareEnd; ++pCompare) 283 { 284 OSL_ENSURE(pLookup->compareTo(*pCompare) < 0, "OPropertyArrayAggregationHelper::fillHandles : property names are not sorted!"); 285 } 286 } 287 } 288 #endif 289 290 const ::com::sun::star::beans::Property* pCur = m_aProperties.getConstArray(); 291 const ::com::sun::star::beans::Property* pEnd = m_aProperties.getConstArray() + m_aProperties.getLength(); 292 293 for( sal_Int32 i = 0; i < nReqLen; ++i ) 294 { 295 // Logarithmus ermitteln 296 sal_uInt32 n = (sal_uInt32)(pEnd - pCur); 297 sal_Int32 nLog = 0; 298 while( n ) 299 { 300 nLog += 1; 301 n = n >> 1; 302 } 303 304 // Anzahl der noch zu suchenden Properties * dem Log2 der verbleibenden 305 // zu dursuchenden Properties. 306 if( (nReqLen - i) * nLog >= pEnd - pCur ) 307 { 308 // linear search is better 309 while( pCur < pEnd && pReqProps[i] > pCur->Name ) 310 { 311 pCur++; 312 } 313 if( pCur < pEnd && pReqProps[i] == pCur->Name ) 314 { 315 _pHandles[i] = pCur->Handle; 316 nHitCount++; 317 } 318 else 319 _pHandles[i] = -1; 320 } 321 else 322 { 323 // binary search is better 324 sal_Int32 nCompVal = 1; 325 const ::com::sun::star::beans::Property* pOldEnd = pEnd--; 326 const ::com::sun::star::beans::Property* pMid = pCur; 327 328 while( nCompVal != 0 && pCur <= pEnd ) 329 { 330 pMid = (pEnd - pCur) / 2 + pCur; 331 332 nCompVal = pReqProps[i].compareTo( pMid->Name ); 333 334 if( nCompVal > 0 ) 335 pCur = pMid + 1; 336 else 337 pEnd = pMid - 1; 338 } 339 340 if( nCompVal == 0 ) 341 { 342 _pHandles[i] = pMid->Handle; 343 nHitCount++; 344 pCur = pMid +1; 345 } 346 else if( nCompVal > 0 ) 347 { 348 _pHandles[i] = -1; 349 pCur = pMid + 1; 350 } 351 else 352 { 353 _pHandles[i] = -1; 354 pCur = pMid; 355 } 356 pEnd = pOldEnd; 357 } 358 } 359 return nHitCount; 360 } 361 362 //================================================================== 363 //= PropertyForwarder 364 //================================================================== 365 namespace internal 366 { 367 class PropertyForwarder 368 { 369 private: 370 OPropertySetAggregationHelper& m_rAggregationHelper; 371 ::std::set< sal_Int32 > m_aProperties; 372 sal_Int32 m_nCurrentlyForwarding; 373 374 public: 375 PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper ); 376 ~PropertyForwarder(); 377 378 /** declares that the forwarder should be responsible for the given property 379 380 @param _nHandle 381 the public handle (<em>not</em> the original handle!) of the property 382 */ 383 void takeResponsibilityFor( sal_Int32 _nHandle ); 384 385 /** checks whether the forwarder is responsible for the given property 386 */ 387 bool isResponsibleFor( sal_Int32 _nHandle ); 388 389 /// actually forwards a property value to the aggregate 390 void doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception ); 391 392 sal_Int32 getCurrentlyForwardedProperty( ) const { return m_nCurrentlyForwarding; } 393 }; 394 395 //-------------------------------------------------------------------------- 396 PropertyForwarder::PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper ) 397 :m_rAggregationHelper( _rAggregationHelper ) 398 ,m_nCurrentlyForwarding( -1 ) 399 { 400 } 401 402 //-------------------------------------------------------------------------- 403 PropertyForwarder::~PropertyForwarder() 404 { 405 } 406 407 //-------------------------------------------------------------------------- 408 void PropertyForwarder::takeResponsibilityFor( sal_Int32 _nHandle ) 409 { 410 m_aProperties.insert( _nHandle ); 411 } 412 413 //-------------------------------------------------------------------------- 414 bool PropertyForwarder::isResponsibleFor( sal_Int32 _nHandle ) 415 { 416 return m_aProperties.find( _nHandle ) != m_aProperties.end(); 417 } 418 419 //-------------------------------------------------------------------------- 420 void PropertyForwarder::doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception ) 421 { 422 OSL_ENSURE( m_rAggregationHelper.m_xAggregateSet.is(), "PropertyForwarder::doForward: no property set!" ); 423 if ( m_rAggregationHelper.m_xAggregateSet.is() ) 424 { 425 m_rAggregationHelper.forwardingPropertyValue( _nHandle ); 426 427 OSL_ENSURE( m_nCurrentlyForwarding == -1, "PropertyForwarder::doForward: reentrance?" ); 428 m_nCurrentlyForwarding = _nHandle; 429 430 try 431 { 432 m_rAggregationHelper.m_xAggregateSet->setPropertyValue( m_rAggregationHelper.getPropertyName( _nHandle ), _rValue ); 433 // TODO: cache the property name? (it's a O(log n) search) 434 } 435 catch( const Exception& ) 436 { 437 m_rAggregationHelper.forwardedPropertyValue( _nHandle, false ); 438 throw; 439 } 440 441 m_nCurrentlyForwarding = -1; 442 443 m_rAggregationHelper.forwardedPropertyValue( _nHandle, true ); 444 } 445 } 446 } 447 448 //================================================================== 449 //= OPropertySetAggregationHelper 450 //================================================================== 451 452 //------------------------------------------------------------------------------ 453 OPropertySetAggregationHelper::OPropertySetAggregationHelper( ::cppu::OBroadcastHelper& rBHlp ) 454 :OPropertyStateHelper( rBHlp ) 455 ,m_bListening( sal_False ) 456 { 457 m_pForwarder = new PropertyForwarder( *this ); 458 } 459 460 //------------------------------------------------------------------------------ 461 OPropertySetAggregationHelper::~OPropertySetAggregationHelper() 462 { 463 delete m_pForwarder; 464 } 465 466 //------------------------------------------------------------------------------ 467 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::queryInterface(const ::com::sun::star::uno::Type& _rType) throw( ::com::sun::star::uno::RuntimeException) 468 { 469 ::com::sun::star::uno::Any aReturn = OPropertyStateHelper::queryInterface(_rType); 470 471 if ( !aReturn.hasValue() ) 472 aReturn = cppu::queryInterface(_rType 473 ,static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this) 474 ,static_cast< ::com::sun::star::beans::XVetoableChangeListener*>(this) 475 ,static_cast< ::com::sun::star::lang::XEventListener*>(static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this)) 476 ); 477 478 return aReturn; 479 } 480 481 //------------------------------------------------------------------------------ 482 void OPropertySetAggregationHelper::disposing() 483 { 484 osl::MutexGuard aGuard(rBHelper.rMutex); 485 486 if ( m_xAggregateSet.is() && m_bListening ) 487 { 488 // als einziger Listener anmelden 489 m_xAggregateMultiSet->removePropertiesChangeListener(this); 490 m_xAggregateSet->removeVetoableChangeListener(::rtl::OUString(), this); 491 m_bListening = sal_False; 492 } 493 494 OPropertyStateHelper::disposing(); 495 } 496 497 //------------------------------------------------------------------------------ 498 void SAL_CALL OPropertySetAggregationHelper::disposing(const ::com::sun::star::lang::EventObject& _rSource) throw ( ::com::sun::star::uno::RuntimeException) 499 { 500 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::disposing : don't have an aggregate anymore !"); 501 if (_rSource.Source == m_xAggregateSet) 502 m_bListening = sal_False; 503 } 504 505 //------------------------------------------------------------------------------ 506 void SAL_CALL OPropertySetAggregationHelper::propertiesChange(const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyChangeEvent>& _rEvents) throw( ::com::sun::star::uno::RuntimeException) 507 { 508 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::propertiesChange : have no aggregate !"); 509 510 sal_Int32 nLen = _rEvents.getLength(); 511 cppu::IPropertyArrayHelper& rPH = getInfoHelper(); 512 513 if (1 == nLen) 514 { 515 const ::com::sun::star::beans::PropertyChangeEvent& evt = _rEvents.getConstArray()[0]; 516 OSL_ENSURE(evt.PropertyName.getLength() > 0, "OPropertySetAggregationHelper::propertiesChange : invalid event !"); 517 // we had a bug where this assertion would have us saved a whole day :) (72514) 518 sal_Int32 nHandle = rPH.getHandleByName( evt.PropertyName ); 519 520 // If nHandle is -1 the event marks a (aggregate) property which we hide to callers 521 // If isCurrentlyForwardingProperty( nHandle ) is <TRUE/>, then we ourself triggered 522 // setting this property. In this case, it will be notified later (by the OPropertySetHelper 523 // implementation) 524 525 if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) ) 526 fire(&nHandle, &evt.NewValue, &evt.OldValue, 1, sal_False); 527 } 528 else 529 { 530 sal_Int32* pHandles = new sal_Int32[nLen]; 531 ::com::sun::star::uno::Any* pNewValues = new ::com::sun::star::uno::Any[nLen]; 532 ::com::sun::star::uno::Any* pOldValues = new ::com::sun::star::uno::Any[nLen]; 533 534 const ::com::sun::star::beans::PropertyChangeEvent* pEvents = _rEvents.getConstArray(); 535 sal_Int32 nDest = 0; 536 for (sal_Int32 nSource=0; nSource<nLen; ++nSource, ++pEvents) 537 { 538 sal_Int32 nHandle = rPH.getHandleByName(pEvents->PropertyName); 539 if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) ) 540 { // same as above : -1 is valid (73247) ... 541 pHandles[nDest] = nHandle; 542 pNewValues[nDest] = pEvents->NewValue; 543 pOldValues[nDest] = pEvents->OldValue; 544 ++nDest; 545 } 546 } 547 548 if (nDest) 549 fire(pHandles, pNewValues, pOldValues, nDest, sal_False); 550 551 delete[] pHandles; 552 delete[] pNewValues; 553 delete[] pOldValues; 554 } 555 } 556 557 //------------------------------------------------------------------------------ 558 void SAL_CALL OPropertySetAggregationHelper::vetoableChange(const ::com::sun::star::beans::PropertyChangeEvent& _rEvent) throw( ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException) 559 { 560 OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::vetoableChange : have no aggregate !"); 561 562 cppu::IPropertyArrayHelper& rPH = getInfoHelper(); 563 564 sal_Int32 nHandle = rPH.getHandleByName(_rEvent.PropertyName); 565 fire(&nHandle, &_rEvent.NewValue, &_rEvent.OldValue, 1, sal_True); 566 } 567 568 //------------------------------------------------------------------------------ 569 void OPropertySetAggregationHelper::setAggregation(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxDelegate) 570 throw( ::com::sun::star::lang::IllegalArgumentException ) 571 { 572 osl::MutexGuard aGuard(rBHelper.rMutex); 573 574 if (m_bListening && m_xAggregateSet.is()) 575 { 576 m_xAggregateMultiSet->removePropertiesChangeListener(this); 577 m_xAggregateSet->removeVetoableChangeListener(::rtl::OUString(), this); 578 m_bListening = sal_False; 579 } 580 581 m_xAggregateState = m_xAggregateState.query( _rxDelegate ); 582 m_xAggregateSet = m_xAggregateSet.query( _rxDelegate ); 583 m_xAggregateMultiSet = m_xAggregateMultiSet.query( _rxDelegate ); 584 m_xAggregateFastSet = m_xAggregateFastSet.query( _rxDelegate ); 585 586 // must support XPropertySet and XMultiPropertySet 587 if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() ) 588 throw ::com::sun::star::lang::IllegalArgumentException(); 589 } 590 591 //------------------------------------------------------------------------------ 592 void OPropertySetAggregationHelper::startListening() 593 { 594 osl::MutexGuard aGuard(rBHelper.rMutex); 595 596 if (!m_bListening && m_xAggregateSet.is()) 597 { 598 // als einziger Listener anmelden 599 ::com::sun::star::uno::Sequence< ::rtl::OUString > aPropertyNames; 600 m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this); 601 m_xAggregateSet->addVetoableChangeListener(::rtl::OUString(), this); 602 603 m_bListening = sal_True; 604 } 605 } 606 607 //------------------------------------------------------------------------------ 608 void SAL_CALL OPropertySetAggregationHelper::addVetoableChangeListener(const ::rtl::OUString& _rPropertyName, 609 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener>& _rxListener) 610 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) 611 { 612 OPropertySetHelper::addVetoableChangeListener(_rPropertyName, _rxListener); 613 if (!m_bListening) 614 startListening(); 615 } 616 617 //------------------------------------------------------------------------------ 618 void SAL_CALL OPropertySetAggregationHelper::addPropertyChangeListener(const ::rtl::OUString& _rPropertyName, 619 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener>& _rxListener) 620 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) 621 { 622 OPropertySetHelper::addPropertyChangeListener(_rPropertyName, _rxListener); 623 if (!m_bListening) 624 startListening(); 625 } 626 627 //------------------------------------------------------------------------------ 628 void SAL_CALL OPropertySetAggregationHelper::addPropertiesChangeListener(const ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rPropertyNames, 629 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener>& _rxListener) 630 throw( ::com::sun::star::uno::RuntimeException) 631 { 632 OPropertySetHelper::addPropertiesChangeListener(_rPropertyNames, _rxListener); 633 if (!m_bListening) 634 startListening(); 635 } 636 637 //------------------------------------------------------------------------------ 638 sal_Int32 OPropertySetAggregationHelper::getOriginalHandle(sal_Int32 nHandle) const 639 { 640 OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper(); 641 sal_Int32 nOriginalHandle = -1; 642 rPH.fillAggregatePropertyInfoByHandle(NULL, &nOriginalHandle, nHandle); 643 return nOriginalHandle; 644 } 645 646 //-------------------------------------------------------------------------- 647 ::rtl::OUString OPropertySetAggregationHelper::getPropertyName( sal_Int32 _nHandle ) const 648 { 649 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() ); 650 Property aProperty; 651 OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) ); 652 return aProperty.Name; 653 } 654 655 //------------------------------------------------------------------------------ 656 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue(sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rValue) 657 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, 658 ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, 659 ::com::sun::star::uno::RuntimeException) 660 { 661 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); 662 ::rtl::OUString aPropName; 663 sal_Int32 nOriginalHandle = -1; 664 665 // does the handle belong to the aggregation ? 666 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, _nHandle)) 667 if (m_xAggregateFastSet.is()) 668 m_xAggregateFastSet->setFastPropertyValue(nOriginalHandle, _rValue); 669 else 670 m_xAggregateSet->setPropertyValue(aPropName, _rValue); 671 else 672 OPropertySetHelper::setFastPropertyValue(_nHandle, _rValue); 673 } 674 675 //------------------------------------------------------------------------------ 676 void OPropertySetAggregationHelper::getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle) const 677 { 678 OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper(); 679 ::rtl::OUString aPropName; 680 sal_Int32 nOriginalHandle = -1; 681 682 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle)) 683 { 684 if (m_xAggregateFastSet.is()) 685 rValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle); 686 else 687 rValue = m_xAggregateSet->getPropertyValue(aPropName); 688 } 689 else if ( m_pForwarder->isResponsibleFor( nHandle ) ) 690 { 691 // this is a property which has been "overwritten" in our instance (thus 692 // fillAggregatePropertyInfoByHandle didn't find it) 693 rValue = m_xAggregateSet->getPropertyValue( getPropertyName( nHandle ) ); 694 } 695 } 696 697 //------------------------------------------------------------------------------ 698 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getFastPropertyValue(sal_Int32 nHandle) 699 throw( ::com::sun::star::beans::UnknownPropertyException, 700 ::com::sun::star::lang::WrappedTargetException, 701 ::com::sun::star::uno::RuntimeException) 702 { 703 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); 704 ::rtl::OUString aPropName; 705 sal_Int32 nOriginalHandle = -1; 706 ::com::sun::star::uno::Any aValue; 707 708 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle)) 709 { 710 if (m_xAggregateFastSet.is()) 711 aValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle); 712 else 713 aValue = m_xAggregateSet->getPropertyValue(aPropName); 714 } 715 else 716 aValue = OPropertySetHelper::getFastPropertyValue(nHandle); 717 718 return aValue; 719 } 720 721 //------------------------------------------------------------------------------ 722 void SAL_CALL OPropertySetAggregationHelper::setPropertyValues( 723 const Sequence< ::rtl::OUString >& _rPropertyNames, const Sequence< Any >& _rValues ) 724 throw ( PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException ) 725 { 726 OSL_ENSURE( !rBHelper.bInDispose, "OPropertySetAggregationHelper::setPropertyValues : do not use within the dispose call !"); 727 OSL_ENSURE( !rBHelper.bDisposed, "OPropertySetAggregationHelper::setPropertyValues : object is disposed" ); 728 729 // check where the properties come from 730 if (!m_xAggregateSet.is()) 731 OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues); 732 else if (_rPropertyNames.getLength() == 1) // use the more efficient way 733 { 734 try 735 { 736 setPropertyValue( _rPropertyNames[0], _rValues[0] ); 737 } 738 catch( const UnknownPropertyException& ) 739 { 740 // by definition of XMultiPropertySet::setPropertyValues, unknown properties are to be ignored 741 #if OSL_DEBUG_LEVEL > 0 742 ::rtl::OStringBuffer aMessage; 743 aMessage.append( "OPropertySetAggregationHelper::setPropertyValues: unknown property '" ); 744 aMessage.append( ::rtl::OUStringToOString( _rPropertyNames[0], RTL_TEXTENCODING_ASCII_US ) ); 745 aMessage.append( "'" ); 746 aMessage.append( "\n(implementation " ); 747 aMessage.append( typeid( *this ).name() ); 748 aMessage.append( ")" ); 749 OSL_ENSURE( false, aMessage.getStr() ); 750 #endif 751 } 752 } 753 else 754 { 755 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); 756 757 // determine which properties belong to the aggregate, and which ones to the delegator 758 const ::rtl::OUString* pNames = _rPropertyNames.getConstArray(); 759 sal_Int32 nAggCount(0); 760 sal_Int32 nLen(_rPropertyNames.getLength()); 761 762 for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames ) 763 { 764 OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( *pNames ); 765 if ( OPropertyArrayAggregationHelper::UNKNOWN_PROPERTY == ePropOrg ) 766 throw WrappedTargetException( ::rtl::OUString(), static_cast< XMultiPropertySet* >( this ), makeAny( UnknownPropertyException( ) ) ); 767 // due to a flaw in the API design, this method is not allowed to throw an UnknownPropertyException 768 // so we wrap it into a WrappedTargetException 769 // #107545# - 2002-02-20 - fs@openoffice.org 770 771 if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == ePropOrg ) 772 ++nAggCount; 773 } 774 775 pNames = _rPropertyNames.getConstArray(); // reset, we'll need it again below ... 776 777 // all properties belong to the aggregate 778 if (nAggCount == nLen) 779 m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues); 780 781 // all properties belong to the aggregating object 782 else if (nAggCount == 0) 783 OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues); 784 785 // mixed 786 else 787 { 788 const ::com::sun::star::uno::Any* pValues = _rValues.getConstArray(); 789 ::com::sun::star::uno::Any* pConvertedValues = NULL; 790 ::com::sun::star::uno::Any* pOldValues = NULL; 791 sal_Int32* pHandles = NULL; 792 793 try 794 { 795 // dividing the Names and _rValues 796 797 // aggregate's names 798 Sequence< ::rtl::OUString > AggPropertyNames( nAggCount ); 799 ::rtl::OUString* pAggNames = AggPropertyNames.getArray(); 800 // aggregate's values 801 Sequence< Any > AggValues( nAggCount ); 802 Any* pAggValues = AggValues.getArray(); 803 804 // delegator names 805 Sequence< ::rtl::OUString > DelPropertyNames( nLen - nAggCount ); 806 ::rtl::OUString* pDelNames = DelPropertyNames.getArray(); 807 808 // delegator values 809 Sequence< Any > DelValues( nLen - nAggCount ); 810 Any* pDelValues = DelValues.getArray(); 811 812 for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames, ++pValues ) 813 { 814 if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == rPH.classifyProperty( *pNames ) ) 815 { 816 *pAggNames++ = *pNames; 817 *pAggValues++ = *pValues; 818 } 819 else 820 { 821 *pDelNames++ = *pNames; 822 *pDelValues++ = *pValues; 823 } 824 } 825 826 // reset, needed below 827 pDelValues = DelValues.getArray(); 828 829 pHandles = new sal_Int32[ nLen - nAggCount ]; 830 831 // get the map table 832 cppu::IPropertyArrayHelper& rPH2 = getInfoHelper(); 833 834 // fill the handle array 835 sal_Int32 nHitCount = rPH2.fillHandles( pHandles, DelPropertyNames ); 836 if (nHitCount != 0) 837 { 838 839 pConvertedValues = new ::com::sun::star::uno::Any[ nHitCount ]; 840 pOldValues = new ::com::sun::star::uno::Any[ nHitCount ]; 841 nHitCount = 0; 842 sal_Int32 i; 843 844 { 845 // must lock the mutex outside the loop. So all values are consistent. 846 osl::MutexGuard aGuard( rBHelper.rMutex ); 847 for( i = 0; i < (nLen - nAggCount); ++i ) 848 { 849 if( pHandles[i] != -1 ) 850 { 851 sal_Int16 nAttributes; 852 rPH2.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] ); 853 if( nAttributes & ::com::sun::star::beans::PropertyAttribute::READONLY ) 854 throw ::com::sun::star::beans::PropertyVetoException(); 855 // Will the property change? 856 if( convertFastPropertyValue( pConvertedValues[ nHitCount ], pOldValues[nHitCount], 857 pHandles[i], pDelValues[i] ) ) 858 { 859 // only increment if the property really change 860 pHandles[nHitCount] = pHandles[i]; 861 nHitCount++; 862 } 863 } 864 } 865 // release guard to fire events 866 } 867 868 // fire vetoable events 869 fire( pHandles, pConvertedValues, pOldValues, nHitCount, sal_True ); 870 871 // setting the agg Properties 872 m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues); 873 874 { 875 // must lock the mutex outside the loop. 876 osl::MutexGuard aGuard( rBHelper.rMutex ); 877 // Loop over all changed properties 878 for( i = 0; i < nHitCount; i++ ) 879 { 880 // Will the property change? 881 setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] ); 882 } 883 // release guard to fire events 884 } 885 886 // fire change events 887 fire( pHandles, pConvertedValues, pOldValues, nHitCount, sal_False ); 888 } 889 else 890 m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues); 891 892 } 893 catch(::com::sun::star::uno::Exception&) 894 { 895 delete [] pHandles; 896 delete [] pOldValues; 897 delete [] pConvertedValues; 898 throw; 899 } 900 901 delete [] pHandles; 902 delete [] pOldValues; 903 delete [] pConvertedValues; 904 } 905 } 906 } 907 908 // XPropertyState 909 //------------------------------------------------------------------------------ 910 ::com::sun::star::beans::PropertyState SAL_CALL OPropertySetAggregationHelper::getPropertyState(const ::rtl::OUString& _rPropertyName) 911 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException) 912 { 913 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); 914 sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName ); 915 916 if (nHandle == -1) 917 { 918 throw ::com::sun::star::beans::UnknownPropertyException(); 919 } 920 921 ::rtl::OUString aPropName; 922 sal_Int32 nOriginalHandle = -1; 923 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle)) 924 { 925 if (m_xAggregateState.is()) 926 return m_xAggregateState->getPropertyState(_rPropertyName); 927 else 928 return ::com::sun::star::beans::PropertyState_DIRECT_VALUE; 929 } 930 else 931 return getPropertyStateByHandle(nHandle); 932 } 933 934 //------------------------------------------------------------------------------ 935 void SAL_CALL OPropertySetAggregationHelper::setPropertyToDefault(const ::rtl::OUString& _rPropertyName) 936 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException) 937 { 938 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); 939 sal_Int32 nHandle = rPH.getHandleByName(_rPropertyName); 940 if (nHandle == -1) 941 { 942 throw ::com::sun::star::beans::UnknownPropertyException(); 943 } 944 945 ::rtl::OUString aPropName; 946 sal_Int32 nOriginalHandle = -1; 947 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle)) 948 { 949 if (m_xAggregateState.is()) 950 m_xAggregateState->setPropertyToDefault(_rPropertyName); 951 } 952 else 953 { 954 try 955 { 956 setPropertyToDefaultByHandle( nHandle ); 957 } 958 catch( const UnknownPropertyException& ) { throw; } 959 catch( const RuntimeException& ) { throw; } 960 catch( const Exception& ) 961 { 962 OSL_ENSURE( sal_False, "OPropertySetAggregationHelper::setPropertyToDefault: caught an exception which is not allowed to leave here!" ); 963 } 964 } 965 } 966 967 //------------------------------------------------------------------------------ 968 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getPropertyDefault(const ::rtl::OUString& aPropertyName) 969 throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) 970 { 971 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); 972 sal_Int32 nHandle = rPH.getHandleByName( aPropertyName ); 973 974 if ( nHandle == -1 ) 975 throw ::com::sun::star::beans::UnknownPropertyException(); 976 977 ::rtl::OUString aPropName; 978 sal_Int32 nOriginalHandle = -1; 979 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle)) 980 { 981 if (m_xAggregateState.is()) 982 return m_xAggregateState->getPropertyDefault(aPropertyName); 983 else 984 return ::com::sun::star::uno::Any(); 985 } 986 else 987 return getPropertyDefaultByHandle(nHandle); 988 } 989 990 //------------------------------------------------------------------------------ 991 sal_Bool SAL_CALL OPropertySetAggregationHelper::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException) 992 { 993 sal_Bool bModified = sal_False; 994 995 OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::convertFastPropertyValue: this is no forwarded property - did you use declareForwardedProperty for it?" ); 996 if ( m_pForwarder->isResponsibleFor( _nHandle ) ) 997 { 998 // need to determine the type of the property for conversion 999 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); 1000 Property aProperty; 1001 OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) ); 1002 1003 Any aCurrentValue; 1004 getFastPropertyValue( aCurrentValue, _nHandle ); 1005 bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, aCurrentValue, aProperty.Type ); 1006 } 1007 1008 return bModified; 1009 } 1010 1011 //------------------------------------------------------------------------------ 1012 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception ) 1013 { 1014 OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast: this is no forwarded property - did you use declareForwardedProperty for it?" ); 1015 if ( m_pForwarder->isResponsibleFor( _nHandle ) ) 1016 m_pForwarder->doForward( _nHandle, _rValue ); 1017 } 1018 1019 //------------------------------------------------------------------------------ 1020 void OPropertySetAggregationHelper::declareForwardedProperty( sal_Int32 _nHandle ) 1021 { 1022 OSL_ENSURE( !m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::declareForwardedProperty: already declared!" ); 1023 m_pForwarder->takeResponsibilityFor( _nHandle ); 1024 } 1025 1026 //------------------------------------------------------------------------------ 1027 void SAL_CALL OPropertySetAggregationHelper::forwardingPropertyValue( sal_Int32 ) 1028 { 1029 // not interested in 1030 } 1031 1032 //------------------------------------------------------------------------------ 1033 void SAL_CALL OPropertySetAggregationHelper::forwardedPropertyValue( sal_Int32, bool ) 1034 { 1035 // not interested in 1036 } 1037 1038 //------------------------------------------------------------------------------ 1039 bool OPropertySetAggregationHelper::isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const 1040 { 1041 return m_pForwarder->getCurrentlyForwardedProperty() == _nHandle; 1042 } 1043 1044 //......................................................................... 1045 } // namespace comphelper 1046 //......................................................................... 1047 1048