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