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 ) 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 ); 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 ) 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) 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) 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) 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.isEmpty(), "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) 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 { 567 osl::MutexGuard aGuard(rBHelper.rMutex); 568 569 if (m_bListening && m_xAggregateSet.is()) 570 { 571 m_xAggregateMultiSet->removePropertiesChangeListener(this); 572 m_xAggregateSet->removeVetoableChangeListener(::rtl::OUString(), this); 573 m_bListening = sal_False; 574 } 575 576 m_xAggregateState = m_xAggregateState.query( _rxDelegate ); 577 m_xAggregateSet = m_xAggregateSet.query( _rxDelegate ); 578 m_xAggregateMultiSet = m_xAggregateMultiSet.query( _rxDelegate ); 579 m_xAggregateFastSet = m_xAggregateFastSet.query( _rxDelegate ); 580 581 // must support XPropertySet and XMultiPropertySet 582 if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() ) 583 throw ::com::sun::star::lang::IllegalArgumentException(); 584 } 585 586 //------------------------------------------------------------------------------ 587 void OPropertySetAggregationHelper::startListening() 588 { 589 osl::MutexGuard aGuard(rBHelper.rMutex); 590 591 if (!m_bListening && m_xAggregateSet.is()) 592 { 593 // als einziger Listener anmelden 594 ::com::sun::star::uno::Sequence< ::rtl::OUString > aPropertyNames; 595 m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this); 596 m_xAggregateSet->addVetoableChangeListener(::rtl::OUString(), this); 597 598 m_bListening = sal_True; 599 } 600 } 601 602 //------------------------------------------------------------------------------ 603 void SAL_CALL OPropertySetAggregationHelper::addVetoableChangeListener(const ::rtl::OUString& _rPropertyName, 604 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener>& _rxListener) 605 { 606 OPropertySetHelper::addVetoableChangeListener(_rPropertyName, _rxListener); 607 if (!m_bListening) 608 startListening(); 609 } 610 611 //------------------------------------------------------------------------------ 612 void SAL_CALL OPropertySetAggregationHelper::addPropertyChangeListener(const ::rtl::OUString& _rPropertyName, 613 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener>& _rxListener) 614 { 615 OPropertySetHelper::addPropertyChangeListener(_rPropertyName, _rxListener); 616 if (!m_bListening) 617 startListening(); 618 } 619 620 //------------------------------------------------------------------------------ 621 void SAL_CALL OPropertySetAggregationHelper::addPropertiesChangeListener(const ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rPropertyNames, 622 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener>& _rxListener) 623 { 624 OPropertySetHelper::addPropertiesChangeListener(_rPropertyNames, _rxListener); 625 if (!m_bListening) 626 startListening(); 627 } 628 629 //------------------------------------------------------------------------------ 630 sal_Int32 OPropertySetAggregationHelper::getOriginalHandle(sal_Int32 nHandle) const 631 { 632 OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper(); 633 sal_Int32 nOriginalHandle = -1; 634 rPH.fillAggregatePropertyInfoByHandle(NULL, &nOriginalHandle, nHandle); 635 return nOriginalHandle; 636 } 637 638 //-------------------------------------------------------------------------- 639 ::rtl::OUString OPropertySetAggregationHelper::getPropertyName( sal_Int32 _nHandle ) const 640 { 641 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() ); 642 Property aProperty; 643 OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) ); 644 return aProperty.Name; 645 } 646 647 //------------------------------------------------------------------------------ 648 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue(sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rValue) 649 { 650 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); 651 ::rtl::OUString aPropName; 652 sal_Int32 nOriginalHandle = -1; 653 654 // does the handle belong to the aggregation ? 655 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, _nHandle)) 656 if (m_xAggregateFastSet.is()) 657 m_xAggregateFastSet->setFastPropertyValue(nOriginalHandle, _rValue); 658 else 659 m_xAggregateSet->setPropertyValue(aPropName, _rValue); 660 else 661 OPropertySetHelper::setFastPropertyValue(_nHandle, _rValue); 662 } 663 664 //------------------------------------------------------------------------------ 665 void OPropertySetAggregationHelper::getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle) const 666 { 667 OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper(); 668 ::rtl::OUString aPropName; 669 sal_Int32 nOriginalHandle = -1; 670 671 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle)) 672 { 673 if (m_xAggregateFastSet.is()) 674 rValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle); 675 else 676 rValue = m_xAggregateSet->getPropertyValue(aPropName); 677 } 678 else if ( m_pForwarder->isResponsibleFor( nHandle ) ) 679 { 680 // this is a property which has been "overwritten" in our instance (thus 681 // fillAggregatePropertyInfoByHandle didn't find it) 682 rValue = m_xAggregateSet->getPropertyValue( getPropertyName( nHandle ) ); 683 } 684 } 685 686 //------------------------------------------------------------------------------ 687 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getFastPropertyValue(sal_Int32 nHandle) 688 { 689 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); 690 ::rtl::OUString aPropName; 691 sal_Int32 nOriginalHandle = -1; 692 ::com::sun::star::uno::Any aValue; 693 694 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle)) 695 { 696 if (m_xAggregateFastSet.is()) 697 aValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle); 698 else 699 aValue = m_xAggregateSet->getPropertyValue(aPropName); 700 } 701 else 702 aValue = OPropertySetHelper::getFastPropertyValue(nHandle); 703 704 return aValue; 705 } 706 707 //------------------------------------------------------------------------------ 708 void SAL_CALL OPropertySetAggregationHelper::setPropertyValues( 709 const Sequence< ::rtl::OUString >& _rPropertyNames, const Sequence< Any >& _rValues ) 710 { 711 OSL_ENSURE( !rBHelper.bInDispose, "OPropertySetAggregationHelper::setPropertyValues : do not use within the dispose call !"); 712 OSL_ENSURE( !rBHelper.bDisposed, "OPropertySetAggregationHelper::setPropertyValues : object is disposed" ); 713 714 // check where the properties come from 715 if (!m_xAggregateSet.is()) 716 OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues); 717 else if (_rPropertyNames.getLength() == 1) // use the more efficient way 718 { 719 try 720 { 721 setPropertyValue( _rPropertyNames[0], _rValues[0] ); 722 } 723 catch( const UnknownPropertyException& ) 724 { 725 // by definition of XMultiPropertySet::setPropertyValues, unknown properties are to be ignored 726 #if OSL_DEBUG_LEVEL > 0 727 ::rtl::OStringBuffer aMessage; 728 aMessage.append( "OPropertySetAggregationHelper::setPropertyValues: unknown property '" ); 729 aMessage.append( ::rtl::OUStringToOString( _rPropertyNames[0], RTL_TEXTENCODING_ASCII_US ) ); 730 aMessage.append( "'" ); 731 aMessage.append( "\n(implementation " ); 732 aMessage.append( typeid( *this ).name() ); 733 aMessage.append( ")" ); 734 OSL_ENSURE( false, aMessage.getStr() ); 735 #endif 736 } 737 } 738 else 739 { 740 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); 741 742 // determine which properties belong to the aggregate, and which ones to the delegator 743 const ::rtl::OUString* pNames = _rPropertyNames.getConstArray(); 744 sal_Int32 nAggCount(0); 745 sal_Int32 nLen(_rPropertyNames.getLength()); 746 747 for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames ) 748 { 749 OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( *pNames ); 750 if ( OPropertyArrayAggregationHelper::UNKNOWN_PROPERTY == ePropOrg ) 751 throw WrappedTargetException( ::rtl::OUString(), static_cast< XMultiPropertySet* >( this ), makeAny( UnknownPropertyException( ) ) ); 752 // due to a flaw in the API design, this method is not allowed to throw an UnknownPropertyException 753 // so we wrap it into a WrappedTargetException 754 // #107545# - 2002-02-20 - fs@openoffice.org 755 756 if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == ePropOrg ) 757 ++nAggCount; 758 } 759 760 pNames = _rPropertyNames.getConstArray(); // reset, we'll need it again below ... 761 762 // all properties belong to the aggregate 763 if (nAggCount == nLen) 764 m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues); 765 766 // all properties belong to the aggregating object 767 else if (nAggCount == 0) 768 OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues); 769 770 // mixed 771 else 772 { 773 const ::com::sun::star::uno::Any* pValues = _rValues.getConstArray(); 774 ::com::sun::star::uno::Any* pConvertedValues = NULL; 775 ::com::sun::star::uno::Any* pOldValues = NULL; 776 sal_Int32* pHandles = NULL; 777 778 try 779 { 780 // dividing the Names and _rValues 781 782 // aggregate's names 783 Sequence< ::rtl::OUString > AggPropertyNames( nAggCount ); 784 ::rtl::OUString* pAggNames = AggPropertyNames.getArray(); 785 // aggregate's values 786 Sequence< Any > AggValues( nAggCount ); 787 Any* pAggValues = AggValues.getArray(); 788 789 // delegator names 790 Sequence< ::rtl::OUString > DelPropertyNames( nLen - nAggCount ); 791 ::rtl::OUString* pDelNames = DelPropertyNames.getArray(); 792 793 // delegator values 794 Sequence< Any > DelValues( nLen - nAggCount ); 795 Any* pDelValues = DelValues.getArray(); 796 797 for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames, ++pValues ) 798 { 799 if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == rPH.classifyProperty( *pNames ) ) 800 { 801 *pAggNames++ = *pNames; 802 *pAggValues++ = *pValues; 803 } 804 else 805 { 806 *pDelNames++ = *pNames; 807 *pDelValues++ = *pValues; 808 } 809 } 810 811 // reset, needed below 812 pDelValues = DelValues.getArray(); 813 814 pHandles = new sal_Int32[ nLen - nAggCount ]; 815 816 // get the map table 817 cppu::IPropertyArrayHelper& rPH2 = getInfoHelper(); 818 819 // fill the handle array 820 sal_Int32 nHitCount = rPH2.fillHandles( pHandles, DelPropertyNames ); 821 if (nHitCount != 0) 822 { 823 824 pConvertedValues = new ::com::sun::star::uno::Any[ nHitCount ]; 825 pOldValues = new ::com::sun::star::uno::Any[ nHitCount ]; 826 nHitCount = 0; 827 sal_Int32 i; 828 829 { 830 // must lock the mutex outside the loop. So all values are consistent. 831 osl::MutexGuard aGuard( rBHelper.rMutex ); 832 for( i = 0; i < (nLen - nAggCount); ++i ) 833 { 834 if( pHandles[i] != -1 ) 835 { 836 sal_Int16 nAttributes; 837 rPH2.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] ); 838 if( nAttributes & ::com::sun::star::beans::PropertyAttribute::READONLY ) 839 throw ::com::sun::star::beans::PropertyVetoException(); 840 // Will the property change? 841 if( convertFastPropertyValue( pConvertedValues[ nHitCount ], pOldValues[nHitCount], 842 pHandles[i], pDelValues[i] ) ) 843 { 844 // only increment if the property really change 845 pHandles[nHitCount] = pHandles[i]; 846 nHitCount++; 847 } 848 } 849 } 850 // release guard to fire events 851 } 852 853 // fire vetoable events 854 fire( pHandles, pConvertedValues, pOldValues, nHitCount, sal_True ); 855 856 // setting the agg Properties 857 m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues); 858 859 { 860 // must lock the mutex outside the loop. 861 osl::MutexGuard aGuard( rBHelper.rMutex ); 862 // Loop over all changed properties 863 for( i = 0; i < nHitCount; i++ ) 864 { 865 // Will the property change? 866 setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] ); 867 } 868 // release guard to fire events 869 } 870 871 // fire change events 872 fire( pHandles, pConvertedValues, pOldValues, nHitCount, sal_False ); 873 } 874 else 875 m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues); 876 877 } 878 catch(::com::sun::star::uno::Exception&) 879 { 880 delete [] pHandles; 881 delete [] pOldValues; 882 delete [] pConvertedValues; 883 throw; 884 } 885 886 delete [] pHandles; 887 delete [] pOldValues; 888 delete [] pConvertedValues; 889 } 890 } 891 } 892 893 // XPropertyState 894 //------------------------------------------------------------------------------ 895 ::com::sun::star::beans::PropertyState SAL_CALL OPropertySetAggregationHelper::getPropertyState(const ::rtl::OUString& _rPropertyName) 896 { 897 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); 898 sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName ); 899 900 if (nHandle == -1) 901 { 902 throw ::com::sun::star::beans::UnknownPropertyException(); 903 } 904 905 ::rtl::OUString aPropName; 906 sal_Int32 nOriginalHandle = -1; 907 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle)) 908 { 909 if (m_xAggregateState.is()) 910 return m_xAggregateState->getPropertyState(_rPropertyName); 911 else 912 return ::com::sun::star::beans::PropertyState_DIRECT_VALUE; 913 } 914 else 915 return getPropertyStateByHandle(nHandle); 916 } 917 918 //------------------------------------------------------------------------------ 919 void SAL_CALL OPropertySetAggregationHelper::setPropertyToDefault(const ::rtl::OUString& _rPropertyName) 920 { 921 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); 922 sal_Int32 nHandle = rPH.getHandleByName(_rPropertyName); 923 if (nHandle == -1) 924 { 925 throw ::com::sun::star::beans::UnknownPropertyException(); 926 } 927 928 ::rtl::OUString aPropName; 929 sal_Int32 nOriginalHandle = -1; 930 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle)) 931 { 932 if (m_xAggregateState.is()) 933 m_xAggregateState->setPropertyToDefault(_rPropertyName); 934 } 935 else 936 { 937 try 938 { 939 setPropertyToDefaultByHandle( nHandle ); 940 } 941 catch( const UnknownPropertyException& ) { throw; } 942 catch( const RuntimeException& ) { throw; } 943 catch( const Exception& ) 944 { 945 OSL_ENSURE( sal_False, "OPropertySetAggregationHelper::setPropertyToDefault: caught an exception which is not allowed to leave here!" ); 946 } 947 } 948 } 949 950 //------------------------------------------------------------------------------ 951 ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getPropertyDefault(const ::rtl::OUString& aPropertyName) 952 { 953 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); 954 sal_Int32 nHandle = rPH.getHandleByName( aPropertyName ); 955 956 if ( nHandle == -1 ) 957 throw ::com::sun::star::beans::UnknownPropertyException(); 958 959 ::rtl::OUString aPropName; 960 sal_Int32 nOriginalHandle = -1; 961 if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle)) 962 { 963 if (m_xAggregateState.is()) 964 return m_xAggregateState->getPropertyDefault(aPropertyName); 965 else 966 return ::com::sun::star::uno::Any(); 967 } 968 else 969 return getPropertyDefaultByHandle(nHandle); 970 } 971 972 //------------------------------------------------------------------------------ 973 sal_Bool SAL_CALL OPropertySetAggregationHelper::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) 974 { 975 sal_Bool bModified = sal_False; 976 977 OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::convertFastPropertyValue: this is no forwarded property - did you use declareForwardedProperty for it?" ); 978 if ( m_pForwarder->isResponsibleFor( _nHandle ) ) 979 { 980 // need to determine the type of the property for conversion 981 OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); 982 Property aProperty; 983 OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) ); 984 985 Any aCurrentValue; 986 getFastPropertyValue( aCurrentValue, _nHandle ); 987 bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, aCurrentValue, aProperty.Type ); 988 } 989 990 return bModified; 991 } 992 993 //------------------------------------------------------------------------------ 994 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) 995 { 996 OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast: this is no forwarded property - did you use declareForwardedProperty for it?" ); 997 if ( m_pForwarder->isResponsibleFor( _nHandle ) ) 998 m_pForwarder->doForward( _nHandle, _rValue ); 999 } 1000 1001 //------------------------------------------------------------------------------ 1002 void OPropertySetAggregationHelper::declareForwardedProperty( sal_Int32 _nHandle ) 1003 { 1004 OSL_ENSURE( !m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::declareForwardedProperty: already declared!" ); 1005 m_pForwarder->takeResponsibilityFor( _nHandle ); 1006 } 1007 1008 //------------------------------------------------------------------------------ 1009 void SAL_CALL OPropertySetAggregationHelper::forwardingPropertyValue( sal_Int32 ) 1010 { 1011 // not interested in 1012 } 1013 1014 //------------------------------------------------------------------------------ 1015 void SAL_CALL OPropertySetAggregationHelper::forwardedPropertyValue( sal_Int32, bool ) 1016 { 1017 // not interested in 1018 } 1019 1020 //------------------------------------------------------------------------------ 1021 bool OPropertySetAggregationHelper::isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const 1022 { 1023 return m_pForwarder->getCurrentlyForwardedProperty() == _nHandle; 1024 } 1025 1026 //......................................................................... 1027 } // namespace comphelper 1028 //......................................................................... 1029