| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_comphelper.hxx" |
| #include "comphelper/propagg.hxx" |
| #include "comphelper/property.hxx" |
| #include <cppuhelper/queryinterface.hxx> |
| #include <osl/diagnose.h> |
| #include <com/sun/star/beans/PropertyAttribute.hpp> |
| |
| #if OSL_DEBUG_LEVEL > 0 |
| #include <typeinfo> |
| #include <rtl/strbuf.hxx> |
| #endif |
| |
| #include <algorithm> |
| #include <set> |
| |
| //......................................................................... |
| namespace comphelper |
| { |
| //......................................................................... |
| |
| using namespace ::com::sun::star::uno; |
| using namespace ::com::sun::star::lang; |
| using namespace ::com::sun::star::beans; |
| |
| using namespace internal; |
| |
| //------------------------------------------------------------------------------ |
| namespace |
| { |
| const Property* lcl_findPropertyByName( const Sequence< Property >& _rProps, const ::rtl::OUString& _rName ) |
| { |
| sal_Int32 nLen = _rProps.getLength(); |
| const Property* pProperties = _rProps.getConstArray(); |
| const Property* pResult = ::std::lower_bound(pProperties, pProperties + nLen,_rName, ::comphelper::PropertyStringLessFunctor()); |
| if ( pResult && ( pResult == pProperties + nLen || pResult->Name != _rName) ) |
| pResult = NULL; |
| |
| return pResult; |
| } |
| } |
| //================================================================== |
| //= OPropertyArrayAggregationHelper |
| //================================================================== |
| |
| //------------------------------------------------------------------------------ |
| OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper( |
| const Sequence< Property >& _rProperties, const Sequence< Property >& _rAggProperties, |
| IPropertyInfoService* _pInfoService, sal_Int32 _nFirstAggregateId ) |
| :m_aProperties( _rProperties ) |
| { |
| sal_Int32 nDelegatorProps = _rProperties.getLength(); |
| sal_Int32 nAggregateProps = _rAggProperties.getLength(); |
| |
| // make room for all properties |
| sal_Int32 nMergedProps = nDelegatorProps + nAggregateProps; |
| m_aProperties.realloc( nMergedProps ); |
| |
| const Property* pAggregateProps = _rAggProperties.getConstArray(); |
| const Property* pDelegateProps = _rProperties.getConstArray(); |
| Property* pMergedProps = m_aProperties.getArray(); |
| |
| // if properties are present both at the delegatee and the aggregate, then the former are supposed to win. |
| // So, we'll need an existence check. |
| ::std::set< ::rtl::OUString > aDelegatorProps; |
| |
| // create the map for the delegator properties |
| sal_Int32 nMPLoop = 0; |
| for ( ; nMPLoop < nDelegatorProps; ++nMPLoop, ++pDelegateProps ) |
| { |
| m_aPropertyAccessors[ pDelegateProps->Handle ] = OPropertyAccessor( -1, nMPLoop, sal_False ); |
| OSL_ENSURE( aDelegatorProps.find( pDelegateProps->Name ) == aDelegatorProps.end(), |
| "OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper: duplicate delegatee property!" ); |
| aDelegatorProps.insert( pDelegateProps->Name ); |
| } |
| |
| // create the map for the aggregate properties |
| sal_Int32 nAggregateHandle = _nFirstAggregateId; |
| pMergedProps += nDelegatorProps; |
| for ( ; nMPLoop < nMergedProps; ++pAggregateProps ) |
| { |
| // if the aggregate property is present at the delegatee already, ignore it |
| if ( aDelegatorProps.find( pAggregateProps->Name ) != aDelegatorProps.end() ) |
| { |
| --nMergedProps; |
| continue; |
| } |
| |
| // next aggregate property - remember it |
| *pMergedProps = *pAggregateProps; |
| |
| // determine the handle for the property which we will expose to the outside world |
| sal_Int32 nHandle = -1; |
| // ask the infor service first |
| if ( _pInfoService ) |
| nHandle = _pInfoService->getPreferedPropertyId( pMergedProps->Name ); |
| |
| if ( -1 == nHandle ) |
| // no handle from the info service -> default |
| nHandle = nAggregateHandle++; |
| else |
| { // check if we alread have a property with the given handle |
| const Property* pPropsTilNow = m_aProperties.getConstArray(); |
| for ( sal_Int32 nCheck = 0; nCheck < nMPLoop; ++nCheck, ++pPropsTilNow ) |
| if ( pPropsTilNow->Handle == nHandle ) |
| { // conflicts -> use another one (which we don't check anymore, assuming _nFirstAggregateId was large enough) |
| nHandle = nAggregateHandle++; |
| break; |
| } |
| } |
| |
| // remember the accessor for this property |
| m_aPropertyAccessors[ nHandle ] = OPropertyAccessor( pMergedProps->Handle, nMPLoop, sal_True ); |
| pMergedProps->Handle = nHandle; |
| |
| ++nMPLoop; |
| ++pMergedProps; |
| } |
| m_aProperties.realloc( nMergedProps ); |
| pMergedProps = m_aProperties.getArray(); // reset, needed again below |
| |
| // sortieren der Properties nach Namen |
| ::std::sort( pMergedProps, pMergedProps+nMergedProps, PropertyCompareByName()); |
| |
| pMergedProps = m_aProperties.getArray(); |
| |
| // Positionen in der Map abgleichen |
| for ( nMPLoop = 0; nMPLoop < nMergedProps; ++nMPLoop, ++pMergedProps ) |
| m_aPropertyAccessors[ pMergedProps->Handle ].nPos = nMPLoop; |
| } |
| |
| //------------------------------------------------------------------ |
| OPropertyArrayAggregationHelper::PropertyOrigin OPropertyArrayAggregationHelper::classifyProperty( const ::rtl::OUString& _rName ) |
| { |
| PropertyOrigin eOrigin = UNKNOWN_PROPERTY; |
| // look up the name |
| const Property* pPropertyDescriptor = lcl_findPropertyByName( m_aProperties, _rName ); |
| if ( pPropertyDescriptor ) |
| { |
| // look up the handle for this name |
| ConstPropertyAccessorMapIterator 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 ? AGGREGATE_PROPERTY : DELEGATOR_PROPERTY; |
| } |
| } |
| return eOrigin; |
| } |
| |
| //------------------------------------------------------------------ |
| Property OPropertyArrayAggregationHelper::getPropertyByName( const ::rtl::OUString& _rPropertyName ) throw( UnknownPropertyException ) |
| { |
| const Property* pProperty = findPropertyByName( _rPropertyName ); |
| |
| if ( !pProperty ) |
| throw UnknownPropertyException(); |
| |
| return *pProperty; |
| } |
| |
| //------------------------------------------------------------------------------ |
| sal_Bool OPropertyArrayAggregationHelper::hasPropertyByName(const ::rtl::OUString& _rPropertyName) |
| { |
| return NULL != findPropertyByName( _rPropertyName ); |
| } |
| |
| //------------------------------------------------------------------------------ |
| const Property* OPropertyArrayAggregationHelper::findPropertyByName(const :: rtl::OUString& _rName ) const |
| { |
| return lcl_findPropertyByName( m_aProperties, _rName ); |
| } |
| |
| //------------------------------------------------------------------------------ |
| sal_Int32 OPropertyArrayAggregationHelper::getHandleByName(const ::rtl::OUString& _rPropertyName) |
| { |
| const Property* pProperty = findPropertyByName( _rPropertyName ); |
| return pProperty ? pProperty->Handle : -1; |
| } |
| |
| //------------------------------------------------------------------------------ |
| sal_Bool OPropertyArrayAggregationHelper::fillPropertyMembersByHandle( |
| ::rtl::OUString* _pPropName, sal_Int16* _pAttributes, sal_Int32 _nHandle) |
| { |
| ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle); |
| sal_Bool bRet = i != m_aPropertyAccessors.end(); |
| if (bRet) |
| { |
| const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos]; |
| if (_pPropName) |
| *_pPropName = rProperty.Name; |
| if (_pAttributes) |
| *_pAttributes = rProperty.Attributes; |
| } |
| return bRet; |
| } |
| |
| //------------------------------------------------------------------------------ |
| sal_Bool OPropertyArrayAggregationHelper::getPropertyByHandle( sal_Int32 _nHandle, Property& _rProperty ) const |
| { |
| ConstPropertyAccessorMapIterator pos = m_aPropertyAccessors.find(_nHandle); |
| if ( pos != m_aPropertyAccessors.end() ) |
| { |
| _rProperty = m_aProperties[ pos->second.nPos ]; |
| return sal_True; |
| } |
| return sal_False; |
| } |
| |
| //------------------------------------------------------------------------------ |
| sal_Bool OPropertyArrayAggregationHelper::fillAggregatePropertyInfoByHandle( |
| ::rtl::OUString* _pPropName, sal_Int32* _pOriginalHandle, sal_Int32 _nHandle) const |
| { |
| ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle); |
| sal_Bool bRet = i != m_aPropertyAccessors.end() && (*i).second.bAggregate; |
| if (bRet) |
| { |
| if (_pOriginalHandle) |
| *_pOriginalHandle = (*i).second.nOriginalHandle; |
| if (_pPropName) |
| { |
| OSL_ENSURE((*i).second.nPos < m_aProperties.getLength(),"Invalid index for sequence!"); |
| const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos]; |
| *_pPropName = rProperty.Name; |
| } |
| } |
| return bRet; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property> OPropertyArrayAggregationHelper::getProperties() |
| { |
| return m_aProperties; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| sal_Int32 OPropertyArrayAggregationHelper::fillHandles( |
| sal_Int32* _pHandles, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rPropNames ) |
| { |
| sal_Int32 nHitCount = 0; |
| const ::rtl::OUString* pReqProps = _rPropNames.getConstArray(); |
| sal_Int32 nReqLen = _rPropNames.getLength(); |
| |
| #if OSL_DEBUG_LEVEL > 0 |
| // assure that the sequence is sorted |
| { |
| const ::rtl::OUString* pLookup = _rPropNames.getConstArray(); |
| const ::rtl::OUString* pEnd = _rPropNames.getConstArray() + _rPropNames.getLength() - 1; |
| for (; pLookup < pEnd; ++pLookup) |
| { |
| const ::rtl::OUString* pCompare = pLookup + 1; |
| const ::rtl::OUString* pCompareEnd = pEnd + 1; |
| for (; pCompare < pCompareEnd; ++pCompare) |
| { |
| OSL_ENSURE(pLookup->compareTo(*pCompare) < 0, "OPropertyArrayAggregationHelper::fillHandles : property names are not sorted!"); |
| } |
| } |
| } |
| #endif |
| |
| const ::com::sun::star::beans::Property* pCur = m_aProperties.getConstArray(); |
| const ::com::sun::star::beans::Property* pEnd = m_aProperties.getConstArray() + m_aProperties.getLength(); |
| |
| for( sal_Int32 i = 0; i < nReqLen; ++i ) |
| { |
| // Logarithmus ermitteln |
| sal_uInt32 n = (sal_uInt32)(pEnd - pCur); |
| sal_Int32 nLog = 0; |
| while( n ) |
| { |
| nLog += 1; |
| n = n >> 1; |
| } |
| |
| // Anzahl der noch zu suchenden Properties * dem Log2 der verbleibenden |
| // zu dursuchenden Properties. |
| if( (nReqLen - i) * nLog >= pEnd - pCur ) |
| { |
| // linear search is better |
| while( pCur < pEnd && pReqProps[i] > pCur->Name ) |
| { |
| pCur++; |
| } |
| if( pCur < pEnd && pReqProps[i] == pCur->Name ) |
| { |
| _pHandles[i] = pCur->Handle; |
| nHitCount++; |
| } |
| else |
| _pHandles[i] = -1; |
| } |
| else |
| { |
| // binary search is better |
| sal_Int32 nCompVal = 1; |
| const ::com::sun::star::beans::Property* pOldEnd = pEnd--; |
| const ::com::sun::star::beans::Property* pMid = pCur; |
| |
| while( nCompVal != 0 && pCur <= pEnd ) |
| { |
| pMid = (pEnd - pCur) / 2 + pCur; |
| |
| nCompVal = pReqProps[i].compareTo( pMid->Name ); |
| |
| if( nCompVal > 0 ) |
| pCur = pMid + 1; |
| else |
| pEnd = pMid - 1; |
| } |
| |
| if( nCompVal == 0 ) |
| { |
| _pHandles[i] = pMid->Handle; |
| nHitCount++; |
| pCur = pMid +1; |
| } |
| else if( nCompVal > 0 ) |
| { |
| _pHandles[i] = -1; |
| pCur = pMid + 1; |
| } |
| else |
| { |
| _pHandles[i] = -1; |
| pCur = pMid; |
| } |
| pEnd = pOldEnd; |
| } |
| } |
| return nHitCount; |
| } |
| |
| //================================================================== |
| //= PropertyForwarder |
| //================================================================== |
| namespace internal |
| { |
| class PropertyForwarder |
| { |
| private: |
| OPropertySetAggregationHelper& m_rAggregationHelper; |
| ::std::set< sal_Int32 > m_aProperties; |
| sal_Int32 m_nCurrentlyForwarding; |
| |
| public: |
| PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper ); |
| ~PropertyForwarder(); |
| |
| /** declares that the forwarder should be responsible for the given property |
| |
| @param _nHandle |
| the public handle (<em>not</em> the original handle!) of the property |
| */ |
| void takeResponsibilityFor( sal_Int32 _nHandle ); |
| |
| /** checks whether the forwarder is responsible for the given property |
| */ |
| bool isResponsibleFor( sal_Int32 _nHandle ); |
| |
| /// actually forwards a property value to the aggregate |
| void doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception ); |
| |
| sal_Int32 getCurrentlyForwardedProperty( ) const { return m_nCurrentlyForwarding; } |
| }; |
| |
| //-------------------------------------------------------------------------- |
| PropertyForwarder::PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper ) |
| :m_rAggregationHelper( _rAggregationHelper ) |
| ,m_nCurrentlyForwarding( -1 ) |
| { |
| } |
| |
| //-------------------------------------------------------------------------- |
| PropertyForwarder::~PropertyForwarder() |
| { |
| } |
| |
| //-------------------------------------------------------------------------- |
| void PropertyForwarder::takeResponsibilityFor( sal_Int32 _nHandle ) |
| { |
| m_aProperties.insert( _nHandle ); |
| } |
| |
| //-------------------------------------------------------------------------- |
| bool PropertyForwarder::isResponsibleFor( sal_Int32 _nHandle ) |
| { |
| return m_aProperties.find( _nHandle ) != m_aProperties.end(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| void PropertyForwarder::doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception ) |
| { |
| OSL_ENSURE( m_rAggregationHelper.m_xAggregateSet.is(), "PropertyForwarder::doForward: no property set!" ); |
| if ( m_rAggregationHelper.m_xAggregateSet.is() ) |
| { |
| m_rAggregationHelper.forwardingPropertyValue( _nHandle ); |
| |
| OSL_ENSURE( m_nCurrentlyForwarding == -1, "PropertyForwarder::doForward: reentrance?" ); |
| m_nCurrentlyForwarding = _nHandle; |
| |
| try |
| { |
| m_rAggregationHelper.m_xAggregateSet->setPropertyValue( m_rAggregationHelper.getPropertyName( _nHandle ), _rValue ); |
| // TODO: cache the property name? (it's a O(log n) search) |
| } |
| catch( const Exception& ) |
| { |
| m_rAggregationHelper.forwardedPropertyValue( _nHandle, false ); |
| throw; |
| } |
| |
| m_nCurrentlyForwarding = -1; |
| |
| m_rAggregationHelper.forwardedPropertyValue( _nHandle, true ); |
| } |
| } |
| } |
| |
| //================================================================== |
| //= OPropertySetAggregationHelper |
| //================================================================== |
| |
| //------------------------------------------------------------------------------ |
| OPropertySetAggregationHelper::OPropertySetAggregationHelper( ::cppu::OBroadcastHelper& rBHlp ) |
| :OPropertyStateHelper( rBHlp ) |
| ,m_bListening( sal_False ) |
| { |
| m_pForwarder = new PropertyForwarder( *this ); |
| } |
| |
| //------------------------------------------------------------------------------ |
| OPropertySetAggregationHelper::~OPropertySetAggregationHelper() |
| { |
| delete m_pForwarder; |
| } |
| |
| //------------------------------------------------------------------------------ |
| ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::queryInterface(const ::com::sun::star::uno::Type& _rType) throw( ::com::sun::star::uno::RuntimeException) |
| { |
| ::com::sun::star::uno::Any aReturn = OPropertyStateHelper::queryInterface(_rType); |
| |
| if ( !aReturn.hasValue() ) |
| aReturn = cppu::queryInterface(_rType |
| ,static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this) |
| ,static_cast< ::com::sun::star::beans::XVetoableChangeListener*>(this) |
| ,static_cast< ::com::sun::star::lang::XEventListener*>(static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this)) |
| ); |
| |
| return aReturn; |
| } |
| |
| //------------------------------------------------------------------------------ |
| void OPropertySetAggregationHelper::disposing() |
| { |
| osl::MutexGuard aGuard(rBHelper.rMutex); |
| |
| if ( m_xAggregateSet.is() && m_bListening ) |
| { |
| // als einziger Listener anmelden |
| m_xAggregateMultiSet->removePropertiesChangeListener(this); |
| m_xAggregateSet->removeVetoableChangeListener(::rtl::OUString(), this); |
| m_bListening = sal_False; |
| } |
| |
| OPropertyStateHelper::disposing(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL OPropertySetAggregationHelper::disposing(const ::com::sun::star::lang::EventObject& _rSource) throw ( ::com::sun::star::uno::RuntimeException) |
| { |
| OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::disposing : don't have an aggregate anymore !"); |
| if (_rSource.Source == m_xAggregateSet) |
| m_bListening = sal_False; |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL OPropertySetAggregationHelper::propertiesChange(const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyChangeEvent>& _rEvents) throw( ::com::sun::star::uno::RuntimeException) |
| { |
| OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::propertiesChange : have no aggregate !"); |
| |
| sal_Int32 nLen = _rEvents.getLength(); |
| cppu::IPropertyArrayHelper& rPH = getInfoHelper(); |
| |
| if (1 == nLen) |
| { |
| const ::com::sun::star::beans::PropertyChangeEvent& evt = _rEvents.getConstArray()[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) |
| |
| if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) ) |
| fire(&nHandle, &evt.NewValue, &evt.OldValue, 1, sal_False); |
| } |
| else |
| { |
| sal_Int32* pHandles = new sal_Int32[nLen]; |
| ::com::sun::star::uno::Any* pNewValues = new ::com::sun::star::uno::Any[nLen]; |
| ::com::sun::star::uno::Any* pOldValues = new ::com::sun::star::uno::Any[nLen]; |
| |
| const ::com::sun::star::beans::PropertyChangeEvent* pEvents = _rEvents.getConstArray(); |
| sal_Int32 nDest = 0; |
| for (sal_Int32 nSource=0; nSource<nLen; ++nSource, ++pEvents) |
| { |
| sal_Int32 nHandle = rPH.getHandleByName(pEvents->PropertyName); |
| if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) ) |
| { // same as above : -1 is valid (73247) ... |
| pHandles[nDest] = nHandle; |
| pNewValues[nDest] = pEvents->NewValue; |
| pOldValues[nDest] = pEvents->OldValue; |
| ++nDest; |
| } |
| } |
| |
| if (nDest) |
| fire(pHandles, pNewValues, pOldValues, nDest, sal_False); |
| |
| delete[] pHandles; |
| delete[] pNewValues; |
| delete[] pOldValues; |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL OPropertySetAggregationHelper::vetoableChange(const ::com::sun::star::beans::PropertyChangeEvent& _rEvent) throw( ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException) |
| { |
| OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::vetoableChange : have no aggregate !"); |
| |
| cppu::IPropertyArrayHelper& rPH = getInfoHelper(); |
| |
| sal_Int32 nHandle = rPH.getHandleByName(_rEvent.PropertyName); |
| fire(&nHandle, &_rEvent.NewValue, &_rEvent.OldValue, 1, sal_True); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void OPropertySetAggregationHelper::setAggregation(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxDelegate) |
| throw( ::com::sun::star::lang::IllegalArgumentException ) |
| { |
| osl::MutexGuard aGuard(rBHelper.rMutex); |
| |
| if (m_bListening && m_xAggregateSet.is()) |
| { |
| m_xAggregateMultiSet->removePropertiesChangeListener(this); |
| m_xAggregateSet->removeVetoableChangeListener(::rtl::OUString(), this); |
| m_bListening = sal_False; |
| } |
| |
| m_xAggregateState = m_xAggregateState.query( _rxDelegate ); |
| m_xAggregateSet = m_xAggregateSet.query( _rxDelegate ); |
| m_xAggregateMultiSet = m_xAggregateMultiSet.query( _rxDelegate ); |
| m_xAggregateFastSet = m_xAggregateFastSet.query( _rxDelegate ); |
| |
| // must support XPropertySet and XMultiPropertySet |
| if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() ) |
| throw ::com::sun::star::lang::IllegalArgumentException(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void OPropertySetAggregationHelper::startListening() |
| { |
| osl::MutexGuard aGuard(rBHelper.rMutex); |
| |
| if (!m_bListening && m_xAggregateSet.is()) |
| { |
| // als einziger Listener anmelden |
| ::com::sun::star::uno::Sequence< ::rtl::OUString > aPropertyNames; |
| m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this); |
| m_xAggregateSet->addVetoableChangeListener(::rtl::OUString(), this); |
| |
| m_bListening = sal_True; |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL OPropertySetAggregationHelper::addVetoableChangeListener(const ::rtl::OUString& _rPropertyName, |
| const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener>& _rxListener) |
| throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) |
| { |
| OPropertySetHelper::addVetoableChangeListener(_rPropertyName, _rxListener); |
| if (!m_bListening) |
| startListening(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL OPropertySetAggregationHelper::addPropertyChangeListener(const ::rtl::OUString& _rPropertyName, |
| const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener>& _rxListener) |
| throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) |
| { |
| OPropertySetHelper::addPropertyChangeListener(_rPropertyName, _rxListener); |
| if (!m_bListening) |
| startListening(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL OPropertySetAggregationHelper::addPropertiesChangeListener(const ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rPropertyNames, |
| const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener>& _rxListener) |
| throw( ::com::sun::star::uno::RuntimeException) |
| { |
| OPropertySetHelper::addPropertiesChangeListener(_rPropertyNames, _rxListener); |
| if (!m_bListening) |
| startListening(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| sal_Int32 OPropertySetAggregationHelper::getOriginalHandle(sal_Int32 nHandle) const |
| { |
| OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper(); |
| sal_Int32 nOriginalHandle = -1; |
| rPH.fillAggregatePropertyInfoByHandle(NULL, &nOriginalHandle, nHandle); |
| return nOriginalHandle; |
| } |
| |
| //-------------------------------------------------------------------------- |
| ::rtl::OUString OPropertySetAggregationHelper::getPropertyName( sal_Int32 _nHandle ) const |
| { |
| OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() ); |
| Property aProperty; |
| OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) ); |
| return aProperty.Name; |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue(sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rValue) |
| throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, |
| ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, |
| ::com::sun::star::uno::RuntimeException) |
| { |
| OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); |
| ::rtl::OUString aPropName; |
| sal_Int32 nOriginalHandle = -1; |
| |
| // 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); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void OPropertySetAggregationHelper::getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle) const |
| { |
| OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper(); |
| ::rtl::OUString aPropName; |
| sal_Int32 nOriginalHandle = -1; |
| |
| if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle)) |
| { |
| if (m_xAggregateFastSet.is()) |
| rValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle); |
| else |
| rValue = m_xAggregateSet->getPropertyValue(aPropName); |
| } |
| else if ( m_pForwarder->isResponsibleFor( nHandle ) ) |
| { |
| // this is a property which has been "overwritten" in our instance (thus |
| // fillAggregatePropertyInfoByHandle didn't find it) |
| rValue = m_xAggregateSet->getPropertyValue( getPropertyName( nHandle ) ); |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getFastPropertyValue(sal_Int32 nHandle) |
| throw( ::com::sun::star::beans::UnknownPropertyException, |
| ::com::sun::star::lang::WrappedTargetException, |
| ::com::sun::star::uno::RuntimeException) |
| { |
| OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); |
| ::rtl::OUString aPropName; |
| sal_Int32 nOriginalHandle = -1; |
| ::com::sun::star::uno::Any aValue; |
| |
| 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< ::rtl::OUString >& _rPropertyNames, const Sequence< Any >& _rValues ) |
| throw ( PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException ) |
| { |
| 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); |
| else if (_rPropertyNames.getLength() == 1) // use the more efficient way |
| { |
| try |
| { |
| setPropertyValue( _rPropertyNames[0], _rValues[0] ); |
| } |
| catch( const UnknownPropertyException& ) |
| { |
| // by definition of XMultiPropertySet::setPropertyValues, unknown properties are to be ignored |
| #if OSL_DEBUG_LEVEL > 0 |
| ::rtl::OStringBuffer aMessage; |
| aMessage.append( "OPropertySetAggregationHelper::setPropertyValues: unknown property '" ); |
| aMessage.append( ::rtl::OUStringToOString( _rPropertyNames[0], RTL_TEXTENCODING_ASCII_US ) ); |
| aMessage.append( "'" ); |
| aMessage.append( "\n(implementation " ); |
| aMessage.append( typeid( *this ).name() ); |
| aMessage.append( ")" ); |
| OSL_ENSURE( false, aMessage.getStr() ); |
| #endif |
| } |
| } |
| else |
| { |
| OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); |
| |
| // determine which properties belong to the aggregate, and which ones to the delegator |
| const ::rtl::OUString* pNames = _rPropertyNames.getConstArray(); |
| sal_Int32 nAggCount(0); |
| sal_Int32 nLen(_rPropertyNames.getLength()); |
| |
| for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames ) |
| { |
| OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( *pNames ); |
| if ( OPropertyArrayAggregationHelper::UNKNOWN_PROPERTY == ePropOrg ) |
| throw WrappedTargetException( ::rtl::OUString(), static_cast< XMultiPropertySet* >( this ), makeAny( 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 |
| // #107545# - 2002-02-20 - fs@openoffice.org |
| |
| if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == ePropOrg ) |
| ++nAggCount; |
| } |
| |
| pNames = _rPropertyNames.getConstArray(); // reset, we'll need it again below ... |
| |
| // all properties belong to the aggregate |
| if (nAggCount == nLen) |
| m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues); |
| |
| // all properties belong to the aggregating object |
| else if (nAggCount == 0) |
| OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues); |
| |
| // mixed |
| else |
| { |
| const ::com::sun::star::uno::Any* pValues = _rValues.getConstArray(); |
| ::com::sun::star::uno::Any* pConvertedValues = NULL; |
| ::com::sun::star::uno::Any* pOldValues = NULL; |
| sal_Int32* pHandles = NULL; |
| |
| try |
| { |
| // dividing the Names and _rValues |
| |
| // aggregate's names |
| Sequence< ::rtl::OUString > AggPropertyNames( nAggCount ); |
| ::rtl::OUString* pAggNames = AggPropertyNames.getArray(); |
| // aggregate's values |
| Sequence< Any > AggValues( nAggCount ); |
| Any* pAggValues = AggValues.getArray(); |
| |
| // delegator names |
| Sequence< ::rtl::OUString > DelPropertyNames( nLen - nAggCount ); |
| ::rtl::OUString* pDelNames = DelPropertyNames.getArray(); |
| |
| // delegator values |
| Sequence< Any > DelValues( nLen - nAggCount ); |
| Any* pDelValues = DelValues.getArray(); |
| |
| for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames, ++pValues ) |
| { |
| if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == rPH.classifyProperty( *pNames ) ) |
| { |
| *pAggNames++ = *pNames; |
| *pAggValues++ = *pValues; |
| } |
| else |
| { |
| *pDelNames++ = *pNames; |
| *pDelValues++ = *pValues; |
| } |
| } |
| |
| // reset, needed below |
| pDelValues = DelValues.getArray(); |
| |
| pHandles = new sal_Int32[ nLen - nAggCount ]; |
| |
| // get the map table |
| cppu::IPropertyArrayHelper& rPH2 = getInfoHelper(); |
| |
| // fill the handle array |
| sal_Int32 nHitCount = rPH2.fillHandles( pHandles, DelPropertyNames ); |
| if (nHitCount != 0) |
| { |
| |
| pConvertedValues = new ::com::sun::star::uno::Any[ nHitCount ]; |
| pOldValues = new ::com::sun::star::uno::Any[ nHitCount ]; |
| nHitCount = 0; |
| sal_Int32 i; |
| |
| { |
| // must lock the mutex outside the loop. So all values are consistent. |
| osl::MutexGuard aGuard( rBHelper.rMutex ); |
| for( i = 0; i < (nLen - nAggCount); ++i ) |
| { |
| if( pHandles[i] != -1 ) |
| { |
| sal_Int16 nAttributes; |
| rPH2.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] ); |
| if( nAttributes & ::com::sun::star::beans::PropertyAttribute::READONLY ) |
| throw ::com::sun::star::beans::PropertyVetoException(); |
| // Will the property change? |
| if( convertFastPropertyValue( pConvertedValues[ nHitCount ], pOldValues[nHitCount], |
| pHandles[i], pDelValues[i] ) ) |
| { |
| // only increment if the property really change |
| pHandles[nHitCount] = pHandles[i]; |
| nHitCount++; |
| } |
| } |
| } |
| // release guard to fire events |
| } |
| |
| // fire vetoable events |
| fire( pHandles, pConvertedValues, pOldValues, nHitCount, sal_True ); |
| |
| // 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 |
| } |
| |
| // fire change events |
| fire( pHandles, pConvertedValues, pOldValues, nHitCount, sal_False ); |
| } |
| else |
| m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues); |
| |
| } |
| catch(::com::sun::star::uno::Exception&) |
| { |
| delete [] pHandles; |
| delete [] pOldValues; |
| delete [] pConvertedValues; |
| throw; |
| } |
| |
| delete [] pHandles; |
| delete [] pOldValues; |
| delete [] pConvertedValues; |
| } |
| } |
| } |
| |
| // XPropertyState |
| //------------------------------------------------------------------------------ |
| ::com::sun::star::beans::PropertyState SAL_CALL OPropertySetAggregationHelper::getPropertyState(const ::rtl::OUString& _rPropertyName) |
| throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException) |
| { |
| OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); |
| sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName ); |
| |
| if (nHandle == -1) |
| { |
| throw ::com::sun::star::beans::UnknownPropertyException(); |
| } |
| |
| ::rtl::OUString aPropName; |
| sal_Int32 nOriginalHandle = -1; |
| if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle)) |
| { |
| if (m_xAggregateState.is()) |
| return m_xAggregateState->getPropertyState(_rPropertyName); |
| else |
| return ::com::sun::star::beans::PropertyState_DIRECT_VALUE; |
| } |
| else |
| return getPropertyStateByHandle(nHandle); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL OPropertySetAggregationHelper::setPropertyToDefault(const ::rtl::OUString& _rPropertyName) |
| throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException) |
| { |
| OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); |
| sal_Int32 nHandle = rPH.getHandleByName(_rPropertyName); |
| if (nHandle == -1) |
| { |
| throw ::com::sun::star::beans::UnknownPropertyException(); |
| } |
| |
| ::rtl::OUString aPropName; |
| sal_Int32 nOriginalHandle = -1; |
| if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle)) |
| { |
| if (m_xAggregateState.is()) |
| m_xAggregateState->setPropertyToDefault(_rPropertyName); |
| } |
| else |
| { |
| try |
| { |
| setPropertyToDefaultByHandle( nHandle ); |
| } |
| catch( const UnknownPropertyException& ) { throw; } |
| catch( const RuntimeException& ) { throw; } |
| catch( const Exception& ) |
| { |
| OSL_ENSURE( sal_False, "OPropertySetAggregationHelper::setPropertyToDefault: caught an exception which is not allowed to leave here!" ); |
| } |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getPropertyDefault(const ::rtl::OUString& aPropertyName) |
| throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) |
| { |
| OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() ); |
| sal_Int32 nHandle = rPH.getHandleByName( aPropertyName ); |
| |
| if ( nHandle == -1 ) |
| throw ::com::sun::star::beans::UnknownPropertyException(); |
| |
| ::rtl::OUString aPropName; |
| sal_Int32 nOriginalHandle = -1; |
| if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle)) |
| { |
| if (m_xAggregateState.is()) |
| return m_xAggregateState->getPropertyDefault(aPropertyName); |
| else |
| return ::com::sun::star::uno::Any(); |
| } |
| else |
| return getPropertyDefaultByHandle(nHandle); |
| } |
| |
| //------------------------------------------------------------------------------ |
| sal_Bool SAL_CALL OPropertySetAggregationHelper::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException) |
| { |
| sal_Bool bModified = sal_False; |
| |
| 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 ) ); |
| |
| Any aCurrentValue; |
| getFastPropertyValue( aCurrentValue, _nHandle ); |
| bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, aCurrentValue, aProperty.Type ); |
| } |
| |
| return bModified; |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception ) |
| { |
| 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 ); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void OPropertySetAggregationHelper::declareForwardedProperty( sal_Int32 _nHandle ) |
| { |
| OSL_ENSURE( !m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::declareForwardedProperty: already declared!" ); |
| m_pForwarder->takeResponsibilityFor( _nHandle ); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL OPropertySetAggregationHelper::forwardingPropertyValue( sal_Int32 ) |
| { |
| // not interested in |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL OPropertySetAggregationHelper::forwardedPropertyValue( sal_Int32, bool ) |
| { |
| // not interested in |
| } |
| |
| //------------------------------------------------------------------------------ |
| bool OPropertySetAggregationHelper::isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const |
| { |
| return m_pForwarder->getCurrentlyForwardedProperty() == _nHandle; |
| } |
| |
| //......................................................................... |
| } // namespace comphelper |
| //......................................................................... |
| |