diff options
Diffstat (limited to 'comphelper/source/property')
20 files changed, 6419 insertions, 0 deletions
diff --git a/comphelper/source/property/ChainablePropertySet.cxx b/comphelper/source/property/ChainablePropertySet.cxx new file mode 100644 index 000000000000..936510f21309 --- /dev/null +++ b/comphelper/source/property/ChainablePropertySet.cxx @@ -0,0 +1,321 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" +#include <comphelper/ChainablePropertySet.hxx> +#include <comphelper/ChainablePropertySetInfo.hxx> +#include <vos/mutex.hxx> + +#include <memory> // STL auto_ptr + + +using namespace ::rtl; +using namespace ::comphelper; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using ::vos::IMutex; + +ChainablePropertySet::ChainablePropertySet( comphelper::ChainablePropertySetInfo* pInfo, vos::IMutex *pMutex ) + throw() +: mpInfo ( pInfo ) +, mpMutex ( pMutex ) +, mxInfo ( pInfo ) +{ +} + +ChainablePropertySet::~ChainablePropertySet() + throw() +{ +} + +// XPropertySet +Reference< XPropertySetInfo > SAL_CALL ChainablePropertySet::getPropertySetInfo( ) + throw(RuntimeException) +{ + return mxInfo; +} + +void ChainablePropertySet::lockMutex() +{ + if (mpMutex) + mpMutex->acquire(); +} + +void ChainablePropertySet::unlockMutex() +{ + if (mpMutex) + mpMutex->release(); +} + +void SAL_CALL ChainablePropertySet::setPropertyValue( const ::rtl::OUString& rPropertyName, const Any& rValue ) + throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + // acquire mutex in c-tor and releases it in the d-tor (exception safe!). + std::auto_ptr< vos::OGuard > pMutexGuard; + if (mpMutex) + pMutexGuard.reset( new vos::OGuard(mpMutex) ); + + PropertyInfoHash::const_iterator aIter = mpInfo->maMap.find ( rPropertyName ); + + if( aIter == mpInfo->maMap.end()) + throw UnknownPropertyException( rPropertyName, static_cast< XPropertySet* >( this ) ); + + _preSetValues(); + _setSingleValue( *((*aIter).second), rValue ); + _postSetValues(); +} + +Any SAL_CALL ChainablePropertySet::getPropertyValue( const ::rtl::OUString& rPropertyName ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // acquire mutex in c-tor and releases it in the d-tor (exception safe!). + std::auto_ptr< vos::OGuard > pMutexGuard; + if (mpMutex) + pMutexGuard.reset( new vos::OGuard(mpMutex) ); + + PropertyInfoHash::const_iterator aIter = mpInfo->maMap.find ( rPropertyName ); + + if( aIter == mpInfo->maMap.end()) + throw UnknownPropertyException( rPropertyName, static_cast< XPropertySet* >( this ) ); + + Any aAny; + _preGetValues (); + _getSingleValue( *((*aIter).second), aAny ); + _postGetValues (); + + return aAny; +} + +void SAL_CALL ChainablePropertySet::addPropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +void SAL_CALL ChainablePropertySet::removePropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +void SAL_CALL ChainablePropertySet::addVetoableChangeListener( const ::rtl::OUString&, const Reference< XVetoableChangeListener >& ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +void SAL_CALL ChainablePropertySet::removeVetoableChangeListener( const ::rtl::OUString&, const Reference< XVetoableChangeListener >& ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +// XMultiPropertySet +void SAL_CALL ChainablePropertySet::setPropertyValues( const Sequence< ::rtl::OUString >& aPropertyNames, const Sequence< Any >& aValues ) + throw(PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + // acquire mutex in c-tor and releases it in the d-tor (exception safe!). + std::auto_ptr< vos::OGuard > pMutexGuard; + if (mpMutex) + pMutexGuard.reset( new vos::OGuard(mpMutex) ); + + const sal_Int32 nCount = aPropertyNames.getLength(); + + if( nCount != aValues.getLength() ) + throw IllegalArgumentException(); + + if( nCount ) + { + _preSetValues(); + + const Any * pAny = aValues.getConstArray(); + const OUString * pString = aPropertyNames.getConstArray(); + PropertyInfoHash::const_iterator aEnd = mpInfo->maMap.end(), aIter; + + for ( sal_Int32 i = 0; i < nCount; ++i, ++pString, ++pAny ) + { + aIter = mpInfo->maMap.find ( *pString ); + if ( aIter == aEnd ) + throw UnknownPropertyException( *pString, static_cast< XPropertySet* >( this ) ); + + _setSingleValue ( *((*aIter).second), *pAny ); + } + + _postSetValues(); + } +} + +Sequence< Any > SAL_CALL ChainablePropertySet::getPropertyValues( const Sequence< ::rtl::OUString >& aPropertyNames ) + throw(RuntimeException) +{ + // acquire mutex in c-tor and releases it in the d-tor (exception safe!). + std::auto_ptr< vos::OGuard > pMutexGuard; + if (mpMutex) + pMutexGuard.reset( new vos::OGuard(mpMutex) ); + + const sal_Int32 nCount = aPropertyNames.getLength(); + + Sequence < Any > aValues ( nCount ); + + if( nCount ) + { + _preGetValues(); + + Any * pAny = aValues.getArray(); + const OUString * pString = aPropertyNames.getConstArray(); + PropertyInfoHash::const_iterator aEnd = mpInfo->maMap.end(), aIter; + + for ( sal_Int32 i = 0; i < nCount; ++i, ++pString, ++pAny ) + { + aIter = mpInfo->maMap.find ( *pString ); + if ( aIter == aEnd ) + throw UnknownPropertyException( *pString, static_cast< XPropertySet* >( this ) ); + + _getSingleValue ( *((*aIter).second), *pAny ); + } + + _postGetValues(); + } + return aValues; +} + +void SAL_CALL ChainablePropertySet::addPropertiesChangeListener( const Sequence< ::rtl::OUString >&, const Reference< XPropertiesChangeListener >& ) + throw(RuntimeException) +{ + // todo +} + +void SAL_CALL ChainablePropertySet::removePropertiesChangeListener( const Reference< XPropertiesChangeListener >& ) + throw(RuntimeException) +{ + // todo +} + +void SAL_CALL ChainablePropertySet::firePropertiesChangeEvent( const Sequence< ::rtl::OUString >&, const Reference< XPropertiesChangeListener >& ) + throw(RuntimeException) +{ + // todo +} + +// XPropertyState +PropertyState SAL_CALL ChainablePropertySet::getPropertyState( const ::rtl::OUString& PropertyName ) + throw(UnknownPropertyException, RuntimeException) +{ + PropertyInfoHash::const_iterator aIter = mpInfo->maMap.find( PropertyName ); + if( aIter == mpInfo->maMap.end()) + throw UnknownPropertyException( PropertyName, static_cast< XPropertySet* >( this ) ); + + PropertyState aState; + + _preGetPropertyState(); + _getPropertyState( *((*aIter).second), aState ); + _postGetPropertyState(); + + return aState; +} + +Sequence< PropertyState > SAL_CALL ChainablePropertySet::getPropertyStates( const Sequence< ::rtl::OUString >& rPropertyNames ) + throw(UnknownPropertyException, RuntimeException) +{ + const sal_Int32 nCount = rPropertyNames.getLength(); + + Sequence< PropertyState > aStates( nCount ); + if( nCount ) + { + PropertyState * pState = aStates.getArray(); + const OUString * pString = rPropertyNames.getConstArray(); + PropertyInfoHash::const_iterator aEnd = mpInfo->maMap.end(), aIter; + _preGetPropertyState(); + + for ( sal_Int32 i = 0; i < nCount; ++i, ++pString, ++pState ) + { + aIter = mpInfo->maMap.find ( *pString ); + if ( aIter == aEnd ) + throw UnknownPropertyException( *pString, static_cast< XPropertySet* >( this ) ); + + _getPropertyState ( *((*aIter).second), *pState ); + } + _postGetPropertyState(); + } + return aStates; +} + +void SAL_CALL ChainablePropertySet::setPropertyToDefault( const ::rtl::OUString& rPropertyName ) + throw(UnknownPropertyException, RuntimeException) +{ + PropertyInfoHash::const_iterator aIter = mpInfo->maMap.find ( rPropertyName ); + + if( aIter == mpInfo->maMap.end()) + throw UnknownPropertyException( rPropertyName, static_cast< XPropertySet* >( this ) ); + _setPropertyToDefault( *((*aIter).second) ); +} + +Any SAL_CALL ChainablePropertySet::getPropertyDefault( const ::rtl::OUString& rPropertyName ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + PropertyInfoHash::const_iterator aIter = mpInfo->maMap.find ( rPropertyName ); + + if( aIter == mpInfo->maMap.end()) + throw UnknownPropertyException( rPropertyName, static_cast< XPropertySet* >( this ) ); + return _getPropertyDefault( *((*aIter).second) ); +} + +void ChainablePropertySet::_preGetPropertyState () + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException ) +{ + OSL_ENSURE( sal_False, "you have to implement this yourself!"); +} + +void ChainablePropertySet::_getPropertyState( const comphelper::PropertyInfo&, PropertyState& ) + throw(UnknownPropertyException ) +{ + OSL_ENSURE( sal_False, "you have to implement this yourself!"); +} + +void ChainablePropertySet::_postGetPropertyState () + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException ) +{ + OSL_ENSURE( sal_False, "you have to implement this yourself!"); +} + +void ChainablePropertySet::_setPropertyToDefault( const comphelper::PropertyInfo& ) + throw(UnknownPropertyException ) +{ + OSL_ENSURE( sal_False, "you have to implement this yourself!"); +} + +Any ChainablePropertySet::_getPropertyDefault( const comphelper::PropertyInfo& ) + throw(UnknownPropertyException, WrappedTargetException ) +{ + OSL_ENSURE( sal_False, "you have to implement this yourself!"); + + Any aAny; + return aAny; +} diff --git a/comphelper/source/property/ChainablePropertySetInfo.cxx b/comphelper/source/property/ChainablePropertySetInfo.cxx new file mode 100644 index 000000000000..6660517ef97e --- /dev/null +++ b/comphelper/source/property/ChainablePropertySetInfo.cxx @@ -0,0 +1,142 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" +#include <comphelper/ChainablePropertySetInfo.hxx> +#include <comphelper/TypeGeneration.hxx> + +using ::rtl::OUString; +using ::comphelper::PropertyInfo; +using ::comphelper::GenerateCppuType; +using ::comphelper::ChainablePropertySetInfo; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Type; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::beans::Property; +using ::com::sun::star::beans::XPropertySetInfo; +using ::com::sun::star::beans::UnknownPropertyException; + +ChainablePropertySetInfo::ChainablePropertySetInfo() + throw() +{ +} + +ChainablePropertySetInfo::ChainablePropertySetInfo( PropertyInfo* pMap ) + throw() +{ + add ( pMap ); +} + +ChainablePropertySetInfo::~ChainablePropertySetInfo() + throw() +{ +} + +void ChainablePropertySetInfo::add( PropertyInfo* pMap, sal_Int32 nCount ) + throw() +{ + // nCount < 0 => add all + // nCount == 0 => add nothing + // nCount > 0 => add at most nCount entries + if( maProperties.getLength() ) + maProperties.realloc( 0 ); + + while( pMap->mpName && ( ( nCount < 0) || ( nCount-- > 0 ) ) ) + { + OUString aName( pMap->mpName, pMap->mnNameLen, RTL_TEXTENCODING_ASCII_US ); + +#ifdef DBG_UTIL + PropertyInfoHash::iterator aIter = maMap.find( aName ); + if( aIter != maMap.end() ) + OSL_ENSURE( sal_False, "Warning: PropertyInfo added twice, possible error!"); +#endif + maMap[aName] = pMap++; + } +} + +void ChainablePropertySetInfo::remove( const rtl::OUString& aName ) + throw() +{ + maMap.erase ( aName ); + if ( maProperties.getLength() ) + maProperties.realloc( 0 ); +} + +Sequence< ::Property > SAL_CALL ChainablePropertySetInfo::getProperties() + throw(::com::sun::star::uno::RuntimeException) +{ + sal_Int32 nSize = maMap.size(); + if( maProperties.getLength() != nSize ) + { + maProperties.realloc ( nSize ); + Property* pProperties = maProperties.getArray(); + + PropertyInfoHash::iterator aIter = maMap.begin(); + const PropertyInfoHash::iterator aEnd = maMap.end(); + for ( ; aIter != aEnd; ++aIter, ++pProperties) + { + PropertyInfo* pInfo = (*aIter).second; + + pProperties->Name = OUString( pInfo->mpName, pInfo->mnNameLen, RTL_TEXTENCODING_ASCII_US ); + pProperties->Handle = pInfo->mnHandle; + const Type* pType; + GenerateCppuType ( pInfo->meCppuType, pType); + pProperties->Type = *pType; + pProperties->Attributes = pInfo->mnAttributes; + } + } + return maProperties; +} + +Property SAL_CALL ChainablePropertySetInfo::getPropertyByName( const ::rtl::OUString& rName ) + throw(::UnknownPropertyException, ::com::sun::star::uno::RuntimeException) +{ + PropertyInfoHash::iterator aIter = maMap.find( rName ); + + if ( maMap.end() == aIter ) + throw UnknownPropertyException( rName, *this ); + + PropertyInfo *pInfo = (*aIter).second; + Property aProperty; + aProperty.Name = OUString( pInfo->mpName, pInfo->mnNameLen, RTL_TEXTENCODING_ASCII_US ); + aProperty.Handle = pInfo->mnHandle; + const Type* pType = &aProperty.Type; + GenerateCppuType ( pInfo->meCppuType, pType ); + aProperty.Type = *pType; + aProperty.Attributes = pInfo->mnAttributes; + return aProperty; +} + +sal_Bool SAL_CALL ChainablePropertySetInfo::hasPropertyByName( const ::rtl::OUString& rName ) + throw(::com::sun::star::uno::RuntimeException) +{ + return static_cast < sal_Bool > ( maMap.find ( rName ) != maMap.end() ); +} diff --git a/comphelper/source/property/MasterPropertySet.cxx b/comphelper/source/property/MasterPropertySet.cxx new file mode 100644 index 000000000000..28078a8019fc --- /dev/null +++ b/comphelper/source/property/MasterPropertySet.cxx @@ -0,0 +1,505 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" + +#ifndef _COMPHELPER_MASTERPROPERTYSET_HXX_ +#include <comphelper/MasterPropertySet.hxx> +#endif +#include <comphelper/MasterPropertySetInfo.hxx> +#include <comphelper/ChainablePropertySet.hxx> +#include <comphelper/ChainablePropertySetInfo.hxx> +#include <vos/mutex.hxx> + +#include <memory> // STL auto_ptr + +////////////////////////////////////////////////////////////////////// + +class AutoOGuardArray +{ + sal_Int32 nSize; + std::auto_ptr< vos::OGuard > * pGuardArray; + +public: + AutoOGuardArray( sal_Int32 nNumElements ); + ~AutoOGuardArray(); + + std::auto_ptr< vos::OGuard > & operator[] ( sal_Int32 i ) { return pGuardArray[i]; } +}; + +AutoOGuardArray::AutoOGuardArray( sal_Int32 nNumElements ) +{ + nSize = nNumElements; + pGuardArray = new std::auto_ptr< vos::OGuard >[ nSize ]; +} + +AutoOGuardArray::~AutoOGuardArray() +{ + //!! release auto_ptr's and thus the mutexes locks + delete [] pGuardArray; + +} + +////////////////////////////////////////////////////////////////////// + +using namespace ::rtl; +using namespace ::comphelper; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using vos::IMutex; + +SlaveData::SlaveData ( ChainablePropertySet *pSlave) +: mpSlave ( pSlave ) +, mxSlave ( pSlave ) +, mbInit ( sal_False ) +{ +} + +MasterPropertySet::MasterPropertySet( comphelper::MasterPropertySetInfo* pInfo, IMutex *pMutex ) + throw() +: mpInfo ( pInfo ) +, mpMutex ( pMutex ) +, mnLastId ( 0 ) +, mxInfo ( pInfo ) +{ +} + +void MasterPropertySet::lockMutex() +{ + if (mpMutex) + mpMutex->acquire(); +} +void MasterPropertySet::unlockMutex() +{ + if (mpMutex) + mpMutex->release(); +} + +MasterPropertySet::~MasterPropertySet() + throw() +{ + SlaveMap::iterator aEnd = maSlaveMap.end(), aIter = maSlaveMap.begin(); + while (aIter != aEnd ) + { + delete (*aIter).second; + aIter++; + } +} + +// XPropertySet +Reference< XPropertySetInfo > SAL_CALL MasterPropertySet::getPropertySetInfo( ) + throw(RuntimeException) +{ + return mxInfo; +} + +void MasterPropertySet::registerSlave ( ChainablePropertySet *pNewSet ) + throw() +{ + maSlaveMap [ ++mnLastId ] = new SlaveData ( pNewSet ); + mpInfo->add ( pNewSet->mpInfo->maMap, mnLastId ); +} + +void SAL_CALL MasterPropertySet::setPropertyValue( const ::rtl::OUString& rPropertyName, const Any& rValue ) + throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + // acquire mutex in c-tor and releases it in the d-tor (exception safe!). + std::auto_ptr< vos::OGuard > pMutexGuard; + if (mpMutex) + pMutexGuard.reset( new vos::OGuard(mpMutex) ); + + PropertyDataHash::const_iterator aIter = mpInfo->maMap.find ( rPropertyName ); + + if( aIter == mpInfo->maMap.end()) + throw UnknownPropertyException( rPropertyName, static_cast< XPropertySet* >( this ) ); + + if ( (*aIter).second->mnMapId == 0 ) // 0 means it's one of ours ! + { + _preSetValues(); + _setSingleValue( *((*aIter).second->mpInfo), rValue ); + _postSetValues(); + } + else + { + ChainablePropertySet * pSlave = maSlaveMap [ (*aIter).second->mnMapId ]->mpSlave; + + // acquire mutex in c-tor and releases it in the d-tor (exception safe!). + std::auto_ptr< vos::OGuard > pMutexGuard2; + if (pSlave->mpMutex) + pMutexGuard2.reset( new vos::OGuard(pSlave->mpMutex) ); + + pSlave->_preSetValues(); + pSlave->_setSingleValue( *((*aIter).second->mpInfo), rValue ); + pSlave->_postSetValues(); + } +} + +Any SAL_CALL MasterPropertySet::getPropertyValue( const ::rtl::OUString& rPropertyName ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // acquire mutex in c-tor and releases it in the d-tor (exception safe!). + std::auto_ptr< vos::OGuard > pMutexGuard; + if (mpMutex) + pMutexGuard.reset( new vos::OGuard(mpMutex) ); + + PropertyDataHash::const_iterator aIter = mpInfo->maMap.find ( rPropertyName ); + + if( aIter == mpInfo->maMap.end()) + throw UnknownPropertyException( rPropertyName, static_cast< XPropertySet* >( this ) ); + + Any aAny; + if ( (*aIter).second->mnMapId == 0 ) // 0 means it's one of ours ! + { + _preGetValues(); + _getSingleValue( *((*aIter).second->mpInfo), aAny ); + _postGetValues(); + } + else + { + ChainablePropertySet * pSlave = maSlaveMap [ (*aIter).second->mnMapId ]->mpSlave; + + // acquire mutex in c-tor and releases it in the d-tor (exception safe!). + std::auto_ptr< vos::OGuard > pMutexGuard2; + if (pSlave->mpMutex) + pMutexGuard2.reset( new vos::OGuard(pSlave->mpMutex) ); + + pSlave->_preGetValues(); + pSlave->_getSingleValue( *((*aIter).second->mpInfo), aAny ); + pSlave->_postGetValues(); + } + return aAny; +} + +void SAL_CALL MasterPropertySet::addPropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +void SAL_CALL MasterPropertySet::removePropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +void SAL_CALL MasterPropertySet::addVetoableChangeListener( const ::rtl::OUString&, const Reference< XVetoableChangeListener >& ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +void SAL_CALL MasterPropertySet::removeVetoableChangeListener( const ::rtl::OUString&, const Reference< XVetoableChangeListener >& ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +// XMultiPropertySet +void SAL_CALL MasterPropertySet::setPropertyValues( const Sequence< ::rtl::OUString >& aPropertyNames, const Sequence< Any >& aValues ) + throw(PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + // acquire mutex in c-tor and releases it in the d-tor (exception safe!). + std::auto_ptr< vos::OGuard > pMutexGuard; + if (mpMutex) + pMutexGuard.reset( new vos::OGuard(mpMutex) ); + + const sal_Int32 nCount = aPropertyNames.getLength(); + + if( nCount != aValues.getLength() ) + throw IllegalArgumentException(); + + if( nCount ) + { + _preSetValues(); + + const Any * pAny = aValues.getConstArray(); + const OUString * pString = aPropertyNames.getConstArray(); + PropertyDataHash::const_iterator aEnd = mpInfo->maMap.end(), aIter; + + //!! have an auto_ptr to an array of OGuards in order to have the + //!! allocated memory properly freed (exception safe!). + //!! Since the array itself has auto_ptrs as members we have to use a + //!! helper class 'AutoOGuardArray' in order to have + //!! the acquired locks properly released. + AutoOGuardArray aOGuardArray( nCount ); + + for ( sal_Int32 i = 0; i < nCount; ++i, ++pString, ++pAny ) + { + aIter = mpInfo->maMap.find ( *pString ); + if ( aIter == aEnd ) + throw UnknownPropertyException( *pString, static_cast< XPropertySet* >( this ) ); + + if ( (*aIter).second->mnMapId == 0 ) // 0 means it's one of ours ! + _setSingleValue( *((*aIter).second->mpInfo), *pAny ); + else + { + SlaveData * pSlave = maSlaveMap [ (*aIter).second->mnMapId ]; + if (!pSlave->IsInit()) + { + // acquire mutex in c-tor and releases it in the d-tor (exception safe!). + if (pSlave->mpSlave->mpMutex) + aOGuardArray[i].reset( new vos::OGuard(pSlave->mpSlave->mpMutex) ); + + pSlave->mpSlave->_preSetValues(); + pSlave->SetInit ( sal_True ); + } + pSlave->mpSlave->_setSingleValue( *((*aIter).second->mpInfo), *pAny ); + } + } + + _postSetValues(); + SlaveMap::const_iterator aSlaveIter = maSlaveMap.begin(), aSlaveEnd = maSlaveMap.end(); + while (aSlaveIter != aSlaveEnd) + { + if ( (*aSlaveIter).second->IsInit()) + { + (*aSlaveIter).second->mpSlave->_postSetValues(); + (*aSlaveIter).second->SetInit ( sal_False ); + } + ++aSlaveIter; + } + } +} + +Sequence< Any > SAL_CALL MasterPropertySet::getPropertyValues( const Sequence< ::rtl::OUString >& aPropertyNames ) + throw(RuntimeException) +{ + // acquire mutex in c-tor and releases it in the d-tor (exception safe!). + std::auto_ptr< vos::OGuard > pMutexGuard; + if (mpMutex) + pMutexGuard.reset( new vos::OGuard(mpMutex) ); + + const sal_Int32 nCount = aPropertyNames.getLength(); + + Sequence < Any > aValues ( nCount ); + + if( nCount ) + { + _preGetValues(); + + Any * pAny = aValues.getArray(); + const OUString * pString = aPropertyNames.getConstArray(); + PropertyDataHash::const_iterator aEnd = mpInfo->maMap.end(), aIter; + + //!! have an auto_ptr to an array of OGuards in order to have the + //!! allocated memory properly freed (exception safe!). + //!! Since the array itself has auto_ptrs as members we have to use a + //!! helper class 'AutoOGuardArray' in order to have + //!! the acquired locks properly released. + AutoOGuardArray aOGuardArray( nCount ); + + for ( sal_Int32 i = 0; i < nCount; ++i, ++pString, ++pAny ) + { + aIter = mpInfo->maMap.find ( *pString ); + if ( aIter == aEnd ) + throw UnknownPropertyException( *pString, static_cast< XPropertySet* >( this ) ); + + if ( (*aIter).second->mnMapId == 0 ) // 0 means it's one of ours ! + _getSingleValue( *((*aIter).second->mpInfo), *pAny ); + else + { + SlaveData * pSlave = maSlaveMap [ (*aIter).second->mnMapId ]; + if (!pSlave->IsInit()) + { + // acquire mutex in c-tor and releases it in the d-tor (exception safe!). + if (pSlave->mpSlave->mpMutex) + aOGuardArray[i].reset( new vos::OGuard(pSlave->mpSlave->mpMutex) ); + + pSlave->mpSlave->_preGetValues(); + pSlave->SetInit ( sal_True ); + } + pSlave->mpSlave->_getSingleValue( *((*aIter).second->mpInfo), *pAny ); + } + } + + _postSetValues(); + SlaveMap::const_iterator aSlaveIter = maSlaveMap.begin(), aSlaveEnd = maSlaveMap.end(); + while (aSlaveIter != aSlaveEnd) + { + if ( (*aSlaveIter).second->IsInit()) + { + (*aSlaveIter).second->mpSlave->_postSetValues(); + (*aSlaveIter).second->SetInit ( sal_False ); + } + ++aSlaveIter; + } + } + return aValues; +} + +void SAL_CALL MasterPropertySet::addPropertiesChangeListener( const Sequence< ::rtl::OUString >&, const Reference< XPropertiesChangeListener >& ) + throw(RuntimeException) +{ + // todo +} + +void SAL_CALL MasterPropertySet::removePropertiesChangeListener( const Reference< XPropertiesChangeListener >& ) + throw(RuntimeException) +{ + // todo +} + +void SAL_CALL MasterPropertySet::firePropertiesChangeEvent( const Sequence< ::rtl::OUString >&, const Reference< XPropertiesChangeListener >& ) + throw(RuntimeException) +{ + // todo +} + +// XPropertyState +PropertyState SAL_CALL MasterPropertySet::getPropertyState( const ::rtl::OUString& PropertyName ) + throw(UnknownPropertyException, RuntimeException) +{ + PropertyDataHash::const_iterator aIter = mpInfo->maMap.find( PropertyName ); + if( aIter == mpInfo->maMap.end()) + throw UnknownPropertyException( PropertyName, static_cast< XPropertySet* >( this ) ); + + PropertyState aState; + + if ( (*aIter).second->mnMapId == 0 ) // 0 means it's one of ours ! + { + _preGetPropertyState(); + _getPropertyState( *((*aIter).second->mpInfo), aState ); + _postGetPropertyState(); + } + else + { + ChainablePropertySet * pSlave = maSlaveMap [ (*aIter).second->mnMapId ]->mpSlave; + + // acquire mutex in c-tor and releases it in the d-tor (exception safe!). + std::auto_ptr< vos::OGuard > pMutexGuard; + if (pSlave->mpMutex) + pMutexGuard.reset( new vos::OGuard(pSlave->mpMutex) ); + + pSlave->_preGetPropertyState(); + pSlave->_getPropertyState( *((*aIter).second->mpInfo), aState ); + pSlave->_postGetPropertyState(); + } + + return aState; +} + +Sequence< PropertyState > SAL_CALL MasterPropertySet::getPropertyStates( const Sequence< ::rtl::OUString >& rPropertyNames ) + throw(UnknownPropertyException, RuntimeException) +{ + const sal_Int32 nCount = rPropertyNames.getLength(); + + Sequence< PropertyState > aStates( nCount ); + if( nCount ) + { + PropertyState * pState = aStates.getArray(); + const OUString * pString = rPropertyNames.getConstArray(); + PropertyDataHash::const_iterator aEnd = mpInfo->maMap.end(), aIter; + _preGetPropertyState(); + + for ( sal_Int32 i = 0; i < nCount; ++i, ++pString, ++pState ) + { + aIter = mpInfo->maMap.find ( *pString ); + if ( aIter == aEnd ) + throw UnknownPropertyException( *pString, static_cast< XPropertySet* >( this ) ); + + if ( (*aIter).second->mnMapId == 0 ) // 0 means it's one of ours ! + _getPropertyState( *((*aIter).second->mpInfo), *pState ); + else + { + SlaveData * pSlave = maSlaveMap [ (*aIter).second->mnMapId ]; + if (!pSlave->IsInit()) + { + pSlave->mpSlave->_preGetPropertyState(); + pSlave->SetInit ( sal_True ); + } + pSlave->mpSlave->_getPropertyState( *((*aIter).second->mpInfo), *pState ); + } + } + _postGetPropertyState(); + SlaveMap::const_iterator aSlaveIter = maSlaveMap.begin(), aSlaveEnd = maSlaveMap.end(); + while (aSlaveIter != aSlaveEnd) + { + if ( (*aSlaveIter).second->IsInit()) + { + (*aSlaveIter).second->mpSlave->_postGetPropertyState(); + (*aSlaveIter).second->SetInit ( sal_False ); + } + ++aSlaveIter; + } + } + return aStates; +} + +void SAL_CALL MasterPropertySet::setPropertyToDefault( const ::rtl::OUString& rPropertyName ) + throw(UnknownPropertyException, RuntimeException) +{ + PropertyDataHash::const_iterator aIter = mpInfo->maMap.find ( rPropertyName ); + + if( aIter == mpInfo->maMap.end()) + throw UnknownPropertyException( rPropertyName, static_cast< XPropertySet* >( this ) ); + _setPropertyToDefault( *((*aIter).second->mpInfo) ); +} + +Any SAL_CALL MasterPropertySet::getPropertyDefault( const ::rtl::OUString& rPropertyName ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + PropertyDataHash::const_iterator aIter = mpInfo->maMap.find ( rPropertyName ); + + if( aIter == mpInfo->maMap.end()) + throw UnknownPropertyException( rPropertyName, static_cast< XPropertySet* >( this ) ); + return _getPropertyDefault( *((*aIter).second->mpInfo) ); +} + +void MasterPropertySet::_preGetPropertyState () + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException ) +{ + OSL_ENSURE( sal_False, "you have to implement this yourself!"); +} + +void MasterPropertySet::_getPropertyState( const comphelper::PropertyInfo&, PropertyState& ) + throw(UnknownPropertyException ) +{ + OSL_ENSURE( sal_False, "you have to implement this yourself!"); +} + +void MasterPropertySet::_postGetPropertyState () + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException ) +{ + OSL_ENSURE( sal_False, "you have to implement this yourself!"); +} + +void MasterPropertySet::_setPropertyToDefault( const comphelper::PropertyInfo& ) + throw(UnknownPropertyException ) +{ + OSL_ENSURE( sal_False, "you have to implement this yourself!"); +} + +Any MasterPropertySet::_getPropertyDefault( const comphelper::PropertyInfo& ) + throw(UnknownPropertyException, WrappedTargetException ) +{ + OSL_ENSURE( sal_False, "you have to implement this yourself!"); + Any aAny; + return aAny; +} diff --git a/comphelper/source/property/MasterPropertySetInfo.cxx b/comphelper/source/property/MasterPropertySetInfo.cxx new file mode 100644 index 000000000000..57cf22b77508 --- /dev/null +++ b/comphelper/source/property/MasterPropertySetInfo.cxx @@ -0,0 +1,170 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" +#ifndef _COMPHELPER_CHAINABLEPROPERTYSETINFO_HXX_ +#include <comphelper/MasterPropertySetInfo.hxx> +#endif +#include <comphelper/TypeGeneration.hxx> + +using ::rtl::OUString; +using ::comphelper::PropertyInfo; +using ::comphelper::GenerateCppuType; +using ::comphelper::MasterPropertySetInfo; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Type; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::beans::Property; +using ::com::sun::star::beans::XPropertySetInfo; +using ::com::sun::star::beans::UnknownPropertyException; + +MasterPropertySetInfo::MasterPropertySetInfo() + throw() +{ +} + +MasterPropertySetInfo::MasterPropertySetInfo( PropertyInfo* pMap ) + throw() +{ + add ( pMap ); +} + +MasterPropertySetInfo::~MasterPropertySetInfo() + throw() +{ + PropertyDataHash::iterator aEnd = maMap.end(), aIter = maMap.begin(); + while (aIter != aEnd ) + { + delete (*aIter).second; + aIter++; + } +} + +void MasterPropertySetInfo::add( PropertyInfo* pMap, sal_Int32 nCount, sal_uInt8 nMapId ) + throw() +{ + // nCount < 0 => add all + // nCount == 0 => add nothing + // nCount > 0 => add at most nCount entries + if( maProperties.getLength() ) + maProperties.realloc( 0 ); + + for ( ; pMap->mpName && ( ( nCount < 0 ) || ( nCount > 0 ) ); --nCount, ++pMap ) + { + OUString aName( pMap->mpName, pMap->mnNameLen, RTL_TEXTENCODING_ASCII_US ); + +#ifdef DBG_UTIL + PropertyDataHash::iterator aIter = maMap.find( aName ); + if( aIter != maMap.end() ) + OSL_ENSURE( sal_False, "Warning: PropertyInfo added twice, possible error!"); +#endif + maMap[aName] = new PropertyData ( nMapId, pMap ); + } +} + +void MasterPropertySetInfo::add( PropertyInfoHash &rHash, sal_uInt8 nMapId ) + throw() +{ + if( maProperties.getLength() ) + maProperties.realloc( 0 ); + PropertyInfoHash::iterator aIter = rHash.begin(), aEnd = rHash.end(); + + while ( aIter != aEnd ) + { +#ifdef DBG_UTIL + PropertyDataHash::iterator aDebugIter = maMap.find( (*aIter).first ); + if( aDebugIter != maMap.end() ) + OSL_ENSURE( sal_False, "Warning: PropertyInfo added twice, possible error!"); +#endif + maMap[(*aIter).first] = new PropertyData ( nMapId, (*aIter).second ); + aIter++; + } +} + +void MasterPropertySetInfo::remove( const rtl::OUString& aName ) + throw() +{ + maMap.erase ( aName ); + if ( maProperties.getLength() ) + maProperties.realloc( 0 ); +} + +Sequence< ::Property > SAL_CALL MasterPropertySetInfo::getProperties() + throw(::com::sun::star::uno::RuntimeException) +{ + sal_Int32 nSize = maMap.size(); + if( maProperties.getLength() != nSize ) + { + maProperties.realloc ( nSize ); + Property* pProperties = maProperties.getArray(); + + PropertyDataHash::iterator aIter = maMap.begin(); + const PropertyDataHash::iterator aEnd = maMap.end(); + for ( ; aIter != aEnd; ++aIter, ++pProperties) + { + PropertyInfo* pInfo = (*aIter).second->mpInfo; + + pProperties->Name = OUString( pInfo->mpName, pInfo->mnNameLen, RTL_TEXTENCODING_ASCII_US ); + pProperties->Handle = pInfo->mnHandle; + const Type* pType; + GenerateCppuType ( pInfo->meCppuType, pType); + pProperties->Type = *pType; + pProperties->Attributes = pInfo->mnAttributes; + } + } + return maProperties; +} + +Property SAL_CALL MasterPropertySetInfo::getPropertyByName( const ::rtl::OUString& rName ) + throw(::UnknownPropertyException, ::com::sun::star::uno::RuntimeException) +{ + PropertyDataHash::iterator aIter = maMap.find( rName ); + + if ( maMap.end() == aIter ) + throw UnknownPropertyException( rName, *this ); + + PropertyInfo *pInfo = (*aIter).second->mpInfo; + Property aProperty; + aProperty.Name = OUString( pInfo->mpName, pInfo->mnNameLen, RTL_TEXTENCODING_ASCII_US ); + aProperty.Handle = pInfo->mnHandle; + const Type* pType; + GenerateCppuType ( pInfo->meCppuType, pType ); + aProperty.Type = *pType; + + aProperty.Attributes = pInfo->mnAttributes; + return aProperty; +} + +sal_Bool SAL_CALL MasterPropertySetInfo::hasPropertyByName( const ::rtl::OUString& rName ) + throw(::com::sun::star::uno::RuntimeException) +{ + return static_cast < sal_Bool > ( maMap.find ( rName ) != maMap.end() ); +} diff --git a/comphelper/source/property/TypeGeneration.cxx b/comphelper/source/property/TypeGeneration.cxx new file mode 100644 index 000000000000..bf880330ce75 --- /dev/null +++ b/comphelper/source/property/TypeGeneration.cxx @@ -0,0 +1,237 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" +#ifndef _COMPHELPER_TYPEGENERATION_HXX +#include <comphelper/TypeGeneration.hxx> +#endif +#include <com/sun/star/script/XLibraryContainer.hpp> +#include <com/sun/star/style/LineSpacingMode.hpp> +#include <com/sun/star/style/ParagraphAdjust.hpp> +#include <com/sun/star/style/DropCapFormat.hpp> +#include <com/sun/star/style/LineSpacing.hpp> +#include <com/sun/star/style/TabStop.hpp> +#include <com/sun/star/style/TabAlign.hpp> +#include <com/sun/star/style/PageStyleLayout.hpp> +#include <com/sun/star/style/BreakType.hpp> +#include <com/sun/star/text/XModule.hpp> +#include <com/sun/star/text/XTextRangeMover.hpp> +#include <com/sun/star/text/XFootnotesSettingsSupplier.hpp> +#include <com/sun/star/text/XFootnote.hpp> +#include <com/sun/star/text/XFootnotesSupplier.hpp> +#include <com/sun/star/text/XEndnotesSupplier.hpp> +#include <com/sun/star/text/XEndnotesSettingsSupplier.hpp> +#include <com/sun/star/text/FootnoteNumbering.hpp> +#include <com/sun/star/text/XTextSectionsSupplier.hpp> +#include <com/sun/star/text/XTextSection.hpp> +#include <com/sun/star/text/SectionFileLink.hpp> +#include <com/sun/star/text/RelOrientation.hpp> +#include <com/sun/star/text/VertOrientation.hpp> +#include <com/sun/star/text/HorizontalAdjust.hpp> +#include <com/sun/star/text/DocumentStatistic.hpp> +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/text/HoriOrientationFormat.hpp> +#include <com/sun/star/text/NotePrintMode.hpp> +#include <com/sun/star/text/SizeType.hpp> +#include <com/sun/star/text/VertOrientationFormat.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> +//undef to prevent error (from sfx2/docfile.cxx) +#undef SEQUENCE +#include <com/sun/star/text/SetVariableType.hpp> +#include <com/sun/star/text/XTextFieldsSupplier.hpp> +#include <com/sun/star/text/UserDataPart.hpp> +#include <com/sun/star/text/ChapterFormat.hpp> +#include <com/sun/star/text/XTextField.hpp> +#include <com/sun/star/text/PlaceholderType.hpp> +#include <com/sun/star/text/TemplateDisplayFormat.hpp> +#include <com/sun/star/text/UserFieldFormat.hpp> +#include <com/sun/star/text/PageNumberType.hpp> +#include <com/sun/star/text/ReferenceFieldPart.hpp> +#include <com/sun/star/text/FilenameDisplayFormat.hpp> +#include <com/sun/star/text/XDependentTextField.hpp> +#include <com/sun/star/text/GraphicCrop.hpp> +#include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp> +#include <com/sun/star/text/XTextTableCursor.hpp> +#include <com/sun/star/text/XTextTablesSupplier.hpp> +#include <com/sun/star/text/TableColumnSeparator.hpp> +#include <com/sun/star/text/XTextTable.hpp> +#include <com/sun/star/text/XDocumentIndexMark.hpp> +#include <com/sun/star/text/XDocumentIndexesSupplier.hpp> +#include <com/sun/star/text/XDocumentIndex.hpp> +#include <com/sun/star/text/XTextColumns.hpp> +#include <com/sun/star/text/TextColumnSequence.hpp> +#include <com/sun/star/text/XTextFramesSupplier.hpp> +#include <com/sun/star/text/XTextFrame.hpp> +#include <com/sun/star/beans/PropertyValues.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/PropertyState.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XFastPropertySet.hpp> +#include <com/sun/star/beans/XVetoableChangeListener.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/beans/XPropertyStateChangeListener.hpp> +#ifndef _COM_SUN_STAR_BEANS_PropertyAttribute_HPP_ +#include <com/sun/star/beans/PropertyAttribute.hpp> +#endif +#include <com/sun/star/beans/XPropertiesChangeListener.hpp> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/beans/XPropertyContainer.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyStateChangeEvent.hpp> +#include <com/sun/star/beans/PropertyChangeEvent.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/awt/XBitmap.hpp> +#include <com/sun/star/style/GraphicLocation.hpp> +#include <com/sun/star/style/VerticalAlignment.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/table/ShadowFormat.hpp> +#include <com/sun/star/table/BorderLine.hpp> +#include <com/sun/star/table/TableBorder.hpp> +#include <com/sun/star/table/TableBorderDistances.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/drawing/PointSequenceSequence.hpp> +#include <com/sun/star/i18n/XForbiddenCharacters.hpp> +#include <com/sun/star/drawing/ColorMode.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/frame/XModel.hpp> +// --> OD 2004-08-09 #i28749# +#include <com/sun/star/drawing/HomogenMatrix3.hpp> +// <-- +#include <com/sun/star/graphic/XGraphicProvider.hpp> + +using ::rtl::OUString; +using namespace ::com::sun::star; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::i18n; +using namespace ::comphelper; + +namespace comphelper +{ + void GenerateCppuType ( + CppuTypes eType, const com::sun::star::uno::Type*& pType ) + { + switch( eType ) + { + case CPPUTYPE_BOOLEAN: pType = &::getBooleanCppuType(); break; + case CPPUTYPE_INT8: pType = &::getCppuType( (sal_Int8*)0 ); break; + case CPPUTYPE_INT16: pType = &::getCppuType( (sal_Int16*)0 ); break; + case CPPUTYPE_INT32: pType = &::getCppuType( (sal_Int32*)0 ); break; + + case CPPUTYPE_DOUBLE: pType = &::getCppuType( (double*)0 ); break; + case CPPUTYPE_FLOAT: pType = &::getCppuType( (float*)0 ); break; + case CPPUTYPE_OUSTRING: pType = &::getCppuType( (OUString*)0 ); break; + case CPPUTYPE_FONTSLANT: pType = &::getCppuType( (FontSlant*)0 ); break; + case CPPUTYPE_LOCALE: pType = &::getCppuType( (Locale*)0 ); break; + case CPPUTYPE_PROPERTYVALUE:pType = &::getCppuType( (Sequence<PropertyValue>*)0 ); break; + case CPPUTYPE_PROPERTYVALUES: pType = &::getCppuType( (Sequence<PropertyValues>*)0 ); break; + case CPPUTYPE_BORDERLINE: pType = &::getCppuType( (table::BorderLine*)0 ); break; + case CPPUTYPE_BREAK: pType = &::getCppuType( (style::BreakType*)0 ); break; + case CPPUTYPE_GRAPHICLOC: pType = &::getCppuType( (style::GraphicLocation*)0 ); break; + case CPPUTYPE_DROPCAPFMT: pType = &::getCppuType( (style::DropCapFormat*)0 ); break; + case CPPUTYPE_LINESPACE: pType = &::getCppuType( (style::LineSpacing*)0 ); break; + + case CPPUTYPE_AWTSIZE: pType = &::getCppuType( (awt::Size*)0 ); break; + case CPPUTYPE_SHADOWFMT: pType = &::getCppuType( (table::ShadowFormat*)0 ); break; + case CPPUTYPE_TBLCOLSEP: pType = &::getCppuType( (Sequence<text::TableColumnSeparator>*)0 ); break; + case CPPUTYPE_PNTSEQSEQ: pType = &::getCppuType( (PointSequenceSequence*)0 ); break; + case CPPUTYPE_DOCIDXMRK: pType = &::getCppuType( (Sequence< Reference< XDocumentIndexMark > >*)0 ); break; + case CPPUTYPE_SEQINT8: pType = &::getCppuType( (Sequence<sal_Int8>*)0 ); break; + case CPPUTYPE_SEQTABSTOP: pType = &::getCppuType( (Sequence<style::TabStop>*)0 ); break; + case CPPUTYPE_SEQANCHORTYPE:pType = &::getCppuType( (Sequence<text::TextContentAnchorType>*)0 ); break; + case CPPUTYPE_SEQDEPTXTFLD: pType = &::getCppuType( (Sequence<Reference<XDependentTextField> >*)0); break; + case CPPUTYPE_TXTCNTANCHOR: pType = &::getCppuType( (text::TextContentAnchorType*)0 ); break; + case CPPUTYPE_WRAPTXTMODE: pType = &::getCppuType( (text::WrapTextMode*)0 ); break; + + case CPPUTYPE_COLORMODE: pType = &::getCppuType( (drawing::ColorMode*)0 ); break; + case CPPUTYPE_PAGESTYLELAY: pType = &::getCppuType( (style::PageStyleLayout*)0 ); break; + case CPPUTYPE_VERTALIGN: pType = &::getCppuType( (style::VerticalAlignment*)0 ); break; + case CPPUTYPE_TABLEBORDER: pType = &::getCppuType( (table::TableBorder*)0 ); break; + case CPPUTYPE_GRFCROP: pType = &::getCppuType( (text::GraphicCrop*)0 ); break; + case CPPUTYPE_SECTFILELNK: pType = &::getCppuType( (text::SectionFileLink*)0 ); break; + case CPPUTYPE_PAGENUMTYPE: pType = &::getCppuType( (text::PageNumberType*)0); break; + case CPPUTYPE_DATETIME: pType = &::getCppuType( (util::DateTime*)0 ); break; + case CPPUTYPE_DATE: pType = &::getCppuType( (util::Date*)0 ); break; + + case CPPUTYPE_REFINTERFACE: pType = &::getCppuType( (Reference<XInterface>*)0 ); break; + case CPPUTYPE_REFIDXREPL: pType = &::getCppuType( (Reference<container::XIndexReplace>*)0 ); break; + case CPPUTYPE_REFNAMECNT: pType = &::getCppuType( (Reference<container::XNameContainer>*)0 ); break; + case CPPUTYPE_REFTEXTFRAME: pType = &::getCppuType( (Reference<text::XTextFrame>*)0 ); break; + case CPPUTYPE_REFTEXTSECTION: pType = &::getCppuType( (Reference<text::XTextSection>*)0 ); break; + case CPPUTYPE_REFFOOTNOTE: pType = &::getCppuType( (Reference<text::XFootnote>*)0 ); break; + case CPPUTYPE_REFTEXT: pType = &::getCppuType( (Reference<text::XText>*)0 ); break; + case CPPUTYPE_REFTEXTCOL: pType = &::getCppuType( (Reference<text::XTextColumns>*)0 ); break; + case CPPUTYPE_REFFORBCHARS: pType = &::getCppuType( (Reference<XForbiddenCharacters>*)0 ); break; + case CPPUTYPE_REFIDXCNTNR: pType = &::getCppuType( (Reference<XIndexContainer>*)0 ); break; + case CPPUTYPE_REFTEXTCNTNT: pType = &::getCppuType( (Reference<XTextContent>*)0 ); break; + case CPPUTYPE_REFBITMAP: pType = &::getCppuType( (Reference<awt::XBitmap>*)0 ); break; + case CPPUTYPE_REFNMREPLACE: pType = &::getCppuType( (Reference<container::XNameReplace>*)0 ); break; + case CPPUTYPE_REFCELL: pType = &::getCppuType( (Reference<table::XCell>*)0 ); break; + case CPPUTYPE_REFDOCINDEX: pType = &::getCppuType( (Reference<text::XDocumentIndex>*)0 ); break; + case CPPUTYPE_REFDOCIDXMRK: pType = &::getCppuType( (Reference<text::XDocumentIndexMark>*)0 ); break; + case CPPUTYPE_REFTXTFIELD: pType = &::getCppuType( (Reference<text::XTextField>*)0 ); break; + case CPPUTYPE_REFTXTRANGE: pType = &::getCppuType( (Reference<text::XTextRange>*)0 ); break; + case CPPUTYPE_REFTXTTABLE: pType = &::getCppuType( (Reference<text::XTextTable>*)0 ); break; + case CPPUTYPE_AWTPOINT: pType = &::getCppuType( (awt::Point*)0 ); break; + case CPPUTYPE_REFLIBCONTAINER: pType = &::getCppuType( (Reference< script::XLibraryContainer >*)0); break; + case CPPUTYPE_OUSTRINGS: pType = &::getCppuType( (Sequence< ::rtl::OUString >*)0); break; + case CPPUTYPE_SEQANY: pType = &::getCppuType( (Sequence< uno::Any >*)0); break; + case CPPUTYPE_REFRESULTSET: pType = &::getCppuType( (Reference< sdbc::XResultSet >*)0); break; + case CPPUTYPE_REFCONNECTION: pType = &::getCppuType( (Reference< sdbc::XConnection >*)0); break; + case CPPUTYPE_REFMODEL: pType = &::getCppuType( (Reference< frame::XModel >*)0); break; + case CPPUTYPE_REFCOMPONENT: pType = &::getCppuType( (Reference< lang::XComponent >*)0 ); break; + // --> OD 2004-08-09 #i28749# + case CPPUTYPE_TRANSFORMATIONINHORIL2R: + { + pType = &::getCppuType( (drawing::HomogenMatrix3*)0 ); + } + break; + // <-- + case CPPUTYPE_SEQNAMEDVALUE: pType = &::getCppuType( (Sequence<beans::NamedValue>*)0 ); break; + case CPPUTYPE_REFXGRAPHIC: pType = &::getCppuType( (Reference< graphic::XGraphic >*)0); break; + case CPPUTYPE_TABLEBORDERDISTANCES: pType = &::getCppuType( (table::TableBorderDistances*)0 ); break; + default: + OSL_ASSERT( "Unknown CPPU type" ); + } + } +} diff --git a/comphelper/source/property/composedprops.cxx b/comphelper/source/property/composedprops.cxx new file mode 100644 index 000000000000..4b44a8fb474e --- /dev/null +++ b/comphelper/source/property/composedprops.cxx @@ -0,0 +1,357 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" +#include <comphelper/composedprops.hxx> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <cppuhelper/implbase1.hxx> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + + //===================================================================== + //= OComposedPropertySetInfo + //===================================================================== + class OComposedPropertySetInfo : public ::cppu::WeakImplHelper1< XPropertySetInfo > + { + private: + Sequence< Property> m_aProperties; + + public: + OComposedPropertySetInfo(const Sequence< Property>& _rProperties); + + virtual Sequence< Property > SAL_CALL getProperties( ) throw(RuntimeException); + virtual Property SAL_CALL getPropertyByName( const ::rtl::OUString& _rName ) throw(UnknownPropertyException, RuntimeException); + virtual sal_Bool SAL_CALL hasPropertyByName( const ::rtl::OUString& _rName ) throw(RuntimeException); + }; + + //===================================================================== + //= OComposedPropertySet + //===================================================================== + //--------------------------------------------------------------------- + OComposedPropertySet::OComposedPropertySet( + const Sequence< Reference< XPropertySet> > & _rElements, + const IPropertySetComposerCallback* _pPropertyMetaData) + :m_pInfo(NULL) + { + // copy the sequence + sal_Int32 nSingleSets = _rElements.getLength(); + if (nSingleSets) + { + m_aSingleSets.resize(nSingleSets); + const Reference< XPropertySet >* pSingleSets = _rElements.getConstArray(); + ::std::copy(pSingleSets, pSingleSets + nSingleSets, m_aSingleSets.begin()); + } + + // impl ctor + compose(_pPropertyMetaData); + } + + //--------------------------------------------------------------------- + OComposedPropertySet::~OComposedPropertySet() + { + if (m_pInfo) + m_pInfo->release(); + } + + //--------------------------------------------------------------------- + void OComposedPropertySet::compose(const IPropertySetComposerCallback* _pMetaData) + { + sal_Int32 nSingleSets = m_aSingleSets.size(); + + if (nSingleSets>0) + { + // get the properties of the first set + Reference< XPropertySet > xMasterSet = m_aSingleSets[0]; + Sequence< Property> aMasterProps; + if (xMasterSet.is()) + aMasterProps = xMasterSet->getPropertySetInfo()->getProperties(); + sal_Int32 nMasterPropsCount = aMasterProps.getLength(); + const Property* pMasterProps = aMasterProps.getConstArray(); + + // check which of the master properties should be included + Sequence<sal_Bool> aInclusionFlags(nMasterPropsCount); + sal_Bool* pInclusionFlags = aInclusionFlags.getArray(); + + // the states of all these properties + Sequence< PropertyState > aPropertyStates(nMasterPropsCount); + + for (sal_Int32 i=0; i<nMasterPropsCount; ++i) + pInclusionFlags[i] = sal_True; + + Reference< XPropertySet > xSecondarySet; + sal_Int32 nSecondaryPropertyCount; + Sequence< Property > aSecondaryProperties; + const Property* pPrimaryProperty = aMasterProps.getConstArray(); + for (sal_Int32 nPrimary=0; nPrimary<nMasterPropsCount; ++nPrimary, ++pPrimaryProperty) + { + if (_pMetaData && !_pMetaData->isComposeable(pPrimaryProperty->Name)) + // do not include this property + pInclusionFlags[nPrimary] = sal_False; + else + { + // search the property in all secondary sets + for (sal_Int32 i=1; i<nSingleSets; ++i) + { + xSecondarySet = m_aSingleSets[i]; + aSecondaryProperties = xSecondarySet->getPropertySetInfo()->getProperties(); + nSecondaryPropertyCount = aSecondaryProperties.getLength(); + const Property* pSecondaryProperties = aSecondaryProperties.getConstArray(); + + // search the current primary property in the secondary property sequence + sal_Int32 k=0; + while (k<nSecondaryPropertyCount && (pSecondaryProperties[k].Name != pPrimaryProperty->Name)) + ++k; + + if (k >= nSecondaryPropertyCount) + // not found -> do not include + pInclusionFlags[nPrimary] = sal_False; + } + } + } + + // count what's left .... + sal_Int32 nOverallProperties = 0; + for (sal_Int32 nCounter=0; nCounter<nMasterPropsCount; ++nCounter) + { + if (pInclusionFlags[nCounter]) + ++nOverallProperties; + } + + // and finally construct our sequence + m_aProperties = Sequence< Property >(nOverallProperties); + Property* pProperties = m_aProperties.getArray(); + const Property* pMasterProperties = pMasterProps; + sal_Int32 nOwnProperties = 0; + for (sal_Int32 nCopy = 0; nCopy < nMasterPropsCount; ++nCopy, ++pMasterProperties) + { + if (pInclusionFlags[nCopy]) + pProperties[nOwnProperties++] = *pMasterProperties; + } + } + } + + //------------------------------------------------------------------------------ + Reference< XPropertySetInfo > SAL_CALL OComposedPropertySet::getPropertySetInfo( ) throw(RuntimeException) + { + ::osl::MutexGuard aGuard(m_aMutex); + if (!m_pInfo) + { + m_pInfo = new OComposedPropertySetInfo(m_aProperties); + m_pInfo->acquire(); + } + return m_pInfo; + } + + //------------------------------------------------------------------------------ + PropertyState SAL_CALL OComposedPropertySet::getPropertyState( const ::rtl::OUString& _rPropertyName ) throw(UnknownPropertyException, RuntimeException) + { + // assume DIRECT for the moment + PropertyState eState = PropertyState_DIRECT_VALUE; + + sal_Int32 nSingleSets = m_aSingleSets.size(); + if (nSingleSets>0) + { + // check the master state + Reference< XPropertySet > xMasterSet(m_aSingleSets[0]); + Any aPrimaryValue; + if (xMasterSet.is()) + { + Reference< XPropertyState > xMasterState(xMasterSet,UNO_QUERY); + aPrimaryValue = xMasterSet->getPropertyValue(_rPropertyName); + + if (xMasterState.is()) + eState = xMasterState->getPropertyState(_rPropertyName); + } + + // loop through the secondary sets + PropertyState eSecondaryState; + for (sal_Int32 i=1; i<nSingleSets; ++i) + { + Reference< XPropertySet > xSecondary(m_aSingleSets[i]); + Reference< XPropertyState > xSecondaryState(xSecondary, UNO_QUERY); + + // the secondary state + eSecondaryState = PropertyState_DIRECT_VALUE; + if(xSecondaryState.is()) + eSecondaryState = xSecondaryState->getPropertyState(_rPropertyName); + + // the secondary value + Any aSecondaryValue(xSecondary->getPropertyValue(_rPropertyName)); + + if ( (PropertyState_AMBIGUOUS_VALUE == eSecondaryState) // secondary is ambiguous + || !::comphelper::compare(aPrimaryValue, aSecondaryValue) // unequal values + ) + { + eState = PropertyState_AMBIGUOUS_VALUE; + break; + } + } + } + else + { + throw UnknownPropertyException( _rPropertyName, *this ); + } + + return eState; + } + + //--------------------------------------------------------------------- + Sequence< PropertyState > SAL_CALL OComposedPropertySet::getPropertyStates( const Sequence< ::rtl::OUString >& _rPropertyName ) throw(UnknownPropertyException, RuntimeException) + { + sal_Int32 nCount = _rPropertyName.getLength(); + Sequence< PropertyState > aReturn(nCount); + const ::rtl::OUString* pNames = _rPropertyName.getConstArray(); + PropertyState* pStates = aReturn.getArray(); + for (sal_Int32 i=0; i<nCount; ++i, ++pNames, ++pStates) + *pStates = getPropertyState(*pNames); + return aReturn; + } + + //--------------------------------------------------------------------- + void SAL_CALL OComposedPropertySet::setPropertyToDefault( const ::rtl::OUString& _rPropertyName ) throw(UnknownPropertyException, RuntimeException) + { + sal_Int32 nSingleSets = m_aSingleSets.size(); + for (sal_Int32 i=0; i<nSingleSets; ++i) + { + Reference< XPropertyState > xState(m_aSingleSets[i], UNO_QUERY); + if(xState.is()) + xState->setPropertyToDefault(_rPropertyName); + } + } + + //--------------------------------------------------------------------- + Any SAL_CALL OComposedPropertySet::getPropertyDefault( const ::rtl::OUString& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) + { + return Any(); + } + + //------------------------------------------------------------------------------ + void SAL_CALL OComposedPropertySet::setPropertyValue( const ::rtl::OUString& _rPropertyName, const Any& _rValue ) throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) + { + sal_Int32 nSingleSets = m_aSingleSets.size(); + for (sal_Int32 i=0; i<nSingleSets; ++i) + { + if (m_aSingleSets[i].is()) + m_aSingleSets[i]->setPropertyValue(_rPropertyName, _rValue); + } + } + + //------------------------------------------------------------------------------ + Any SAL_CALL OComposedPropertySet::getPropertyValue( const ::rtl::OUString& _rPropertyName ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) + { + sal_Int32 nSingleSets = m_aSingleSets.size(); + + if ((nSingleSets>0) && (m_aSingleSets[0].is())) + return m_aSingleSets[0]->getPropertyValue(_rPropertyName); + return Any(); + } + + //------------------------------------------------------------------------------ + void SAL_CALL OComposedPropertySet::addPropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) + { + // TODO: + // hold the single property sets weak + // be a property change listener on all single property sets (for all composed properties) + // upon property change + // determine the new state/value of the composed property + // broadcast the new composed property value + } + + //------------------------------------------------------------------------------ + void SAL_CALL OComposedPropertySet::removePropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) + { + // TODO + } + + //------------------------------------------------------------------------------ + void SAL_CALL OComposedPropertySet::addVetoableChangeListener( const ::rtl::OUString&, const Reference< XVetoableChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) + { + OSL_ENSURE(sal_False, "OComposedPropertySet::addVetoableChangeListener: no implemented (yet)!"); + } + + //------------------------------------------------------------------------------ + void SAL_CALL OComposedPropertySet::removeVetoableChangeListener( const ::rtl::OUString&, const Reference< XVetoableChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) + { + OSL_ENSURE(sal_False, "OComposedPropertySet::removeVetoableChangeListener: no implemented (yet)!"); + } + + //------------------------------------------------------------------------------ + OComposedPropertySetInfo::OComposedPropertySetInfo(const Sequence< Property>& rSeq) + :m_aProperties(rSeq) + { + } + + //------------------------------------------------------------------------------ + Sequence< Property> SAL_CALL OComposedPropertySetInfo::getProperties() throw(RuntimeException) + { + return m_aProperties; + } + + //------------------------------------------------------------------------------ + Property SAL_CALL OComposedPropertySetInfo::getPropertyByName( const ::rtl::OUString& _rName ) throw(UnknownPropertyException, RuntimeException) + { + sal_Int32 nLength = m_aProperties.getLength(); + const Property* pProps = m_aProperties.getConstArray(); + // TODO TODO TODO: this O(n) search really sucks ... + for (sal_Int32 i=0; i<nLength; ++i, ++pProps) + { + if (pProps->Name == _rName) + return *pProps; + } + + throw UnknownPropertyException( _rName, *this ); + } + + //------------------------------------------------------------------------------ + sal_Bool SAL_CALL OComposedPropertySetInfo::hasPropertyByName( const ::rtl::OUString& _rName ) throw(RuntimeException) + { + sal_Int32 nLength = m_aProperties.getLength(); + const Property* pProps = m_aProperties.getConstArray(); + // TODO TODO TODO: this O(n) search really sucks ... + for( sal_Int32 i=0; i<nLength; ++i,++pProps ) + { + if(pProps->Name == _rName) + return sal_True; + } + + return sal_False; + } + +//......................................................................... +} // namespace comphelper +//......................................................................... + + diff --git a/comphelper/source/property/genericpropertyset.cxx b/comphelper/source/property/genericpropertyset.cxx new file mode 100644 index 000000000000..b7fb09912153 --- /dev/null +++ b/comphelper/source/property/genericpropertyset.cxx @@ -0,0 +1,301 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XTypeProvider.hpp> +#include <cppuhelper/weakagg.hxx> +#include <cppuhelper/interfacecontainer.hxx> +#include <comphelper/propertysethelper.hxx> +#include <osl/mutex.hxx> +#include <comphelper/genericpropertyset.hxx> +#include <comphelper/propertysetinfo.hxx> +#include <comphelper/stl_types.hxx> +#include <vos/mutex.hxx> +#include <rtl/uuid.h> +#include <boost/mem_fn.hpp> +#include <boost/bind.hpp> +#include <boost/utility.hpp> + +/////////////////////////////////////////////////////////////////////// + +using namespace ::rtl; +using namespace ::osl; +using namespace ::cppu; +using namespace ::comphelper; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; + +DECLARE_STL_USTRINGACCESS_MAP( Any, GenericAnyMapImpl ); + +namespace comphelper +{ + struct IMPL_GenericPropertySet_MutexContainer + { + Mutex maMutex ; + } ; + + class GenericPropertySet : public OWeakAggObject, + public XServiceInfo, + public XTypeProvider, + public PropertySetHelper, + private IMPL_GenericPropertySet_MutexContainer + { + private: + GenericAnyMapImpl maAnyMap; + ::cppu::OMultiTypeInterfaceContainerHelperVar< ::rtl::OUString,UStringHash,UStringEqual> m_aListener; + + protected: + virtual void _setPropertyValues( const PropertyMapEntry** ppEntries, const Any* pValues ) throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException ); + virtual void _getPropertyValues( const PropertyMapEntry** ppEntries, Any* pValue ) throw( UnknownPropertyException, WrappedTargetException ); + + public: + GenericPropertySet( PropertySetInfo* pInfo ) throw(); + virtual ~GenericPropertySet() throw(); + + // XInterface + virtual Any SAL_CALL queryAggregation( const Type & rType ) throw( RuntimeException); + virtual Any SAL_CALL queryInterface( const Type & rType ) throw( RuntimeException); + virtual void SAL_CALL acquire() throw(); + virtual void SAL_CALL release() throw(); + + // XTypeProvider + virtual Sequence< Type > SAL_CALL getTypes( ) throw( RuntimeException); + virtual Sequence< sal_Int8 > SAL_CALL getImplementationId( ) throw( RuntimeException); + + // XServiceInfo + virtual rtl::OUString SAL_CALL getImplementationName() throw( RuntimeException ); + virtual sal_Bool SAL_CALL supportsService( const rtl::OUString& ServiceName ) throw( RuntimeException ); + virtual Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames() throw( RuntimeException ); + + // XPropertySet + virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + }; + +} + +/////////////////////////////////////////////////////////////////////// + +GenericPropertySet::GenericPropertySet( PropertySetInfo* pInfo ) throw() +: PropertySetHelper( pInfo ) +,m_aListener(maMutex) +{ +} + +GenericPropertySet::~GenericPropertySet() throw() +{ +} +void SAL_CALL GenericPropertySet::addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + Reference < XPropertySetInfo > xInfo = getPropertySetInfo( ); + if ( xInfo.is() ) + { + if ( !aPropertyName.getLength() ) + { + Sequence< Property> aSeq = xInfo->getProperties(); + const Property* pIter = aSeq.getConstArray(); + const Property* pEnd = pIter + aSeq.getLength(); + for( ; pIter != pEnd ; ++pIter) + { + m_aListener.addInterface(pIter->Name,xListener); + } + } + else if ( xInfo->hasPropertyByName(aPropertyName) ) + m_aListener.addInterface(aPropertyName,xListener); + else + throw UnknownPropertyException( aPropertyName, *this ); + } +} + +void SAL_CALL GenericPropertySet::removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + ResettableMutexGuard aGuard( maMutex ); + Reference < XPropertySetInfo > xInfo = getPropertySetInfo( ); + aGuard.clear(); + if ( xInfo.is() ) + { + if ( !aPropertyName.getLength() ) + { + Sequence< Property> aSeq = xInfo->getProperties(); + const Property* pIter = aSeq.getConstArray(); + const Property* pEnd = pIter + aSeq.getLength(); + for( ; pIter != pEnd ; ++pIter) + { + m_aListener.removeInterface(pIter->Name,xListener); + } + } + else if ( xInfo->hasPropertyByName(aPropertyName) ) + m_aListener.removeInterface(aPropertyName,xListener); + else + throw UnknownPropertyException( aPropertyName, *this ); + } +} + +void GenericPropertySet::_setPropertyValues( const PropertyMapEntry** ppEntries, const Any* pValues ) + throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException ) +{ + ResettableMutexGuard aGuard( maMutex ); + + while( *ppEntries ) + { + const OUString aPropertyName( (*ppEntries)->mpName, (*ppEntries)->mnNameLen, RTL_TEXTENCODING_ASCII_US ); + OInterfaceContainerHelper * pHelper = m_aListener.getContainer(aPropertyName); + + maAnyMap[ aPropertyName ] = *pValues; + + if ( pHelper ) + { + PropertyChangeEvent aEvt; + aEvt.PropertyName = aPropertyName; + aEvt.NewValue = *pValues; + aGuard.clear(); + pHelper->notifyEach( &XPropertyChangeListener::propertyChange, aEvt ); + aGuard.reset(); + } + + ppEntries++; + pValues++; + } +} + +void GenericPropertySet::_getPropertyValues( const comphelper::PropertyMapEntry** ppEntries, Any* pValue ) + throw( UnknownPropertyException, WrappedTargetException ) +{ + MutexGuard aGuard( maMutex ); + + while( *ppEntries ) + { + const OUString aPropertyName( (*ppEntries)->mpName, (*ppEntries)->mnNameLen, RTL_TEXTENCODING_ASCII_US ); + *pValue = maAnyMap[ aPropertyName ]; + + ppEntries++; + pValue++; + } +} + +// XInterface + +Any SAL_CALL GenericPropertySet::queryInterface( const Type & rType ) + throw( RuntimeException ) +{ + return OWeakAggObject::queryInterface( rType ); +} + +Any SAL_CALL GenericPropertySet::queryAggregation( const Type & rType ) + throw(RuntimeException) +{ + Any aAny; + + if( rType == ::getCppuType((const Reference< XServiceInfo >*)0) ) + aAny <<= Reference< XServiceInfo >(this); + else if( rType == ::getCppuType((const Reference< XTypeProvider >*)0) ) + aAny <<= Reference< XTypeProvider >(this); + else if( rType == ::getCppuType((const Reference< XPropertySet >*)0) ) + aAny <<= Reference< XPropertySet >(this); + else if( rType == ::getCppuType((const Reference< XMultiPropertySet >*)0) ) + aAny <<= Reference< XMultiPropertySet >(this); + else + aAny <<= OWeakAggObject::queryAggregation( rType ); + + return aAny; +} + +void SAL_CALL GenericPropertySet::acquire() throw() +{ + OWeakAggObject::acquire(); +} + +void SAL_CALL GenericPropertySet::release() throw() +{ + OWeakAggObject::release(); +} + +uno::Sequence< uno::Type > SAL_CALL GenericPropertySet::getTypes() + throw (uno::RuntimeException) +{ + uno::Sequence< uno::Type > aTypes( 5 ); + uno::Type* pTypes = aTypes.getArray(); + + *pTypes++ = ::getCppuType((const uno::Reference< XAggregation>*)0); + *pTypes++ = ::getCppuType((const uno::Reference< XServiceInfo>*)0); + *pTypes++ = ::getCppuType((const uno::Reference< XTypeProvider>*)0); + *pTypes++ = ::getCppuType((const uno::Reference< XPropertySet>*)0); + *pTypes++ = ::getCppuType((const uno::Reference< XMultiPropertySet>*)0); + + return aTypes; +} + +uno::Sequence< sal_Int8 > SAL_CALL GenericPropertySet::getImplementationId() + throw (uno::RuntimeException) +{ + MutexGuard aGuard( maMutex ); + + static uno::Sequence< sal_Int8 > aId; + if( aId.getLength() == 0 ) + { + aId.realloc( 16 ); + rtl_createUuid( (sal_uInt8 *)aId.getArray(), 0, sal_True ); + } + return aId; +} + +// XServiceInfo + +sal_Bool SAL_CALL GenericPropertySet::supportsService( const OUString& ServiceName ) throw(RuntimeException) +{ + Sequence< OUString > aSNL( getSupportedServiceNames() ); + const OUString * pArray = aSNL.getConstArray(); + + for( sal_Int32 i = 0; i < aSNL.getLength(); ++i ) + if( pArray[i] == ServiceName ) + return sal_True; + + return sal_False; +} + +OUString SAL_CALL GenericPropertySet::getImplementationName() throw( RuntimeException ) +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.comphelper.GenericPropertySet") ); +} + +Sequence< OUString > SAL_CALL GenericPropertySet::getSupportedServiceNames( ) + throw( RuntimeException ) +{ + Sequence< OUString > aSNS( 1 ); + aSNS.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.beans.XPropertySet" )); + return aSNS; +} + +::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > comphelper::GenericPropertySet_CreateInstance( comphelper::PropertySetInfo* pInfo ) +{ + return (XPropertySet*)new GenericPropertySet( pInfo ); +} + diff --git a/comphelper/source/property/makefile.mk b/comphelper/source/property/makefile.mk new file mode 100644 index 000000000000..1bcdb4c8dd63 --- /dev/null +++ b/comphelper/source/property/makefile.mk @@ -0,0 +1,65 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. +PRJINC=..$/..$/inc +PRJNAME=comphelper +TARGET=property + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES= \ + $(SLO)$/MasterPropertySetInfo.obj \ + $(SLO)$/MasterPropertySet.obj \ + $(SLO)$/ChainablePropertySetInfo.obj \ + $(SLO)$/ChainablePropertySet.obj \ + $(SLO)$/TypeGeneration.obj \ + $(SLO)$/genericpropertyset.obj\ + $(SLO)$/propertysethelper.obj \ + $(SLO)$/propertysetinfo.obj \ + $(SLO)$/composedprops.obj \ + $(SLO)$/propagg.obj \ + $(SLO)$/property.obj \ + $(SLO)$/propmultiplex.obj \ + $(SLO)$/propstate.obj \ + $(SLO)$/propertystatecontainer.obj \ + $(SLO)$/propertycontainer.obj \ + $(SLO)$/propertycontainerhelper.obj \ + $(SLO)$/propertybag.obj \ + $(SLO)$/opropertybag.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/comphelper/source/property/opropertybag.cxx b/comphelper/source/property/opropertybag.cxx new file mode 100644 index 000000000000..f1282a48c2dd --- /dev/null +++ b/comphelper/source/property/opropertybag.cxx @@ -0,0 +1,585 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" + +#include "opropertybag.hxx" +#include "comphelper_module.hxx" + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/Property.hpp> + +#include <comphelper/namedvaluecollection.hxx> + +#include <cppuhelper/exc_hlp.hxx> +#include <osl/thread.h> + +#include <algorithm> +#include <functional> + + +//-------------------------------------------------------------------------- +using namespace ::com::sun::star; + +void createRegistryInfo_OPropertyBag() +{ + static ::comphelper::module::OAutoRegistration< ::comphelper::OPropertyBag > aAutoRegistration; +} + +//........................................................................ +namespace comphelper +{ +//........................................................................ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::container; + + //==================================================================== + //= OPropertyBag + //==================================================================== + //-------------------------------------------------------------------- + OPropertyBag::OPropertyBag( const Reference< XComponentContext >& _rxContext ) + :OPropertyBag_PBase( GetBroadcastHelper(), this ) + ,::cppu::IEventNotificationHook() + ,m_aContext( _rxContext ) + ,m_bAutoAddProperties( false ) + ,m_NotifyListeners(m_aMutex) + ,m_isModified(false) + + { + } + + //-------------------------------------------------------------------- + OPropertyBag::~OPropertyBag() + { + } + + //-------------------------------------------------------------------- + IMPLEMENT_FORWARD_XINTERFACE2( OPropertyBag, OPropertyBag_Base, OPropertyBag_PBase ) + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OPropertyBag, OPropertyBag_Base, OPropertyBag_PBase ) + + //-------------------------------------------------------------------- + Sequence< ::rtl::OUString > OPropertyBag::getSupportedServiceNames_static() throw( RuntimeException ) + { + Sequence< ::rtl::OUString > aServices(1); + aServices[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.beans.PropertyBag" ) ); + return aServices; + } + + //-------------------------------------------------------------------- + void SAL_CALL OPropertyBag::initialize( const Sequence< Any >& _rArguments ) throw (Exception, RuntimeException) + { + ::comphelper::NamedValueCollection aArguments( _rArguments ); + + Sequence< Type > aTypes; + if ( aArguments.get_ensureType( "AllowedTypes", aTypes ) ) + ::std::copy( + aTypes.getConstArray(), + aTypes.getConstArray() + aTypes.getLength(), + ::std::insert_iterator< TypeBag >( m_aAllowedTypes, m_aAllowedTypes.begin() ) + ); + + aArguments.get_ensureType( "AutomaticAddition", m_bAutoAddProperties ); + bool AllowEmptyPropertyName(false); + aArguments.get_ensureType( "AllowEmptyPropertyName", + AllowEmptyPropertyName ); + if (AllowEmptyPropertyName) { + m_aDynamicProperties.setAllowEmptyPropertyName( + AllowEmptyPropertyName); + } + } + + //-------------------------------------------------------------------- + ::rtl::OUString OPropertyBag::getImplementationName_static() throw( RuntimeException ) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.comphelper.OPropertyBag" ) ); + } + + //-------------------------------------------------------------------- + Reference< XInterface > SAL_CALL OPropertyBag::Create( const Reference< XComponentContext >& _rxContext ) + { + return *new OPropertyBag( _rxContext ); + } + + //-------------------------------------------------------------------- + ::rtl::OUString SAL_CALL OPropertyBag::getImplementationName() throw (RuntimeException) + { + return getImplementationName_static(); + } + + //-------------------------------------------------------------------- + ::sal_Bool SAL_CALL OPropertyBag::supportsService( const ::rtl::OUString& rServiceName ) throw (RuntimeException) + { + Sequence< ::rtl::OUString > aServices( getSupportedServiceNames_static() ); + const ::rtl::OUString* pStart = aServices.getConstArray(); + const ::rtl::OUString* pEnd = aServices.getConstArray() + aServices.getLength(); + return ::std::find( pStart, pEnd, rServiceName ) != pEnd; + } + + //-------------------------------------------------------------------- + Sequence< ::rtl::OUString > SAL_CALL OPropertyBag::getSupportedServiceNames( ) throw (RuntimeException) + { + return getSupportedServiceNames_static(); + } + + //-------------------------------------------------------------------- + void OPropertyBag::fireEvents( + sal_Int32 * /*pnHandles*/, + sal_Int32 nCount, + sal_Bool bVetoable, + bool bIgnoreRuntimeExceptionsWhileFiring) + { + if (nCount && !bVetoable) { + setModifiedImpl(sal_True, bIgnoreRuntimeExceptionsWhileFiring); + } + } + + void OPropertyBag::setModifiedImpl(::sal_Bool bModified, + bool bIgnoreRuntimeExceptionsWhileFiring) + { + { // do not lock mutex while notifying (#i93514#) to prevent deadlock + ::osl::MutexGuard aGuard( m_aMutex ); + m_isModified = bModified; + } + if (bModified) { + try { + Reference<XInterface> xThis(*this); + EventObject event(xThis); + m_NotifyListeners.notifyEach( + &XModifyListener::modified, event); + } catch (RuntimeException &) { + if (!bIgnoreRuntimeExceptionsWhileFiring) { + throw; + } + } catch (Exception &) { + // ignore + } + } + } + + //-------------------------------------------------------------------- + ::sal_Bool SAL_CALL OPropertyBag::isModified() + throw (RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return m_isModified; + } + + void SAL_CALL OPropertyBag::setModified( ::sal_Bool bModified ) + throw (PropertyVetoException, RuntimeException) + { + setModifiedImpl(bModified, false); + } + + void SAL_CALL OPropertyBag::addModifyListener( + const Reference< XModifyListener > & xListener) + throw (RuntimeException) + { + m_NotifyListeners.addInterface(xListener); + } + + void SAL_CALL OPropertyBag::removeModifyListener( + const Reference< XModifyListener > & xListener) + throw (RuntimeException) + { + m_NotifyListeners.removeInterface(xListener); + } + + //-------------------------------------------------------------------- + Reference< XPropertySetInfo > SAL_CALL OPropertyBag::getPropertySetInfo( ) throw(RuntimeException) + { + return createPropertySetInfo( getInfoHelper() ); + } + + //-------------------------------------------------------------------- + ::sal_Bool SAL_CALL OPropertyBag::has( const Any& /*aElement*/ ) throw (RuntimeException) + { + // XSet is only a workaround for addProperty not being able to add default-void properties. + // So, everything of XSet except insert is implemented empty + return sal_False; + } + + //-------------------------------------------------------------------- + void SAL_CALL OPropertyBag::insert( const Any& _element ) throw (IllegalArgumentException, ElementExistException, RuntimeException) + { + // This is a workaround for addProperty not being able to add default-void properties. + // If we ever have a smarter XPropertyContainer::addProperty interface, we can remove this, ehm, well, hack. + Property aProperty; + if ( !( _element >>= aProperty ) ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); + + ::osl::ClearableMutexGuard g( m_aMutex ); + + // check whether the type is allowed, everything else will be checked + // by m_aDynamicProperties + if ( !m_aAllowedTypes.empty() + && m_aAllowedTypes.find( aProperty.Type ) == m_aAllowedTypes.end() + ) + throw IllegalTypeException( ::rtl::OUString(), *this ); + + m_aDynamicProperties.addVoidProperty( aProperty.Name, aProperty.Type, findFreeHandle(), aProperty.Attributes ); + + // our property info is dirty + m_pArrayHelper.reset(); + + g.clear(); + setModified(sal_True); + } + + //-------------------------------------------------------------------- + void SAL_CALL OPropertyBag::remove( const Any& /*aElement*/ ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException) + { + // XSet is only a workaround for addProperty not being able to add default-void properties. + // So, everything of XSet except insert is implemented empty + throw NoSuchElementException( ::rtl::OUString(), *this ); + } + + + //-------------------------------------------------------------------- + Reference< XEnumeration > SAL_CALL OPropertyBag::createEnumeration( ) throw (RuntimeException) + { + // XSet is only a workaround for addProperty not being able to add default-void properties. + // So, everything of XSet except insert is implemented empty + return NULL; + } + + //-------------------------------------------------------------------- + Type SAL_CALL OPropertyBag::getElementType( ) throw (RuntimeException) + { + // XSet is only a workaround for addProperty not being able to add default-void properties. + // So, everything of XSet except insert is implemented empty + return Type(); + } + + //-------------------------------------------------------------------- + ::sal_Bool SAL_CALL OPropertyBag::hasElements( ) throw (RuntimeException) + { + // XSet is only a workaround for addProperty not being able to add default-void properties. + // So, everything of XSet except insert is implemented empty + return sal_False; + } + + //-------------------------------------------------------------------- + void SAL_CALL OPropertyBag::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const + { + m_aDynamicProperties.getFastPropertyValue( _nHandle, _rValue ); + } + + //-------------------------------------------------------------------- + sal_Bool SAL_CALL OPropertyBag::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw (IllegalArgumentException) + { + return m_aDynamicProperties.convertFastPropertyValue( _nHandle, _rValue, _rConvertedValue, _rOldValue ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OPropertyBag::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) throw (Exception) + { + m_aDynamicProperties.setFastPropertyValue( nHandle, rValue ); + } + + //-------------------------------------------------------------------- + ::cppu::IPropertyArrayHelper& SAL_CALL OPropertyBag::getInfoHelper() + { + if ( !m_pArrayHelper.get() ) + { + Sequence< Property > aProperties; + m_aDynamicProperties.describeProperties( aProperties ); + m_pArrayHelper.reset( new ::cppu::OPropertyArrayHelper( aProperties ) ); + } + return *m_pArrayHelper; + + } + + //-------------------------------------------------------------------- + sal_Int32 OPropertyBag::findFreeHandle() const + { + const sal_Int32 nPrime = 1009; + const sal_Int32 nSeed = 11; + + sal_Int32 nCheck = nSeed; + while ( m_aDynamicProperties.hasPropertyByHandle( nCheck ) && ( nCheck != 1 ) ) + { + nCheck = ( nCheck * nSeed ) % nPrime; + } + + if ( nCheck == 1 ) + { // uh ... we already have 1008 handles used up + // -> simply count upwards + while ( m_aDynamicProperties.hasPropertyByHandle( nCheck ) ) + ++nCheck; + } + + return nCheck; + } + + //-------------------------------------------------------------------- + void SAL_CALL OPropertyBag::addProperty( const ::rtl::OUString& _rName, ::sal_Int16 _nAttributes, const Any& _rInitialValue ) throw (PropertyExistException, IllegalTypeException, IllegalArgumentException, RuntimeException) + { + ::osl::ClearableMutexGuard g( m_aMutex ); + + // check whether the type is allowed, everything else will be checked + // by m_aDynamicProperties + Type aPropertyType = _rInitialValue.getValueType(); + if ( _rInitialValue.hasValue() + && !m_aAllowedTypes.empty() + && m_aAllowedTypes.find( aPropertyType ) == m_aAllowedTypes.end() + ) + throw IllegalTypeException( ::rtl::OUString(), *this ); + + m_aDynamicProperties.addProperty( _rName, findFreeHandle(), _nAttributes, _rInitialValue ); + + // our property info is dirty + m_pArrayHelper.reset(); + + g.clear(); + setModified(sal_True); + } + + //-------------------------------------------------------------------- + void SAL_CALL OPropertyBag::removeProperty( const ::rtl::OUString& _rName ) throw (UnknownPropertyException, NotRemoveableException, RuntimeException) + { + ::osl::ClearableMutexGuard g( m_aMutex ); + + m_aDynamicProperties.removeProperty( _rName ); + + // our property info is dirty + m_pArrayHelper.reset(); + + g.clear(); + setModified(sal_True); + } + + //-------------------------------------------------------------------- + namespace + { + struct ComparePropertyValueByName : public ::std::binary_function< PropertyValue, PropertyValue, bool > + { + bool operator()( const PropertyValue& _rLHS, const PropertyValue& _rRHS ) + { + return _rLHS.Name < _rRHS.Name; + } + }; + + template< typename CLASS > + struct TransformPropertyToName : public ::std::unary_function< CLASS, ::rtl::OUString > + { + const ::rtl::OUString& operator()( const CLASS& _rProp ) + { + return _rProp.Name; + } + }; + + struct ExtractPropertyValue : public ::std::unary_function< PropertyValue, Any > + { + const Any& operator()( const PropertyValue& _rProp ) + { + return _rProp.Value; + } + }; + } + + //-------------------------------------------------------------------- + Sequence< PropertyValue > SAL_CALL OPropertyBag::getPropertyValues( ) throw (RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // all registered properties + Sequence< Property > aProperties; + m_aDynamicProperties.describeProperties( aProperties ); + + // their names + Sequence< ::rtl::OUString > aNames( aProperties.getLength() ); + ::std::transform( + aProperties.getConstArray(), + aProperties.getConstArray() + aProperties.getLength(), + aNames.getArray(), + TransformPropertyToName< Property >() + ); + + // their values + Sequence< Any > aValues; + try + { + aValues = OPropertyBag_PBase::getPropertyValues( aNames ); + if ( aValues.getLength() != aNames.getLength() ) + throw RuntimeException(); + } + catch( const RuntimeException& ) + { + throw; + } + catch( const Exception& ) + { + // ignore + } + + // merge names and values, and retrieve the state/handle + ::cppu::IPropertyArrayHelper& rPropInfo = getInfoHelper(); + + Sequence< PropertyValue > aPropertyValues( aNames.getLength() ); + const ::rtl::OUString* pName = aNames.getConstArray(); + const ::rtl::OUString* pNamesEnd = aNames.getConstArray() + aNames.getLength(); + const Any* pValue = aValues.getArray(); + PropertyValue* pPropertyValue = aPropertyValues.getArray(); + + for ( ; pName != pNamesEnd; ++pName, ++pValue, ++pPropertyValue ) + { + pPropertyValue->Name = *pName; + pPropertyValue->Handle = rPropInfo.getHandleByName( *pName ); + pPropertyValue->Value = *pValue; + pPropertyValue->State = getPropertyStateByHandle( pPropertyValue->Handle ); + } + + return aPropertyValues; + } + + //-------------------------------------------------------------------- + void OPropertyBag::impl_setPropertyValues_throw( const Sequence< PropertyValue >& _rProps ) + { + // sort (the XMultiPropertySet interface requires this) + Sequence< PropertyValue > aProperties( _rProps ); + ::std::sort( + aProperties.getArray(), + aProperties.getArray() + aProperties.getLength(), + ComparePropertyValueByName() + ); + + // a sequence of names + Sequence< ::rtl::OUString > aNames( aProperties.getLength() ); + ::std::transform( + aProperties.getConstArray(), + aProperties.getConstArray() + aProperties.getLength(), + aNames.getArray(), + TransformPropertyToName< PropertyValue >() + ); + + try + { + ::cppu::IPropertyArrayHelper& rPropInfo = getInfoHelper(); + + // check for unknown properties + // we cannot simply rely on the XMultiPropertySet::setPropertyValues + // implementation of our base class, since it does not throw + // an UnknownPropertyException. More precise, XMultiPropertySet::setPropertyValues + // does not allow to throw this exception, while XPropertyAccess::setPropertyValues + // requires it + sal_Int32 nCount = aNames.getLength(); + + Sequence< sal_Int32 > aHandles( nCount ); + sal_Int32* pHandle = aHandles.getArray(); + const PropertyValue* pProperty = aProperties.getConstArray(); + for ( const ::rtl::OUString* pName = aNames.getConstArray(); + pName != aNames.getConstArray() + aNames.getLength(); + ++pName, ++pHandle, ++pProperty + ) + { + *pHandle = rPropInfo.getHandleByName( *pName ); + if ( *pHandle != -1 ) + continue; + + // there's a property requested which we do not know + if ( m_bAutoAddProperties ) + { + // add the property + sal_Int16 nAttributes = PropertyAttribute::BOUND | PropertyAttribute::REMOVEABLE | PropertyAttribute::MAYBEDEFAULT; + addProperty( *pName, nAttributes, pProperty->Value ); + // rPropInfo is invalid, refetch + rPropInfo = getInfoHelper(); + *pHandle = rPropInfo.getHandleByName( *pName ); + continue; + } + + // no way out + throw UnknownPropertyException( *pName, *this ); + } + + // a sequence of values + Sequence< Any > aValues( aProperties.getLength() ); + ::std::transform( + aProperties.getConstArray(), + aProperties.getConstArray() + aProperties.getLength(), + aValues.getArray(), + ExtractPropertyValue() + ); + + setFastPropertyValues( nCount, aHandles.getArray(), aValues.getConstArray(), nCount ); + } + catch( const PropertyVetoException& ) { throw; } + catch( const IllegalArgumentException& ) { throw; } + catch( const WrappedTargetException& ) { throw; } + catch( const RuntimeException& ) { throw; } + catch( const UnknownPropertyException& ) { throw; } + catch( const Exception& ) + { + throw WrappedTargetException( ::rtl::OUString(), *this, ::cppu::getCaughtException() ); + } + } + + //-------------------------------------------------------------------- + void SAL_CALL OPropertyBag::setPropertyValues( const Sequence< PropertyValue >& _rProps ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + impl_setPropertyValues_throw( _rProps ); + } + + //-------------------------------------------------------------------- + PropertyState OPropertyBag::getPropertyStateByHandle( sal_Int32 _nHandle ) + { + // for properties which do not support the MAYBEDEFAULT attribute, don't rely on the base class, but + // assume they're always in DIRECT state. + // (Note that this probably would belong into the base class. However, this would mean we would need + // to check all existent usages of the base class, where MAYBEDEFAULT is *not* set, but + // a default is nonetheless supplied/used. This is hard to accomplish reliably, in the + // current phase. + // #i78593# / 2007-07-07 / frank.schoenheit@sun.com + + ::cppu::IPropertyArrayHelper& rPropInfo = getInfoHelper(); + sal_Int16 nAttributes(0); + OSL_VERIFY( rPropInfo.fillPropertyMembersByHandle( NULL, &nAttributes, _nHandle ) ); + if ( ( nAttributes & PropertyAttribute::MAYBEDEFAULT ) == 0 ) + return PropertyState_DIRECT_VALUE; + + return OPropertyBag_PBase::getPropertyStateByHandle( _nHandle ); + } + + //-------------------------------------------------------------------- + Any OPropertyBag::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const + { + Any aDefault; + m_aDynamicProperties.getPropertyDefaultByHandle( _nHandle, aDefault ); + return aDefault; + } + +//........................................................................ +} // namespace comphelper +//........................................................................ + diff --git a/comphelper/source/property/opropertybag.hxx b/comphelper/source/property/opropertybag.hxx new file mode 100644 index 000000000000..3b9549f7c023 --- /dev/null +++ b/comphelper/source/property/opropertybag.hxx @@ -0,0 +1,242 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef COMPHELPER_OPROPERTYBAG_HXX +#define COMPHELPER_OPROPERTYBAG_HXX + +/** === begin UNO includes === **/ +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyContainer.hpp> +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/container/XSet.hpp> +/** === end UNO includes === **/ + +#include <cppuhelper/implbase6.hxx> +#include <comphelper/propstate.hxx> +#include <comphelper/broadcasthelper.hxx> +#include <comphelper/propertybag.hxx> +#include <comphelper/componentcontext.hxx> +#include <comphelper/uno3.hxx> + +#include <map> +#include <set> +#include <memory> + +//........................................................................ +namespace comphelper +{ +//........................................................................ + + struct SAL_DLLPRIVATE UnoTypeLess : public ::std::unary_function< ::com::sun::star::uno::Type, bool > + { + inline bool operator()( const ::com::sun::star::uno::Type& _rLHS, const ::com::sun::star::uno::Type& _rRHS ) const + { + return rtl_ustr_compare( + _rLHS.getTypeLibType()->pTypeName->buffer, + _rRHS.getTypeLibType()->pTypeName->buffer + ) < 0; + } + }; + + typedef ::std::map< sal_Int32, ::com::sun::star::uno::Any > MapInt2Any; + typedef ::std::set< ::com::sun::star::uno::Type, UnoTypeLess > TypeBag; + + //==================================================================== + //= OPropertyBag + //==================================================================== + typedef ::cppu::WeakAggImplHelper6 < ::com::sun::star::beans::XPropertyContainer + , ::com::sun::star::beans::XPropertyAccess + , ::com::sun::star::util::XModifiable + , ::com::sun::star::lang::XServiceInfo + , ::com::sun::star::lang::XInitialization + , ::com::sun::star::container::XSet + > OPropertyBag_Base; + typedef ::comphelper::OPropertyStateHelper OPropertyBag_PBase; + + class OPropertyBag :public ::comphelper::OMutexAndBroadcastHelper // must be before OPropertyBag_PBase + ,public OPropertyBag_PBase + ,public OPropertyBag_Base + ,public ::cppu::IEventNotificationHook + { + private: + ::comphelper::ComponentContext + m_aContext; + + /// our IPropertyArrayHelper implementation + ::std::auto_ptr< ::cppu::OPropertyArrayHelper > + m_pArrayHelper; + ::comphelper::PropertyBag + m_aDynamicProperties; + /// set of allowed property types + TypeBag m_aAllowedTypes; + /// should we automatically add properties which are tried to set, if they don't exist previously? + bool m_bAutoAddProperties; + + /// for notification + ::cppu::OInterfaceContainerHelper m_NotifyListeners; + /// modify flag + bool m_isModified; + + public: + OPropertyBag( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& _rxContext ); + + // XServiceInfo - static versions + static ::com::sun::star::uno::Sequence< ::rtl::OUString > getSupportedServiceNames_static(void) throw( ::com::sun::star::uno::RuntimeException ); + static ::rtl::OUString getImplementationName_static(void) throw( ::com::sun::star::uno::RuntimeException ); + static ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > + SAL_CALL Create(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >&); + + protected: + virtual ~OPropertyBag(); + DECLARE_XINTERFACE() + DECLARE_XTYPEPROVIDER() + + /** === begin UNO interface implementations == **/ + // XInitialization + virtual void SAL_CALL initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (::com::sun::star::uno::RuntimeException); + + // XModifiable: + virtual ::sal_Bool SAL_CALL isModified( ) + throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setModified( ::sal_Bool bModified ) + throw (::com::sun::star::beans::PropertyVetoException, + ::com::sun::star::uno::RuntimeException); + + // XModifyBroadcaster + virtual void SAL_CALL addModifyListener( + const ::com::sun::star::uno::Reference< + ::com::sun::star::util::XModifyListener > & xListener) + throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeModifyListener( + const ::com::sun::star::uno::Reference< + ::com::sun::star::util::XModifyListener > & xListener) + throw (::com::sun::star::uno::RuntimeException); + + // XPropertyContainer + virtual void SAL_CALL addProperty( const ::rtl::OUString& Name, ::sal_Int16 Attributes, const ::com::sun::star::uno::Any& DefaultValue ) throw (::com::sun::star::beans::PropertyExistException, ::com::sun::star::beans::IllegalTypeException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeProperty( const ::rtl::OUString& Name ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::NotRemoveableException, ::com::sun::star::uno::RuntimeException); + + // XPropertyAccess + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getPropertyValues( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setPropertyValues( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aProps ) 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); + + // XPropertySet + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw(::com::sun::star::uno::RuntimeException); + + // XSet + virtual ::sal_Bool SAL_CALL has( const ::com::sun::star::uno::Any& aElement ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL insert( const ::com::sun::star::uno::Any& aElement ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::ElementExistException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL remove( const ::com::sun::star::uno::Any& aElement ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException); + + // XEnumerationAccess (base of XSet) + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL createEnumeration( ) throw (::com::sun::star::uno::RuntimeException); + + // XElementAccess (basf of XEnumerationAccess + virtual ::com::sun::star::uno::Type SAL_CALL getElementType( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL hasElements( ) throw (::com::sun::star::uno::RuntimeException); + /** === UNO interface implementations == **/ + + // XPropertyState + virtual ::com::sun::star::uno::Any getPropertyDefaultByHandle( sal_Int32 _nHandle ) const; + + // OPropertyStateHelper + virtual ::com::sun::star::beans::PropertyState getPropertyStateByHandle( sal_Int32 _nHandle ); + + // OPropertySetHelper + virtual void SAL_CALL getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle ) const; + virtual sal_Bool SAL_CALL convertFastPropertyValue( ::com::sun::star::uno::Any & rConvertedValue, ::com::sun::star::uno::Any & rOldValue, sal_Int32 nHandle, const ::com::sun::star::uno::Any& rValue ) throw (::com::sun::star::lang::IllegalArgumentException); + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const ::com::sun::star::uno::Any& rValue ) throw (::com::sun::star::uno::Exception); + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper(); + + // IEventNotificationHook + virtual void fireEvents( + sal_Int32 * pnHandles, + sal_Int32 nCount, + sal_Bool bVetoable, + bool bIgnoreRuntimeExceptionsWhileFiring); + + void SAL_CALL setModifiedImpl( ::sal_Bool bModified, + bool bIgnoreRuntimeExceptionsWhileFiring); + + private: + /** finds a free property handle + @precond + our mutex is locked + */ + sal_Int32 findFreeHandle() const; + + /** implements the setPropertyValues method + @param _rProps + the property values to set + + @throws PropertyVetoException + if the XMultiPropertySet::setPropertyValues call does so + + @throws ::com::sun::star::lang::IllegalArgumentException + if the XMultiPropertySet::setPropertyValues call does so + + @throws ::com::sun::star::lang::WrappedTargetException + if the XMultiPropertySet::setPropertyValues call does so + + @throws ::com::sun::star::uno::RuntimeException + if the XMultiPropertySet::setPropertyValues call does so + + @throws ::com::sun::star::beans::UnknownPropertyException + if the XMultiPropertySet::setPropertyValues call does so, and <arg>_bTolerateUnknownProperties</arg> + was set to <FALSE/> + + @throws ::com::sun::star::lang::WrappedTargetException + if the XMultiPropertySet::setPropertyValues call did throw an exception not listed + above + */ + void impl_setPropertyValues_throw( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& _rProps ); + + private: + OPropertyBag(); // never implemented + OPropertyBag( const OPropertyBag& ); // never implemented + OPropertyBag& operator=( const OPropertyBag& ); // never implemented + protected: + using ::cppu::OPropertySetHelper::getPropertyValues; + using ::cppu::OPropertySetHelper::setPropertyValues; + using ::cppu::OPropertySetHelper::getFastPropertyValue; + }; + +//........................................................................ +} // namespace comphelper +//........................................................................ + +#endif // COMPHELPER_OPROPERTYBAG_HXX diff --git a/comphelper/source/property/propagg.cxx b/comphelper/source/property/propagg.cxx new file mode 100644 index 000000000000..9c2fd868d973 --- /dev/null +++ b/comphelper/source/property/propagg.cxx @@ -0,0 +1,1047 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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.getLength() > 0, "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 +//......................................................................... + diff --git a/comphelper/source/property/property.cxx b/comphelper/source/property/property.cxx new file mode 100644 index 000000000000..6ab48aa1965b --- /dev/null +++ b/comphelper/source/property/property.cxx @@ -0,0 +1,245 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" + + +#include <comphelper/property.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/types.hxx> +#include <osl/diagnose.h> + +#if OSL_DEBUG_LEVEL > 0 + #include <rtl/strbuf.hxx> + #include <cppuhelper/exc_hlp.hxx> + #include <osl/thread.h> + #include <com/sun/star/lang/XServiceInfo.hpp> + #include <typeinfo> +#endif +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/uno/genfunc.h> + +#include <algorithm> +#include <boost/bind.hpp> + +//......................................................................... +namespace comphelper +{ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::beans::XPropertySetInfo; + using ::com::sun::star::beans::Property; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::Type; + using ::com::sun::star::uno::cpp_queryInterface; + using ::com::sun::star::uno::cpp_acquire; + using ::com::sun::star::uno::cpp_release; +#if OSL_DEBUG_LEVEL > 0 + using ::com::sun::star::lang::XServiceInfo; +#endif + using ::com::sun::star::uno::UNO_QUERY; + /** === end UNO using === **/ + namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute; + +//------------------------------------------------------------------ +void copyProperties(const Reference<XPropertySet>& _rxSource, + const Reference<XPropertySet>& _rxDest) +{ + if (!_rxSource.is() || !_rxDest.is()) + { + OSL_ENSURE(sal_False, "copyProperties: invalid arguments !"); + return; + } + + Reference< XPropertySetInfo > xSourceProps = _rxSource->getPropertySetInfo(); + Reference< XPropertySetInfo > xDestProps = _rxDest->getPropertySetInfo(); + + Sequence< Property > aSourceProps = xSourceProps->getProperties(); + const Property* pSourceProps = aSourceProps.getConstArray(); + Property aDestProp; + for (sal_Int32 i=0; i<aSourceProps.getLength(); ++i, ++pSourceProps) + { + if ( xDestProps->hasPropertyByName(pSourceProps->Name) ) + { + try + { + aDestProp = xDestProps->getPropertyByName(pSourceProps->Name); + if (0 == (aDestProp.Attributes & PropertyAttribute::READONLY) ) + { + const Any aSourceValue = _rxSource->getPropertyValue(pSourceProps->Name); + if ( 0 != (aDestProp.Attributes & PropertyAttribute::MAYBEVOID) || aSourceValue.hasValue() ) + _rxDest->setPropertyValue(pSourceProps->Name, aSourceValue); + } + } + catch (Exception&) + { +#if OSL_DEBUG_LEVEL > 0 + ::rtl::OStringBuffer aBuffer; + aBuffer.append( "::comphelper::copyProperties: could not copy property '" ); + aBuffer.append( ::rtl::OString( pSourceProps->Name.getStr(), pSourceProps->Name.getLength(), RTL_TEXTENCODING_ASCII_US ) ); + aBuffer.append( "' to the destination set (a '" ); + + Reference< XServiceInfo > xSI( _rxDest, UNO_QUERY ); + if ( xSI.is() ) + { + aBuffer.append( ::rtl::OUStringToOString( xSI->getImplementationName(), osl_getThreadTextEncoding() ) ); + } + else + { + aBuffer.append( typeid( *_rxDest.get() ).name() ); + } + aBuffer.append( "' implementation).\n" ); + + Any aException( ::cppu::getCaughtException() ); + aBuffer.append( "Caught an exception of type '" ); + ::rtl::OUString sExceptionType( aException.getValueTypeName() ); + aBuffer.append( ::rtl::OString( sExceptionType.getStr(), sExceptionType.getLength(), RTL_TEXTENCODING_ASCII_US ) ); + aBuffer.append( "'" ); + + Exception aBaseException; + if ( ( aException >>= aBaseException ) && aBaseException.Message.getLength() ) + { + aBuffer.append( ", saying '" ); + aBuffer.append( ::rtl::OString( aBaseException.Message.getStr(), aBaseException.Message.getLength(), osl_getThreadTextEncoding() ) ); + aBuffer.append( "'" ); + } + aBuffer.append( "." ); + + OSL_ENSURE( sal_False, aBuffer.getStr() ); +#endif + } + } + } +} + +//------------------------------------------------------------------ +sal_Bool hasProperty(const rtl::OUString& _rName, const Reference<XPropertySet>& _rxSet) +{ + if (_rxSet.is()) + { + // XPropertySetInfoRef xInfo(rxSet->getPropertySetInfo()); + return _rxSet->getPropertySetInfo()->hasPropertyByName(_rName); + } + return sal_False; +} + +//------------------------------------------------------------------ +bool findProperty(Property& o_rProp, + Sequence<Property>& i_seqProps, + const ::rtl::OUString& i_rPropName) +{ + const Property* pAry(i_seqProps.getConstArray()); + const sal_Int32 nLen(i_seqProps.getLength()); + const Property* pRes( + std::find_if(pAry,pAry+nLen, + boost::bind(PropertyStringEqualFunctor(), + _1, + boost::cref(i_rPropName)))); + if( pRes == pAry+nLen ) + return false; + + o_rProp = *pRes; + return true; +} + +//------------------------------------------------------------------ +void RemoveProperty(Sequence<Property>& _rProps, const rtl::OUString& _rPropName) +{ + sal_Int32 nLen = _rProps.getLength(); + + // binaere Suche + const Property* pProperties = _rProps.getConstArray(); + const Property* pResult = ::std::lower_bound(pProperties, pProperties + nLen, _rPropName,PropertyStringLessFunctor()); + + // gefunden ? + if ( pResult && (pResult != pProperties + nLen) && (pResult->Name == _rPropName) ) + { + OSL_ENSURE(pResult->Name.equals(_rPropName), "::RemoveProperty Properties nicht sortiert"); + removeElementAt(_rProps, pResult - pProperties); + } +} + +//------------------------------------------------------------------ +void ModifyPropertyAttributes(Sequence<Property>& seqProps, const ::rtl::OUString& sPropName, sal_Int16 nAddAttrib, sal_Int16 nRemoveAttrib) +{ + sal_Int32 nLen = seqProps.getLength(); + + // binaere Suche + Property* pProperties = seqProps.getArray(); + Property* pResult = ::std::lower_bound(pProperties, pProperties + nLen,sPropName, PropertyStringLessFunctor()); + + // gefunden ? + if ( pResult && (pResult != pProperties + nLen) && (pResult->Name == sPropName) ) + { + pResult->Attributes |= nAddAttrib; + pResult->Attributes &= ~nRemoveAttrib; + } +} + +//------------------------------------------------------------------ +sal_Bool tryPropertyValue(Any& _rConvertedValue, Any& _rOldValue, const Any& _rValueToSet, const Any& _rCurrentValue, const Type& _rExpectedType) +{ + sal_Bool bModified(sal_False); + if (_rCurrentValue.getValue() != _rValueToSet.getValue()) + { + if ( _rValueToSet.hasValue() && ( !_rExpectedType.equals( _rValueToSet.getValueType() ) ) ) + { + _rConvertedValue = Any( NULL, _rExpectedType.getTypeLibType() ); + + if ( !uno_type_assignData( + const_cast< void* >( _rConvertedValue.getValue() ), _rConvertedValue.getValueType().getTypeLibType(), + const_cast< void* >( _rValueToSet.getValue() ), _rValueToSet.getValueType().getTypeLibType(), + reinterpret_cast< uno_QueryInterfaceFunc >( + cpp_queryInterface), + reinterpret_cast< uno_AcquireFunc >(cpp_acquire), + reinterpret_cast< uno_ReleaseFunc >(cpp_release) + ) + ) + throw starlang::IllegalArgumentException(); + } + else + _rConvertedValue = _rValueToSet; + + if ( _rCurrentValue != _rConvertedValue ) + { + _rOldValue = _rCurrentValue; + bModified = sal_True; + } + } + return bModified; +} + +//......................................................................... +} +//......................................................................... + diff --git a/comphelper/source/property/propertybag.cxx b/comphelper/source/property/propertybag.cxx new file mode 100644 index 000000000000..88f925e20db7 --- /dev/null +++ b/comphelper/source/property/propertybag.cxx @@ -0,0 +1,221 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" +#include "comphelper/propertybag.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/beans/IllegalTypeException.hpp> +#include <com/sun/star/beans/PropertyExistException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/NotRemoveableException.hpp> +/** === end UNO includes === **/ + +#include <map> + +//........................................................................ +namespace comphelper +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::Type; + using ::com::sun::star::uno::TypeClass_VOID; + using ::com::sun::star::beans::IllegalTypeException; + using ::com::sun::star::beans::PropertyExistException; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::beans::Property; + using ::com::sun::star::beans::NotRemoveableException; + using ::com::sun::star::beans::UnknownPropertyException; + /** === end UNO using === **/ + namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute; + + //==================================================================== + //= PropertyBag_Impl + //==================================================================== + typedef ::std::map< sal_Int32, Any > MapInt2Any; + struct PropertyBag_Impl + { + PropertyBag_Impl() : m_bAllowEmptyPropertyName(false) { } + MapInt2Any aDefaults; + bool m_bAllowEmptyPropertyName; + }; + + //==================================================================== + //= PropertyBag + //==================================================================== + //-------------------------------------------------------------------- + PropertyBag::PropertyBag() + :m_pImpl( new PropertyBag_Impl ) + { + } + + PropertyBag::~PropertyBag() + { + } + + //-------------------------------------------------------------------- + void PropertyBag::setAllowEmptyPropertyName( bool i_isAllowed ) + { + m_pImpl->m_bAllowEmptyPropertyName = i_isAllowed; + } + + //-------------------------------------------------------------------- + namespace + { + void lcl_checkForEmptyName( const bool _allowEmpty, const ::rtl::OUString& _name ) + { + if ( !_allowEmpty && !_name.getLength() ) + throw IllegalArgumentException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "The property name must not be empty." ) ), + // TODO: resource + NULL, + 1 + ); + } + + void lcl_checkNameAndHandle( const ::rtl::OUString& _name, const sal_Int32 _handle, const PropertyBag& _container ) + { + if ( _container.hasPropertyByName( _name ) || _container.hasPropertyByHandle( _handle ) ) + throw PropertyExistException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Property name or handle already used." ) ), + // TODO: resource + NULL ); + + } + } + + //-------------------------------------------------------------------- + void PropertyBag::addVoidProperty( const ::rtl::OUString& _rName, const Type& _rType, sal_Int32 _nHandle, sal_Int32 _nAttributes ) + { + if ( _rType.getTypeClass() == TypeClass_VOID ) + throw IllegalArgumentException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Illegal property type: VOID" ) ), + // TODO: resource + NULL, + 1 + ); + + // check name/handle sanity + lcl_checkForEmptyName( m_pImpl->m_bAllowEmptyPropertyName, _rName ); + lcl_checkNameAndHandle( _rName, _nHandle, *this ); + + // register the property + OSL_ENSURE( _nAttributes & PropertyAttribute::MAYBEVOID, "PropertyBag::addVoidProperty: this is for default-void properties only!" ); + registerPropertyNoMember( _rName, _nHandle, _nAttributes | PropertyAttribute::MAYBEVOID, _rType, NULL ); + + // remember the default + m_pImpl->aDefaults.insert( MapInt2Any::value_type( _nHandle, Any() ) ); + } + + //-------------------------------------------------------------------- + void PropertyBag::addProperty( const ::rtl::OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes, const Any& _rInitialValue ) + { + // check type sanity + Type aPropertyType = _rInitialValue.getValueType(); + if ( aPropertyType.getTypeClass() == TypeClass_VOID ) + throw IllegalTypeException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "The initial value must be non-NULL to determine the property type." ) ), + // TODO: resource + NULL ); + + // check name/handle sanity + lcl_checkForEmptyName( m_pImpl->m_bAllowEmptyPropertyName, _rName ); + lcl_checkNameAndHandle( _rName, _nHandle, *this ); + + // register the property + registerPropertyNoMember( _rName, _nHandle, _nAttributes, aPropertyType, + _rInitialValue.hasValue() ? _rInitialValue.getValue() : NULL ); + + // remember the default + m_pImpl->aDefaults.insert( MapInt2Any::value_type( _nHandle, _rInitialValue ) ); + } + + //-------------------------------------------------------------------- + void PropertyBag::removeProperty( const ::rtl::OUString& _rName ) + { + const Property& rProp = getProperty( _rName ); + // will throw an UnknownPropertyException if necessary + if ( ( rProp.Attributes & PropertyAttribute::REMOVEABLE ) == 0 ) + throw NotRemoveableException( ::rtl::OUString(), NULL ); + const sal_Int32 nHandle = rProp.Handle; + + revokeProperty( nHandle ); + + m_pImpl->aDefaults.erase( nHandle ); + } + + //-------------------------------------------------------------------- + void PropertyBag::getFastPropertyValue( sal_Int32 _nHandle, Any& _out_rValue ) const + { + if ( !hasPropertyByHandle( _nHandle ) ) + throw UnknownPropertyException(); + + OPropertyContainerHelper::getFastPropertyValue( _out_rValue, _nHandle ); + } + + //-------------------------------------------------------------------- + bool PropertyBag::convertFastPropertyValue( sal_Int32 _nHandle, const Any& _rNewValue, Any& _out_rConvertedValue, Any& _out_rCurrentValue ) const + { + if ( !hasPropertyByHandle( _nHandle ) ) + throw UnknownPropertyException(); + + return const_cast< PropertyBag* >( this )->OPropertyContainerHelper::convertFastPropertyValue( + _out_rConvertedValue, _out_rCurrentValue, _nHandle, _rNewValue ); + } + + //-------------------------------------------------------------------- + void PropertyBag::setFastPropertyValue( sal_Int32 _nHandle, const Any& _rValue ) + { + if ( !hasPropertyByHandle( _nHandle ) ) + throw UnknownPropertyException(); + + OPropertyContainerHelper::setFastPropertyValue( _nHandle, _rValue ); + } + + //-------------------------------------------------------------------- + void PropertyBag::getPropertyDefaultByHandle( sal_Int32 _nHandle, Any& _out_rValue ) const + { + if ( !hasPropertyByHandle( _nHandle ) ) + throw UnknownPropertyException(); + + MapInt2Any::const_iterator pos = m_pImpl->aDefaults.find( _nHandle ); + OSL_ENSURE( pos != m_pImpl->aDefaults.end(), "PropertyBag::getPropertyDefaultByHandle: inconsistency!" ); + if ( pos != m_pImpl->aDefaults.end() ) + _out_rValue = pos->second; + else + _out_rValue.clear(); + } + + +//........................................................................ +} // namespace comphelper +//........................................................................ + diff --git a/comphelper/source/property/propertycontainer.cxx b/comphelper/source/property/propertycontainer.cxx new file mode 100644 index 000000000000..c385107733fe --- /dev/null +++ b/comphelper/source/property/propertycontainer.cxx @@ -0,0 +1,105 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" +#include <comphelper/propertycontainer.hxx> +#include <comphelper/property.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <osl/diagnose.h> +#include <uno/data.h> +#include <com/sun/star/uno/genfunc.h> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <rtl/ustrbuf.hxx> + +#include <algorithm> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +//========================================================================== +//= OPropertyContainer +//========================================================================== +//-------------------------------------------------------------------------- +OPropertyContainer::OPropertyContainer(::cppu::OBroadcastHelper& _rBHelper) + :OPropertyContainer_Base(_rBHelper) +{ +} + +// ------------------------------------------------------------------------- +OPropertyContainer::~OPropertyContainer() +{ +} + +//-------------------------------------------------------------------------- +Sequence< Type > SAL_CALL OPropertyContainer::getTypes() throw (RuntimeException) +{ + // just the types from our one and only base class + ::cppu::OTypeCollection aTypes( + ::getCppuType( static_cast< Reference< XPropertySet >* >(NULL)), + ::getCppuType( static_cast< Reference< XFastPropertySet >* >(NULL)), + ::getCppuType( static_cast< Reference< XMultiPropertySet >* >(NULL)) + ); + return aTypes.getTypes(); +} + +//-------------------------------------------------------------------------- +void SAL_CALL OPropertyContainer::setFastPropertyValue( sal_Int32 nHandle, const Any& rValue ) throw ( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + OPropertyContainer_Base::setFastPropertyValue( nHandle, rValue ); +} + +//-------------------------------------------------------------------------- +sal_Bool OPropertyContainer::convertFastPropertyValue( + Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw (IllegalArgumentException) +{ + return OPropertyContainerHelper::convertFastPropertyValue( _rConvertedValue, _rOldValue, _nHandle, _rValue ); +} + +//-------------------------------------------------------------------------- +void OPropertyContainer::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue) throw (Exception) +{ + OPropertyContainerHelper::setFastPropertyValue( _nHandle, _rValue ); +} + +//-------------------------------------------------------------------------- +void OPropertyContainer::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const +{ + OPropertyContainerHelper::getFastPropertyValue( _rValue, _nHandle ); +} + +//......................................................................... +} // namespace comphelper +//......................................................................... + + diff --git a/comphelper/source/property/propertycontainerhelper.cxx b/comphelper/source/property/propertycontainerhelper.cxx new file mode 100644 index 000000000000..0b420a3eebd8 --- /dev/null +++ b/comphelper/source/property/propertycontainerhelper.cxx @@ -0,0 +1,552 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" +#include <comphelper/propertycontainerhelper.hxx> +#include <comphelper/property.hxx> +#include <osl/diagnose.h> +#include <uno/data.h> +#include <com/sun/star/uno/genfunc.h> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <rtl/ustrbuf.hxx> + +#include <algorithm> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +//-------------------------------------------------------------------------- +namespace +{ + // comparing two property descriptions + struct PropertyDescriptionCompareByHandle : public ::std::binary_function< PropertyDescription, PropertyDescription, bool > + { + bool operator() (const PropertyDescription& x, const PropertyDescription& y) const + { + return x.aProperty.Handle < y.aProperty.Handle; + } + }; + // comparing two property descriptions + struct PropertyDescriptionHandleCompare : public ::std::binary_function< PropertyDescription, sal_Int32, bool > + { + bool operator() (const PropertyDescription& x, const sal_Int32& y) const + { + return x.aProperty.Handle < y; + } + bool operator() (const sal_Int32& x, const PropertyDescription& y) const + { + return x < y.aProperty.Handle; + } + }; + // comparing two property descriptions (by name) + struct PropertyDescriptionNameMatch : public ::std::unary_function< PropertyDescription, bool > + { + ::rtl::OUString m_rCompare; + PropertyDescriptionNameMatch( const ::rtl::OUString& _rCompare ) : m_rCompare( _rCompare ) { } + + bool operator() (const PropertyDescription& x ) const + { + return x.aProperty.Name.equals(m_rCompare); + } + }; +} + +//========================================================================== +//= OPropertyContainerHelper +//========================================================================== +//-------------------------------------------------------------------------- +OPropertyContainerHelper::OPropertyContainerHelper() + :m_bUnused(sal_False) +{ +} + +// ------------------------------------------------------------------------- +OPropertyContainerHelper::~OPropertyContainerHelper() +{ +} + +//-------------------------------------------------------------------------- +void OPropertyContainerHelper::registerProperty(const ::rtl::OUString& _rName, sal_Int32 _nHandle, + sal_Int32 _nAttributes, void* _pPointerToMember, const Type& _rMemberType) +{ + OSL_ENSURE((_nAttributes & PropertyAttribute::MAYBEVOID) == 0, + "OPropertyContainerHelper::registerProperty: don't use this for properties which may be void ! There is a method called \"registerMayBeVoidProperty\" for this !"); + OSL_ENSURE(!_rMemberType.equals(::getCppuType(static_cast< Any* >(NULL))), + "OPropertyContainerHelper::registerProperty: don't give my the type of an uno::Any ! Really can't handle this !"); + OSL_ENSURE(_pPointerToMember, + "OPropertyContainerHelper::registerProperty: you gave me nonsense : the pointer must be non-NULL"); + + PropertyDescription aNewProp; + aNewProp.aProperty = Property( _rName, _nHandle, _rMemberType, (sal_Int16)_nAttributes ); + aNewProp.eLocated = PropertyDescription::ltDerivedClassRealType; + aNewProp.aLocation.pDerivedClassMember = _pPointerToMember; + + implPushBackProperty(aNewProp); +} + +//-------------------------------------------------------------------------- +void OPropertyContainerHelper::revokeProperty( sal_Int32 _nHandle ) +{ + PropertiesIterator aPos = searchHandle( _nHandle ); + if ( aPos == m_aProperties.end() ) + throw UnknownPropertyException(); + m_aProperties.erase( aPos ); +} + +//-------------------------------------------------------------------------- +void OPropertyContainerHelper::registerMayBeVoidProperty(const ::rtl::OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes, + Any* _pPointerToMember, const Type& _rExpectedType) +{ + OSL_ENSURE((_nAttributes & PropertyAttribute::MAYBEVOID) != 0, + "OPropertyContainerHelper::registerMayBeVoidProperty: why calling this when the attributes say nothing about may-be-void ?"); + OSL_ENSURE(!_rExpectedType.equals(::getCppuType(static_cast< Any* >(NULL))), + "OPropertyContainerHelper::registerMayBeVoidProperty: don't give my the type of an uno::Any ! Really can't handle this !"); + OSL_ENSURE(_pPointerToMember, + "OPropertyContainerHelper::registerMayBeVoidProperty: you gave me nonsense : the pointer must be non-NULL"); + + _nAttributes |= PropertyAttribute::MAYBEVOID; + + PropertyDescription aNewProp; + aNewProp.aProperty = Property( _rName, _nHandle, _rExpectedType, (sal_Int16)_nAttributes ); + aNewProp.eLocated = PropertyDescription::ltDerivedClassAnyType; + aNewProp.aLocation.pDerivedClassMember = _pPointerToMember; + + implPushBackProperty(aNewProp); +} + + +//-------------------------------------------------------------------------- +void OPropertyContainerHelper::registerPropertyNoMember(const ::rtl::OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes, + const Type& _rType, const void* _pInitialValue) +{ + OSL_ENSURE(!_rType.equals(::getCppuType(static_cast< Any* >(NULL))), + "OPropertyContainerHelper::registerPropertyNoMember : don't give my the type of an uno::Any ! Really can't handle this !"); + OSL_ENSURE(_pInitialValue || ((_nAttributes & PropertyAttribute::MAYBEVOID) != 0), + "OPropertyContainerHelper::registerPropertyNoMember : you should not ommit the initial value if the property can't be void ! This will definitivly crash later !"); + + PropertyDescription aNewProp; + aNewProp.aProperty = Property( _rName, _nHandle, _rType, (sal_Int16)_nAttributes ); + aNewProp.eLocated = PropertyDescription::ltHoldMyself; + aNewProp.aLocation.nOwnClassVectorIndex = m_aHoldProperties.size(); + if (_pInitialValue) + m_aHoldProperties.push_back(Any(_pInitialValue, _rType)); + else + m_aHoldProperties.push_back(Any()); + + implPushBackProperty(aNewProp); +} + +//-------------------------------------------------------------------------- +sal_Bool OPropertyContainerHelper::isRegisteredProperty( sal_Int32 _nHandle ) const +{ + return const_cast< OPropertyContainerHelper* >( this )->searchHandle( _nHandle ) != m_aProperties.end(); +} + +//-------------------------------------------------------------------------- +sal_Bool OPropertyContainerHelper::isRegisteredProperty( const ::rtl::OUString& _rName ) const +{ + // TODO: the current structure is from a time where properties were + // static, not dynamic. Since we allow that properties are also dynamic, + // i.e. registered and revoked even though the XPropertySet has already been + // accessed, a vector is not really the best data structure anymore ... + + ConstPropertiesIterator pos = ::std::find_if( + m_aProperties.begin(), + m_aProperties.end(), + PropertyDescriptionNameMatch( _rName ) + ); + return pos != m_aProperties.end(); +} + +//-------------------------------------------------------------------------- +namespace +{ + struct ComparePropertyWithHandle + { + bool operator()( const PropertyDescription& _rLHS, sal_Int32 _nRHS ) const + { + return _rLHS.aProperty.Handle < _nRHS; + } + bool operator()( sal_Int32 _nLHS, const PropertyDescription& _rRHS ) const + { + return _nLHS < _rRHS.aProperty.Handle; + } + }; +} + +//-------------------------------------------------------------------------- +void OPropertyContainerHelper::implPushBackProperty(const PropertyDescription& _rProp) +{ +#ifdef DBG_UTIL + for ( PropertiesIterator checkConflicts = m_aProperties.begin(); + checkConflicts != m_aProperties.end(); + ++checkConflicts + ) + { + OSL_ENSURE(checkConflicts->aProperty.Name != _rProp.aProperty.Name, "OPropertyContainerHelper::implPushBackProperty: name already exists!"); + OSL_ENSURE(checkConflicts->aProperty.Handle != _rProp.aProperty.Handle, "OPropertyContainerHelper::implPushBackProperty: handle already exists!"); + } +#endif + + PropertiesIterator pos = ::std::lower_bound( + m_aProperties.begin(), m_aProperties.end(), + _rProp.aProperty.Handle, ComparePropertyWithHandle() ); + + m_aProperties.insert( pos, _rProp ); +} + +//-------------------------------------------------------------------------- +namespace +{ + void lcl_throwIllegalPropertyValueTypeException( const PropertyDescription& _rProperty, const Any& _rValue ) + { + ::rtl::OUStringBuffer aErrorMessage; + aErrorMessage.appendAscii( "The given value cannot be converted to the required property type." ); + aErrorMessage.appendAscii( "\n(property name \"" ); + aErrorMessage.append( _rProperty.aProperty.Name ); + aErrorMessage.appendAscii( "\", found value type \"" ); + aErrorMessage.append( _rValue.getValueType().getTypeName() ); + aErrorMessage.appendAscii( "\", required property type \"" ); + aErrorMessage.append( _rProperty.aProperty.Type.getTypeName() ); + aErrorMessage.appendAscii( "\")" ); + throw IllegalArgumentException( aErrorMessage.makeStringAndClear(), NULL, 4 ); + } +} + +//-------------------------------------------------------------------------- +sal_Bool OPropertyContainerHelper::convertFastPropertyValue( + Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) SAL_THROW( (IllegalArgumentException) ) +{ + sal_Bool bModified = sal_False; + + // get the property somebody is asking for + PropertiesIterator aPos = searchHandle(_nHandle); + if (aPos == m_aProperties.end()) + { + OSL_ENSURE( false, "OPropertyContainerHelper::convertFastPropertyValue: unknown handle!" ); + // should not happen if the derived class has built a correct property set info helper to be used by + // our base class OPropertySetHelper + return bModified; + } + + switch (aPos->eLocated) + { + // similar handling for the two cases where the value is stored in an any + case PropertyDescription::ltHoldMyself: + case PropertyDescription::ltDerivedClassAnyType: + { + sal_Bool bMayBeVoid = ((aPos->aProperty.Attributes & PropertyAttribute::MAYBEVOID) != 0); + + + // non modifiable version of the value-to-be-set + Any aNewRequestedValue( _rValue ); + + // normalization + // (#102329# - 2002-08-14 - fs@openoffice.org) + // (#i29490# - 2004-06-16 - fs@openoffice.org) + if ( !aNewRequestedValue.getValueType().equals( aPos->aProperty.Type ) ) + { // the actually given value is not of the same type as the one required + Any aProperlyTyped( NULL, aPos->aProperty.Type.getTypeLibType() ); + + if ( uno_type_assignData( + const_cast< void* >( aProperlyTyped.getValue() ), aProperlyTyped.getValueType().getTypeLibType(), + const_cast< void* >( aNewRequestedValue.getValue() ), aNewRequestedValue.getValueType().getTypeLibType(), + reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ), + reinterpret_cast< uno_AcquireFunc >( cpp_acquire ), + reinterpret_cast< uno_ReleaseFunc >( cpp_release ) + ) + ) + { + // we were able to query the given XInterface-derivee for the interface + // which is required for this property + aNewRequestedValue = aProperlyTyped; + } + } + + // argument check + if ( ! ( (bMayBeVoid && !aNewRequestedValue.hasValue()) // void is allowed if the attribute says so + || (aNewRequestedValue.getValueType().equals(aPos->aProperty.Type)) // else the types have to be equal + ) + ) + { + lcl_throwIllegalPropertyValueTypeException( *aPos, _rValue ); + } + + Any* pPropContainer = NULL; + // the pointer to the any which holds the property value, no matter if located in the derived clas + // or in out vector + + if (PropertyDescription::ltHoldMyself == aPos->eLocated) + { + OSL_ENSURE(aPos->aLocation.nOwnClassVectorIndex < (sal_Int32)m_aHoldProperties.size(), + "OPropertyContainerHelper::convertFastPropertyValue: invalid position !"); + PropertyContainerIterator aIter = m_aHoldProperties.begin() + aPos->aLocation.nOwnClassVectorIndex; + pPropContainer = &(*aIter); + } + else + pPropContainer = reinterpret_cast<Any*>(aPos->aLocation.pDerivedClassMember); + + // check if the new value differs from the current one + if (!pPropContainer->hasValue() || !aNewRequestedValue.hasValue()) + bModified = pPropContainer->hasValue() != aNewRequestedValue.hasValue(); + else + bModified = !uno_type_equalData( + const_cast< void* >( pPropContainer->getValue() ), aPos->aProperty.Type.getTypeLibType(), + const_cast< void* >( aNewRequestedValue.getValue() ), aPos->aProperty.Type.getTypeLibType(), + reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ), + reinterpret_cast< uno_ReleaseFunc >( cpp_release ) + ); + + if (bModified) + { + _rOldValue = *pPropContainer; + _rConvertedValue = aNewRequestedValue; + } + } + break; + case PropertyDescription::ltDerivedClassRealType: + // let the UNO runtime library do any possible conversion + // this may include a change of the type - for instance, if a LONG is required, + // but a short is given, then this is valid, as it can be converted without any potential + // data loss + + Any aProperlyTyped; + const Any* pNewValue = &_rValue; + + if (!_rValue.getValueType().equals(aPos->aProperty.Type)) + { + sal_Bool bConverted = sal_False; + + // a temporary any of the correct (required) type + aProperlyTyped = Any( NULL, aPos->aProperty.Type.getTypeLibType() ); + // (need this as we do not want to overwrite the derived class member here) + + if ( uno_type_assignData( + const_cast<void*>(aProperlyTyped.getValue()), aProperlyTyped.getValueType().getTypeLibType(), + const_cast<void*>(_rValue.getValue()), _rValue.getValueType().getTypeLibType(), + reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ), + reinterpret_cast< uno_AcquireFunc >( cpp_acquire ), + reinterpret_cast< uno_ReleaseFunc >( cpp_release ) + ) + ) + { + // could query for the requested interface + bConverted = sal_True; + pNewValue = &aProperlyTyped; + } + + if ( !bConverted ) + lcl_throwIllegalPropertyValueTypeException( *aPos, _rValue ); + } + + // from here on, we should have the proper type + OSL_ENSURE( pNewValue->getValueType() == aPos->aProperty.Type, + "OPropertyContainerHelper::convertFastPropertyValue: conversion failed!" ); + bModified = !uno_type_equalData( + aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type.getTypeLibType(), + const_cast<void*>(pNewValue->getValue()), aPos->aProperty.Type.getTypeLibType(), + reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ), + reinterpret_cast< uno_ReleaseFunc >( cpp_release ) + ); + + if (bModified) + { + _rOldValue.setValue(aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type); + _rConvertedValue = *pNewValue; + } + break; + } + + return bModified; +} + +//-------------------------------------------------------------------------- +void OPropertyContainerHelper::setFastPropertyValue(sal_Int32 _nHandle, const Any& _rValue) SAL_THROW( (Exception) ) +{ + // get the property somebody is asking for + PropertiesIterator aPos = searchHandle(_nHandle); + if (aPos == m_aProperties.end()) + { + OSL_ENSURE( false, "OPropertyContainerHelper::setFastPropertyValue: unknown handle!" ); + // should not happen if the derived class has built a correct property set info helper to be used by + // our base class OPropertySetHelper + return; + } + + switch (aPos->eLocated) + { + case PropertyDescription::ltHoldMyself: + m_aHoldProperties[aPos->aLocation.nOwnClassVectorIndex] = _rValue; + break; + + case PropertyDescription::ltDerivedClassAnyType: + *reinterpret_cast< Any* >(aPos->aLocation.pDerivedClassMember) = _rValue; + break; + + case PropertyDescription::ltDerivedClassRealType: +#if OSL_DEBUG_LEVEL > 0 + sal_Bool bSuccess = +#endif + // copy the data from the to-be-set value + uno_type_assignData( + aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type.getTypeLibType(), + const_cast< void* >( _rValue.getValue() ), _rValue.getValueType().getTypeLibType(), + reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ), + reinterpret_cast< uno_AcquireFunc >( cpp_acquire ), + reinterpret_cast< uno_ReleaseFunc >( cpp_release ) ); + + OSL_ENSURE( bSuccess, + "OPropertyContainerHelper::setFastPropertyValue: ooops .... the value could not be assigned!"); + + break; + } +} + +//-------------------------------------------------------------------------- +void OPropertyContainerHelper::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const +{ + // get the property somebody is asking for + PropertiesIterator aPos = const_cast<OPropertyContainerHelper*>(this)->searchHandle(_nHandle); + if (aPos == m_aProperties.end()) + { + OSL_ENSURE( false, "OPropertyContainerHelper::getFastPropertyValue: unknown handle!" ); + // should not happen if the derived class has built a correct property set info helper to be used by + // our base class OPropertySetHelper + return; + } + + switch (aPos->eLocated) + { + case PropertyDescription::ltHoldMyself: + OSL_ENSURE(aPos->aLocation.nOwnClassVectorIndex < (sal_Int32)m_aHoldProperties.size(), + "OPropertyContainerHelper::convertFastPropertyValue: invalid position !"); + _rValue = m_aHoldProperties[aPos->aLocation.nOwnClassVectorIndex]; + break; + case PropertyDescription::ltDerivedClassAnyType: + _rValue = *reinterpret_cast<Any*>(aPos->aLocation.pDerivedClassMember); + break; + case PropertyDescription::ltDerivedClassRealType: + _rValue.setValue(aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type); + break; + } +} + +//-------------------------------------------------------------------------- +OPropertyContainerHelper::PropertiesIterator OPropertyContainerHelper::searchHandle(sal_Int32 _nHandle) +{ + // search a lower bound + PropertiesIterator aLowerBound = ::std::lower_bound( + m_aProperties.begin(), + m_aProperties.end(), + _nHandle, + PropertyDescriptionHandleCompare()); + + // check for identity + if ((aLowerBound != m_aProperties.end()) && aLowerBound->aProperty.Handle != _nHandle) + aLowerBound = m_aProperties.end(); + + return aLowerBound; +} + +//-------------------------------------------------------------------------- +const Property& OPropertyContainerHelper::getProperty( const ::rtl::OUString& _rName ) const +{ + ConstPropertiesIterator pos = ::std::find_if( + m_aProperties.begin(), + m_aProperties.end(), + PropertyDescriptionNameMatch( _rName ) + ); + if ( pos == m_aProperties.end() ) + throw UnknownPropertyException( _rName, NULL ); + + return pos->aProperty; +} + +//-------------------------------------------------------------------------- +void OPropertyContainerHelper::modifyAttributes(sal_Int32 _nHandle, sal_Int32 _nAddAttrib, sal_Int32 _nRemoveAttrib) +{ + // get the property somebody is asking for + PropertiesIterator aPos = searchHandle(_nHandle); + if (aPos == m_aProperties.end()) + { + OSL_ENSURE( false, "OPropertyContainerHelper::modifyAttributes: unknown handle!" ); + // should not happen if the derived class has built a correct property set info helper to be used by + // our base class OPropertySetHelper + return; + } + aPos->aProperty.Handle |= _nAddAttrib; + aPos->aProperty.Handle &= ~_nRemoveAttrib; +} + +//-------------------------------------------------------------------------- +void OPropertyContainerHelper::describeProperties(Sequence< Property >& _rProps) const +{ + Sequence< Property > aOwnProps(m_aProperties.size()); + Property* pOwnProps = aOwnProps.getArray(); + + for ( ConstPropertiesIterator aLoop = m_aProperties.begin(); + aLoop != m_aProperties.end(); + ++aLoop, ++pOwnProps + ) + { + pOwnProps->Name = aLoop->aProperty.Name; + pOwnProps->Handle = aLoop->aProperty.Handle; + pOwnProps->Attributes = (sal_Int16)aLoop->aProperty.Attributes; + pOwnProps->Type = aLoop->aProperty.Type; + } + + // as our property vector is sorted by handles, not by name, we have to sort aOwnProps + ::std::sort(aOwnProps.getArray(), aOwnProps.getArray() + aOwnProps.getLength(), PropertyCompareByName()); + + // unfortunally the STL merge function does not allow the output range to overlap one of the input ranges, + // so we need an extra sequence + Sequence< Property > aOutput; + aOutput.realloc(_rProps.getLength() + aOwnProps.getLength()); + // do the merge + ::std::merge( _rProps.getConstArray(), _rProps.getConstArray() + _rProps.getLength(), // input 1 + aOwnProps.getConstArray(), aOwnProps.getConstArray() + aOwnProps.getLength(), // input 2 + aOutput.getArray(), // output + PropertyCompareByName() // compare operator + ); + + // copy the output + _rProps = aOutput; +} + +//......................................................................... +} // namespace comphelper +//......................................................................... + + diff --git a/comphelper/source/property/propertysethelper.cxx b/comphelper/source/property/propertysethelper.cxx new file mode 100644 index 000000000000..9d2abf784c1b --- /dev/null +++ b/comphelper/source/property/propertysethelper.cxx @@ -0,0 +1,328 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" + +#include "comphelper/propertysetinfo.hxx" +#include "comphelper/propertysethelper.hxx" + +/////////////////////////////////////////////////////////////////////// + +using namespace ::rtl; +using namespace ::comphelper; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; + +namespace comphelper +{ +class PropertySetHelperImpl +{ +public: + PropertyMapEntry* find( const OUString& aName ) const throw(); + + PropertySetInfo* mpInfo; +}; +} + +PropertyMapEntry* PropertySetHelperImpl::find( const OUString& aName ) const throw() +{ + PropertyMap::const_iterator aIter = mpInfo->getPropertyMap()->find( aName ); + + if( mpInfo->getPropertyMap()->end() != aIter ) + { + return (*aIter).second; + } + else + { + return NULL; + } +} + +/////////////////////////////////////////////////////////////////////// + +PropertySetHelper::PropertySetHelper( ) +{ + mp = new PropertySetHelperImpl; + mp->mpInfo = new PropertySetInfo; + mp->mpInfo->acquire(); +} + +PropertySetHelper::PropertySetHelper( comphelper::PropertySetInfo* pInfo ) throw() +{ + mp = new PropertySetHelperImpl; + mp->mpInfo = pInfo; + pInfo->acquire(); +} + +PropertySetHelper::PropertySetHelper( comphelper::PropertySetInfo* pInfo, __sal_NoAcquire ) throw() +{ + mp = new PropertySetHelperImpl; + mp->mpInfo = pInfo; +} + +PropertySetHelper::~PropertySetHelper() throw() +{ + mp->mpInfo->release(); + delete mp; +} + +void PropertySetHelper::setInfo( comphelper::PropertySetInfo* pInfo ) throw() +{ + OSL_ENSURE( pInfo != NULL, "need pInfo" ); + OSL_ENSURE( mp->mpInfo != NULL, "where's the old pInfo?" ); + + mp->mpInfo->release(); + mp->mpInfo = pInfo; + mp->mpInfo->acquire(); +} + +// XPropertySet +Reference< XPropertySetInfo > SAL_CALL PropertySetHelper::getPropertySetInfo( ) throw(RuntimeException) +{ + return mp->mpInfo; +} + +void SAL_CALL PropertySetHelper::setPropertyValue( const ::rtl::OUString& aPropertyName, const Any& aValue ) throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + PropertyMapEntry* aEntries[2]; + aEntries[0] = mp->find( aPropertyName ); + + if( NULL == aEntries[0] ) + throw UnknownPropertyException( aPropertyName, static_cast< XPropertySet* >( this ) ); + + aEntries[1] = NULL; + + _setPropertyValues( (const PropertyMapEntry**)aEntries, &aValue ); +} + +Any SAL_CALL PropertySetHelper::getPropertyValue( const ::rtl::OUString& PropertyName ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + PropertyMapEntry* aEntries[2]; + aEntries[0] = mp->find( PropertyName ); + + if( NULL == aEntries[0] ) + throw UnknownPropertyException( PropertyName, static_cast< XPropertySet* >( this ) ); + + aEntries[1] = NULL; + + Any aAny; + _getPropertyValues( (const PropertyMapEntry**)aEntries, &aAny ); + + return aAny; +} + +void SAL_CALL PropertySetHelper::addPropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +void SAL_CALL PropertySetHelper::removePropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +void SAL_CALL PropertySetHelper::addVetoableChangeListener( const ::rtl::OUString&, const Reference< XVetoableChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +void SAL_CALL PropertySetHelper::removeVetoableChangeListener( const ::rtl::OUString&, const Reference< XVetoableChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +// XMultiPropertySet +void SAL_CALL PropertySetHelper::setPropertyValues( const Sequence< ::rtl::OUString >& aPropertyNames, const Sequence< Any >& aValues ) throw(PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + const sal_Int32 nCount = aPropertyNames.getLength(); + + if( nCount != aValues.getLength() ) + throw IllegalArgumentException(); + + if( nCount ) + { + PropertyMapEntry** pEntries = new PropertyMapEntry*[nCount+1]; + pEntries[nCount] = NULL; + const OUString* pNames = aPropertyNames.getConstArray(); + + sal_Bool bUnknown = sal_False; + sal_Int32 n; + for( n = 0; !bUnknown && ( n < nCount ); n++, pNames++ ) + { + pEntries[n] = mp->find( *pNames ); + bUnknown = NULL == pEntries[n]; + } + + if( !bUnknown ) + _setPropertyValues( (const PropertyMapEntry**)pEntries, aValues.getConstArray() ); + + delete[] pEntries; + + if( bUnknown ) + throw UnknownPropertyException( *pNames, static_cast< XPropertySet* >( this ) ); + } +} + +Sequence< Any > SAL_CALL PropertySetHelper::getPropertyValues( const Sequence< ::rtl::OUString >& aPropertyNames ) throw(RuntimeException) +{ + const sal_Int32 nCount = aPropertyNames.getLength(); + + Sequence< Any > aValues; + if( nCount ) + { + PropertyMapEntry** pEntries = new PropertyMapEntry*[nCount+1]; + pEntries[nCount] = NULL; + const OUString* pNames = aPropertyNames.getConstArray(); + + sal_Bool bUnknown = sal_False; + sal_Int32 n; + for( n = 0; !bUnknown && ( n < nCount ); n++, pNames++ ) + { + pEntries[n] = mp->find( *pNames ); + bUnknown = NULL == pEntries[n]; + } + + if( !bUnknown ) + { + aValues.realloc(nCount); + _getPropertyValues( (const PropertyMapEntry**)pEntries, aValues.getArray() ); + } + + delete[] pEntries; + + if( bUnknown ) + throw UnknownPropertyException( *pNames, static_cast< XPropertySet* >( this ) ); + } + + return aValues; +} + +void SAL_CALL PropertySetHelper::addPropertiesChangeListener( const Sequence< ::rtl::OUString >&, const Reference< XPropertiesChangeListener >& ) throw(RuntimeException) +{ + // todo +} + +void SAL_CALL PropertySetHelper::removePropertiesChangeListener( const Reference< XPropertiesChangeListener >& ) throw(RuntimeException) +{ + // todo +} + +void SAL_CALL PropertySetHelper::firePropertiesChangeEvent( const Sequence< ::rtl::OUString >&, const Reference< XPropertiesChangeListener >& ) throw(RuntimeException) +{ + // todo +} + +// XPropertyState +PropertyState SAL_CALL PropertySetHelper::getPropertyState( const ::rtl::OUString& PropertyName ) throw(UnknownPropertyException, RuntimeException) +{ + PropertyMapEntry* aEntries[2]; + + aEntries[0] = mp->find( PropertyName ); + if( aEntries[0] == NULL ) + throw UnknownPropertyException( PropertyName, static_cast< XPropertySet* >( this ) ); + + aEntries[1] = NULL; + + PropertyState aState; + _getPropertyStates( (const PropertyMapEntry**)aEntries, &aState ); + + return aState; +} + +Sequence< PropertyState > SAL_CALL PropertySetHelper::getPropertyStates( const Sequence< ::rtl::OUString >& aPropertyName ) throw(UnknownPropertyException, RuntimeException) +{ + const sal_Int32 nCount = aPropertyName.getLength(); + + Sequence< PropertyState > aStates( nCount ); + + if( nCount ) + { + const OUString* pNames = aPropertyName.getConstArray(); + + sal_Bool bUnknown = sal_False; + + PropertyMapEntry** pEntries = new PropertyMapEntry*[nCount+1]; + + sal_Int32 n; + for( n = 0; !bUnknown && (n < nCount); n++, pNames++ ) + { + pEntries[n] = mp->find( *pNames ); + bUnknown = NULL == pEntries[n]; + } + + pEntries[nCount] = NULL; + + if( !bUnknown ) + _getPropertyStates( (const PropertyMapEntry**)pEntries, aStates.getArray() ); + + delete[] pEntries; + + if( bUnknown ) + throw UnknownPropertyException( *pNames, static_cast< XPropertySet* >( this ) ); + } + + return aStates; +} + +void SAL_CALL PropertySetHelper::setPropertyToDefault( const ::rtl::OUString& PropertyName ) throw(UnknownPropertyException, RuntimeException) +{ + PropertyMapEntry *pEntry = mp->find( PropertyName ); + if( NULL == pEntry ) + throw UnknownPropertyException( PropertyName, static_cast< XPropertySet* >( this ) ); + + _setPropertyToDefault( pEntry ); +} + +Any SAL_CALL PropertySetHelper::getPropertyDefault( const ::rtl::OUString& aPropertyName ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + PropertyMapEntry* pEntry = mp->find( aPropertyName ); + if( NULL == pEntry ) + throw UnknownPropertyException( aPropertyName, static_cast< XPropertySet* >( this ) ); + + return _getPropertyDefault( pEntry ); +} + +void PropertySetHelper::_getPropertyStates( const comphelper::PropertyMapEntry**, PropertyState* ) throw(UnknownPropertyException ) +{ + OSL_ENSURE( sal_False, "you have to implement this yourself!"); +} + +void PropertySetHelper::_setPropertyToDefault( const comphelper::PropertyMapEntry* ) throw(UnknownPropertyException ) +{ + OSL_ENSURE( sal_False, "you have to implement this yourself!"); +} + +Any PropertySetHelper::_getPropertyDefault( const comphelper::PropertyMapEntry* ) throw(UnknownPropertyException, WrappedTargetException ) +{ + OSL_ENSURE( sal_False, "you have to implement this yourself!"); + + Any aAny; + return aAny; +} diff --git a/comphelper/source/property/propertysetinfo.cxx b/comphelper/source/property/propertysetinfo.cxx new file mode 100644 index 000000000000..efdd495ac1bc --- /dev/null +++ b/comphelper/source/property/propertysetinfo.cxx @@ -0,0 +1,214 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" + +#include "comphelper/propertysetinfo.hxx" + +using namespace ::rtl; +using namespace ::comphelper; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; + +namespace comphelper +{ +class PropertyMapImpl +{ +public: + PropertyMapImpl() throw(); + virtual ~PropertyMapImpl() throw(); + + void add( PropertyMapEntry* pMap, sal_Int32 nCount = -1 ) throw(); + void remove( const OUString& aName ) throw(); + + Sequence< Property > getProperties() throw(); + + const PropertyMap* getPropertyMap() const throw(); + + Property getPropertyByName( const OUString& aName ) throw( UnknownPropertyException ); + sal_Bool hasPropertyByName( const OUString& aName ) throw(); + +private: + PropertyMap maPropertyMap; + Sequence< Property > maProperties; +}; +} + +PropertyMapImpl::PropertyMapImpl() throw() +{ +} + +PropertyMapImpl::~PropertyMapImpl() throw() +{ +} + +void PropertyMapImpl::add( PropertyMapEntry* pMap, sal_Int32 nCount ) throw() +{ + // nCount < 0 => add all + // nCount == 0 => add nothing + // nCount > 0 => add at most nCount entries + + while( pMap->mpName && ( ( nCount < 0) || ( nCount-- > 0 ) ) ) + { + OUString aName( pMap->mpName, pMap->mnNameLen, RTL_TEXTENCODING_ASCII_US ); + +#ifdef DBG_UTIL + PropertyMap::iterator aIter = maPropertyMap.find( aName ); + if( aIter != maPropertyMap.end() ) + { + OSL_ENSURE( sal_False, "Warning: PropertyMapEntry added twice, possible error!"); + } +#endif + if( NULL == pMap->mpType ) + { + OSL_ENSURE( sal_False, "No type in PropertyMapEntry!"); + pMap->mpType = &::getCppuType((const sal_Int32*)0); + } + + maPropertyMap[aName] = pMap; + + if( maProperties.getLength() ) + maProperties.realloc( 0 ); + + pMap = &pMap[1]; + } +} + +void PropertyMapImpl::remove( const OUString& aName ) throw() +{ + maPropertyMap.erase( aName ); + + if( maProperties.getLength() ) + maProperties.realloc( 0 ); +} + +Sequence< Property > PropertyMapImpl::getProperties() throw() +{ + // maybe we have to generate the properties after + // a change in the property map or at first call + // to getProperties + if( maProperties.getLength() != (sal_Int32)maPropertyMap.size() ) + { + maProperties = Sequence< Property >( maPropertyMap.size() ); + Property* pProperties = maProperties.getArray(); + + PropertyMap::iterator aIter = maPropertyMap.begin(); + const PropertyMap::iterator aEnd = maPropertyMap.end(); + while( aIter != aEnd ) + { + PropertyMapEntry* pEntry = (*aIter).second; + + pProperties->Name = OUString( pEntry->mpName, pEntry->mnNameLen, RTL_TEXTENCODING_ASCII_US ); + pProperties->Handle = pEntry->mnHandle; + pProperties->Type = *pEntry->mpType; + pProperties->Attributes = pEntry->mnAttributes; + + pProperties++; + aIter++; + } + } + + return maProperties; +} + +const PropertyMap* PropertyMapImpl::getPropertyMap() const throw() +{ + return &maPropertyMap; +} + +Property PropertyMapImpl::getPropertyByName( const OUString& aName ) throw( UnknownPropertyException ) +{ + PropertyMap::iterator aIter = maPropertyMap.find( aName ); + + if( maPropertyMap.end() == aIter ) + throw UnknownPropertyException( aName, NULL ); + + PropertyMapEntry* pEntry = (*aIter).second; + + return Property( aName, pEntry->mnHandle, *pEntry->mpType, pEntry->mnAttributes ); +} + +sal_Bool PropertyMapImpl::hasPropertyByName( const OUString& aName ) throw() +{ + return maPropertyMap.find( aName ) != maPropertyMap.end(); +} + +/////////////////////////////////////////////////////////////////////// + +PropertySetInfo::PropertySetInfo() throw() +{ + mpMap = new PropertyMapImpl(); +} + +PropertySetInfo::PropertySetInfo( PropertyMapEntry* pMap ) throw() +{ + mpMap = new PropertyMapImpl(); + mpMap->add( pMap ); +} + +PropertySetInfo::~PropertySetInfo() throw() +{ + delete mpMap; +} + +void PropertySetInfo::add( PropertyMapEntry* pMap ) throw() +{ + mpMap->add( pMap ); +} + +void PropertySetInfo::add( PropertyMapEntry* pMap, sal_Int32 nCount ) throw() +{ + mpMap->add( pMap, nCount ); +} + +void PropertySetInfo::remove( const rtl::OUString& aName ) throw() +{ + mpMap->remove( aName ); +} + +Sequence< ::com::sun::star::beans::Property > SAL_CALL PropertySetInfo::getProperties() throw(::com::sun::star::uno::RuntimeException) +{ + return mpMap->getProperties(); +} + +Property SAL_CALL PropertySetInfo::getPropertyByName( const ::rtl::OUString& aName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException) +{ + return mpMap->getPropertyByName( aName ); +} + +sal_Bool SAL_CALL PropertySetInfo::hasPropertyByName( const ::rtl::OUString& Name ) throw(::com::sun::star::uno::RuntimeException) +{ + return mpMap->hasPropertyByName( Name ); +} + +const PropertyMap* PropertySetInfo::getPropertyMap() const throw() +{ + return mpMap->getPropertyMap(); +} diff --git a/comphelper/source/property/propertystatecontainer.cxx b/comphelper/source/property/propertystatecontainer.cxx new file mode 100644 index 000000000000..341dc1b43a78 --- /dev/null +++ b/comphelper/source/property/propertystatecontainer.cxx @@ -0,0 +1,339 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" +#include "comphelper/propertystatecontainer.hxx" +#include <rtl/ustrbuf.hxx> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + + namespace + { + static ::rtl::OUString lcl_getUnknownPropertyErrorMessage( const ::rtl::OUString& _rPropertyName ) + { + // TODO: perhaps it's time to think about resources in the comphelper module? + // Would be nice to have localized exception strings (a simply resource file containing + // strings only would suffice, and could be realized with an UNO service, so we do not + // need the dependency to the Tools project) + ::rtl::OUStringBuffer sMessage; + sMessage.appendAscii( "The property \"" ); + sMessage.append( _rPropertyName ); + sMessage.appendAscii( "\" is unknown." ); + return sMessage.makeStringAndClear(); + } + } + + //===================================================================== + //= OPropertyStateContainer + //===================================================================== + //--------------------------------------------------------------------- + OPropertyStateContainer::OPropertyStateContainer( ::cppu::OBroadcastHelper& _rBHelper ) + :OPropertyContainer( _rBHelper ) + { + } + + //-------------------------------------------------------------------- + Any SAL_CALL OPropertyStateContainer::queryInterface( const Type& _rType ) throw (RuntimeException) + { + Any aReturn = OPropertyContainer::queryInterface( _rType ); + if ( !aReturn.hasValue() ) + aReturn = OPropertyStateContainer_TBase::queryInterface( _rType ); + return aReturn; + } + + //-------------------------------------------------------------------- + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OPropertyStateContainer, OPropertyContainer, OPropertyStateContainer_TBase ) + + //-------------------------------------------------------------------- + sal_Int32 OPropertyStateContainer::getHandleForName( const ::rtl::OUString& _rPropertyName ) SAL_THROW( ( UnknownPropertyException ) ) + { + // look up the handle for the name + ::cppu::IPropertyArrayHelper& rPH = getInfoHelper(); + sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName ); + + if ( -1 == nHandle ) + throw UnknownPropertyException( lcl_getUnknownPropertyErrorMessage( _rPropertyName ), static_cast< XPropertyState* >( this ) ); + + return nHandle; + } + + //-------------------------------------------------------------------- + PropertyState SAL_CALL OPropertyStateContainer::getPropertyState( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, RuntimeException) + { + return getPropertyStateByHandle( getHandleForName( _rPropertyName ) ); + } + + //-------------------------------------------------------------------- + Sequence< PropertyState > SAL_CALL OPropertyStateContainer::getPropertyStates( const Sequence< ::rtl::OUString >& _rPropertyNames ) throw (UnknownPropertyException, RuntimeException) + { + sal_Int32 nProperties = _rPropertyNames.getLength(); + Sequence< PropertyState> aStates( nProperties ); + if ( !nProperties ) + return aStates; + +#ifdef _DEBUG + // precondition: property sequence is sorted (the algorythm below relies on this) + { + const ::rtl::OUString* pNames = _rPropertyNames.getConstArray(); + const ::rtl::OUString* pNamesCompare = pNames + 1; + const ::rtl::OUString* pNamesEnd = _rPropertyNames.getConstArray() + _rPropertyNames.getLength(); + for ( ; pNamesCompare != pNamesEnd; ++pNames, ++pNamesCompare ) + OSL_PRECOND( pNames->compareTo( *pNamesCompare ) < 0, + "OPropertyStateContainer::getPropertyStates: property sequence not sorted!" ); + } +#endif + + const ::rtl::OUString* pLookup = _rPropertyNames.getConstArray(); + const ::rtl::OUString* pLookupEnd = pLookup + nProperties; + PropertyState* pStates = aStates.getArray(); + + cppu::IPropertyArrayHelper& rHelper = getInfoHelper(); + Sequence< Property> aAllProperties = rHelper.getProperties(); + sal_Int32 nAllProperties = aAllProperties.getLength(); + const Property* pAllProperties = aAllProperties.getConstArray(); + const Property* pAllPropertiesEnd = pAllProperties + nAllProperties; + + osl::MutexGuard aGuard( rBHelper.rMutex ); + for ( ; ( pAllProperties != pAllPropertiesEnd ) && ( pLookup != pLookupEnd ); ++pAllProperties ) + { +#ifdef _DEBUG + if ( pAllProperties < pAllPropertiesEnd - 1 ) + OSL_ENSURE( pAllProperties->Name.compareTo( (pAllProperties + 1)->Name ) < 0, + "OPropertyStateContainer::getPropertyStates: all-properties not sorted!" ); +#endif + if ( pAllProperties->Name.equals( *pLookup ) ) + { + *pStates++ = getPropertyState( *pLookup ); + ++pLookup; + } + } + + if ( pLookup != pLookupEnd ) + // we run out of properties from the IPropertyArrayHelper, but still have properties to lookup + // -> we were asked for a nonexistent property + throw UnknownPropertyException( lcl_getUnknownPropertyErrorMessage( *pLookup ), static_cast< XPropertyState* >( this ) ); + + return aStates; + } + + //-------------------------------------------------------------------- + void SAL_CALL OPropertyStateContainer::setPropertyToDefault( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, RuntimeException) + { + setPropertyToDefaultByHandle( getHandleForName( _rPropertyName ) ); + } + + //-------------------------------------------------------------------- + Any SAL_CALL OPropertyStateContainer::getPropertyDefault( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) + { + Any aDefault; + getPropertyDefaultByHandle( getHandleForName( _rPropertyName ), aDefault ); + return aDefault; + } + + //-------------------------------------------------------------------- + PropertyState OPropertyStateContainer::getPropertyStateByHandle( sal_Int32 _nHandle ) + { + // simply compare the current and the default value + Any aCurrentValue; getFastPropertyValue( aCurrentValue, _nHandle ); + Any aDefaultValue; getPropertyDefaultByHandle( _nHandle, aDefaultValue ); + + sal_Bool bEqual = uno_type_equalData( + const_cast< void* >( aCurrentValue.getValue() ), aCurrentValue.getValueType().getTypeLibType(), + const_cast< void* >( aDefaultValue.getValue() ), aDefaultValue.getValueType().getTypeLibType(), + reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface), + reinterpret_cast< uno_ReleaseFunc >(cpp_release) + ); + if ( bEqual ) + return PropertyState_DEFAULT_VALUE; + else + return PropertyState_DIRECT_VALUE; + } + + //-------------------------------------------------------------------- + void OPropertyStateContainer::setPropertyToDefaultByHandle( sal_Int32 _nHandle ) + { + Any aDefault; + getPropertyDefaultByHandle( _nHandle, aDefault ); + setFastPropertyValue( _nHandle, aDefault ); + } + +//......................................................................... +} // namespace comphelper +//......................................................................... + +#ifdef FS_PRIV_DEBUG +#define STATECONTAINER_TEST +#endif + +#ifdef STATECONTAINER_TEST +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <comphelper/proparrhlp.hxx> +#include <comphelper/broadcasthelper.hxx> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + + //===================================================================== + //= Test - compiler test + //===================================================================== + typedef ::cppu::OWeakAggObject Test_RefCountBase; + class Test :public OMutexAndBroadcastHelper + ,public OPropertyStateContainer + ,public OPropertyArrayUsageHelper< Test > + ,public Test_RefCountBase + { + private: + ::rtl::OUString m_sStringProperty; + Reference< XInterface > m_xInterfaceProperty; + Any m_aMayBeVoidProperty; + + protected: + Test( ); + + DECLARE_XINTERFACE( ) + + public: + static Test* Create( ); + + protected: + virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw(RuntimeException); + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper(); + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const; + + protected: + // OPropertyStateContainer overridables + virtual void getPropertyDefaultByHandle( sal_Int32 _nHandle, Any& _rDefault ) const; + }; + + //--------------------------------------------------------------------- + Test::Test( ) + :OPropertyStateContainer( GetBroadcastHelper() ) + { + registerProperty( + ::rtl::OUString::createFromAscii( "StringProperty" ), + 1, + PropertyAttribute::BOUND, + &m_sStringProperty, + ::getCppuType( &m_sStringProperty ) + ); + + registerProperty( + ::rtl::OUString::createFromAscii( "InterfaceProperty" ), + 2, + PropertyAttribute::BOUND, + &m_xInterfaceProperty, + ::getCppuType( &m_xInterfaceProperty ) + ); + + registerMayBeVoidProperty( + ::rtl::OUString::createFromAscii( "IntProperty" ), + 3, + PropertyAttribute::BOUND, + &m_aMayBeVoidProperty, + ::getCppuType( static_cast< sal_Int32* >( NULL ) ) + ); + + registerPropertyNoMember( + ::rtl::OUString::createFromAscii( "OtherInterfaceProperty" ), + 4, + PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID, + ::getCppuType( static_cast< Reference< XInterface >* >( NULL ) ), + NULL + ); + } + + //--------------------------------------------------------------------- + IMPLEMENT_FORWARD_XINTERFACE2( Test, Test_RefCountBase, OPropertyStateContainer ) + + //--------------------------------------------------------------------- + void Test::getPropertyDefaultByHandle( sal_Int32 _nHandle, Any& _rDefault ) const + { + switch ( _nHandle ) + { + case 1: + _rDefault = makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StringPropertyDefault" ) ) ); + break; + case 2: + _rDefault = makeAny( Reference< XInterface >( ) ); + break; + case 3: + // void + break; + case 4: + _rDefault = makeAny( Reference< XInterface >( ) ); + break; + default: + OSL_ENSURE( sal_False, "Test::getPropertyDefaultByHandle: invalid handle!" ); + } + } + + //--------------------------------------------------------------------- + Reference< XPropertySetInfo > SAL_CALL Test::getPropertySetInfo( ) throw(RuntimeException) + { + return createPropertySetInfo( getInfoHelper() ); + } + + //--------------------------------------------------------------------- + ::cppu::IPropertyArrayHelper& SAL_CALL Test::getInfoHelper() + { + return *getArrayHelper(); + } + + //--------------------------------------------------------------------- + ::cppu::IPropertyArrayHelper* Test::createArrayHelper( ) const + { + Sequence< Property > aProps; + describeProperties( aProps ); + return new ::cppu::OPropertyArrayHelper( aProps ); + } + + //--------------------------------------------------------------------- + Test* Test::Create( ) + { + Test* pInstance = new Test; + return pInstance; + } + +//......................................................................... +} // namespace comphelper +//......................................................................... + +#endif + diff --git a/comphelper/source/property/propmultiplex.cxx b/comphelper/source/property/propmultiplex.cxx new file mode 100644 index 000000000000..db0b35650d32 --- /dev/null +++ b/comphelper/source/property/propmultiplex.cxx @@ -0,0 +1,182 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" +#include <comphelper/propmultiplex.hxx> +#include <osl/diagnose.h> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +//======================================================================== +//= OPropertyChangeListener +//======================================================================== +//------------------------------------------------------------------------ +OPropertyChangeListener::~OPropertyChangeListener() +{ + if (m_pAdapter) + m_pAdapter->dispose(); +} + +//------------------------------------------------------------------ +void OPropertyChangeListener::_disposing(const EventObject&) throw( RuntimeException) +{ + // nothing to do here +} + +//------------------------------------------------------------------ +void OPropertyChangeListener::disposeAdapter() +{ + if ( m_pAdapter ) + m_pAdapter->dispose(); + + // will automatically set a new adapter + OSL_ENSURE( !m_pAdapter, "OPropertyChangeListener::disposeAdapter: what did dispose do?" ); +} + +//------------------------------------------------------------------ +void OPropertyChangeListener::setAdapter(OPropertyChangeMultiplexer* pAdapter) +{ + if (m_pAdapter) + { + ::osl::MutexGuard aGuard(m_rMutex); + m_pAdapter->release(); + m_pAdapter = NULL; + } + + if (pAdapter) + { + ::osl::MutexGuard aGuard(m_rMutex); + m_pAdapter = pAdapter; + m_pAdapter->acquire(); + } +} + +//======================================================================== +//= OPropertyChangeMultiplexer +//======================================================================== +//------------------------------------------------------------------ +OPropertyChangeMultiplexer::OPropertyChangeMultiplexer(OPropertyChangeListener* _pListener, const Reference< XPropertySet>& _rxSet, sal_Bool _bAutoReleaseSet) + :m_xSet(_rxSet) + ,m_pListener(_pListener) + ,m_nLockCount(0) + ,m_bListening(sal_False) + ,m_bAutoSetRelease(_bAutoReleaseSet) +{ + m_pListener->setAdapter(this); +} + +//------------------------------------------------------------------ +OPropertyChangeMultiplexer::~OPropertyChangeMultiplexer() +{ +} + +//------------------------------------------------------------------ +void OPropertyChangeMultiplexer::lock() +{ + ++m_nLockCount; +} + +//------------------------------------------------------------------ +void OPropertyChangeMultiplexer::unlock() +{ + --m_nLockCount; +} + +//------------------------------------------------------------------ +void OPropertyChangeMultiplexer::dispose() +{ + if (m_bListening) + { + Reference< XPropertyChangeListener> xPreventDelete(this); + + const ::rtl::OUString* pProperties = m_aProperties.getConstArray(); + for (sal_Int32 i = 0; i < m_aProperties.getLength(); ++i, ++pProperties) + m_xSet->removePropertyChangeListener(*pProperties, static_cast< XPropertyChangeListener*>(this)); + + m_pListener->setAdapter(NULL); + + m_pListener = NULL; + m_bListening = sal_False; + + if (m_bAutoSetRelease) + m_xSet = NULL; + } +} + +// XEventListener +//------------------------------------------------------------------ +void SAL_CALL OPropertyChangeMultiplexer::disposing( const EventObject& _rSource) throw( RuntimeException) +{ + if (m_pListener) + { + // tell the listener + if (!locked()) + m_pListener->_disposing(_rSource); + // disconnect the listener + if (m_pListener) // may have been reset whilest calling into _disposing + m_pListener->setAdapter(NULL); + } + + m_pListener = NULL; + m_bListening = sal_False; + + if (m_bAutoSetRelease) + m_xSet = NULL; +} + +// XPropertyChangeListener +//------------------------------------------------------------------ +void SAL_CALL OPropertyChangeMultiplexer::propertyChange( const PropertyChangeEvent& _rEvent ) throw( RuntimeException) +{ + if (m_pListener && !locked()) + m_pListener->_propertyChanged(_rEvent); +} + +//------------------------------------------------------------------ +void OPropertyChangeMultiplexer::addProperty(const ::rtl::OUString& _sPropertyName) +{ + if (m_xSet.is()) + { + m_xSet->addPropertyChangeListener(_sPropertyName, static_cast< XPropertyChangeListener*>(this)); + m_aProperties.realloc(m_aProperties.getLength() + 1); + m_aProperties.getArray()[m_aProperties.getLength()-1] = _sPropertyName; + m_bListening = sal_True; + } +} + +//......................................................................... +} +//......................................................................... + diff --git a/comphelper/source/property/propstate.cxx b/comphelper/source/property/propstate.cxx new file mode 100644 index 000000000000..214bccb3f40f --- /dev/null +++ b/comphelper/source/property/propstate.cxx @@ -0,0 +1,261 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_comphelper.hxx" +#include <comphelper/propstate.hxx> +#include <com/sun/star/uno/genfunc.h> +#include <cppuhelper/queryinterface.hxx> +#include <comphelper/sequence.hxx> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::Type; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::lang::XTypeProvider; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::cpp_queryInterface; + using ::com::sun::star::uno::cpp_release; + using ::com::sun::star::beans::PropertyState_DEFAULT_VALUE; + using ::com::sun::star::beans::PropertyState_DIRECT_VALUE; + + //===================================================================== + // OPropertyStateHelper + //===================================================================== + + //--------------------------------------------------------------------- + ::com::sun::star::uno::Any SAL_CALL OPropertyStateHelper::queryInterface(const ::com::sun::star::uno::Type& _rType) throw( ::com::sun::star::uno::RuntimeException) + { + ::com::sun::star::uno::Any aReturn = OPropertySetHelper::queryInterface(_rType); + // our own ifaces + if ( !aReturn.hasValue() ) + aReturn = ::cppu::queryInterface(_rType, static_cast< ::com::sun::star::beans::XPropertyState*>(this)); + + return aReturn; + } + + //--------------------------------------------------------------------- + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> OPropertyStateHelper::getTypes() throw( ::com::sun::star::uno::RuntimeException) + { + static ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> aTypes; + if (!aTypes.getLength()) + { + aTypes.realloc(4); + ::com::sun::star::uno::Type* pTypes = aTypes.getArray(); + // base class types + pTypes[0] = getCppuType(( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet>*)NULL); + pTypes[1] = getCppuType(( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XMultiPropertySet>*)NULL); + pTypes[2] = getCppuType(( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XFastPropertySet>*)NULL); + // my own type + pTypes[3] = getCppuType(( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyState>*)NULL); + } + return aTypes; + } + + OPropertyStateHelper::OPropertyStateHelper( + ::cppu::OBroadcastHelper& rBHlp, + ::cppu::IEventNotificationHook *i_pFireEvents) + : ::cppu::OPropertySetHelper(rBHlp, i_pFireEvents) { } + + OPropertyStateHelper::~OPropertyStateHelper() {} + + //--------------------------------------------------------------------- + void OPropertyStateHelper::firePropertyChange(sal_Int32 nHandle, const ::com::sun::star::uno::Any& aNewValue, const ::com::sun::star::uno::Any& aOldValue) + { + fire(&nHandle, &aNewValue, &aOldValue, 1, sal_False); + } + + // XPropertyState + //--------------------------------------------------------------------- + ::com::sun::star::beans::PropertyState SAL_CALL OPropertyStateHelper::getPropertyState(const ::rtl::OUString& _rsName) throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException) + { + cppu::IPropertyArrayHelper& rPH = getInfoHelper(); + sal_Int32 nHandle = rPH.getHandleByName(_rsName); + + if (nHandle == -1) + throw ::com::sun::star::beans::UnknownPropertyException(); + + return getPropertyStateByHandle(nHandle); + } + + //--------------------------------------------------------------------- + void SAL_CALL OPropertyStateHelper::setPropertyToDefault(const ::rtl::OUString& _rsName) throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException) + { + cppu::IPropertyArrayHelper& rPH = getInfoHelper(); + sal_Int32 nHandle = rPH.getHandleByName(_rsName); + + if (nHandle == -1) + throw ::com::sun::star::beans::UnknownPropertyException(); + + setPropertyToDefaultByHandle(nHandle); + } + + //--------------------------------------------------------------------- + ::com::sun::star::uno::Any SAL_CALL OPropertyStateHelper::getPropertyDefault(const ::rtl::OUString& _rsName) throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) + { + cppu::IPropertyArrayHelper& rPH = getInfoHelper(); + sal_Int32 nHandle = rPH.getHandleByName(_rsName); + + if (nHandle == -1) + throw ::com::sun::star::beans::UnknownPropertyException(); + + return getPropertyDefaultByHandle(nHandle); + } + + //--------------------------------------------------------------------- + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyState> SAL_CALL OPropertyStateHelper::getPropertyStates(const ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rPropertyNames) throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException) + { + sal_Int32 nLen = _rPropertyNames.getLength(); + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyState> aRet(nLen); + ::com::sun::star::beans::PropertyState* pValues = aRet.getArray(); + const ::rtl::OUString* pNames = _rPropertyNames.getConstArray(); + + cppu::IPropertyArrayHelper& rHelper = getInfoHelper(); + + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property> aProps = rHelper.getProperties(); + const ::com::sun::star::beans::Property* pProps = aProps.getConstArray(); + sal_Int32 nPropCount = aProps.getLength(); + + osl::MutexGuard aGuard(rBHelper.rMutex); + for (sal_Int32 i=0, j=0; i<nPropCount && j<nLen; ++i, ++pProps) + { + // get the values only for valid properties + if (pProps->Name.equals(*pNames)) + { + *pValues = getPropertyState(*pNames); + ++pValues; + ++pNames; + ++j; + } + } + + return aRet; + } + + //--------------------------------------------------------------------- + ::com::sun::star::beans::PropertyState OPropertyStateHelper::getPropertyStateByHandle( sal_Int32 _nHandle ) + { + // simply compare the current and the default value + Any aCurrentValue = getPropertyDefaultByHandle( _nHandle ); + Any aDefaultValue; getFastPropertyValue( aDefaultValue, _nHandle ); + + sal_Bool bEqual = uno_type_equalData( + const_cast< void* >( aCurrentValue.getValue() ), aCurrentValue.getValueType().getTypeLibType(), + const_cast< void* >( aDefaultValue.getValue() ), aDefaultValue.getValueType().getTypeLibType(), + reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface), + reinterpret_cast< uno_ReleaseFunc >(cpp_release) + ); + return bEqual ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE; + } + + //--------------------------------------------------------------------- + void OPropertyStateHelper::setPropertyToDefaultByHandle( sal_Int32 _nHandle ) + { + setFastPropertyValue( _nHandle, getPropertyDefaultByHandle( _nHandle ) ); + } + + //--------------------------------------------------------------------- + ::com::sun::star::uno::Any OPropertyStateHelper::getPropertyDefaultByHandle( sal_Int32 ) const + { + return ::com::sun::star::uno::Any(); + } + + //===================================================================== + // OStatefulPropertySet + //===================================================================== + //--------------------------------------------------------------------- + OStatefulPropertySet::OStatefulPropertySet() + :OPropertyStateHelper( GetBroadcastHelper() ) + { + } + + //--------------------------------------------------------------------- + OStatefulPropertySet::~OStatefulPropertySet() + { + } + + //--------------------------------------------------------------------- + Sequence< Type > SAL_CALL OStatefulPropertySet::getTypes() throw(RuntimeException) + { + Sequence< Type > aOwnTypes( 2 ); + aOwnTypes[0] = XWeak::static_type(); + aOwnTypes[1] = XTypeProvider::static_type(); + + return concatSequences( + aOwnTypes, + OPropertyStateHelper::getTypes() + ); + } + + //--------------------------------------------------------------------- + Sequence< sal_Int8 > SAL_CALL OStatefulPropertySet::getImplementationId() throw(RuntimeException) + { + static ::cppu::OImplementationId * pId = NULL; + if ( !pId ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if ( !pId ) + { + static ::cppu::OImplementationId aId; + pId = &aId; + } + } + return pId->getImplementationId(); + } + + //--------------------------------------------------------------------- + Any SAL_CALL OStatefulPropertySet::queryInterface( const Type& _rType ) throw(RuntimeException) + { + Any aReturn = OWeakObject::queryInterface( _rType ); + if ( !aReturn.hasValue() ) + aReturn = ::cppu::queryInterface( _rType, static_cast< XTypeProvider* >( this ) ); + if ( !aReturn.hasValue() ) + aReturn = OPropertyStateHelper::queryInterface( _rType ); + return aReturn; + } + + //--------------------------------------------------------------------- + void SAL_CALL OStatefulPropertySet::acquire() throw() + { + ::cppu::OWeakObject::acquire(); + } + + //--------------------------------------------------------------------- + void SAL_CALL OStatefulPropertySet::release() throw() + { + ::cppu::OWeakObject::release(); + } + +//......................................................................... +} +//......................................................................... + |