LibreOffice Module comphelper (master)  1
propagg.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <comphelper/propagg.hxx>
21 #include <comphelper/property.hxx>
22 #include <comphelper/sequence.hxx>
24 #include <osl/diagnose.h>
25 #include <sal/log.hxx>
26 #include <com/sun/star/beans/PropertyAttribute.hpp>
27 #include <o3tl/sorted_vector.hxx>
28 #include <typeinfo>
29 #include <algorithm>
30 #include <unordered_set>
31 #include <memory>
32 
33 
34 namespace comphelper
35 {
36 
37 
38  using namespace ::com::sun::star::uno;
39  using namespace ::com::sun::star::lang;
40  using namespace ::com::sun::star::beans;
41 
42  using namespace internal;
43 
44 
45  namespace
46  {
47  const Property* lcl_findPropertyByName( const std::vector< Property >& _rProps, const OUString& _rName )
48  {
49  Property aNameProp(_rName, 0, Type(), 0);
50  auto pResult = std::lower_bound(_rProps.begin(), _rProps.end(), aNameProp, PropertyCompareByName());
51  if ( pResult == _rProps.end() || pResult->Name != _rName )
52  return nullptr;
53 
54  return &*pResult;
55  }
56  }
57 
59  const Sequence< Property >& _rProperties, const Sequence< Property >& _rAggProperties,
60  IPropertyInfoService* _pInfoService, sal_Int32 _nFirstAggregateId )
61 {
62  // if properties are present both at the delegatee and the aggregate, then the former are supposed to win
63  // merge and sort properties by name, delete duplicates (stable sort ensures delegator properties win)
64  m_aProperties.insert( m_aProperties.end(), _rProperties.begin(), _rProperties.end() );
65  m_aProperties.insert( m_aProperties.end(), _rAggProperties.begin(), _rAggProperties.end() );
66  std::stable_sort( m_aProperties.begin(), m_aProperties.end(), PropertyCompareByName() );
67  m_aProperties.erase( std::unique(m_aProperties.begin(), m_aProperties.end(),
68  []( const css::beans::Property& x, const css::beans::Property& y ) -> bool { return x.Name == y.Name; } ),
69  m_aProperties.end() );
70  m_aProperties.shrink_to_fit();
71 
72  // fill aDelegatorProps with names from _rProperties for a fast existence check
73  // different kinds of properties are processed differently
74  std::unordered_set< OUString > aDelegatorProps;
75  aDelegatorProps.reserve( _rProperties.getLength() );
76  for( auto &delegateProp: _rProperties )
77  {
78  const auto inserted = aDelegatorProps.insert( delegateProp.Name );
79  OSL_ENSURE( inserted.second,
80  "OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper: duplicate delegatee property!" );
81  }
82 
83  std::unordered_set< sal_Int32 > existingHandles;
84  existingHandles.reserve( m_aProperties.size() );
85  sal_Int32 nAggregateHandle = _nFirstAggregateId;
86  for ( sal_Int32 nMPLoop = 0; nMPLoop < static_cast< sal_Int32 >( m_aProperties.size() ); ++nMPLoop )
87  {
88  auto &prop = m_aProperties[ nMPLoop ];
89  if ( aDelegatorProps.find( prop.Name ) != aDelegatorProps.end() )
90  {
91  m_aPropertyAccessors[ prop.Handle ] = OPropertyAccessor( -1, nMPLoop, false );
92  existingHandles.insert( prop.Handle );
93  }
94  else
95  {
96  // determine the handle for the property which we will expose to the outside world
97  sal_Int32 nHandle = -1;
98  // ask the info service first
99  if ( _pInfoService )
100  nHandle = _pInfoService->getPreferredPropertyId( prop.Name );
101 
102  if ( ( -1 == nHandle ) || ( existingHandles.find( nHandle ) != existingHandles.end() ) )
103  {
104  // 1. no handle from the info service -> default
105  // 2. conflicts -> use another one (which we don't check anymore, assuming _nFirstAggregateId was large enough)
106  nHandle = nAggregateHandle++;
107  }
108  else
109  {
110  existingHandles.insert( nHandle );
111  }
112 
113  // remember the accessor for this property
114  m_aPropertyAccessors[ nHandle ] = OPropertyAccessor( prop.Handle, nMPLoop, true );
115  prop.Handle = nHandle;
116  }
117  }
118 }
119 
120 
122 {
123  PropertyOrigin eOrigin = PropertyOrigin::Unknown;
124  // look up the name
125  const Property* pPropertyDescriptor = lcl_findPropertyByName( m_aProperties, _rName );
126  if ( pPropertyDescriptor )
127  {
128  // look up the handle for this name
129  ConstPropertyAccessorMapIterator aPos = m_aPropertyAccessors.find( pPropertyDescriptor->Handle );
130  OSL_ENSURE( m_aPropertyAccessors.end() != aPos, "OPropertyArrayAggregationHelper::classifyProperty: should have this handle in my map!" );
131  if ( m_aPropertyAccessors.end() != aPos )
132  {
133  eOrigin = aPos->second.bAggregate ? PropertyOrigin::Aggregate : PropertyOrigin::Delegator;
134  }
135  }
136  return eOrigin;
137 }
138 
139 
141 {
142  const Property* pProperty = findPropertyByName( _rPropertyName );
143 
144  if ( !pProperty )
145  throw UnknownPropertyException(_rPropertyName);
146 
147  return *pProperty;
148 }
149 
150 
152 {
153  return nullptr != findPropertyByName( _rPropertyName );
154 }
155 
156 
158 {
159  return lcl_findPropertyByName( m_aProperties, _rName );
160 }
161 
162 
163 sal_Int32 OPropertyArrayAggregationHelper::getHandleByName(const OUString& _rPropertyName)
164 {
165  const Property* pProperty = findPropertyByName( _rPropertyName );
166  return pProperty ? pProperty->Handle : -1;
167 }
168 
169 
171  OUString* _pPropName, sal_Int16* _pAttributes, sal_Int32 _nHandle)
172 {
173  ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
174  bool bRet = i != m_aPropertyAccessors.end();
175  if (bRet)
176  {
177  const css::beans::Property& rProperty = m_aProperties[(*i).second.nPos];
178  if (_pPropName)
179  *_pPropName = rProperty.Name;
180  if (_pAttributes)
181  *_pAttributes = rProperty.Attributes;
182  }
183  return bRet;
184 }
185 
186 
187 bool OPropertyArrayAggregationHelper::getPropertyByHandle( sal_Int32 _nHandle, Property& _rProperty ) const
188 {
189  ConstPropertyAccessorMapIterator pos = m_aPropertyAccessors.find(_nHandle);
190  if ( pos != m_aPropertyAccessors.end() )
191  {
192  _rProperty = m_aProperties[ pos->second.nPos ];
193  return true;
194  }
195  return false;
196 }
197 
198 
200  OUString* _pPropName, sal_Int32* _pOriginalHandle, sal_Int32 _nHandle) const
201 {
202  ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
203  bool bRet = i != m_aPropertyAccessors.end() && (*i).second.bAggregate;
204  if (bRet)
205  {
206  if (_pOriginalHandle)
207  *_pOriginalHandle = (*i).second.nOriginalHandle;
208  if (_pPropName)
209  {
210  OSL_ENSURE((*i).second.nPos < static_cast<sal_Int32>(m_aProperties.size()),"Invalid index for sequence!");
211  const css::beans::Property& rProperty = m_aProperties[(*i).second.nPos];
212  *_pPropName = rProperty.Name;
213  }
214  }
215  return bRet;
216 }
217 
218 
219 css::uno::Sequence< css::beans::Property> OPropertyArrayAggregationHelper::getProperties()
220 {
221  return comphelper::containerToSequence(m_aProperties);
222 }
223 
224 
226  sal_Int32* _pHandles, const css::uno::Sequence< OUString >& _rPropNames )
227 {
228  sal_Int32 nHitCount = 0;
229  const OUString* pReqProps = _rPropNames.getConstArray();
230  sal_Int32 nReqLen = _rPropNames.getLength();
231 
232  Property aNameProp;
233  for( sal_Int32 i = 0; i < nReqLen; ++i )
234  {
235  aNameProp.Name = pReqProps[i];
236  auto findIter = std::lower_bound(m_aProperties.begin(), m_aProperties.end(), aNameProp, PropertyCompareByName());
237  if ( findIter != m_aProperties.end() && findIter->Name == pReqProps[i] )
238  {
239  _pHandles[i] = findIter->Handle;
240  nHitCount++;
241  }
242  }
243  return nHitCount;
244 }
245 
246 namespace internal
247 {
249  {
250  private:
251  OPropertySetAggregationHelper& m_rAggregationHelper;
254 
255  public:
256  explicit PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper );
257 
263  void takeResponsibilityFor( sal_Int32 _nHandle );
264 
267  bool isResponsibleFor( sal_Int32 _nHandle );
268 
272  void doForward( sal_Int32 _nHandle, const Any& _rValue );
273 
274  sal_Int32 getCurrentlyForwardedProperty( ) const { return m_nCurrentlyForwarding; }
275  };
276 
277 
278  PropertyForwarder::PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper )
279  :m_rAggregationHelper( _rAggregationHelper )
280  ,m_nCurrentlyForwarding( -1 )
281  {
282  }
283 
284 
285  void PropertyForwarder::takeResponsibilityFor( sal_Int32 _nHandle )
286  {
287  m_aProperties.insert( _nHandle );
288  }
289 
290 
291  bool PropertyForwarder::isResponsibleFor( sal_Int32 _nHandle )
292  {
293  return m_aProperties.find( _nHandle ) != m_aProperties.end();
294  }
295 
296 
297  void PropertyForwarder::doForward( sal_Int32 _nHandle, const Any& _rValue )
298  {
299  OSL_ENSURE( m_rAggregationHelper.m_xAggregateSet.is(), "PropertyForwarder::doForward: no property set!" );
300  if ( !m_rAggregationHelper.m_xAggregateSet.is() )
301  return;
302 
303  m_rAggregationHelper.forwardingPropertyValue( _nHandle );
304 
305  OSL_ENSURE( m_nCurrentlyForwarding == -1, "PropertyForwarder::doForward: reentrance?" );
306  m_nCurrentlyForwarding = _nHandle;
307 
308  try
309  {
310  m_rAggregationHelper.m_xAggregateSet->setPropertyValue( m_rAggregationHelper.getPropertyName( _nHandle ), _rValue );
311  // TODO: cache the property name? (it's a O(log n) search)
312  }
313  catch( const Exception& )
314  {
315  m_rAggregationHelper.forwardedPropertyValue( _nHandle );
316  throw;
317  }
318 
320 
321  m_rAggregationHelper.forwardedPropertyValue( _nHandle );
322  }
323 }
324 
325 OPropertySetAggregationHelper::OPropertySetAggregationHelper( ::cppu::OBroadcastHelper& rBHlp )
326  :OPropertyStateHelper( rBHlp )
327  ,m_bListening( false )
328 {
329  m_pForwarder.reset( new PropertyForwarder( *this ) );
330 }
331 
332 
333 OPropertySetAggregationHelper::~OPropertySetAggregationHelper()
334 {
335 }
336 
337 
338 css::uno::Any SAL_CALL OPropertySetAggregationHelper::queryInterface(const css::uno::Type& _rType)
339 {
340  css::uno::Any aReturn = OPropertyStateHelper::queryInterface(_rType);
341 
342  if ( !aReturn.hasValue() )
343  aReturn = cppu::queryInterface(_rType
344  ,static_cast< css::beans::XPropertiesChangeListener*>(this)
345  ,static_cast< css::beans::XVetoableChangeListener*>(this)
346  ,static_cast< css::lang::XEventListener*>(static_cast< css::beans::XPropertiesChangeListener*>(this))
347  );
348 
349  return aReturn;
350 }
351 
352 
353 void OPropertySetAggregationHelper::disposing()
354 {
355  osl::MutexGuard aGuard(rBHelper.rMutex);
356 
357  if ( m_xAggregateSet.is() && m_bListening )
358  {
359  // register as a single listener
360  m_xAggregateMultiSet->removePropertiesChangeListener(this);
361  m_xAggregateSet->removeVetoableChangeListener(OUString(), this);
362  m_bListening = false;
363  }
364 
365  OPropertyStateHelper::disposing();
366 }
367 
368 
369 void SAL_CALL OPropertySetAggregationHelper::disposing(const css::lang::EventObject& _rSource)
370 {
371  OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::disposing : don't have an aggregate anymore !");
372  if (_rSource.Source == m_xAggregateSet)
373  m_bListening = false;
374 }
375 
376 
377 void SAL_CALL OPropertySetAggregationHelper::propertiesChange(const css::uno::Sequence< css::beans::PropertyChangeEvent>& _rEvents)
378 {
379  OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::propertiesChange : have no aggregate !");
380 
381  sal_Int32 nLen = _rEvents.getLength();
382  cppu::IPropertyArrayHelper& rPH = getInfoHelper();
383 
384  if (1 == nLen)
385  {
386  const css::beans::PropertyChangeEvent& evt = _rEvents.getConstArray()[0];
387  OSL_ENSURE(!evt.PropertyName.isEmpty(), "OPropertySetAggregationHelper::propertiesChange : invalid event !");
388  // we had a bug where this assertion would have us saved a whole day :) (72514)
389  sal_Int32 nHandle = rPH.getHandleByName( evt.PropertyName );
390 
391  // If nHandle is -1 the event marks a (aggregate) property which we hide to callers
392  // If isCurrentlyForwardingProperty( nHandle ) is <TRUE/>, then we ourself triggered
393  // setting this property. In this case, it will be notified later (by the OPropertySetHelper
394  // implementation)
395 
396  if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
397  fire(&nHandle, &evt.NewValue, &evt.OldValue, 1, false);
398  }
399  else
400  {
401  std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nLen]);
402  std::unique_ptr< css::uno::Any[]> pNewValues(new css::uno::Any[nLen]);
403  std::unique_ptr< css::uno::Any[]> pOldValues(new css::uno::Any[nLen]);
404 
405  sal_Int32 nDest = 0;
406  for (const css::beans::PropertyChangeEvent& rEvent : _rEvents)
407  {
408  sal_Int32 nHandle = rPH.getHandleByName(rEvent.PropertyName);
409  if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
410  { // same as above : -1 is valid (73247) ...
411  pHandles[nDest] = nHandle;
412  pNewValues[nDest] = rEvent.NewValue;
413  pOldValues[nDest] = rEvent.OldValue;
414  ++nDest;
415  }
416  }
417 
418  if (nDest)
419  fire(pHandles.get(), pNewValues.get(), pOldValues.get(), nDest, false);
420  }
421 }
422 
423 
424 void SAL_CALL OPropertySetAggregationHelper::vetoableChange(const css::beans::PropertyChangeEvent& _rEvent)
425 {
426  OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::vetoableChange : have no aggregate !");
427 
428  cppu::IPropertyArrayHelper& rPH = getInfoHelper();
429 
430  sal_Int32 nHandle = rPH.getHandleByName(_rEvent.PropertyName);
431  fire(&nHandle, &_rEvent.NewValue, &_rEvent.OldValue, 1, true);
432 }
433 
434 
435 void OPropertySetAggregationHelper::setAggregation(const css::uno::Reference< css::uno::XInterface >& _rxDelegate)
436 {
437  osl::MutexGuard aGuard(rBHelper.rMutex);
438 
439  if (m_bListening && m_xAggregateSet.is())
440  {
441  m_xAggregateMultiSet->removePropertiesChangeListener(this);
442  m_xAggregateSet->removeVetoableChangeListener(OUString(), this);
443  m_bListening = false;
444  }
445 
446  m_xAggregateState.set(_rxDelegate, css::uno::UNO_QUERY);
447  m_xAggregateSet.set(_rxDelegate, css::uno::UNO_QUERY);
448  m_xAggregateMultiSet.set(_rxDelegate, css::uno::UNO_QUERY);
449  m_xAggregateFastSet.set(_rxDelegate, css::uno::UNO_QUERY);
450 
451  // must support XPropertySet and XMultiPropertySet
452  if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() )
453  throw css::lang::IllegalArgumentException();
454 }
455 
456 
457 void OPropertySetAggregationHelper::startListening()
458 {
459  osl::MutexGuard aGuard(rBHelper.rMutex);
460 
461  if (!m_bListening && m_xAggregateSet.is())
462  {
463  // register as a single listener
464  css::uno::Sequence< OUString > aPropertyNames;
465  m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this);
466  m_xAggregateSet->addVetoableChangeListener(OUString(), this);
467 
468  m_bListening = true;
469  }
470 }
471 
472 
473 void SAL_CALL OPropertySetAggregationHelper::addVetoableChangeListener(const OUString& _rPropertyName,
474  const css::uno::Reference< css::beans::XVetoableChangeListener>& _rxListener)
475 {
476  OPropertySetHelper::addVetoableChangeListener(_rPropertyName, _rxListener);
477  if (!m_bListening)
478  startListening();
479 }
480 
481 
482 void SAL_CALL OPropertySetAggregationHelper::addPropertyChangeListener(const OUString& _rPropertyName,
483  const css::uno::Reference< css::beans::XPropertyChangeListener>& _rxListener)
484 {
485  OPropertySetHelper::addPropertyChangeListener(_rPropertyName, _rxListener);
486  if (!m_bListening)
487  startListening();
488 }
489 
490 
491 void SAL_CALL OPropertySetAggregationHelper::addPropertiesChangeListener(const css::uno::Sequence< OUString >& _rPropertyNames,
492  const css::uno::Reference< css::beans::XPropertiesChangeListener>& _rxListener)
493 {
494  OPropertySetHelper::addPropertiesChangeListener(_rPropertyNames, _rxListener);
495  if (!m_bListening)
496  startListening();
497 }
498 
499 
500 sal_Int32 OPropertySetAggregationHelper::getOriginalHandle(sal_Int32 nHandle) const
501 {
502  OPropertyArrayAggregationHelper& rPH = static_cast<OPropertyArrayAggregationHelper&>( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
503  sal_Int32 nOriginalHandle = -1;
504  (void)rPH.fillAggregatePropertyInfoByHandle(nullptr, &nOriginalHandle, nHandle);
505  return nOriginalHandle;
506 }
507 
508 
509 OUString OPropertySetAggregationHelper::getPropertyName( sal_Int32 _nHandle ) const
510 {
511  OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
512  Property aProperty;
513  OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
514  return aProperty.Name;
515 }
516 
517 
518 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue(sal_Int32 _nHandle, const css::uno::Any& _rValue)
519 {
520  OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
521  OUString aPropName;
522  sal_Int32 nOriginalHandle = -1;
523 
524  // does the handle belong to the aggregation ?
525  if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, _nHandle))
526  if (m_xAggregateFastSet.is())
527  m_xAggregateFastSet->setFastPropertyValue(nOriginalHandle, _rValue);
528  else
529  m_xAggregateSet->setPropertyValue(aPropName, _rValue);
530  else
531  OPropertySetHelper::setFastPropertyValue(_nHandle, _rValue);
532 }
533 
534 
535 void OPropertySetAggregationHelper::getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle) const
536 {
537  OPropertyArrayAggregationHelper& rPH = static_cast<OPropertyArrayAggregationHelper&>( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
538  OUString aPropName;
539  sal_Int32 nOriginalHandle = -1;
540 
541  if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
542  {
543  if (m_xAggregateFastSet.is())
544  rValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
545  else
546  rValue = m_xAggregateSet->getPropertyValue(aPropName);
547  }
548  else if ( m_pForwarder->isResponsibleFor( nHandle ) )
549  {
550  // this is a property which has been "overwritten" in our instance (thus
551  // fillAggregatePropertyInfoByHandle didn't find it)
552  rValue = m_xAggregateSet->getPropertyValue( getPropertyName( nHandle ) );
553  }
554 }
555 
556 
557 css::uno::Any SAL_CALL OPropertySetAggregationHelper::getFastPropertyValue(sal_Int32 nHandle)
558 {
559  OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
560  OUString aPropName;
561  sal_Int32 nOriginalHandle = -1;
562  css::uno::Any aValue;
563 
564  if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
565  {
566  if (m_xAggregateFastSet.is())
567  aValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
568  else
569  aValue = m_xAggregateSet->getPropertyValue(aPropName);
570  }
571  else
572  aValue = OPropertySetHelper::getFastPropertyValue(nHandle);
573 
574  return aValue;
575 }
576 
577 
578 void SAL_CALL OPropertySetAggregationHelper::setPropertyValues(
579  const Sequence< OUString >& _rPropertyNames, const Sequence< Any >& _rValues )
580 {
581  OSL_ENSURE( !rBHelper.bInDispose, "OPropertySetAggregationHelper::setPropertyValues : do not use within the dispose call !");
582  OSL_ENSURE( !rBHelper.bDisposed, "OPropertySetAggregationHelper::setPropertyValues : object is disposed" );
583 
584  // check where the properties come from
585  if (!m_xAggregateSet.is())
586  OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
587  else if (_rPropertyNames.getLength() == 1) // use the more efficient way
588  {
589  try
590  {
591  setPropertyValue( _rPropertyNames[0], _rValues[0] );
592  }
593  catch( const UnknownPropertyException& )
594  {
595  // by definition of XMultiPropertySet::setPropertyValues, unknown properties are to be ignored
596  SAL_WARN( "comphelper", "OPropertySetAggregationHelper::setPropertyValues: unknown property: '"
597  << _rPropertyNames[0] << "', implementation: " << typeid( *this ).name() );
598  }
599  }
600  else
601  {
602  OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
603 
604  // determine which properties belong to the aggregate, and which ones to the delegator
605  sal_Int32 nAggCount(0);
606  sal_Int32 nLen(_rPropertyNames.getLength());
607 
608  for ( const OUString& rName : _rPropertyNames )
609  {
610  OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( rName );
612  throw WrappedTargetException( OUString(), static_cast< XMultiPropertySet* >( this ), Any( UnknownPropertyException( ) ) );
613  // due to a flaw in the API design, this method is not allowed to throw an UnknownPropertyException
614  // so we wrap it into a WrappedTargetException
615 
617  ++nAggCount;
618  }
619 
620  // all properties belong to the aggregate
621  if (nAggCount == nLen)
622  m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues);
623 
624  // all properties belong to the aggregating object
625  else if (nAggCount == 0)
626  OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
627 
628  // mixed
629  else
630  {
631  const css::uno::Any* pValues = _rValues.getConstArray();
632 
633  // dividing the Names and _rValues
634 
635  // aggregate's names
636  Sequence< OUString > AggPropertyNames( nAggCount );
637  OUString* pAggNames = AggPropertyNames.getArray();
638  // aggregate's values
639  Sequence< Any > AggValues( nAggCount );
640  Any* pAggValues = AggValues.getArray();
641 
642  // delegator names
643  Sequence< OUString > DelPropertyNames( nLen - nAggCount );
644  OUString* pDelNames = DelPropertyNames.getArray();
645 
646  // delegator values
647  Sequence< Any > DelValues( nLen - nAggCount );
648  Any* pDelValues = DelValues.getArray();
649 
650  for ( const OUString& rName : _rPropertyNames )
651  {
652  if ( OPropertyArrayAggregationHelper::PropertyOrigin::Aggregate == rPH.classifyProperty( rName ) )
653  {
654  *pAggNames++ = rName;
655  *pAggValues++ = *pValues++;
656  }
657  else
658  {
659  *pDelNames++ = rName;
660  *pDelValues++ = *pValues++;
661  }
662  }
663 
664  // reset, needed below
665  pDelValues = DelValues.getArray();
666 
667  std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[ nLen - nAggCount ]);
668 
669  // get the map table
670  cppu::IPropertyArrayHelper& rPH2 = getInfoHelper();
671 
672  // fill the handle array
673  sal_Int32 nHitCount = rPH2.fillHandles( pHandles.get(), DelPropertyNames );
674  if (nHitCount != 0)
675  {
676  std::unique_ptr< css::uno::Any[]> pConvertedValues(new css::uno::Any[ nHitCount ]);
677  std::unique_ptr< css::uno::Any[]> pOldValues(new css::uno::Any[ nHitCount ]);
678  nHitCount = 0;
679  sal_Int32 i;
680 
681  {
682  // must lock the mutex outside the loop. So all values are consistent.
683  osl::MutexGuard aGuard( rBHelper.rMutex );
684  for( i = 0; i < (nLen - nAggCount); ++i )
685  {
686  if( pHandles[i] != -1 )
687  {
688  sal_Int16 nAttributes;
689  rPH2.fillPropertyMembersByHandle( nullptr, &nAttributes, pHandles[i] );
690  if( nAttributes & css::beans::PropertyAttribute::READONLY )
691  throw css::beans::PropertyVetoException();
692  // Will the property change?
693  if( convertFastPropertyValue( pConvertedValues[ nHitCount ], pOldValues[nHitCount],
694  pHandles[i], pDelValues[i] ) )
695  {
696  // only increment if the property really change
697  pHandles[nHitCount] = pHandles[i];
698  nHitCount++;
699  }
700  }
701  }
702  // release guard to fire events
703  }
704 
705  // fire vetoable events
706  fire( pHandles.get(), pConvertedValues.get(), pOldValues.get(), nHitCount, true );
707 
708  // setting the agg Properties
709  m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
710 
711  {
712  // must lock the mutex outside the loop.
713  osl::MutexGuard aGuard( rBHelper.rMutex );
714  // Loop over all changed properties
715  for( i = 0; i < nHitCount; i++ )
716  {
717  // Will the property change?
718  setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
719  }
720  // release guard to fire events
721  }
722 
723  // fire change events
724  fire( pHandles.get(), pConvertedValues.get(), pOldValues.get(), nHitCount, false );
725  }
726  else
727  m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
728  }
729  }
730 }
731 
732 // XPropertyState
733 
734 css::beans::PropertyState SAL_CALL OPropertySetAggregationHelper::getPropertyState(const OUString& _rPropertyName)
735 {
736  OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
737  sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName );
738 
739  if (nHandle == -1)
740  {
741  throw css::beans::UnknownPropertyException(_rPropertyName);
742  }
743 
744  OUString aPropName;
745  sal_Int32 nOriginalHandle = -1;
746  if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
747  {
748  if (m_xAggregateState.is())
749  return m_xAggregateState->getPropertyState(_rPropertyName);
750  else
751  return css::beans::PropertyState_DIRECT_VALUE;
752  }
753  else
754  return getPropertyStateByHandle(nHandle);
755 }
756 
757 
758 void SAL_CALL OPropertySetAggregationHelper::setPropertyToDefault(const OUString& _rPropertyName)
759 {
760  OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
761  sal_Int32 nHandle = rPH.getHandleByName(_rPropertyName);
762  if (nHandle == -1)
763  {
764  throw css::beans::UnknownPropertyException(_rPropertyName);
765  }
766 
767  OUString aPropName;
768  sal_Int32 nOriginalHandle = -1;
769  if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
770  {
771  if (m_xAggregateState.is())
772  m_xAggregateState->setPropertyToDefault(_rPropertyName);
773  }
774  else
775  {
776  try
777  {
778  setPropertyToDefaultByHandle( nHandle );
779  }
780  catch( const UnknownPropertyException& ) { throw; }
781  catch( const RuntimeException& ) { throw; }
782  catch( const Exception& )
783  {
784  OSL_FAIL( "OPropertySetAggregationHelper::setPropertyToDefault: caught an exception which is not allowed to leave here!" );
785  }
786  }
787 }
788 
789 
790 css::uno::Any SAL_CALL OPropertySetAggregationHelper::getPropertyDefault(const OUString& aPropertyName)
791 {
792  OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
793  sal_Int32 nHandle = rPH.getHandleByName( aPropertyName );
794 
795  if ( nHandle == -1 )
796  throw css::beans::UnknownPropertyException(aPropertyName);
797 
798  OUString aPropName;
799  sal_Int32 nOriginalHandle = -1;
800  if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
801  {
802  if (m_xAggregateState.is())
803  return m_xAggregateState->getPropertyDefault(aPropertyName);
804  else
805  return css::uno::Any();
806  }
807  else
808  return getPropertyDefaultByHandle(nHandle);
809 }
810 
811 sal_Bool SAL_CALL OPropertySetAggregationHelper::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue )
812 {
813  bool bModified = false;
814 
815  OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::convertFastPropertyValue: this is no forwarded property - did you use declareForwardedProperty for it?" );
816  if ( m_pForwarder->isResponsibleFor( _nHandle ) )
817  {
818  // need to determine the type of the property for conversion
819  OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
820  Property aProperty;
821  OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
822 
823  Any aCurrentValue;
824  getFastPropertyValue( aCurrentValue, _nHandle );
825  bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, aCurrentValue, aProperty.Type );
826  }
827 
828  return bModified;
829 }
830 
831 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue )
832 {
833  OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast: this is no forwarded property - did you use declareForwardedProperty for it?" );
834  if ( m_pForwarder->isResponsibleFor( _nHandle ) )
835  m_pForwarder->doForward( _nHandle, _rValue );
836 }
837 
838 
839 void OPropertySetAggregationHelper::declareForwardedProperty( sal_Int32 _nHandle )
840 {
841  OSL_ENSURE( !m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::declareForwardedProperty: already declared!" );
842  m_pForwarder->takeResponsibilityFor( _nHandle );
843 }
844 
845 
846 void OPropertySetAggregationHelper::forwardingPropertyValue( sal_Int32 )
847 {
848  // not interested in
849 }
850 
851 
852 void OPropertySetAggregationHelper::forwardedPropertyValue( sal_Int32 )
853 {
854  // not interested in
855 }
856 
857 
858 bool OPropertySetAggregationHelper::isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const
859 {
860  return m_pForwarder->getCurrentlyForwardedProperty() == _nHandle;
861 }
862 
863 
864 } // namespace comphelper
865 
866 
867 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Type
PropertyForwarder(OPropertySetAggregationHelper &_rAggregationHelper)
Definition: propagg.cxx:278
virtual sal_Int32 SAL_CALL getHandleByName(const OUString &_rPropertyName) override
inherited from IPropertyArrayHelper
Definition: propagg.cxx:163
virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties() override
inherited from IPropertyArrayHelper
Definition: propagg.cxx:219
virtual sal_Bool SAL_CALL fillPropertyMembersByHandle(OUString *_pPropName, sal_Int16 *_pAttributes, sal_Int32 _nHandle) override
inherited from IPropertyArrayHelper
Definition: propagg.cxx:170
const_iterator find(const Value &x) const
float x
o3tl::sorted_vector< sal_Int32 > m_aProperties
Definition: propagg.cxx:252
PropertyAccessorMap::const_iterator ConstPropertyAccessorMapIterator
Definition: propagg.hxx:65
size_t pos
bool fillAggregatePropertyInfoByHandle(OUString *_pPropName, sal_Int32 *_pOriginalHandle, sal_Int32 _nHandle) const
returns information about a property of the aggregate.
Definition: propagg.cxx:199
used as callback for an OPropertyArrayAggregationHelper
Definition: propagg.hxx:72
virtual sal_Int32 getPreferredPropertyId(const OUString &_rName)=0
get the preferred handle for the given property
sal_Int32 nHandle
virtual sal_Int32 SAL_CALL fillHandles(sal_Int32 *_pHandles, const css::uno::Sequence< OUString > &_rPropNames) override
inherited from IPropertyArrayHelper
Definition: propagg.cxx:225
float y
void doForward(sal_Int32 _nHandle, const Any &_rValue)
actually forwards a property value to the aggregate
Definition: propagg.cxx:297
int i
virtual sal_Bool SAL_CALL fillPropertyMembersByHandle(::rtl::OUString *pPropName, sal_Int16 *pAttributes, sal_Int32 nHandle)=0
void takeResponsibilityFor(sal_Int32 _nHandle)
declares that the forwarder should be responsible for the given property
Definition: propagg.cxx:285
DECL_LISTENERMULTIPLEXER_END void SAL_CALL inserted(::sal_Int32 ID) override
sal_Int16 nAttributes
unsigned char sal_Bool
const_iterator end() const
bool setPropertyValue(uno::Sequence< beans::PropertyValue > &aProp, const OUString &aName, const uno::Any &aValue)
bool getPropertyByHandle(sal_Int32 _nHandle, css::beans::Property &_rProperty) const
returns information about a property given by handle
Definition: propagg.cxx:187
const PropertyValue * pValues
virtual sal_Bool SAL_CALL hasPropertyByName(const OUString &_rPropertyName) override
inherited from IPropertyArrayHelper
Definition: propagg.cxx:151
virtual sal_Int32 SAL_CALL fillHandles(sal_Int32 *pHandles, const css::uno::Sequence< ::rtl::OUString > &rPropNames)=0
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Copy from a container into a Sequence.
Definition: sequence.hxx:182
PropertyOrigin classifyProperty(const OUString &_rName)
prefer this one over the XPropertySetInfo of the aggregate!
Definition: propagg.cxx:121
sal_Int32 getCurrentlyForwardedProperty() const
Definition: propagg.cxx:274
bool tryPropertyValue(Any &_rConvertedValue, Any &_rOldValue, const Any &_rValueToSet, const Any &_rCurrentValue, const Type &_rExpectedType)
Definition: property.cxx:173
bool isResponsibleFor(sal_Int32 _nHandle)
checks whether the forwarder is responsible for the given property
Definition: propagg.cxx:291
OUString getPropertyName(sal_Int32 nPropertyType)
#define SAL_WARN(area, stream)
const css::beans::Property * findPropertyByName(const OUString &_rName) const
Definition: propagg.cxx:157
std::pair< const_iterator, bool > insert(Value &&x)
OPropertyArrayAggregationHelper(const css::uno::Sequence< css::beans::Property > &_rProperties, const css::uno::Sequence< css::beans::Property > &_rAggProperties, IPropertyInfoService *_pInfoService=nullptr, sal_Int32 _nFirstAggregateId=DEFAULT_AGGREGATE_PROPERTY_ID)
construct the object.
Definition: propagg.cxx:58
virtual sal_Int32 SAL_CALL getHandleByName(const ::rtl::OUString &rPropertyName)=0
virtual css::beans::Property SAL_CALL getPropertyByName(const OUString &_rPropertyName) override
inherited from IPropertyArrayHelper
Definition: propagg.cxx:140
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType, Interface1 *p1)
OPropertySetAggregationHelper & m_rAggregationHelper
Definition: propagg.cxx:251
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo