/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper( const Sequence< Property >& _rProperties, const Sequence< Property >& _rAggProperties,
IPropertyInfoService* _pInfoService, sal_Int32 _nFirstAggregateId )
{ // if properties are present both at the delegatee and the aggregate, then the former are supposed to win // merge and sort properties by name, delete duplicates (stable sort ensures delegator properties win)
m_aProperties.insert( m_aProperties.end(), _rProperties.begin(), _rProperties.end() );
m_aProperties.insert( m_aProperties.end(), _rAggProperties.begin(), _rAggProperties.end() );
std::stable_sort( m_aProperties.begin(), m_aProperties.end(), PropertyCompareByName() );
m_aProperties.erase( std::unique(m_aProperties.begin(), m_aProperties.end(),
[]( const css::beans::Property& x, const css::beans::Property& y ) -> bool { return x.Name == y.Name; } ),
m_aProperties.end() );
m_aProperties.shrink_to_fit();
// fill aDelegatorProps with names from _rProperties for a fast existence check // different kinds of properties are processed differently
std::unordered_set< OUString > aDelegatorProps;
aDelegatorProps.reserve( _rProperties.getLength() ); for( auto &delegateProp: _rProperties )
{ constauto inserted = aDelegatorProps.insert( delegateProp.Name );
OSL_ENSURE( inserted.second, "OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper: duplicate delegatee property!" );
}
std::unordered_set< sal_Int32 > existingHandles;
existingHandles.reserve( m_aProperties.size() );
sal_Int32 nAggregateHandle = _nFirstAggregateId; for ( std::size_t nMPLoop = 0; nMPLoop < m_aProperties.size(); ++nMPLoop )
{ auto &prop = m_aProperties[ nMPLoop ]; if ( aDelegatorProps.find( prop.Name ) != aDelegatorProps.end() )
{
m_aPropertyAccessors.insert_or_assign(
prop.Handle, OPropertyAccessor( -1, nMPLoop, false ));
existingHandles.insert( prop.Handle );
} else
{ // determine the handle for the property which we will expose to the outside world
sal_Int32 nHandle = -1; // ask the info service first if ( _pInfoService )
nHandle = _pInfoService->getPreferredPropertyId( prop.Name );
if ( ( -1 == nHandle ) || ( existingHandles.find( nHandle ) != existingHandles.end() ) )
{ // 1. no handle from the info service -> default // 2. conflicts -> use another one (which we don't check anymore, assuming _nFirstAggregateId was large enough)
nHandle = nAggregateHandle++;
} else
{
existingHandles.insert( nHandle );
}
// remember the accessor for this property
m_aPropertyAccessors.insert_or_assign(
nHandle, OPropertyAccessor( prop.Handle, nMPLoop, true ));
prop.Handle = nHandle;
}
}
}
OPropertyArrayAggregationHelper::PropertyOrigin OPropertyArrayAggregationHelper::classifyProperty( const OUString& _rName )
{
PropertyOrigin eOrigin = PropertyOrigin::Unknown; // look up the name const Property* pPropertyDescriptor = lcl_findPropertyByName( m_aProperties, _rName ); if ( pPropertyDescriptor )
{ // look up the handle for this name auto aPos = m_aPropertyAccessors.find( pPropertyDescriptor->Handle );
OSL_ENSURE( m_aPropertyAccessors.end() != aPos, "OPropertyArrayAggregationHelper::classifyProperty: should have this handle in my map!" ); if ( m_aPropertyAccessors.end() != aPos )
{
eOrigin = aPos->second.bAggregate ? PropertyOrigin::Aggregate : PropertyOrigin::Delegator;
}
} return eOrigin;
}
if ( m_xAggregateSet.is() && m_bListening )
{ // register as a single listener
m_xAggregateMultiSet->removePropertiesChangeListener(this);
m_xAggregateSet->removeVetoableChangeListener(OUString(), this);
m_bListening = false;
}
OPropertyStateHelper::disposing();
}
void SAL_CALL OPropertySetAggregationHelper::disposing(const css::lang::EventObject& _rSource)
{
OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::disposing : don't have an aggregate anymore !"); if (_rSource.Source == m_xAggregateSet)
m_bListening = false;
}
void SAL_CALL OPropertySetAggregationHelper::propertiesChange(const css::uno::Sequence< css::beans::PropertyChangeEvent>& _rEvents)
{
OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::propertiesChange : have no aggregate !");
if (1 == nLen)
{ const css::beans::PropertyChangeEvent& evt = _rEvents[0];
OSL_ENSURE(!evt.PropertyName.isEmpty(), "OPropertySetAggregationHelper::propertiesChange : invalid event !"); // we had a bug where this assertion would have us saved a whole day :) (72514)
sal_Int32 nHandle = rPH.getHandleByName( evt.PropertyName );
// If nHandle is -1 the event marks a (aggregate) property which we hide to callers // If isCurrentlyForwardingProperty( nHandle ) is <TRUE/>, then we ourself triggered // setting this property. In this case, it will be notified later (by the OPropertySetHelper // implementation)
// must support XPropertySet and XMultiPropertySet if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() ) throw css::lang::IllegalArgumentException();
}
if (!m_bListening && m_xAggregateSet.is())
{ // register as a single listener
css::uno::Sequence< OUString > aPropertyNames;
m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this);
m_xAggregateSet->addVetoableChangeListener(OUString(), this);
// does the handle belong to the aggregation ? if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, _nHandle)) if (m_xAggregateFastSet.is())
m_xAggregateFastSet->setFastPropertyValue(nOriginalHandle, _rValue); else
m_xAggregateSet->setPropertyValue(aPropName, _rValue); else
OPropertySetHelper::setFastPropertyValue(_nHandle, _rValue);
}
if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
{ if (m_xAggregateFastSet.is())
aValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle); else
aValue = m_xAggregateSet->getPropertyValue(aPropName);
} else
aValue = OPropertySetHelper::getFastPropertyValue(nHandle);
return aValue;
}
void SAL_CALL OPropertySetAggregationHelper::setPropertyValues( const Sequence< OUString >& _rPropertyNames, const Sequence< Any >& _rValues )
{
OSL_ENSURE( !rBHelper.bInDispose, "OPropertySetAggregationHelper::setPropertyValues : do not use within the dispose call !");
OSL_ENSURE( !rBHelper.bDisposed, "OPropertySetAggregationHelper::setPropertyValues : object is disposed" );
// check where the properties come from if (!m_xAggregateSet.is())
OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues); elseif (_rPropertyNames.getLength() == 1) // use the more efficient way
{ if (_rValues.getLength() != 1) throw IllegalArgumentException(u"lengths do not match"_ustr, static_cast<XPropertySet*>(this),
-1); try
{
setPropertyValue( _rPropertyNames[0], _rValues[0] );
} catch( const UnknownPropertyException& )
{ // by definition of XMultiPropertySet::setPropertyValues, unknown properties are to be ignored
SAL_WARN( "comphelper", "OPropertySetAggregationHelper::setPropertyValues: unknown property: '"
<< _rPropertyNames[0] << "', implementation: " << typeid( *this ).name() );
}
} else
{
OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
// determine which properties belong to the aggregate, and which ones to the delegator
sal_Int32 nAggCount(0);
sal_Int32 nLen(_rPropertyNames.getLength());
for ( const OUString& rName : _rPropertyNames )
{
OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( rName ); if ( OPropertyArrayAggregationHelper::PropertyOrigin::Unknown == ePropOrg ) throw WrappedTargetException( OUString(), static_cast< XMultiPropertySet* >( this ), Any( UnknownPropertyException( ) ) ); // due to a flaw in the API design, this method is not allowed to throw an UnknownPropertyException // so we wrap it into a WrappedTargetException
if ( OPropertyArrayAggregationHelper::PropertyOrigin::Aggregate == ePropOrg )
++nAggCount;
}
// all properties belong to the aggregate if (nAggCount == nLen)
m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues);
// all properties belong to the aggregating object elseif (nAggCount == 0)
OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
// mixed else
{ if (_rValues.getLength() != nLen) throw IllegalArgumentException(u"lengths do not match"_ustr, static_cast<XPropertySet*>(this), -1);
// setting the agg Properties
m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
{ // must lock the mutex outside the loop.
osl::MutexGuard aGuard( rBHelper.rMutex ); // Loop over all changed properties for( i = 0; i < nHitCount; i++ )
{ // Will the property change?
setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
} // release guard to fire events
}
OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::convertFastPropertyValue: this is no forwarded property - did you use declareForwardedProperty for it?" ); if ( m_pForwarder->isResponsibleFor( _nHandle ) )
{ // need to determine the type of the property for conversion
OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
Property aProperty;
OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue )
{
OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast: this is no forwarded property - did you use declareForwardedProperty for it?" ); if ( m_pForwarder->isResponsibleFor( _nHandle ) )
m_pForwarder->doForward( _nHandle, _rValue );
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.