diff options
Diffstat (limited to 'comphelper/source')
112 files changed, 30702 insertions, 0 deletions
diff --git a/comphelper/source/compare/AnyCompareFactory.cxx b/comphelper/source/compare/AnyCompareFactory.cxx new file mode 100644 index 000000000000..136bff63f69b --- /dev/null +++ b/comphelper/source/compare/AnyCompareFactory.cxx @@ -0,0 +1,191 @@ +/************************************************************************* + * + * 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_module.hxx" + +#include <com/sun/star/ucb/XAnyCompareFactory.hpp> +#include <com/sun/star/i18n/XCollator.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <cppuhelper/implbase3.hxx> +#include <cppuhelper/implbase1.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> +#include <comphelper/stl_types.hxx> +#include <map> + + +using namespace com::sun::star::uno; +using namespace com::sun::star::ucb; +using namespace com::sun::star::lang; +using namespace com::sun::star::i18n; +using namespace rtl; + +//============================================================================= + +class AnyCompare : public ::cppu::WeakImplHelper1< XAnyCompare > +{ + Reference< XCollator > m_rCollator; + +public: + AnyCompare( Reference< XComponentContext > xContext, const Locale& rLocale ) throw() + { + Reference< XMultiComponentFactory > xFactory = xContext->getServiceManager(); + if ( xFactory.is() ) + { + m_rCollator = Reference< XCollator >( + xFactory->createInstanceWithContext( OUString::createFromAscii( "com.sun.star.i18n.Collator" ), xContext ), + UNO_QUERY ); + m_rCollator->loadDefaultCollator( rLocale, + 0 ); //??? + } + + } + + virtual sal_Int16 SAL_CALL compare( const Any& any1, const Any& any2 ) throw(RuntimeException); +}; + +//============================================================================= + +class AnyCompareFactory : public cppu::WeakImplHelper3< XAnyCompareFactory, XInitialization, XServiceInfo > +{ + Reference< XAnyCompare > m_rAnyCompare; + Reference< XComponentContext > m_rContext; + Locale m_Locale; + +public: + AnyCompareFactory( Reference< XComponentContext > xContext ) : m_rContext( xContext ) + {} + + // XAnyCompareFactory + virtual Reference< XAnyCompare > SAL_CALL createAnyCompareByName ( const OUString& aPropertyName ) throw(::com::sun::star::uno::RuntimeException); + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) + throw ( Exception, RuntimeException ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) throw(RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw(RuntimeException); + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) throw(RuntimeException); + + // XServiceInfo - static versions (used for component registration) + static ::rtl::OUString SAL_CALL getImplementationName_static(); + static Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static(); + static Reference< XInterface > SAL_CALL Create( const Reference< XComponentContext >& ); +}; + +//=========================================================================================== + +sal_Int16 SAL_CALL AnyCompare::compare( const Any& any1, const Any& any2 ) throw(::com::sun::star::uno::RuntimeException) +{ + sal_Int16 aResult = 0; + + if( m_rCollator.is() ) + { + OUString aStr1; + OUString aStr2; + + any1 >>= aStr1; + any2 >>= aStr2; + + aResult = ( sal_Int16 )m_rCollator->compareString( aStr1, aStr2 ); + } + + return aResult; +} + +//=========================================================================================== + +Reference< XAnyCompare > SAL_CALL AnyCompareFactory::createAnyCompareByName( const OUString& aPropertyName ) throw(::com::sun::star::uno::RuntimeException) +{ + // for now only OUString properties compare is implemented + // so no check for the property name is done + + if( aPropertyName.equals( OUString::createFromAscii( "Title" ) ) ) + return m_rAnyCompare; + + return Reference< XAnyCompare >(); +} + +void SAL_CALL AnyCompareFactory::initialize( const Sequence< Any >& aArguments ) throw ( Exception, RuntimeException ) +{ + if( aArguments.getLength() ) + { + if( aArguments[0] >>= m_Locale ) + { + m_rAnyCompare = new AnyCompare( m_rContext, m_Locale ); + return; + } + } + +} + +OUString SAL_CALL AnyCompareFactory::getImplementationName( ) throw( RuntimeException ) +{ + return getImplementationName_static(); +} + +OUString SAL_CALL AnyCompareFactory::getImplementationName_static( ) +{ + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AnyCompareFactory" ) ); +} + +sal_Bool SAL_CALL AnyCompareFactory::supportsService( const OUString& ServiceName ) throw(RuntimeException) +{ + rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ucb.AnyCompareFactory" ) ); + return aServiceName == ServiceName; +} + +Sequence< OUString > SAL_CALL AnyCompareFactory::getSupportedServiceNames( ) throw(RuntimeException) +{ + return getSupportedServiceNames_static(); +} + +Sequence< OUString > SAL_CALL AnyCompareFactory::getSupportedServiceNames_static( ) +{ + const rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ucb.AnyCompareFactory" ) ); + const Sequence< rtl::OUString > aSeq( &aServiceName, 1 ); + return aSeq; +} + +Reference< XInterface > SAL_CALL AnyCompareFactory::Create( + const Reference< XComponentContext >& rxContext ) +{ + return (cppu::OWeakObject*)new AnyCompareFactory( rxContext ); +} + +void createRegistryInfo_AnyCompareFactory() +{ + static ::comphelper::module::OAutoRegistration< AnyCompareFactory > aAutoRegistration; +} diff --git a/comphelper/source/compare/makefile.mk b/comphelper/source/compare/makefile.mk new file mode 100644 index 000000000000..156701d1d969 --- /dev/null +++ b/comphelper/source/compare/makefile.mk @@ -0,0 +1,47 @@ +#************************************************************************* +# +# 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=compare + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES=$(SLO)$/AnyCompareFactory.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/comphelper/source/container/IndexedPropertyValuesContainer.cxx b/comphelper/source/container/IndexedPropertyValuesContainer.cxx new file mode 100644 index 000000000000..928cb78a8b85 --- /dev/null +++ b/comphelper/source/container/IndexedPropertyValuesContainer.cxx @@ -0,0 +1,270 @@ +/************************************************************************* + * + * 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_module.hxx" + +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <cppuhelper/implbase2.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + + +#ifndef __SGI_STL_VECTOR +#include <vector> +#endif + +using namespace com::sun::star; + +typedef std::vector < uno::Sequence< beans::PropertyValue > > IndexedPropertyValues; + +class IndexedPropertyValuesContainer : public cppu::WeakImplHelper2< container::XIndexContainer, lang::XServiceInfo > +{ +public: + IndexedPropertyValuesContainer() throw(); + virtual ~IndexedPropertyValuesContainer() throw(); + + // XIndexContainer + virtual void SAL_CALL insertByIndex( sal_Int32 nIndex, const ::com::sun::star::uno::Any& aElement ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeByIndex( sal_Int32 nIndex ) + throw(::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException); + + // XIndexReplace + virtual void SAL_CALL replaceByIndex( sal_Int32 nIndex, const ::com::sun::star::uno::Any& aElement ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount( ) + throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getByIndex( sal_Int32 nIndex ) + throw(::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException); + + // XElementAccess + 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); + + //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); + + // XServiceInfo - static versions (used for component registration) + static ::rtl::OUString SAL_CALL getImplementationName_static(); + static uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static(); + static uno::Reference< uno::XInterface > SAL_CALL Create( const uno::Reference< uno::XComponentContext >& ); + +private: + IndexedPropertyValues maProperties; +}; + +IndexedPropertyValuesContainer::IndexedPropertyValuesContainer() throw() +{ +} + +IndexedPropertyValuesContainer::~IndexedPropertyValuesContainer() throw() +{ +} + +// XIndexContainer +void SAL_CALL IndexedPropertyValuesContainer::insertByIndex( sal_Int32 nIndex, const ::com::sun::star::uno::Any& aElement ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) +{ + sal_Int32 nSize(maProperties.size()); + if ((nSize >= nIndex) && (nIndex >= 0)) + { + uno::Sequence<beans::PropertyValue> aProps; + if (!(aElement >>= aProps)) + throw lang::IllegalArgumentException(); + if (nSize == nIndex) + maProperties.push_back(aProps); + else + { + IndexedPropertyValues::iterator aItr; + if ((nIndex * 2) < nSize) + { + aItr = maProperties.begin(); + sal_Int32 i(0); + while(i < nIndex) + { + i++; + aItr++; + } + } + else + { + aItr = maProperties.end(); + sal_Int32 i(nSize - 1); + while(i > nIndex) + { + i--; + aItr--; + } + } + maProperties.insert(aItr, aProps); + } + } + else + throw lang::IndexOutOfBoundsException(); +} + +void SAL_CALL IndexedPropertyValuesContainer::removeByIndex( sal_Int32 nIndex ) + throw(::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException) +{ + sal_Int32 nSize(maProperties.size()); + if ((nIndex < nSize) && (nIndex >= 0)) + { + IndexedPropertyValues::iterator aItr; + if ((nIndex * 2) < nSize) + { + aItr = maProperties.begin(); + sal_Int32 i(0); + while(i < nIndex) + { + i++; + aItr++; + } + } + else + { + aItr = maProperties.end(); + sal_Int32 i(nSize - 1); + while(i > nIndex) + { + i--; + aItr--; + } + } + maProperties.erase(aItr); + } + else + throw lang::IndexOutOfBoundsException(); +} + +// XIndexReplace +void SAL_CALL IndexedPropertyValuesContainer::replaceByIndex( sal_Int32 nIndex, const ::com::sun::star::uno::Any& aElement ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) +{ + sal_Int32 nSize(maProperties.size()); + if ((nIndex < nSize) && (nIndex >= 0)) + { + uno::Sequence<beans::PropertyValue> aProps; + if (!(aElement >>= aProps)) + throw lang::IllegalArgumentException(); + maProperties[nIndex] = aProps; + } + else + throw lang::IndexOutOfBoundsException(); +} + +// XIndexAccess +sal_Int32 SAL_CALL IndexedPropertyValuesContainer::getCount( ) + throw(::com::sun::star::uno::RuntimeException) +{ + return maProperties.size(); +} + +::com::sun::star::uno::Any SAL_CALL IndexedPropertyValuesContainer::getByIndex( sal_Int32 nIndex ) + throw(::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException) +{ + sal_Int32 nSize(maProperties.size()); + if (!((nIndex < nSize) && (nIndex >= 0))) + throw lang::IndexOutOfBoundsException(); + + uno::Any aAny; + aAny <<= maProperties[nIndex]; + return aAny; +} + +// XElementAccess +::com::sun::star::uno::Type SAL_CALL IndexedPropertyValuesContainer::getElementType( ) + throw(::com::sun::star::uno::RuntimeException) +{ + return ::getCppuType((uno::Sequence<beans::PropertyValue> *)0); +} + +sal_Bool SAL_CALL IndexedPropertyValuesContainer::hasElements( ) + throw(::com::sun::star::uno::RuntimeException) +{ + return !maProperties.empty(); +} + +//XServiceInfo +::rtl::OUString SAL_CALL IndexedPropertyValuesContainer::getImplementationName( ) throw(::com::sun::star::uno::RuntimeException) +{ + return getImplementationName_static(); +} + +::rtl::OUString SAL_CALL IndexedPropertyValuesContainer::getImplementationName_static( ) +{ + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IndexedPropertyValuesContainer" ) ); +} + +sal_Bool SAL_CALL IndexedPropertyValuesContainer::supportsService( const ::rtl::OUString& ServiceName ) throw(::com::sun::star::uno::RuntimeException) +{ + rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.IndexedPropertyValues" ) ); + return aServiceName == ServiceName; +} + +::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL IndexedPropertyValuesContainer::getSupportedServiceNames( ) throw(::com::sun::star::uno::RuntimeException) +{ + return getSupportedServiceNames_static(); +} + + +::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL IndexedPropertyValuesContainer::getSupportedServiceNames_static( ) +{ + const rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.IndexedPropertyValues" ) ); + const uno::Sequence< rtl::OUString > aSeq( &aServiceName, 1 ); + return aSeq; +} + + +uno::Reference< uno::XInterface > SAL_CALL IndexedPropertyValuesContainer::Create( + const uno::Reference< uno::XComponentContext >&) +{ + return (cppu::OWeakObject*)new IndexedPropertyValuesContainer(); +} + +void createRegistryInfo_IndexedPropertyValuesContainer() +{ + static ::comphelper::module::OAutoRegistration< IndexedPropertyValuesContainer > aAutoRegistration; +} diff --git a/comphelper/source/container/NamedPropertyValuesContainer.cxx b/comphelper/source/container/NamedPropertyValuesContainer.cxx new file mode 100644 index 000000000000..e57efaec9118 --- /dev/null +++ b/comphelper/source/container/NamedPropertyValuesContainer.cxx @@ -0,0 +1,239 @@ +/************************************************************************* + * + * 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_module.hxx" + +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <cppuhelper/implbase2.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <comphelper/stl_types.hxx> + + +#include <map> + + +using namespace com::sun::star; + +DECLARE_STL_USTRINGACCESS_MAP( uno::Sequence<beans::PropertyValue>, NamedPropertyValues ); + +class NamedPropertyValuesContainer : public cppu::WeakImplHelper2< container::XNameContainer, lang::XServiceInfo > +{ +public: + NamedPropertyValuesContainer() throw(); + virtual ~NamedPropertyValuesContainer() throw(); + + // XNameContainer + virtual void SAL_CALL insertByName( const ::rtl::OUString& aName, const ::com::sun::star::uno::Any& aElement ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::ElementExistException, + ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeByName( const ::rtl::OUString& Name ) + throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException); + + // XNameReplace + virtual void SAL_CALL replaceByName( const ::rtl::OUString& aName, const ::com::sun::star::uno::Any& aElement ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XNameAccess + virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) + throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames( ) + throw(::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) + throw(::com::sun::star::uno::RuntimeException); + + // XElementAccess + 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); + + //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); + + // XServiceInfo - static versions (used for component registration) + static ::rtl::OUString SAL_CALL getImplementationName_static(); + static uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static(); + static uno::Reference< uno::XInterface > SAL_CALL Create( const uno::Reference< uno::XComponentContext >& ); + +private: + NamedPropertyValues maProperties; +}; + +NamedPropertyValuesContainer::NamedPropertyValuesContainer() throw() +{ +} + +NamedPropertyValuesContainer::~NamedPropertyValuesContainer() throw() +{ +} + +// XNameContainer +void SAL_CALL NamedPropertyValuesContainer::insertByName( const rtl::OUString& aName, const uno::Any& aElement ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::ElementExistException, + ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) +{ + if( maProperties.find( aName ) != maProperties.end() ) + throw container::ElementExistException(); + + uno::Sequence<beans::PropertyValue> aProps; + if( !(aElement >>= aProps ) ) + throw lang::IllegalArgumentException(); + + maProperties.insert( NamedPropertyValues::value_type(aName ,aProps) ); +} + +void SAL_CALL NamedPropertyValuesContainer::removeByName( const ::rtl::OUString& Name ) + throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException) +{ + NamedPropertyValues::iterator aIter = maProperties.find( Name ); + if( aIter == maProperties.end() ) + throw container::NoSuchElementException(); + + maProperties.erase( aIter ); +} + +// XNameReplace +void SAL_CALL NamedPropertyValuesContainer::replaceByName( const ::rtl::OUString& aName, const ::com::sun::star::uno::Any& aElement ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) +{ + NamedPropertyValues::iterator aIter = maProperties.find( aName ); + if( aIter == maProperties.end() ) + throw container::NoSuchElementException(); + + uno::Sequence<beans::PropertyValue> aProps; + if( !(aElement >>= aProps) ) + throw lang::IllegalArgumentException(); + + (*aIter).second = aProps; +} + +// XNameAccess +::com::sun::star::uno::Any SAL_CALL NamedPropertyValuesContainer::getByName( const ::rtl::OUString& aName ) + throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException) +{ + NamedPropertyValues::iterator aIter = maProperties.find( aName ); + if( aIter == maProperties.end() ) + throw container::NoSuchElementException(); + + uno::Any aElement; + + aElement <<= (*aIter).second; + + return aElement; +} + +::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL NamedPropertyValuesContainer::getElementNames( ) + throw(::com::sun::star::uno::RuntimeException) +{ + NamedPropertyValues::iterator aIter = maProperties.begin(); + const NamedPropertyValues::iterator aEnd = maProperties.end(); + + uno::Sequence< rtl::OUString > aNames( maProperties.size() ); + rtl::OUString* pNames = aNames.getArray(); + + while( aIter != aEnd ) + { + *pNames++ = (*aIter++).first; + } + + return aNames; +} + +sal_Bool SAL_CALL NamedPropertyValuesContainer::hasByName( const ::rtl::OUString& aName ) + throw(::com::sun::star::uno::RuntimeException) +{ + NamedPropertyValues::iterator aIter = maProperties.find( aName ); + return aIter != maProperties.end(); +} + +// XElementAccess +::com::sun::star::uno::Type SAL_CALL NamedPropertyValuesContainer::getElementType( ) + throw(::com::sun::star::uno::RuntimeException) +{ + return ::getCppuType((uno::Sequence<beans::PropertyValue> *)0); +} + +sal_Bool SAL_CALL NamedPropertyValuesContainer::hasElements( ) + throw(::com::sun::star::uno::RuntimeException) +{ + return !maProperties.empty(); +} + +//XServiceInfo +::rtl::OUString SAL_CALL NamedPropertyValuesContainer::getImplementationName( ) throw(::com::sun::star::uno::RuntimeException) +{ + return getImplementationName_static(); +} + +::rtl::OUString SAL_CALL NamedPropertyValuesContainer::getImplementationName_static( ) +{ + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NamedPropertyValuesContainer" ) ); +} + +sal_Bool SAL_CALL NamedPropertyValuesContainer::supportsService( const ::rtl::OUString& ServiceName ) throw(::com::sun::star::uno::RuntimeException) +{ + rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.NamedPropertyValues" ) ); + return aServiceName == ServiceName; +} + +::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL NamedPropertyValuesContainer::getSupportedServiceNames( ) throw(::com::sun::star::uno::RuntimeException) +{ + return getSupportedServiceNames_static(); +} + + +::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL NamedPropertyValuesContainer::getSupportedServiceNames_static( ) +{ + const rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.NamedPropertyValues" ) ); + const uno::Sequence< rtl::OUString > aSeq( &aServiceName, 1 ); + return aSeq; +} + +uno::Reference< uno::XInterface > SAL_CALL NamedPropertyValuesContainer::Create( + const uno::Reference< uno::XComponentContext >&) +{ + return (cppu::OWeakObject*)new NamedPropertyValuesContainer(); +} + +void createRegistryInfo_NamedPropertyValuesContainer() +{ + static ::comphelper::module::OAutoRegistration< NamedPropertyValuesContainer > aAutoRegistration; +} diff --git a/comphelper/source/container/container.cxx b/comphelper/source/container/container.cxx new file mode 100644 index 000000000000..9f834de85b66 --- /dev/null +++ b/comphelper/source/container/container.cxx @@ -0,0 +1,153 @@ +/************************************************************************* + * + * 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/uno/XInterface.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <comphelper/container.hxx> +#include <osl/diagnose.h> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + +//============================================================================== +IndexAccessIterator::IndexAccessIterator(::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface> xStartingPoint) + :m_xStartingPoint(xStartingPoint) + ,m_xCurrentObject(NULL) +{ + OSL_ENSURE(m_xStartingPoint.is(), "IndexAccessIterator::IndexAccessIterator : no starting point !"); +} + +IndexAccessIterator::~IndexAccessIterator() {} + +//------------------------------------------------------------------------------ +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface> IndexAccessIterator::Next() +{ + sal_Bool bCheckingStartingPoint = !m_xCurrentObject.is(); + // ist die aktuelle Node der Anfangspunkt ? + sal_Bool bAlreadyCheckedCurrent = m_xCurrentObject.is(); + // habe ich die aktuelle Node schon mal mittels ShouldHandleElement testen ? + if (!m_xCurrentObject.is()) + m_xCurrentObject = m_xStartingPoint; + + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface> xSearchLoop( m_xCurrentObject); + sal_Bool bHasMoreToSearch = sal_True; + sal_Bool bFoundSomething = sal_False; + while (!bFoundSomething && bHasMoreToSearch) + { + // pre-order-traversierung + if (!bAlreadyCheckedCurrent && ShouldHandleElement(xSearchLoop)) + { + m_xCurrentObject = xSearchLoop; + bFoundSomething = sal_True; + } + else + { + // zuerst absteigen, wenn moeglich + ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexAccess> xContainerAccess(xSearchLoop, ::com::sun::star::uno::UNO_QUERY); + if (xContainerAccess.is() && xContainerAccess->getCount() && ShouldStepInto(xContainerAccess)) + { // zum ersten Child + ::com::sun::star::uno::Any aElement(xContainerAccess->getByIndex(0)); + xSearchLoop = *(::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>*)aElement.getValue(); + bCheckingStartingPoint = sal_False; + + m_arrChildIndizies.push_back((sal_Int32)0); + } + else + { + // dann nach oben und nach rechts, wenn moeglich + while (m_arrChildIndizies.size() > 0) + { // (mein Stack ist nich leer, also kann ich noch nach oben gehen) + ::com::sun::star::uno::Reference< ::com::sun::star::container::XChild> xChild(xSearchLoop, ::com::sun::star::uno::UNO_QUERY); + OSL_ENSURE(xChild.is(), "IndexAccessIterator::Next : a content has no approriate interface !"); + + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface> xParent( xChild->getParent()); + xContainerAccess = ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexAccess>(xParent, ::com::sun::star::uno::UNO_QUERY); + OSL_ENSURE(xContainerAccess.is(), "IndexAccessIterator::Next : a content has an invalid parent !"); + + // den Index, den SearchLoop in diesem Parent hatte, von meinem 'Stack' + sal_Int32 nOldSearchChildIndex = m_arrChildIndizies[m_arrChildIndizies.size() - 1]; + m_arrChildIndizies.pop_back(); + + if (nOldSearchChildIndex < xContainerAccess->getCount() - 1) + { // auf dieser Ebene geht es noch nach rechts + ++nOldSearchChildIndex; + // also das naechste Child + ::com::sun::star::uno::Any aElement(xContainerAccess->getByIndex(nOldSearchChildIndex)); + xSearchLoop = *(::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>*) aElement.getValue(); + bCheckingStartingPoint = sal_False; + // und dessen Position auf den 'Stack' + m_arrChildIndizies.push_back((sal_Int32)nOldSearchChildIndex); + + break; + } + // hierher komme ich, wenn es auf der aktuellen Ebene nicht nach rechts geht, dann mache ich eine darueber weiter + xSearchLoop = xParent; + bCheckingStartingPoint = sal_False; + } + + if ((m_arrChildIndizies.size() == 0) && !bCheckingStartingPoint) + { // das ist genau dann der Fall, wenn ich keinen rechten Nachbarn fuer irgendeinen der direkten Vorfahren des + // urspruenglichen xSearchLoop gefunden habe + bHasMoreToSearch = sal_False; + } + } + + if (bHasMoreToSearch) + { // ich habe in xSearchLoop jetzt ein Interface eines 'Knotens' meines 'Baumes', den ich noch abtesten kann + if (ShouldHandleElement(xSearchLoop)) + { + m_xCurrentObject = xSearchLoop; + bFoundSomething = sal_True; + } + else + if (bCheckingStartingPoint) + // ich bin noch am Anfang, konnte nicht absteigen, und habe an diesem Anfang nix gefunden -> nix mehr zu tun + bHasMoreToSearch = sal_False; + bAlreadyCheckedCurrent = sal_True; + } + } + } + + if (!bFoundSomething) + { + OSL_ENSURE(m_arrChildIndizies.size() == 0, "IndexAccessIterator::Next : items left on stack ! how this ?"); + Invalidate(); + } + + return m_xCurrentObject; +} + +//......................................................................... +} // namespace comphelper +//......................................................................... + + diff --git a/comphelper/source/container/containermultiplexer.cxx b/comphelper/source/container/containermultiplexer.cxx new file mode 100644 index 000000000000..176f9cab6f8f --- /dev/null +++ b/comphelper/source/container/containermultiplexer.cxx @@ -0,0 +1,203 @@ +/************************************************************************* + * + * 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/containermultiplexer.hxx" +#include "comphelper/uno3.hxx" +#include <osl/diagnose.h> +//......................................................................... +namespace comphelper +{ +//......................................................................... + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::container; + + //===================================================================== + //= OContainerListener + //===================================================================== + //--------------------------------------------------------------------- + OContainerListener::OContainerListener(::osl::Mutex& _rMutex) + :m_pAdapter(NULL) + ,m_rMutex(_rMutex) + { + } + + //--------------------------------------------------------------------- + OContainerListener::~OContainerListener() + { + if (m_pAdapter) + { + m_pAdapter->dispose(); + m_pAdapter = NULL; + } + } + + //--------------------------------------------------------------------- + void OContainerListener::_elementInserted( const ContainerEvent& /*_rEvent*/ ) throw(RuntimeException) + { + } + + //--------------------------------------------------------------------- + void OContainerListener::_elementRemoved( const ContainerEvent& ) throw(RuntimeException) + { + } + + //--------------------------------------------------------------------- + void OContainerListener::_elementReplaced( const ContainerEvent& /*_rEvent*/ ) throw(RuntimeException) + { + } + + //--------------------------------------------------------------------- + void OContainerListener::_disposing(const EventObject& ) throw( RuntimeException) + { + } + + //------------------------------------------------------------------ + void OContainerListener::setAdapter(OContainerListenerAdapter* 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(); + } + } + + //===================================================================== + //= OContainerListenerAdapter + //===================================================================== + //--------------------------------------------------------------------- + OContainerListenerAdapter::OContainerListenerAdapter(OContainerListener* _pListener, + const Reference< XContainer >& _rxContainer) + :m_xContainer(_rxContainer) + ,m_pListener(_pListener) + ,m_nLockCount(0) + { + if (m_pListener) + m_pListener->setAdapter(this); + + ::comphelper::increment(m_refCount); + try + { + m_xContainer->addContainerListener(this); + } + catch(const Exception&) + { + OSL_ENSURE(0,"Exceptiopn catched!"); + } + ::comphelper::decrement(m_refCount); + } + + //--------------------------------------------------------------------- + OContainerListenerAdapter::~OContainerListenerAdapter() + { + } + + //------------------------------------------------------------------ + void OContainerListenerAdapter::lock() + { + ++m_nLockCount; + } + + //------------------------------------------------------------------ + void OContainerListenerAdapter::unlock() + { + --m_nLockCount; + } + + //------------------------------------------------------------------ + void OContainerListenerAdapter::dispose() + { + if (m_xContainer.is()) + { + try + { + Reference< XContainerListener > xPreventDelete(this); + m_xContainer->removeContainerListener(xPreventDelete); + m_pListener->setAdapter(NULL); + } + catch(const Exception&) + { + OSL_ENSURE(0,"Exception catched!"); + } + m_xContainer = NULL; + m_pListener = NULL; + } + } + + //------------------------------------------------------------------ + void SAL_CALL OContainerListenerAdapter::disposing( const EventObject& _rSource) throw(RuntimeException) + { + if (m_pListener) + { + // tell the listener + if (!locked()) + m_pListener->_disposing(_rSource); + // disconnect the listener + if ( m_pListener ) + m_pListener->setAdapter(NULL); + } + + m_xContainer = NULL; + m_pListener = NULL; + } + + //------------------------------------------------------------------ + void SAL_CALL OContainerListenerAdapter::elementInserted( const ContainerEvent& _rEvent ) throw(RuntimeException) + { + if (m_pListener && !locked()) + m_pListener->_elementInserted(_rEvent); + } + + //------------------------------------------------------------------ + void SAL_CALL OContainerListenerAdapter::elementRemoved( const ContainerEvent& _rEvent ) throw(RuntimeException) + { + if (m_pListener && !locked()) + m_pListener->_elementRemoved(_rEvent); + } + + //------------------------------------------------------------------ + void SAL_CALL OContainerListenerAdapter::elementReplaced( const ContainerEvent& _rEvent ) throw(RuntimeException) + { + if (m_pListener && !locked()) + m_pListener->_elementReplaced(_rEvent); + } + +//......................................................................... +} // namespace comphelper +//......................................................................... + diff --git a/comphelper/source/container/embeddedobjectcontainer.cxx b/comphelper/source/container/embeddedobjectcontainer.cxx new file mode 100644 index 000000000000..17740e7ef09b --- /dev/null +++ b/comphelper/source/container/embeddedobjectcontainer.cxx @@ -0,0 +1,1663 @@ +/************************************************************************* + * + * 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/container/XChild.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/embed/XEmbedObjectCreator.hpp> +#include <com/sun/star/embed/XLinkCreator.hpp> +#include <com/sun/star/embed/XEmbedPersist.hpp> +#include <com/sun/star/embed/XLinkageSupport.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/embed/XOptimizedStorage.hpp> +#include <com/sun/star/embed/EntryInitModes.hpp> +#include <com/sun/star/util/XCloseable.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/embed/EmbedStates.hpp> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/embed/Aspects.hpp> +#include <com/sun/star/embed/EmbedMisc.hpp> + +#include <comphelper/seqstream.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/storagehelper.hxx> +#include <comphelper/embeddedobjectcontainer.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/weakref.hxx> +#include <hash_map> +#include <algorithm> + +#include <rtl/logfile.hxx> + +using namespace ::com::sun::star; + +namespace comphelper +{ + +struct hashObjectName_Impl +{ + size_t operator()(const ::rtl::OUString Str) const + { + return (size_t)Str.hashCode(); + } +}; + +struct eqObjectName_Impl +{ + sal_Bool operator()(const ::rtl::OUString Str1, const ::rtl::OUString Str2) const + { + return ( Str1 == Str2 ); + } +}; + +typedef std::hash_map +< + ::rtl::OUString, + ::com::sun::star::uno::Reference < com::sun::star::embed::XEmbeddedObject >, + hashObjectName_Impl, + eqObjectName_Impl +> +EmbeddedObjectContainerNameMap; + +struct EmbedImpl +{ + // TODO/LATER: remove objects from temp. Container storage when object is disposed + EmbeddedObjectContainerNameMap maObjectContainer; + uno::Reference < embed::XStorage > mxStorage; + EmbeddedObjectContainer* mpTempObjectContainer; + uno::Reference < embed::XStorage > mxImageStorage; + uno::WeakReference < uno::XInterface > m_xModel; + //EmbeddedObjectContainerNameMap maTempObjectContainer; + //uno::Reference < embed::XStorage > mxTempStorage; + sal_Bool bOwnsStorage; + + const uno::Reference < embed::XStorage >& GetReplacements(); +}; + +const uno::Reference < embed::XStorage >& EmbedImpl::GetReplacements() +{ + if ( !mxImageStorage.is() ) + { + try + { + mxImageStorage = mxStorage->openStorageElement( + ::rtl::OUString::createFromAscii( "ObjectReplacements" ), embed::ElementModes::READWRITE ); + } + catch ( uno::Exception& ) + { + mxImageStorage = mxStorage->openStorageElement( + ::rtl::OUString::createFromAscii( "ObjectReplacements" ), embed::ElementModes::READ ); + } + } + + if ( !mxImageStorage.is() ) + throw io::IOException(); + + return mxImageStorage; +} + +EmbeddedObjectContainer::EmbeddedObjectContainer() +{ + pImpl = new EmbedImpl; + pImpl->mxStorage = ::comphelper::OStorageHelper::GetTemporaryStorage(); + pImpl->bOwnsStorage = sal_True; + pImpl->mpTempObjectContainer = 0; +} + +EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference < embed::XStorage >& rStor ) +{ + pImpl = new EmbedImpl; + pImpl->mxStorage = rStor; + pImpl->bOwnsStorage = sal_False; + pImpl->mpTempObjectContainer = 0; +} + +EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference < embed::XStorage >& rStor, const uno::Reference < uno::XInterface >& xModel ) +{ + pImpl = new EmbedImpl; + pImpl->mxStorage = rStor; + pImpl->bOwnsStorage = sal_False; + pImpl->mpTempObjectContainer = 0; + pImpl->m_xModel = xModel; +} + +void EmbeddedObjectContainer::SwitchPersistence( const uno::Reference < embed::XStorage >& rStor ) +{ + ReleaseImageSubStorage(); + + if ( pImpl->bOwnsStorage ) + pImpl->mxStorage->dispose(); + + pImpl->mxStorage = rStor; + pImpl->bOwnsStorage = sal_False; +} + +sal_Bool EmbeddedObjectContainer::CommitImageSubStorage() +{ + if ( pImpl->mxImageStorage.is() ) + { + try + { + sal_Bool bReadOnlyMode = sal_True; + uno::Reference < beans::XPropertySet > xSet(pImpl->mxImageStorage,uno::UNO_QUERY); + if ( xSet.is() ) + { + // get the open mode from the parent storage + sal_Int32 nMode = 0; + uno::Any aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("OpenMode") ); + if ( aAny >>= nMode ) + bReadOnlyMode = !(nMode & embed::ElementModes::WRITE ); + } // if ( xSet.is() ) + if ( !bReadOnlyMode ) + { + uno::Reference< embed::XTransactedObject > xTransact( pImpl->mxImageStorage, uno::UNO_QUERY_THROW ); + xTransact->commit(); + } + } + catch( uno::Exception& ) + { + return sal_False; + } + } + + return sal_True; +} + +void EmbeddedObjectContainer::ReleaseImageSubStorage() +{ + CommitImageSubStorage(); + + if ( pImpl->mxImageStorage.is() ) + { + try + { + pImpl->mxImageStorage->dispose(); + pImpl->mxImageStorage = uno::Reference< embed::XStorage >(); + } + catch( uno::Exception& ) + { + OSL_ASSERT( "Problems releasing image substorage!\n" ); + } + } +} + +EmbeddedObjectContainer::~EmbeddedObjectContainer() +{ + ReleaseImageSubStorage(); + + if ( pImpl->bOwnsStorage ) + pImpl->mxStorage->dispose(); + + delete pImpl->mpTempObjectContainer; + delete pImpl; +} + +void EmbeddedObjectContainer::CloseEmbeddedObjects() +{ + EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); + while ( aIt != pImpl->maObjectContainer.end() ) + { + uno::Reference < util::XCloseable > xClose( (*aIt).second, uno::UNO_QUERY ); + if ( xClose.is() ) + { + try + { + xClose->close( sal_True ); + } + catch ( uno::Exception& ) + { + } + } + + aIt++; + } +} + +::rtl::OUString EmbeddedObjectContainer::CreateUniqueObjectName() +{ + ::rtl::OUString aPersistName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Object ") ); + ::rtl::OUString aStr; + sal_Int32 i=1; + do + { + aStr = aPersistName; + aStr += ::rtl::OUString::valueOf( i++ ); + } + while( HasEmbeddedObject( aStr ) ); + // TODO/LATER: should we consider deleted objects? + + return aStr; +} + +uno::Sequence < ::rtl::OUString > EmbeddedObjectContainer::GetObjectNames() +{ + uno::Sequence < ::rtl::OUString > aSeq( pImpl->maObjectContainer.size() ); + EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); + sal_Int32 nIdx=0; + while ( aIt != pImpl->maObjectContainer.end() ) + aSeq[nIdx++] = (*aIt++).first; + return aSeq; +} + +sal_Bool EmbeddedObjectContainer::HasEmbeddedObjects() +{ + return pImpl->maObjectContainer.size() != 0; +} + +sal_Bool EmbeddedObjectContainer::HasEmbeddedObject( const ::rtl::OUString& rName ) +{ + EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName ); + if ( aIt == pImpl->maObjectContainer.end() ) + { + uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY ); + return xAccess->hasByName(rName); + } + else + return sal_True; +} + +sal_Bool EmbeddedObjectContainer::HasEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj ) +{ + EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); + while ( aIt != pImpl->maObjectContainer.end() ) + { + if ( (*aIt).second == xObj ) + return sal_True; + else + aIt++; + } + + return sal_False; +} + +sal_Bool EmbeddedObjectContainer::HasInstantiatedEmbeddedObject( const ::rtl::OUString& rName ) +{ + // allows to detect whether the object was already instantiated + // currently the filter instantiate it on loading, so this method allows + // to avoid objects pointing to the same persistence + EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName ); + return ( aIt != pImpl->maObjectContainer.end() ); +} + +::rtl::OUString EmbeddedObjectContainer::GetEmbeddedObjectName( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj ) +{ + EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); + while ( aIt != pImpl->maObjectContainer.end() ) + { + if ( (*aIt).second == xObj ) + return (*aIt).first; + else + aIt++; + } + + OSL_ENSURE( 0, "Unknown object!" ); + return ::rtl::OUString(); +} + +uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::GetEmbeddedObject( const ::rtl::OUString& rName ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetEmbeddedObject" ); + + OSL_ENSURE( rName.getLength(), "Empty object name!"); + + uno::Reference < embed::XEmbeddedObject > xObj; + EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName ); + +#if OSL_DEBUG_LEVEL > 1 + uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY ); + uno::Sequence< ::rtl::OUString> aSeq = xAccess->getElementNames(); + const ::rtl::OUString* pIter = aSeq.getConstArray(); + const ::rtl::OUString* pEnd = pIter + aSeq.getLength(); + for(;pIter != pEnd;++pIter) + { + (void)*pIter; + } + OSL_ENSURE( aIt != pImpl->maObjectContainer.end() || xAccess->hasByName(rName), "Could not return object!" ); +#endif + + // check if object was already created + if ( aIt != pImpl->maObjectContainer.end() ) + xObj = (*aIt).second; + else + xObj = Get_Impl( rName, uno::Reference < embed::XEmbeddedObject >() ); + + return xObj; +} + +uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::Get_Impl( const ::rtl::OUString& rName, const uno::Reference < embed::XEmbeddedObject >& xCopy ) +{ + uno::Reference < embed::XEmbeddedObject > xObj; + try + { + // create the object from the storage + uno::Reference < beans::XPropertySet > xSet( pImpl->mxStorage, uno::UNO_QUERY ); + sal_Bool bReadOnlyMode = sal_True; + if ( xSet.is() ) + { + // get the open mode from the parent storage + sal_Int32 nMode = 0; + uno::Any aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("OpenMode") ); + if ( aAny >>= nMode ) + bReadOnlyMode = !(nMode & embed::ElementModes::WRITE ); + } + + // object was not added until now - should happen only by calling this method from "inside" + //TODO/LATER: it would be good to detect an error when an object should be created already, but isn't (not an "inside" call) + uno::Reference < embed::XEmbedObjectCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY ); + uno::Sequence< beans::PropertyValue > aObjDescr( xCopy.is() ? 2 : 1 ); + aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) ); + aObjDescr[0].Value <<= pImpl->m_xModel.get(); + if ( xCopy.is() ) + { + aObjDescr[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CloneFrom" ) ); + aObjDescr[1].Value <<= xCopy; + } + + uno::Sequence< beans::PropertyValue > aMediaDescr( 1 ); + aMediaDescr[0].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ReadOnly")); + aMediaDescr[0].Value <<= bReadOnlyMode; + xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitFromEntry( + pImpl->mxStorage, rName, + aMediaDescr, aObjDescr ), uno::UNO_QUERY ); + + // insert object into my list + AddEmbeddedObject( xObj, rName ); + } + catch ( uno::Exception& ) + { + } + + return xObj; +} + +uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence < sal_Int8 >& rClassId, + const uno::Sequence < beans::PropertyValue >& rArgs, ::rtl::OUString& rNewName ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CreateEmbeddedObject" ); + + if ( !rNewName.getLength() ) + rNewName = CreateUniqueObjectName(); + + OSL_ENSURE( !HasEmbeddedObject(rNewName), "Object to create already exists!"); + + // create object from classid by inserting it into storage + uno::Reference < embed::XEmbeddedObject > xObj; + try + { + uno::Reference < embed::XEmbedObjectCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY ); + + uno::Sequence< beans::PropertyValue > aObjDescr( rArgs.getLength() + 1 ); + aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) ); + aObjDescr[0].Value <<= pImpl->m_xModel.get(); + ::std::copy( rArgs.getConstArray(), rArgs.getConstArray() + rArgs.getLength(), aObjDescr.getArray() + 1 ); + xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitNew( + rClassId, ::rtl::OUString(), pImpl->mxStorage, rNewName, + aObjDescr ), uno::UNO_QUERY ); + + AddEmbeddedObject( xObj, rNewName ); + + OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED, + "A freshly create object should be running always!\n" ); + } + catch ( uno::Exception& ) + { + } + + return xObj; +} + +uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence < sal_Int8 >& rClassId, ::rtl::OUString& rNewName ) +{ + return CreateEmbeddedObject( rClassId, uno::Sequence < beans::PropertyValue >(), rNewName ); +} + +void EmbeddedObjectContainer::AddEmbeddedObject( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj, const ::rtl::OUString& rName ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::AddEmbeddedObject" ); + +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( rName.getLength(), "Added object doesn't have a name!"); + uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY ); + uno::Reference < embed::XEmbedPersist > xEmb( xObj, uno::UNO_QUERY ); + uno::Reference < embed::XLinkageSupport > xLink( xEmb, uno::UNO_QUERY ); + // if the object has a persistance and the object is not a link than it must have persistence entry in the storage + OSL_ENSURE( !( xEmb.is() && ( !xLink.is() || !xLink->isLink() ) ) || xAccess->hasByName(rName), + "Added element not in storage!" ); +#endif + + // remember object - it needs to be in storage already + EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName ); + OSL_ENSURE( aIt == pImpl->maObjectContainer.end(), "Element already inserted!" ); + pImpl->maObjectContainer[ rName ] = xObj; + uno::Reference < container::XChild > xChild( xObj, uno::UNO_QUERY ); + if ( xChild.is() && xChild->getParent() != pImpl->m_xModel.get() ) + xChild->setParent( pImpl->m_xModel.get() ); + + // look for object in temorary container + if ( pImpl->mpTempObjectContainer ) + { + aIt = pImpl->mpTempObjectContainer->pImpl->maObjectContainer.begin(); + while ( aIt != pImpl->mpTempObjectContainer->pImpl->maObjectContainer.end() ) + { + if ( (*aIt).second == xObj ) + { + // copy replacement image from temporary container (if there is any) + ::rtl::OUString aTempName = (*aIt).first; + ::rtl::OUString aMediaType; + uno::Reference < io::XInputStream > xStream = pImpl->mpTempObjectContainer->GetGraphicStream( xObj, &aMediaType ); + if ( xStream.is() ) + { + InsertGraphicStream( xStream, rName, aMediaType ); + xStream = 0; + pImpl->mpTempObjectContainer->RemoveGraphicStream( aTempName ); + } + + // remove object from storage of temporary container + uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); + if ( xPersist.is() ) + { + try + { + pImpl->mpTempObjectContainer->pImpl->mxStorage->removeElement( aTempName ); + } + catch ( uno::Exception& ) + { + } + } + + // temp. container needs to forget the object + pImpl->mpTempObjectContainer->pImpl->maObjectContainer.erase( aIt ); + break; + } + else + aIt++; + } + } +} + +sal_Bool EmbeddedObjectContainer::StoreEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName, sal_Bool bCopy ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::StoreEmbeddedObject" ); + + uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); + if ( !rName.getLength() ) + rName = CreateUniqueObjectName(); + +#if OSL_DEBUG_LEVEL > 1 + uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY ); + OSL_ENSURE( !xPersist.is() || !xAccess->hasByName(rName), "Inserting element already present in storage!" ); + OSL_ENSURE( xPersist.is() || xObj->getCurrentState() == embed::EmbedStates::RUNNING, "Non persistent object inserted!"); +#endif + + // insert objects' storage into the container storage (if object has one) + try + { + if ( xPersist.is() ) + { + uno::Sequence < beans::PropertyValue > aSeq; + if ( bCopy ) + xPersist->storeToEntry( pImpl->mxStorage, rName, aSeq, aSeq ); + else + { + //TODO/LATER: possible optimisation, don't store immediately + //xPersist->setPersistentEntry( pImpl->mxStorage, rName, embed::EntryInitModes::ENTRY_NO_INIT, aSeq, aSeq ); + xPersist->storeAsEntry( pImpl->mxStorage, rName, aSeq, aSeq ); + xPersist->saveCompleted( sal_True ); + } + } + } + catch ( uno::Exception& ) + { + // TODO/LATER: better error recovery should keep storage intact + return sal_False; + } + + return sal_True; +} + +sal_Bool EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( Object )" ); + // store it into the container storage + if ( StoreEmbeddedObject( xObj, rName, sal_False ) ) + { + // remember object + AddEmbeddedObject( xObj, rName ); + return sal_True; + } + else + return sal_False; +} + +uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference < io::XInputStream >& xStm, ::rtl::OUString& rNewName ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( InputStream )" ); + + if ( !rNewName.getLength() ) + rNewName = CreateUniqueObjectName(); + + // store it into the container storage + sal_Bool bIsStorage = sal_False; + try + { + // first try storage persistence + uno::Reference < embed::XStorage > xStore = ::comphelper::OStorageHelper::GetStorageFromInputStream( xStm ); + + // storage was created from stream successfully + bIsStorage = sal_True; + + uno::Reference < embed::XStorage > xNewStore = pImpl->mxStorage->openStorageElement( rNewName, embed::ElementModes::READWRITE ); + xStore->copyToStorage( xNewStore ); + } + catch ( uno::Exception& ) + { + if ( bIsStorage ) + // it is storage persistence, but opening of new substorage or copying to it failed + return uno::Reference < embed::XEmbeddedObject >(); + + // stream didn't contain a storage, now try stream persistence + try + { + uno::Reference < io::XStream > xNewStream = pImpl->mxStorage->openStreamElement( rNewName, embed::ElementModes::READWRITE ); + ::comphelper::OStorageHelper::CopyInputToOutput( xStm, xNewStream->getOutputStream() ); + + // No mediatype is provided so the default for OLE objects value is used + // it is correct so for now, but what if somebody introduces a new stream based embedded object? + // Probably introducing of such an object must be restricted ( a storage must be used! ). + uno::Reference< beans::XPropertySet > xProps( xNewStream, uno::UNO_QUERY_THROW ); + xProps->setPropertyValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ), + uno::makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.sun.star.oleobject" ) ) ) ); + } + catch ( uno::Exception& ) + { + // complete disaster! + return uno::Reference < embed::XEmbeddedObject >(); + } + } + + // stream was copied into the container storage in either way, now try to open something form it + uno::Reference < embed::XEmbeddedObject > xRet = GetEmbeddedObject( rNewName ); + try + { + if ( !xRet.is() ) + // no object could be created, so withdraw insertion + pImpl->mxStorage->removeElement( rNewName ); + } + catch ( uno::Exception& ) + { + } + + return xRet; +} + +uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedObject( const ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& aMedium, ::rtl::OUString& rNewName ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( MediaDescriptor )" ); + + if ( !rNewName.getLength() ) + rNewName = CreateUniqueObjectName(); + + uno::Reference < embed::XEmbeddedObject > xObj; + try + { + uno::Reference < embed::XEmbedObjectCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY ); + uno::Sequence< beans::PropertyValue > aObjDescr( 1 ); + aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) ); + aObjDescr[0].Value <<= pImpl->m_xModel.get(); + xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitFromMediaDescriptor( + pImpl->mxStorage, rNewName, aMedium, aObjDescr ), uno::UNO_QUERY ); + uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); + + OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED, + "A freshly create object should be running always!\n" ); + + // possible optimization: store later! + if ( xPersist.is()) + xPersist->storeOwn(); + + AddEmbeddedObject( xObj, rNewName ); + } + catch ( uno::Exception& ) + { + } + + return xObj; +} + +uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedLink( const ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& aMedium, ::rtl::OUString& rNewName ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedLink" ); + + if ( !rNewName.getLength() ) + rNewName = CreateUniqueObjectName(); + + uno::Reference < embed::XEmbeddedObject > xObj; + try + { + uno::Reference < embed::XLinkCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY ); + uno::Sequence< beans::PropertyValue > aObjDescr( 1 ); + aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) ); + aObjDescr[0].Value <<= pImpl->m_xModel.get(); + xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceLink( + pImpl->mxStorage, rNewName, aMedium, aObjDescr ), uno::UNO_QUERY ); + + uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); + + OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED, + "A freshly create object should be running always!\n" ); + + // possible optimization: store later! + if ( xPersist.is()) + xPersist->storeOwn(); + + AddEmbeddedObject( xObj, rNewName ); + } + catch ( uno::Exception& ) + { + } + + return xObj; +} + +sal_Bool EmbeddedObjectContainer::TryToCopyGraphReplacement( EmbeddedObjectContainer& rSrc, + const ::rtl::OUString& aOrigName, + const ::rtl::OUString& aTargetName ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::TryToCopyGraphReplacement" ); + + sal_Bool bResult = sal_False; + + if ( ( &rSrc != this || !aOrigName.equals( aTargetName ) ) && aOrigName.getLength() && aTargetName.getLength() ) + { + ::rtl::OUString aMediaType; + uno::Reference < io::XInputStream > xGrStream = rSrc.GetGraphicStream( aOrigName, &aMediaType ); + if ( xGrStream.is() ) + bResult = InsertGraphicStream( xGrStream, aTargetName, aMediaType ); + } + + return bResult; +} + +sal_Bool EmbeddedObjectContainer::CopyEmbeddedObject( EmbeddedObjectContainer& rSrc, const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CopyEmbeddedObject" ); + + OSL_ENSURE( sal_False, + "This method is depricated! Use EmbeddedObjectContainer::CopyAndGetEmbeddedObject() to copy object!\n" ); + + // get the object name before(!) it is assigned to a new storage + ::rtl::OUString aOrigName; + uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); + if ( xPersist.is() ) + aOrigName = xPersist->getEntryName(); + + if ( !rName.getLength() ) + rName = CreateUniqueObjectName(); + + if ( StoreEmbeddedObject( xObj, rName, sal_True ) ) + { + TryToCopyGraphReplacement( rSrc, aOrigName, rName ); + return sal_True; + } + + return sal_False; +} + +uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CopyAndGetEmbeddedObject( EmbeddedObjectContainer& rSrc, const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CopyAndGetEmbeddedObject" ); + + uno::Reference< embed::XEmbeddedObject > xResult; + + // TODO/LATER: For now only objects that implement XEmbedPersist have a replacement image, it might change in future + // do an incompatible change so that object name is provided in all the move and copy methods + ::rtl::OUString aOrigName; + try + { + uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY_THROW ); + aOrigName = xPersist->getEntryName(); + } + catch( uno::Exception& ) + {} + + if ( !rName.getLength() ) + rName = CreateUniqueObjectName(); + + // objects without persistance are not really stored by the method + if ( xObj.is() && StoreEmbeddedObject( xObj, rName, sal_True ) ) + { + xResult = Get_Impl( rName, xObj); + if ( !xResult.is() ) + { + // this is a case when object has no real persistence + // in such cases a new object should be explicitly created and initialized with the data of the old one + try + { + uno::Reference< embed::XLinkageSupport > xOrigLinkage( xObj, uno::UNO_QUERY ); + if ( xOrigLinkage.is() && xOrigLinkage->isLink() ) + { + // this is a OOo link, it has no persistence + ::rtl::OUString aURL = xOrigLinkage->getLinkURL(); + if ( !aURL.getLength() ) + throw uno::RuntimeException(); + + // create new linked object from the URL the link is based on + uno::Reference < embed::XLinkCreator > xCreator( + ::comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator") ) ), + uno::UNO_QUERY_THROW ); + + uno::Sequence< beans::PropertyValue > aMediaDescr( 1 ); + aMediaDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) ); + aMediaDescr[0].Value <<= aURL; + uno::Sequence< beans::PropertyValue > aObjDescr( 1 ); + aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) ); + aObjDescr[0].Value <<= pImpl->m_xModel.get(); + xResult = uno::Reference < embed::XEmbeddedObject >( + xCreator->createInstanceLink( + pImpl->mxStorage, + rName, + aMediaDescr, + aObjDescr ), + uno::UNO_QUERY_THROW ); + } + else + { + // the component is required for copying of this object + if ( xObj->getCurrentState() == embed::EmbedStates::LOADED ) + xObj->changeState( embed::EmbedStates::RUNNING ); + + // this must be an object based on properties, otherwise we can not copy it currently + uno::Reference< beans::XPropertySet > xOrigProps( xObj->getComponent(), uno::UNO_QUERY_THROW ); + + // use object class ID to create a new one and tranfer all the properties + uno::Reference < embed::XEmbedObjectCreator > xCreator( + ::comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator") ) ), + uno::UNO_QUERY_THROW ); + + uno::Sequence< beans::PropertyValue > aObjDescr( 1 ); + aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) ); + aObjDescr[0].Value <<= pImpl->m_xModel.get(); + xResult = uno::Reference < embed::XEmbeddedObject >( + xCreator->createInstanceInitNew( + xObj->getClassID(), + xObj->getClassName(), + pImpl->mxStorage, + rName, + aObjDescr ), + uno::UNO_QUERY_THROW ); + + if ( xResult->getCurrentState() == embed::EmbedStates::LOADED ) + xResult->changeState( embed::EmbedStates::RUNNING ); + + uno::Reference< beans::XPropertySet > xTargetProps( xResult->getComponent(), uno::UNO_QUERY_THROW ); + + // copy all the properties from xOrigProps to xTargetProps + uno::Reference< beans::XPropertySetInfo > xOrigInfo = xOrigProps->getPropertySetInfo(); + if ( !xOrigInfo.is() ) + throw uno::RuntimeException(); + + uno::Sequence< beans::Property > aPropertiesList = xOrigInfo->getProperties(); + for ( sal_Int32 nInd = 0; nInd < aPropertiesList.getLength(); nInd++ ) + { + try + { + xTargetProps->setPropertyValue( + aPropertiesList[nInd].Name, + xOrigProps->getPropertyValue( aPropertiesList[nInd].Name ) ); + } + catch( beans::PropertyVetoException& ) + { + // impossibility to copy readonly property is not treated as an error for now + // but the assertion is helpful to detect such scenarios and review them + OSL_ENSURE( sal_False, "Could not copy readonly property!\n" ); + } + } + } + + if ( xResult.is() ) + AddEmbeddedObject( xResult, rName ); + } + catch( uno::Exception& ) + { + if ( xResult.is() ) + { + try + { + xResult->close( sal_True ); + } + catch( uno::Exception& ) + {} + xResult = uno::Reference< embed::XEmbeddedObject >(); + } + } + } + } + + OSL_ENSURE( xResult.is(), "Can not copy embedded object that has no persistance!\n" ); + + if ( xResult.is() ) + { + // the object is successfully copied, try to copy graphical replacement + if ( aOrigName.getLength() ) + TryToCopyGraphReplacement( rSrc, aOrigName, rName ); + + // the object might need the size to be set + try + { + if ( xResult->getStatus( embed::Aspects::MSOLE_CONTENT ) & embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD ) + xResult->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, + xObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ) ); + } + catch( uno::Exception& ) + {} + } + + return xResult; +} + +sal_Bool EmbeddedObjectContainer::MoveEmbeddedObject( EmbeddedObjectContainer& rSrc, const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::MoveEmbeddedObject( Object )" ); + + // get the object name before(!) it is assigned to a new storage + uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); + ::rtl::OUString aName; + if ( xPersist.is() ) + aName = xPersist->getEntryName(); + + // now move the object to the new container; the returned name is the new persist name in this container + sal_Bool bRet; + + try + { + bRet = InsertEmbeddedObject( xObj, rName ); + if ( bRet ) + TryToCopyGraphReplacement( rSrc, aName, rName ); + } + catch ( uno::Exception& e ) + { + (void)e; + OSL_ENSURE( sal_False, "Failed to insert embedded object into storage!" ); + bRet = sal_False; + } + + if ( bRet ) + { + // now remove the object from the former container + bRet = sal_False; + EmbeddedObjectContainerNameMap::iterator aIt = rSrc.pImpl->maObjectContainer.begin(); + while ( aIt != rSrc.pImpl->maObjectContainer.end() ) + { + if ( (*aIt).second == xObj ) + { + rSrc.pImpl->maObjectContainer.erase( aIt ); + bRet = sal_True; + break; + } + + aIt++; + } + + OSL_ENSURE( bRet, "Object not found for removal!" ); + if ( xPersist.is() ) + { + // now it's time to remove the storage from the container storage + try + { + if ( xPersist.is() ) + rSrc.pImpl->mxStorage->removeElement( aName ); + } + catch ( uno::Exception& ) + { + OSL_ENSURE( sal_False, "Failed to remove object from storage!" ); + bRet = sal_False; + } + } + + // rSrc.RemoveGraphicStream( aName ); + } + + return bRet; +} + +sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const ::rtl::OUString& rName, sal_Bool bClose ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveEmbeddedObject( Name )" ); + + uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( rName ); + if ( xObj.is() ) + return RemoveEmbeddedObject( xObj, bClose ); + else + return sal_False; +} + +sal_Bool EmbeddedObjectContainer::MoveEmbeddedObject( const ::rtl::OUString& rName, EmbeddedObjectContainer& rCnt ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::MoveEmbeddedObject( Name )" ); + + // find object entry + EmbeddedObjectContainerNameMap::iterator aIt2 = rCnt.pImpl->maObjectContainer.find( rName ); + OSL_ENSURE( aIt2 == rCnt.pImpl->maObjectContainer.end(), "Object does already exist in target container!" ); + + if ( aIt2 != rCnt.pImpl->maObjectContainer.end() ) + return sal_False; + + uno::Reference < embed::XEmbeddedObject > xObj; + EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName ); + if ( aIt != pImpl->maObjectContainer.end() ) + { + xObj = (*aIt).second; + try + { + if ( xObj.is() ) + { + // move object + ::rtl::OUString aName( rName ); + rCnt.InsertEmbeddedObject( xObj, aName ); + pImpl->maObjectContainer.erase( aIt ); + uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); + if ( xPersist.is() ) + pImpl->mxStorage->removeElement( rName ); + } + else + { + // copy storages; object *must* have persistence! + uno::Reference < embed::XStorage > xOld = pImpl->mxStorage->openStorageElement( rName, embed::ElementModes::READ ); + uno::Reference < embed::XStorage > xNew = rCnt.pImpl->mxStorage->openStorageElement( rName, embed::ElementModes::READWRITE ); + xOld->copyToStorage( xNew ); + } + + rCnt.TryToCopyGraphReplacement( *this, rName, rName ); + // RemoveGraphicStream( rName ); + + return sal_True; + } + catch ( uno::Exception& ) + { + OSL_ENSURE(0,"Could not move object!"); + return sal_False; + } + + } + else + OSL_ENSURE(0,"Unknown object!"); + return sal_False; +} + +sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Bool bClose ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveEmbeddedObject( Object )" ); + + uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); + ::rtl::OUString aName; + if ( xPersist.is() ) + aName = xPersist->getEntryName(); + +#if OSL_DEBUG_LEVEL > 1 + uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY ); + uno::Reference < embed::XLinkageSupport > xLink( xPersist, uno::UNO_QUERY ); + sal_Bool bIsNotEmbedded = !xPersist.is() || xLink.is() && xLink->isLink(); + + // if the object has a persistance and the object is not a link than it must have persistence entry in the storage + OSL_ENSURE( bIsNotEmbedded || xAccess->hasByName(aName), "Removing element not present in storage!" ); +#endif + + // try to close it if permitted + if ( bClose ) + { + uno::Reference < ::util::XCloseable > xClose( xObj, uno::UNO_QUERY ); + try + { + xClose->close( sal_True ); + } + catch ( util::CloseVetoException& ) + { + bClose = sal_False; + } + } + + if ( !bClose ) + { + // somebody still needs the object, so we must assign a temporary persistence + try + { + if ( xPersist.is() ) + { + /* + //TODO/LATER: needs storage handling! Why not letting the object do it?! + if ( !pImpl->mxTempStorage.is() ) + pImpl->mxTempStorage = ::comphelper::OStorageHelper::GetTemporaryStorage(); + uno::Sequence < beans::PropertyValue > aSeq; + + ::rtl::OUString aTmpPersistName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Object ") ); + aTmpPersistName += ::rtl::OUString::valueOf( (sal_Int32) pImpl->maTempObjectContainer.size() ); + + xPersist->storeAsEntry( pImpl->mxTempStorage, aTmpPersistName, aSeq, aSeq ); + xPersist->saveCompleted( sal_True ); + + pImpl->maTempObjectContainer[ aTmpPersistName ] = uno::Reference < embed::XEmbeddedObject >(); + */ + + if ( !pImpl->mpTempObjectContainer ) + { + pImpl->mpTempObjectContainer = new EmbeddedObjectContainer(); + try + { + // TODO/LATER: in future probably the temporary container will have two storages ( of two formats ) + // the media type will be provided with object insertion + ::rtl::OUString aOrigStorMediaType; + uno::Reference< beans::XPropertySet > xStorProps( pImpl->mxStorage, uno::UNO_QUERY_THROW ); + static const ::rtl::OUString s_sMediaType(RTL_CONSTASCII_USTRINGPARAM("MediaType")); + xStorProps->getPropertyValue( s_sMediaType ) >>= aOrigStorMediaType; + + OSL_ENSURE( aOrigStorMediaType.getLength(), "No valuable media type in the storage!\n" ); + + uno::Reference< beans::XPropertySet > xTargetStorProps( + pImpl->mpTempObjectContainer->pImpl->mxStorage, + uno::UNO_QUERY_THROW ); + xTargetStorProps->setPropertyValue( s_sMediaType,uno::makeAny( aOrigStorMediaType ) ); + } + catch( uno::Exception& ) + { + OSL_ENSURE( sal_False, "Can not set the new media type to a storage!\n" ); + } + } + + ::rtl::OUString aTempName, aMediaType; + pImpl->mpTempObjectContainer->InsertEmbeddedObject( xObj, aTempName ); + + uno::Reference < io::XInputStream > xStream = GetGraphicStream( xObj, &aMediaType ); + if ( xStream.is() ) + pImpl->mpTempObjectContainer->InsertGraphicStream( xStream, aTempName, aMediaType ); + + // object is stored, so at least it can be set to loaded state + xObj->changeState( embed::EmbedStates::LOADED ); + } + else + // objects without persistence need to stay in running state if they shall not be closed + xObj->changeState( embed::EmbedStates::RUNNING ); + } + catch ( uno::Exception& ) + { + return sal_False; + } + } + + sal_Bool bFound = sal_False; + EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); + while ( aIt != pImpl->maObjectContainer.end() ) + { + if ( (*aIt).second == xObj ) + { + pImpl->maObjectContainer.erase( aIt ); + bFound = sal_True; + uno::Reference < container::XChild > xChild( xObj, uno::UNO_QUERY ); + if ( xChild.is() ) + xChild->setParent( uno::Reference < uno::XInterface >() ); + break; + } + + aIt++; + } + + OSL_ENSURE( bFound, "Object not found for removal!" ); + if ( xPersist.is() ) + { + // remove replacement image (if there is one) + RemoveGraphicStream( aName ); + + // now it's time to remove the storage from the container storage + try + { +#if OSL_DEBUG_LEVEL > 1 + // if the object has a persistance and the object is not a link than it must have persistence entry in storage + OSL_ENSURE( bIsNotEmbedded || pImpl->mxStorage->hasByName( aName ), "The object has no persistence entry in the storage!" ); +#endif + if ( xPersist.is() && pImpl->mxStorage->hasByName( aName ) ) + pImpl->mxStorage->removeElement( aName ); + } + catch ( uno::Exception& ) + { + OSL_ENSURE( sal_False, "Failed to remove object from storage!" ); + return sal_False; + } + } + + return sal_True; +} + +sal_Bool EmbeddedObjectContainer::CloseEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CloseEmbeddedObject" ); + + // disconnect the object from the container and close it if possible + + sal_Bool bFound = sal_False; + EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); + while ( aIt != pImpl->maObjectContainer.end() ) + { + if ( (*aIt).second == xObj ) + { + pImpl->maObjectContainer.erase( aIt ); + bFound = sal_True; + break; + } + + aIt++; + } + + if ( bFound ) + { + uno::Reference < ::util::XCloseable > xClose( xObj, uno::UNO_QUERY ); + try + { + xClose->close( sal_True ); + } + catch ( uno::Exception& ) + { + // it is no problem if the object is already closed + // TODO/LATER: what if the object can not be closed? + } + } + + return bFound; +} + +uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetGraphicStream( const ::rtl::OUString& aName, rtl::OUString* pMediaType ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetGraphicStream( Name )" ); + + uno::Reference < io::XInputStream > xStream; + + OSL_ENSURE( aName.getLength(), "Retrieving graphic for unknown object!" ); + if ( aName.getLength() ) + { + try + { + uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements(); + uno::Reference < io::XStream > xGraphicStream = xReplacements->openStreamElement( aName, embed::ElementModes::READ ); + xStream = xGraphicStream->getInputStream(); + if ( pMediaType ) + { + uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY ); + if ( xSet.is() ) + { + uno::Any aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("MediaType") ); + aAny >>= *pMediaType; + } + } + } + catch ( uno::Exception& ) + { + } + } + + return xStream; +} + +uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetGraphicStream( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj, rtl::OUString* pMediaType ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetGraphicStream( Object )" ); + + // get the object name + ::rtl::OUString aName; + EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); + while ( aIt != pImpl->maObjectContainer.end() ) + { + if ( (*aIt).second == xObj ) + { + aName = (*aIt).first; + break; + } + + aIt++; + } + + // try to load it from the container storage + return GetGraphicStream( aName, pMediaType ); +} + +sal_Bool EmbeddedObjectContainer::InsertGraphicStream( const com::sun::star::uno::Reference < com::sun::star::io::XInputStream >& rStream, const ::rtl::OUString& rObjectName, const rtl::OUString& rMediaType ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertGraphicStream" ); + + try + { + uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements(); + + // store it into the subfolder + uno::Reference < io::XOutputStream > xOutStream; + uno::Reference < io::XStream > xGraphicStream = xReplacements->openStreamElement( rObjectName, + embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE ); + xOutStream = xGraphicStream->getOutputStream(); + ::comphelper::OStorageHelper::CopyInputToOutput( rStream, xOutStream ); + xOutStream->flush(); + + uno::Reference< beans::XPropertySet > xPropSet( xGraphicStream, uno::UNO_QUERY ); + if ( !xPropSet.is() ) + throw uno::RuntimeException(); + + xPropSet->setPropertyValue( ::rtl::OUString::createFromAscii( "UseCommonStoragePasswordEncryption" ), + uno::makeAny( (sal_Bool)sal_True ) ); + uno::Any aAny; + aAny <<= rMediaType; + xPropSet->setPropertyValue( ::rtl::OUString::createFromAscii("MediaType"), aAny ); + + xPropSet->setPropertyValue( ::rtl::OUString::createFromAscii( "Compressed" ), + uno::makeAny( (sal_Bool)sal_True ) ); + } + catch( uno::Exception& ) + { + return sal_False; + } + + return sal_True; +} + +sal_Bool EmbeddedObjectContainer::InsertGraphicStreamDirectly( const com::sun::star::uno::Reference < com::sun::star::io::XInputStream >& rStream, const ::rtl::OUString& rObjectName, const rtl::OUString& rMediaType ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertGraphicStreamDirectly" ); + + try + { + uno::Reference < embed::XStorage > xReplacement = pImpl->GetReplacements(); + uno::Reference < embed::XOptimizedStorage > xOptRepl( xReplacement, uno::UNO_QUERY_THROW ); + + // store it into the subfolder + uno::Sequence< beans::PropertyValue > aProps( 3 ); + aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ); + aProps[0].Value <<= rMediaType; + aProps[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseCommonStoragePasswordEncryption" ) ); + aProps[1].Value <<= (sal_Bool)sal_True; + aProps[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Compressed" ) ); + aProps[2].Value <<= (sal_Bool)sal_True; + + if ( xReplacement->hasByName( rObjectName ) ) + xReplacement->removeElement( rObjectName ); + + xOptRepl->insertStreamElementDirect( rObjectName, rStream, aProps ); + } + catch( uno::Exception& ) + { + return sal_False; + } + + return sal_True; +} + + +sal_Bool EmbeddedObjectContainer::RemoveGraphicStream( const ::rtl::OUString& rObjectName ) +{ + RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveGraphicStream" ); + + try + { + uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements(); + xReplacements->removeElement( rObjectName ); + } + catch( uno::Exception& ) + { + return sal_False; + } + + return sal_True; +} +namespace { + void InsertStreamIntoPicturesStorage_Impl( const uno::Reference< embed::XStorage >& xDocStor, + const uno::Reference< io::XInputStream >& xInStream, + const ::rtl::OUString& aStreamName ) + { + OSL_ENSURE( aStreamName.getLength() && xInStream.is() && xDocStor.is(), "Misuse of the method!\n" ); + + try + { + uno::Reference< embed::XStorage > xPictures = xDocStor->openStorageElement( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Pictures" ) ), + embed::ElementModes::READWRITE ); + uno::Reference< io::XStream > xObjReplStr = xPictures->openStreamElement( + aStreamName, + embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE ); + uno::Reference< io::XOutputStream > xOutStream( + xObjReplStr->getInputStream(), uno::UNO_QUERY_THROW ); + + ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xOutStream ); + xOutStream->closeOutput(); + + uno::Reference< embed::XTransactedObject > xTransact( xPictures, uno::UNO_QUERY ); + if ( xTransact.is() ) + xTransact->commit(); + } + catch( uno::Exception& ) + { + OSL_ENSURE( sal_False, "The pictures storage is not available!\n" ); + } + } + +} +// ----------------------------------------------------------------------------- +sal_Bool EmbeddedObjectContainer::StoreAsChildren(sal_Bool _bOasisFormat,sal_Bool _bCreateEmbedded,const uno::Reference < embed::XStorage >& _xStorage) +{ + sal_Bool bResult = sal_False; + try + { + comphelper::EmbeddedObjectContainer aCnt( _xStorage ); + const uno::Sequence < ::rtl::OUString > aNames = GetObjectNames(); + const ::rtl::OUString* pIter = aNames.getConstArray(); + const ::rtl::OUString* pEnd = pIter + aNames.getLength(); + for(;pIter != pEnd;++pIter) + { + uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter ); + OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" ); + if ( xObj.is() ) + { + sal_Bool bSwitchBackToLoaded = sal_False; + uno::Reference< embed::XLinkageSupport > xLink( xObj, uno::UNO_QUERY ); + + uno::Reference < io::XInputStream > xStream; + ::rtl::OUString aMediaType; + + sal_Int32 nCurState = xObj->getCurrentState(); + if ( nCurState == embed::EmbedStates::LOADED || nCurState == embed::EmbedStates::RUNNING ) + { + // means that the object is not active + // copy replacement image from old to new container + xStream = GetGraphicStream( xObj, &aMediaType ); + } + + if ( !xStream.is() ) + { + // the image must be regenerated + // TODO/LATER: another aspect could be used + if ( xObj->getCurrentState() == embed::EmbedStates::LOADED ) + bSwitchBackToLoaded = sal_True; + + xStream = GetGraphicReplacementStream( + embed::Aspects::MSOLE_CONTENT, + xObj, + &aMediaType ); + } + + if ( _bOasisFormat || (xLink.is() && xLink->isLink()) ) + { + if ( xStream.is() ) + { + if ( _bOasisFormat ) + { + // if it is an embedded object or the optimized inserting fails the normal inserting should be done + if ( _bCreateEmbedded + || !aCnt.InsertGraphicStreamDirectly( xStream, *pIter, aMediaType ) ) + aCnt.InsertGraphicStream( xStream, *pIter, aMediaType ); + } + else + { + // it is a linked object exported into SO7 format + InsertStreamIntoPicturesStorage_Impl( _xStorage, xStream, *pIter ); + } + } + } + + uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); + if ( xPersist.is() ) + { + uno::Sequence< beans::PropertyValue > aArgs( _bOasisFormat ? 2 : 3 ); + aArgs[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StoreVisualReplacement" ) ); + aArgs[0].Value <<= (sal_Bool)( !_bOasisFormat ); + + // if it is an embedded object or the optimized inserting fails the normal inserting should be done + aArgs[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CanTryOptimization" ) ); + aArgs[1].Value <<= !_bCreateEmbedded; + if ( !_bOasisFormat ) + { + // if object has no cached replacement it will use this one + aArgs[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VisualReplacement" ) ); + aArgs[2].Value <<= xStream; + } + + xPersist->storeAsEntry( _xStorage, + xPersist->getEntryName(), + uno::Sequence< beans::PropertyValue >(), + aArgs ); + } + + if ( bSwitchBackToLoaded ) + // switch back to loaded state; that way we have a minimum cache confusion + xObj->changeState( embed::EmbedStates::LOADED ); + } + } + + bResult = aCnt.CommitImageSubStorage(); + + } + catch ( uno::Exception& ) + { + // TODO/LATER: error handling + bResult = sal_False; + } + + // the old SO6 format does not store graphical replacements + if ( !_bOasisFormat && bResult ) + { + try + { + // the substorage still can not be locked by the embedded object conteiner + ::rtl::OUString aObjReplElement( RTL_CONSTASCII_USTRINGPARAM( "ObjectReplacements" ) ); + if ( _xStorage->hasByName( aObjReplElement ) && _xStorage->isStorageElement( aObjReplElement ) ) + _xStorage->removeElement( aObjReplElement ); + } + catch ( uno::Exception& ) + { + // TODO/LATER: error handling; + bResult = sal_False; + } + } + return bResult; +} +// ----------------------------------------------------------------------------- +sal_Bool EmbeddedObjectContainer::StoreChildren(sal_Bool _bOasisFormat,sal_Bool _bObjectsOnly) +{ + sal_Bool bResult = sal_True; + const uno::Sequence < ::rtl::OUString > aNames = GetObjectNames(); + const ::rtl::OUString* pIter = aNames.getConstArray(); + const ::rtl::OUString* pEnd = pIter + aNames.getLength(); + for(;pIter != pEnd;++pIter) + { + uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter ); + OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" ); + if ( xObj.is() ) + { + sal_Int32 nCurState = xObj->getCurrentState(); + if ( _bOasisFormat && nCurState != embed::EmbedStates::LOADED && nCurState != embed::EmbedStates::RUNNING ) + { + // means that the object is active + // the image must be regenerated + ::rtl::OUString aMediaType; + + // TODO/LATER: another aspect could be used + uno::Reference < io::XInputStream > xStream = + GetGraphicReplacementStream( + embed::Aspects::MSOLE_CONTENT, + xObj, + &aMediaType ); + if ( xStream.is() ) + { + if ( !InsertGraphicStreamDirectly( xStream, *pIter, aMediaType ) ) + InsertGraphicStream( xStream, *pIter, aMediaType ); + } + } + + // TODO/LATER: currently the object by default does not cache replacement image + // that means that if somebody loads SO7 document and store its objects using + // this method the images might be lost. + // Currently this method is only used on storing to alien formats, that means + // that SO7 documents storing does not use it, and all other filters are + // based on OASIS format. But if it changes the method must be fixed. The fix + // must be done only on demand since it can affect performance. + + uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); + if ( xPersist.is() ) + { + try + { + //TODO/LATER: only storing if changed! + xPersist->storeOwn(); + } + catch( uno::Exception& ) + { + // TODO/LATER: error handling + bResult = sal_False; + break; + } + } + + if ( !_bOasisFormat && !_bObjectsOnly ) + { + // copy replacement images for linked objects + try + { + uno::Reference< embed::XLinkageSupport > xLink( xObj, uno::UNO_QUERY ); + if ( xLink.is() && xLink->isLink() ) + { + ::rtl::OUString aMediaType; + uno::Reference < io::XInputStream > xInStream = GetGraphicStream( xObj, &aMediaType ); + if ( xInStream.is() ) + InsertStreamIntoPicturesStorage_Impl( pImpl->mxStorage, xInStream, *pIter ); + } + } + catch( uno::Exception& ) + { + } + } + } + } + + if ( bResult && _bOasisFormat ) + bResult = CommitImageSubStorage(); + + if ( bResult && !_bObjectsOnly ) + { + try + { + ReleaseImageSubStorage(); + ::rtl::OUString aObjReplElement( RTL_CONSTASCII_USTRINGPARAM( "ObjectReplacements" ) ); + if ( !_bOasisFormat && pImpl->mxStorage->hasByName( aObjReplElement ) && pImpl->mxStorage->isStorageElement( aObjReplElement ) ) + pImpl->mxStorage->removeElement( aObjReplElement ); + } + catch( uno::Exception& ) + { + // TODO/LATER: error handling + bResult = sal_False; + } + } + return bResult; +} +// ----------------------------------------------------------------------------- +uno::Reference< io::XInputStream > EmbeddedObjectContainer::GetGraphicReplacementStream( + sal_Int64 nViewAspect, + const uno::Reference< embed::XEmbeddedObject >& xObj, + ::rtl::OUString* pMediaType ) +{ + uno::Reference< io::XInputStream > xInStream; + if ( xObj.is() ) + { + try + { + // retrieving of the visual representation can switch object to running state + embed::VisualRepresentation aRep = xObj->getPreferredVisualRepresentation( nViewAspect ); + if ( pMediaType ) + *pMediaType = aRep.Flavor.MimeType; + + uno::Sequence < sal_Int8 > aSeq; + aRep.Data >>= aSeq; + xInStream = new ::comphelper::SequenceInputStream( aSeq ); + } + catch ( uno::Exception& ) + { + } + } + + return xInStream; +} +// ----------------------------------------------------------------------------- +sal_Bool EmbeddedObjectContainer::SetPersistentEntries(const uno::Reference< embed::XStorage >& _xStorage,bool _bClearModifedFlag) +{ + sal_Bool bError = sal_False; + const uno::Sequence < ::rtl::OUString > aNames = GetObjectNames(); + const ::rtl::OUString* pIter = aNames.getConstArray(); + const ::rtl::OUString* pEnd = pIter + aNames.getLength(); + for(;pIter != pEnd;++pIter) + { + uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter ); + OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" ); + if ( xObj.is() ) + { + uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); + if ( xPersist.is() ) + { + try + { + xPersist->setPersistentEntry( _xStorage, + *pIter, + embed::EntryInitModes::NO_INIT, + uno::Sequence< beans::PropertyValue >(), + uno::Sequence< beans::PropertyValue >() ); + + } + catch( uno::Exception& ) + { + // TODO/LATER: error handling + bError = sal_True; + break; + } + } + if ( _bClearModifedFlag ) + { + // if this method is used as part of SaveCompleted the object must stay unmodified after execution + try + { + uno::Reference< util::XModifiable > xModif( xObj->getComponent(), uno::UNO_QUERY_THROW ); + if ( xModif->isModified() ) + xModif->setModified( sal_False ); + } + catch( uno::Exception& ) + { + } + } + } + } + return bError; +} +} diff --git a/comphelper/source/container/enumerablemap.cxx b/comphelper/source/container/enumerablemap.cxx new file mode 100644 index 000000000000..15241cd72dd6 --- /dev/null +++ b/comphelper/source/container/enumerablemap.cxx @@ -0,0 +1,1000 @@ +/************************************************************************* + * 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_module.hxx" +#include "comphelper/anytostring.hxx" +#include "comphelper/componentbase.hxx" +#include "comphelper/componentcontext.hxx" +#include "comphelper/extract.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/container/XEnumerableMap.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/ucb/AlreadyInitializedException.hpp> +#include <com/sun/star/beans/Pair.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +/** === end UNO includes === **/ + +#include <cppuhelper/compbase3.hxx> +#include <cppuhelper/implbase1.hxx> +#include <rtl/math.hxx> +#include <rtl/ustrbuf.hxx> +#include <typelib/typedescription.hxx> + +#include <functional> +#include <map> +#include <memory> +#include <boost/shared_ptr.hpp> + +//........................................................................ +namespace comphelper +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Type; + using ::com::sun::star::container::XEnumerableMap; + using ::com::sun::star::lang::NoSupportException; + using ::com::sun::star::beans::IllegalTypeException; + using ::com::sun::star::container::NoSuchElementException; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::lang::XInitialization; + using ::com::sun::star::ucb::AlreadyInitializedException; + using ::com::sun::star::beans::Pair; + using ::com::sun::star::uno::TypeClass; + using ::com::sun::star::uno::TypeClass_VOID; + using ::com::sun::star::uno::TypeClass_CHAR; + using ::com::sun::star::uno::TypeClass_BOOLEAN; + using ::com::sun::star::uno::TypeClass_BYTE; + using ::com::sun::star::uno::TypeClass_SHORT; + using ::com::sun::star::uno::TypeClass_UNSIGNED_SHORT; + using ::com::sun::star::uno::TypeClass_LONG; + using ::com::sun::star::uno::TypeClass_UNSIGNED_LONG; + using ::com::sun::star::uno::TypeClass_HYPER; + using ::com::sun::star::uno::TypeClass_UNSIGNED_HYPER; + using ::com::sun::star::uno::TypeClass_FLOAT; + using ::com::sun::star::uno::TypeClass_DOUBLE; + using ::com::sun::star::uno::TypeClass_STRING; + using ::com::sun::star::uno::TypeClass_TYPE; + using ::com::sun::star::uno::TypeClass_ENUM; + using ::com::sun::star::uno::TypeClass_INTERFACE; + using ::com::sun::star::uno::TypeClass_UNKNOWN; + using ::com::sun::star::uno::TypeClass_ANY; + using ::com::sun::star::uno::TypeClass_EXCEPTION; + using ::com::sun::star::uno::TypeClass_STRUCT; + using ::com::sun::star::uno::TypeClass_UNION; + using ::com::sun::star::lang::XServiceInfo; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::container::XEnumeration; + using ::com::sun::star::uno::TypeDescription; + using ::com::sun::star::lang::WrappedTargetException; + using ::com::sun::star::lang::DisposedException; + /** === end UNO using === **/ + + //==================================================================== + //= IKeyPredicateLess + //==================================================================== + class SAL_NO_VTABLE IKeyPredicateLess + { + public: + virtual bool isLess( const Any& _lhs, const Any& _rhs ) const = 0; + virtual ~IKeyPredicateLess() {} + }; + + //==================================================================== + //= LessPredicateAdapter + //==================================================================== + struct LessPredicateAdapter : public ::std::binary_function< Any, Any, bool > + { + LessPredicateAdapter( const IKeyPredicateLess& _predicate ) + :m_predicate( _predicate ) + { + } + + bool operator()( const Any& _lhs, const Any& _rhs ) const + { + return m_predicate.isLess( _lhs, _rhs ); + } + + private: + const IKeyPredicateLess& m_predicate; + + private: + LessPredicateAdapter(); // never implemented + }; + + //==================================================================== + //= ScalarPredicateLess + //==================================================================== + template< typename SCALAR > + class ScalarPredicateLess : public IKeyPredicateLess + { + public: + virtual bool isLess( const Any& _lhs, const Any& _rhs ) const + { + SCALAR lhs(0), rhs(0); + if ( !( _lhs >>= lhs ) + || !( _rhs >>= rhs ) + ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 ); + return lhs < rhs; + } + }; + + //==================================================================== + //= StringPredicateLess + //==================================================================== + class StringPredicateLess : public IKeyPredicateLess + { + public: + virtual bool isLess( const Any& _lhs, const Any& _rhs ) const + { + ::rtl::OUString lhs, rhs; + if ( !( _lhs >>= lhs ) + || !( _rhs >>= rhs ) + ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 ); + return lhs < rhs; + } + }; + + //==================================================================== + //= TypePredicateLess + //==================================================================== + class TypePredicateLess : public IKeyPredicateLess + { + public: + virtual bool isLess( const Any& _lhs, const Any& _rhs ) const + { + Type lhs, rhs; + if ( !( _lhs >>= lhs ) + || !( _rhs >>= rhs ) + ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 ); + return lhs.getTypeName() < rhs.getTypeName(); + } + }; + + //==================================================================== + //= EnumPredicateLess + //==================================================================== + class EnumPredicateLess : public IKeyPredicateLess + { + public: + EnumPredicateLess( const Type& _enumType ) + :m_enumType( _enumType ) + { + } + + virtual bool isLess( const Any& _lhs, const Any& _rhs ) const + { + sal_Int32 lhs(0), rhs(0); + if ( !::cppu::enum2int( lhs, _lhs ) + || !::cppu::enum2int( rhs, _rhs ) + || !_lhs.getValueType().equals( m_enumType ) + || !_rhs.getValueType().equals( m_enumType ) + ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 ); + return lhs < rhs; + } + + private: + const Type m_enumType; + }; + + //==================================================================== + //= InterfacePredicateLess + //==================================================================== + class InterfacePredicateLess : public IKeyPredicateLess + { + public: + virtual bool isLess( const Any& _lhs, const Any& _rhs ) const + { + if ( ( _lhs.getValueTypeClass() != TypeClass_INTERFACE ) + || ( _rhs.getValueTypeClass() != TypeClass_INTERFACE ) + ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 ); + + Reference< XInterface > lhs( _lhs, UNO_QUERY ); + Reference< XInterface > rhs( _rhs, UNO_QUERY ); + return lhs.get() < rhs.get(); + } + }; + + //==================================================================== + //= MapData + //==================================================================== + class IMapModificationListener; + typedef ::std::vector< IMapModificationListener* > MapListeners; + + typedef ::std::map< Any, Any, LessPredicateAdapter > KeyedValues; + struct MapData + { + Type m_aKeyType; + Type m_aValueType; + ::std::auto_ptr< KeyedValues > m_pValues; + ::boost::shared_ptr< IKeyPredicateLess > m_pKeyCompare; + bool m_bMutable; + MapListeners m_aModListeners; + + MapData() + :m_bMutable( true ) + { + } + + MapData( const MapData& _source ) + :m_aKeyType( _source.m_aKeyType ) + ,m_aValueType( _source.m_aValueType ) + ,m_pValues( new KeyedValues( *_source.m_pValues ) ) + ,m_pKeyCompare( _source.m_pKeyCompare ) + ,m_bMutable( false ) + ,m_aModListeners() + { + } + private: + MapData& operator=( const MapData& _source ); // not implemented + }; + + //==================================================================== + //= IMapModificationListener + //==================================================================== + /** implemented by components who want to be notified of modifications in the MapData they work with + */ + class SAL_NO_VTABLE IMapModificationListener + { + public: + /// called when the map was modified + virtual void mapModified() = 0; + virtual ~IMapModificationListener() + { + } + }; + + //==================================================================== + //= MapData helpers + //==================================================================== + //-------------------------------------------------------------------- + static void lcl_registerMapModificationListener( MapData& _mapData, IMapModificationListener& _listener ) + { + #if OSL_DEBUG_LEVEL > 0 + for ( MapListeners::const_iterator lookup = _mapData.m_aModListeners.begin(); + lookup != _mapData.m_aModListeners.end(); + ++lookup + ) + { + OSL_ENSURE( *lookup != &_listener, "lcl_registerMapModificationListener: this listener is already registered!" ); + } + #endif + _mapData.m_aModListeners.push_back( &_listener ); + } + + //-------------------------------------------------------------------- + static void lcl_revokeMapModificationListener( MapData& _mapData, IMapModificationListener& _listener ) + { + for ( MapListeners::iterator lookup = _mapData.m_aModListeners.begin(); + lookup != _mapData.m_aModListeners.end(); + ++lookup + ) + { + if ( *lookup == &_listener ) + { + _mapData.m_aModListeners.erase( lookup ); + return; + } + } + OSL_ENSURE( false, "lcl_revokeMapModificationListener: the listener is not registered!" ); + } + + //-------------------------------------------------------------------- + static void lcl_notifyMapDataListeners_nothrow( const MapData& _mapData ) + { + for ( MapListeners::const_iterator loop = _mapData.m_aModListeners.begin(); + loop != _mapData.m_aModListeners.end(); + ++loop + ) + { + (*loop)->mapModified(); + } + } + + //==================================================================== + //= EnumerableMap + //==================================================================== + typedef ::cppu::WeakAggComponentImplHelper3 < XInitialization + , XEnumerableMap + , XServiceInfo + > Map_IFace; + + class COMPHELPER_DLLPRIVATE EnumerableMap :public Map_IFace + ,public ComponentBase + { + protected: + EnumerableMap( const ComponentContext& _rContext ); + virtual ~EnumerableMap(); + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException); + + // XEnumerableMap + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL createKeyEnumeration( ::sal_Bool _Isolated ) throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL createValueEnumeration( ::sal_Bool _Isolated ) throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL createElementEnumeration( ::sal_Bool _Isolated ) throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + + // XMap + virtual Type SAL_CALL getKeyType() throw (RuntimeException); + virtual Type SAL_CALL getValueType() throw (RuntimeException); + virtual void SAL_CALL clear( ) throw (NoSupportException, RuntimeException); + virtual ::sal_Bool SAL_CALL containsKey( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException); + virtual ::sal_Bool SAL_CALL containsValue( const Any& _value ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException); + virtual Any SAL_CALL get( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException); + virtual Any SAL_CALL put( const Any& _key, const Any& _value ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, RuntimeException); + virtual Any SAL_CALL remove( const Any& _key ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException); + + // XElementAccess (base of XMap) + virtual Type SAL_CALL getElementType() throw (RuntimeException); + virtual ::sal_Bool SAL_CALL hasElements() 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); + + public: + // XServiceInfo, static version (used for component registration) + static ::rtl::OUString SAL_CALL getImplementationName_static( ); + static Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static( ); + static Reference< XInterface > SAL_CALL Create( const Reference< XComponentContext >& ); + + private: + void impl_initValues_throw( const Sequence< Pair< Any, Any > >& _initialValues ); + + /// throws a IllegalTypeException if the given value is not compatible with our ValueType + void impl_checkValue_throw( const Any& _value ) const; + void impl_checkKey_throw( const Any& _key ) const; + void impl_checkNaN_throw( const Any& _keyOrValue, const Type& _keyOrValueType ) const; + void impl_checkMutable_throw() const; + + private: + ::osl::Mutex m_aMutex; + ComponentContext m_aContext; + MapData m_aData; + + ::std::vector< ::com::sun::star::uno::WeakReference< XInterface > > + m_aDependentComponents; + }; + + //==================================================================== + //= EnumerationType + //==================================================================== + enum EnumerationType + { + eKeys, eValues, eBoth + }; + + //==================================================================== + //= MapEnumerator + //==================================================================== + class MapEnumerator : public IMapModificationListener + { + public: + MapEnumerator( ::cppu::OWeakObject& _rParent, MapData& _mapData, const EnumerationType _type ) + :m_rParent( _rParent ) + ,m_rMapData( _mapData ) + ,m_eType( _type ) + ,m_mapPos( _mapData.m_pValues->begin() ) + ,m_disposed( false ) + { + lcl_registerMapModificationListener( m_rMapData, *this ); + } + + virtual ~MapEnumerator() + { + dispose(); + } + + void dispose() + { + if ( !m_disposed ) + { + lcl_revokeMapModificationListener( m_rMapData, *this ); + m_disposed = true; + } + } + + // XEnumeration equivalents + ::sal_Bool hasMoreElements(); + Any nextElement(); + + // IMapModificationListener + virtual void mapModified(); + + private: + ::cppu::OWeakObject& m_rParent; + MapData& m_rMapData; + const EnumerationType m_eType; + KeyedValues::const_iterator m_mapPos; + bool m_disposed; + + private: + MapEnumerator(); // not implemented + MapEnumerator( const MapEnumerator& ); // not implemented + MapEnumerator& operator=( const MapEnumerator& ); // not implemented + }; + + //==================================================================== + //= MapEnumeration + //==================================================================== + typedef ::cppu::WeakImplHelper1 < XEnumeration + > MapEnumeration_Base; + class MapEnumeration :public ComponentBase + ,public MapEnumeration_Base + { + public: + MapEnumeration( ::cppu::OWeakObject& _parentMap, MapData& _mapData, ::cppu::OBroadcastHelper& _rBHelper, + const EnumerationType _type, const bool _isolated ) + :ComponentBase( _rBHelper, ComponentBase::NoInitializationNeeded() ) + ,m_xKeepMapAlive( _parentMap ) + ,m_pMapDataCopy( _isolated ? new MapData( _mapData ) : NULL ) + ,m_aEnumerator( *this, _isolated ? *m_pMapDataCopy : _mapData, _type ) + { + } + + // XEnumeration + virtual ::sal_Bool SAL_CALL hasMoreElements( ) throw (RuntimeException); + virtual Any SAL_CALL nextElement( ) throw (NoSuchElementException, WrappedTargetException, RuntimeException); + + protected: + virtual ~MapEnumeration() + { + acquire(); + { + ::osl::MutexGuard aGuard( getMutex() ); + m_aEnumerator.dispose(); + m_pMapDataCopy.reset(); + } + } + + private: + // sicne we share our mutex with the main map, we need to keep it alive as long as we live + Reference< XInterface > m_xKeepMapAlive; + ::std::auto_ptr< MapData > m_pMapDataCopy; + MapEnumerator m_aEnumerator; + }; + + //==================================================================== + //= EnumerableMap + //==================================================================== + //-------------------------------------------------------------------- + EnumerableMap::EnumerableMap( const ComponentContext& _rContext ) + :Map_IFace( m_aMutex ) + ,ComponentBase( Map_IFace::rBHelper ) + ,m_aContext( _rContext ) + { + } + + //-------------------------------------------------------------------- + EnumerableMap::~EnumerableMap() + { + if ( !impl_isDisposed() ) + { + acquire(); + dispose(); + } + } + + //-------------------------------------------------------------------- + void SAL_CALL EnumerableMap::initialize( const Sequence< Any >& _arguments ) throw (Exception, RuntimeException) + { + ComponentMethodGuard aGuard( *this, ComponentMethodGuard::WithoutInit ); + if ( impl_isInitialized_nothrow() ) + throw AlreadyInitializedException(); + + sal_Int32 nArgumentCount = _arguments.getLength(); + if ( ( nArgumentCount != 2 ) && ( nArgumentCount != 3 ) ) + throw IllegalArgumentException(); + + Type aKeyType, aValueType; + if ( !( _arguments[0] >>= aKeyType ) ) + throw IllegalArgumentException( ::rtl::OUString::createFromAscii( "com.sun.star.uno.Type expected." ), *this, 1 ); + if ( !( _arguments[1] >>= aValueType ) ) + throw IllegalArgumentException( ::rtl::OUString::createFromAscii( "com.sun.star.uno.Type expected." ), *this, 2 ); + + Sequence< Pair< Any, Any > > aInitialValues; + bool bMutable = true; + if ( nArgumentCount == 3 ) + { + if ( !( _arguments[2] >>= aInitialValues ) ) + throw IllegalArgumentException( ::rtl::OUString::createFromAscii( "[]com.sun.star.beans.Pair<any,any> expected." ), *this, 2 ); + bMutable = false; + } + + // for the value, anything is allowed, except VOID + if ( ( aValueType.getTypeClass() == TypeClass_VOID ) || ( aValueType.getTypeClass() == TypeClass_UNKNOWN ) ) + throw IllegalTypeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported value type." ) ), *this ); + + // create the comparator for the KeyType, and throw if the type is not supported + TypeClass eKeyTypeClass = aKeyType.getTypeClass(); + ::std::auto_ptr< IKeyPredicateLess > pComparator; + switch ( eKeyTypeClass ) + { + case TypeClass_CHAR: + pComparator.reset( new ScalarPredicateLess< sal_Unicode >() ); + break; + case TypeClass_BOOLEAN: + pComparator.reset( new ScalarPredicateLess< sal_Bool >() ); + break; + case TypeClass_BYTE: + pComparator.reset( new ScalarPredicateLess< sal_Int8 >() ); + break; + case TypeClass_SHORT: + pComparator.reset( new ScalarPredicateLess< sal_Int16 >() ); + break; + case TypeClass_UNSIGNED_SHORT: + pComparator.reset( new ScalarPredicateLess< sal_uInt16 >() ); + break; + case TypeClass_LONG: + pComparator.reset( new ScalarPredicateLess< sal_Int32 >() ); + break; + case TypeClass_UNSIGNED_LONG: + pComparator.reset( new ScalarPredicateLess< sal_uInt32 >() ); + break; + case TypeClass_HYPER: + pComparator.reset( new ScalarPredicateLess< sal_Int64 >() ); + break; + case TypeClass_UNSIGNED_HYPER: + pComparator.reset( new ScalarPredicateLess< sal_uInt64 >() ); + break; + case TypeClass_FLOAT: + pComparator.reset( new ScalarPredicateLess< float >() ); + break; + case TypeClass_DOUBLE: + pComparator.reset( new ScalarPredicateLess< double >() ); + break; + case TypeClass_STRING: + pComparator.reset( new StringPredicateLess() ); + break; + case TypeClass_TYPE: + pComparator.reset( new TypePredicateLess() ); + break; + case TypeClass_ENUM: + pComparator.reset( new EnumPredicateLess( aKeyType ) ); + break; + case TypeClass_INTERFACE: + pComparator.reset( new InterfacePredicateLess() ); + break; + default: + throw IllegalTypeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), *this ); + } + + // init members + m_aData.m_aKeyType = aKeyType; + m_aData.m_aValueType = aValueType; + m_aData.m_pKeyCompare = pComparator; + m_aData.m_pValues.reset( new KeyedValues( *m_aData.m_pKeyCompare ) ); + m_aData.m_bMutable = bMutable; + + if ( aInitialValues.getLength() ) + impl_initValues_throw( aInitialValues ); + + setInitialized(); + } + + //-------------------------------------------------------------------- + void EnumerableMap::impl_initValues_throw( const Sequence< Pair< Any, Any > >& _initialValues ) + { + OSL_PRECOND( m_aData.m_pValues.get() && m_aData.m_pValues->empty(), "EnumerableMap::impl_initValues_throw: illegal call!" ); + if ( !m_aData.m_pValues.get() || !m_aData.m_pValues->empty() ) + throw RuntimeException(); + + const Pair< Any, Any >* mapping = _initialValues.getConstArray(); + const Pair< Any, Any >* mappingEnd = mapping + _initialValues.getLength(); + Any normalizedValue; + for ( ; mapping != mappingEnd; ++mapping ) + { + impl_checkValue_throw( mapping->Second ); + (*m_aData.m_pValues)[ mapping->First ] = mapping->Second; + } + } + + //-------------------------------------------------------------------- + void EnumerableMap::impl_checkValue_throw( const Any& _value ) const + { + if ( !_value.hasValue() ) + // nothing to do, NULL values are always allowed, regardless of the ValueType + return; + + TypeClass eAllowedTypeClass = m_aData.m_aValueType.getTypeClass(); + bool bValid = false; + + switch ( eAllowedTypeClass ) + { + default: + bValid = ( _value.getValueTypeClass() == eAllowedTypeClass ); + break; + case TypeClass_ANY: + bValid = true; + break; + case TypeClass_INTERFACE: + { + // special treatment: _value might contain the proper type, but the interface + // might actually be NULL. Which is still valid ... + if ( m_aData.m_aValueType.isAssignableFrom( _value.getValueType() ) ) + // this also catches the special case where XFoo is our value type, + // and _value contains a NULL-reference to XFoo, or a derived type + bValid = true; + else + { + Reference< XInterface > xValue( _value, UNO_QUERY ); + Any aTypedValue; + if ( xValue.is() ) + // XInterface is not-NULL, but is X(ValueType) not-NULL, too? + xValue.set( xValue->queryInterface( m_aData.m_aValueType ), UNO_QUERY ); + bValid = xValue.is(); + } + } + break; + case TypeClass_EXCEPTION: + case TypeClass_STRUCT: + case TypeClass_UNION: + { + // values are accepted if and only if their type equals, or is derived from, our value type + + if ( _value.getValueTypeClass() != eAllowedTypeClass ) + bValid = false; + else + { + const TypeDescription aValueTypeDesc( _value.getValueType() ); + const TypeDescription aRequiredTypeDesc( m_aData.m_aValueType ); + + const _typelib_CompoundTypeDescription* pValueCompoundTypeDesc = + reinterpret_cast< const _typelib_CompoundTypeDescription* >( aValueTypeDesc.get() ); + + while ( pValueCompoundTypeDesc ) + { + if ( typelib_typedescription_equals( &pValueCompoundTypeDesc->aBase, aRequiredTypeDesc.get() ) ) + break; + pValueCompoundTypeDesc = pValueCompoundTypeDesc->pBaseTypeDescription; + } + bValid = ( pValueCompoundTypeDesc != NULL ); + } + } + break; + } + + if ( !bValid ) + { + ::rtl::OUStringBuffer aMessage; + aMessage.appendAscii( "Incompatible value type. Found '" ); + aMessage.append( _value.getValueTypeName() ); + aMessage.appendAscii( "', where '" ); + aMessage.append( m_aData.m_aValueType.getTypeName() ); + aMessage.appendAscii( "' (or compatible type) is expected." ); + throw IllegalTypeException( aMessage.makeStringAndClear(), *const_cast< EnumerableMap* >( this ) ); + } + + impl_checkNaN_throw( _value, m_aData.m_aValueType ); + } + + //-------------------------------------------------------------------- + void EnumerableMap::impl_checkNaN_throw( const Any& _keyOrValue, const Type& _keyOrValueType ) const + { + if ( ( _keyOrValueType.getTypeClass() == TypeClass_DOUBLE ) + || ( _keyOrValueType.getTypeClass() == TypeClass_FLOAT ) + ) + { + double nValue(0); + if ( _keyOrValue >>= nValue ) + if ( ::rtl::math::isNan( nValue ) ) + throw IllegalArgumentException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NaN (not-a-number) not supported by this implementation." ) ), + *const_cast< EnumerableMap* >( this ), 0 ); + // (note that the case of _key not containing a float/double value is handled in the + // respective IKeyPredicateLess implementation, so there's no need to handle this here.) + } + } + + //-------------------------------------------------------------------- + void EnumerableMap::impl_checkKey_throw( const Any& _key ) const + { + if ( !_key.hasValue() ) + throw IllegalArgumentException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NULL keys not supported by this implementation." ) ), + *const_cast< EnumerableMap* >( this ), 0 ); + + impl_checkNaN_throw( _key, m_aData.m_aKeyType ); + } + + //-------------------------------------------------------------------- + void EnumerableMap::impl_checkMutable_throw() const + { + if ( !m_aData.m_bMutable ) + throw NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "The map is immutable." ) ), + *const_cast< EnumerableMap* >( this ) ); + } + + //-------------------------------------------------------------------- + Reference< XEnumeration > SAL_CALL EnumerableMap::createKeyEnumeration( ::sal_Bool _Isolated ) throw (NoSupportException, RuntimeException) + { + ComponentMethodGuard aGuard( *this ); + return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eKeys, _Isolated ); + } + + //-------------------------------------------------------------------- + Reference< XEnumeration > SAL_CALL EnumerableMap::createValueEnumeration( ::sal_Bool _Isolated ) throw (NoSupportException, RuntimeException) + { + ComponentMethodGuard aGuard( *this ); + return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eValues, _Isolated ); + } + + //-------------------------------------------------------------------- + Reference< XEnumeration > SAL_CALL EnumerableMap::createElementEnumeration( ::sal_Bool _Isolated ) throw (NoSupportException, RuntimeException) + { + ComponentMethodGuard aGuard( *this ); + return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eBoth, _Isolated ); + } + + //-------------------------------------------------------------------- + Type SAL_CALL EnumerableMap::getKeyType() throw (RuntimeException) + { + ComponentMethodGuard aGuard( *this ); + return m_aData.m_aKeyType; + } + + //-------------------------------------------------------------------- + Type SAL_CALL EnumerableMap::getValueType() throw (RuntimeException) + { + ComponentMethodGuard aGuard( *this ); + return m_aData.m_aValueType; + } + + //-------------------------------------------------------------------- + void SAL_CALL EnumerableMap::clear( ) throw (NoSupportException, RuntimeException) + { + ComponentMethodGuard aGuard( *this ); + impl_checkMutable_throw(); + + m_aData.m_pValues->clear(); + + lcl_notifyMapDataListeners_nothrow( m_aData ); + } + + //-------------------------------------------------------------------- + ::sal_Bool SAL_CALL EnumerableMap::containsKey( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException) + { + ComponentMethodGuard aGuard( *this ); + impl_checkKey_throw( _key ); + + KeyedValues::const_iterator pos = m_aData.m_pValues->find( _key ); + return ( pos != m_aData.m_pValues->end() ); + } + + //-------------------------------------------------------------------- + ::sal_Bool SAL_CALL EnumerableMap::containsValue( const Any& _value ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException) + { + ComponentMethodGuard aGuard( *this ); + impl_checkValue_throw( _value ); + + for ( KeyedValues::const_iterator mapping = m_aData.m_pValues->begin(); + mapping != m_aData.m_pValues->end(); + ++mapping + ) + { + if ( mapping->second == _value ) + return sal_True; + } + return sal_False; + } + + //-------------------------------------------------------------------- + Any SAL_CALL EnumerableMap::get( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException) + { + ComponentMethodGuard aGuard( *this ); + impl_checkKey_throw( _key ); + + KeyedValues::const_iterator pos = m_aData.m_pValues->find( _key ); + if ( pos == m_aData.m_pValues->end() ) + throw NoSuchElementException( anyToString( _key ), *this ); + + return pos->second; + } + + //-------------------------------------------------------------------- + Any SAL_CALL EnumerableMap::put( const Any& _key, const Any& _value ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, RuntimeException) + { + ComponentMethodGuard aGuard( *this ); + impl_checkMutable_throw(); + impl_checkKey_throw( _key ); + impl_checkValue_throw( _value ); + + Any previousValue; + + KeyedValues::iterator pos = m_aData.m_pValues->find( _key ); + if ( pos != m_aData.m_pValues->end() ) + { + previousValue = pos->second; + pos->second = _value; + } + else + { + (*m_aData.m_pValues)[ _key ] = _value; + } + + lcl_notifyMapDataListeners_nothrow( m_aData ); + + return previousValue; + } + + //-------------------------------------------------------------------- + Any SAL_CALL EnumerableMap::remove( const Any& _key ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException) + { + ComponentMethodGuard aGuard( *this ); + impl_checkMutable_throw(); + impl_checkKey_throw( _key ); + + Any previousValue; + + KeyedValues::iterator pos = m_aData.m_pValues->find( _key ); + if ( pos != m_aData.m_pValues->end() ) + { + previousValue = pos->second; + m_aData.m_pValues->erase( pos ); + } + + lcl_notifyMapDataListeners_nothrow( m_aData ); + + return previousValue; + } + + //-------------------------------------------------------------------- + Type SAL_CALL EnumerableMap::getElementType() throw (RuntimeException) + { + return ::cppu::UnoType< Pair< Any, Any > >::get(); + } + + //-------------------------------------------------------------------- + ::sal_Bool SAL_CALL EnumerableMap::hasElements() throw (RuntimeException) + { + ComponentMethodGuard aGuard( *this ); + return m_aData.m_pValues->empty(); + } + + //-------------------------------------------------------------------- + ::rtl::OUString SAL_CALL EnumerableMap::getImplementationName( ) throw (RuntimeException) + { + return getImplementationName_static(); + } + + //-------------------------------------------------------------------- + ::sal_Bool SAL_CALL EnumerableMap::supportsService( const ::rtl::OUString& _serviceName ) throw (RuntimeException) + { + Sequence< ::rtl::OUString > aServices( getSupportedServiceNames() ); + for ( sal_Int32 i=0; i<aServices.getLength(); ++i ) + if ( _serviceName == aServices[i] ) + return sal_True; + return sal_False; + } + + //-------------------------------------------------------------------- + Sequence< ::rtl::OUString > SAL_CALL EnumerableMap::getSupportedServiceNames( ) throw (RuntimeException) + { + return getSupportedServiceNames_static(); + } + + //-------------------------------------------------------------------- + ::rtl::OUString SAL_CALL EnumerableMap::getImplementationName_static( ) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.comphelper.EnumerableMap" ) ); + } + + //-------------------------------------------------------------------- + Sequence< ::rtl::OUString > SAL_CALL EnumerableMap::getSupportedServiceNames_static( ) + { + Sequence< ::rtl::OUString > aServiceNames(1); + aServiceNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.container.EnumerableMap" ) ); + return aServiceNames; + } + + //-------------------------------------------------------------------- + Reference< XInterface > SAL_CALL EnumerableMap::Create( const Reference< XComponentContext >& _context ) + { + return *new EnumerableMap( ComponentContext( _context ) ); + } + + //==================================================================== + //= MapEnumerator + //==================================================================== + //-------------------------------------------------------------------- + ::sal_Bool MapEnumerator::hasMoreElements() + { + if ( m_disposed ) + throw DisposedException( ::rtl::OUString(), m_rParent ); + return m_mapPos != m_rMapData.m_pValues->end(); + } + + //-------------------------------------------------------------------- + Any MapEnumerator::nextElement() + { + if ( m_disposed ) + throw DisposedException( ::rtl::OUString(), m_rParent ); + if ( m_mapPos == m_rMapData.m_pValues->end() ) + throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "No more elements." ) ), m_rParent ); + + Any aNextElement; + switch ( m_eType ) + { + case eKeys: aNextElement = m_mapPos->first; break; + case eValues: aNextElement = m_mapPos->second; break; + case eBoth: aNextElement <<= Pair< Any, Any >( m_mapPos->first, m_mapPos->second ); break; + } + ++m_mapPos; + return aNextElement; + } + + //-------------------------------------------------------------------- + void MapEnumerator::mapModified() + { + m_disposed = true; + } + + //==================================================================== + //= MapEnumeration - implementation + //==================================================================== + //-------------------------------------------------------------------- + ::sal_Bool SAL_CALL MapEnumeration::hasMoreElements( ) throw (RuntimeException) + { + ComponentMethodGuard aGuard( *this ); + return m_aEnumerator.hasMoreElements(); + } + + //-------------------------------------------------------------------- + Any SAL_CALL MapEnumeration::nextElement( ) throw (NoSuchElementException, WrappedTargetException, RuntimeException) + { + ComponentMethodGuard aGuard( *this ); + return m_aEnumerator.nextElement(); + } + +//........................................................................ +} // namespace comphelper +//........................................................................ + +void createRegistryInfo_Map() +{ + ::comphelper::module::OAutoRegistration< ::comphelper::EnumerableMap > aAutoRegistration; +} diff --git a/comphelper/source/container/enumhelper.cxx b/comphelper/source/container/enumhelper.cxx new file mode 100644 index 000000000000..646bffa9810f --- /dev/null +++ b/comphelper/source/container/enumhelper.cxx @@ -0,0 +1,297 @@ +/************************************************************************* + * + * 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/enumhelper.hxx> +#include <com/sun/star/lang/XComponent.hpp> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + +//================================================================== +//= OEnumerationByName +//================================================================== +//------------------------------------------------------------------------------ +OEnumerationByName::OEnumerationByName(const staruno::Reference<starcontainer::XNameAccess>& _rxAccess) + :m_aNames(_rxAccess->getElementNames()) + ,m_nPos(0) + ,m_xAccess(_rxAccess) + ,m_bListening(sal_False) +{ + impl_startDisposeListening(); +} + +//------------------------------------------------------------------------------ +OEnumerationByName::OEnumerationByName(const staruno::Reference<starcontainer::XNameAccess>& _rxAccess, + const staruno::Sequence< ::rtl::OUString >& _aNames ) + :m_aNames(_aNames) + ,m_nPos(0) + ,m_xAccess(_rxAccess) + ,m_bListening(sal_False) +{ + impl_startDisposeListening(); +} + +//------------------------------------------------------------------------------ +OEnumerationByName::~OEnumerationByName() +{ + impl_stopDisposeListening(); +} + +//------------------------------------------------------------------------------ +sal_Bool SAL_CALL OEnumerationByName::hasMoreElements( ) throw(staruno::RuntimeException) +{ + ::osl::ResettableMutexGuard aLock(m_aLock); + + if (m_xAccess.is() && m_aNames.getLength() > m_nPos) + return sal_True; + + if (m_xAccess.is()) + { + impl_stopDisposeListening(); + m_xAccess.clear(); + } + + return sal_False; +} + +//------------------------------------------------------------------------------ +staruno::Any SAL_CALL OEnumerationByName::nextElement( ) + throw(starcontainer::NoSuchElementException, starlang::WrappedTargetException, staruno::RuntimeException) +{ + ::osl::ResettableMutexGuard aLock(m_aLock); + + staruno::Any aRes; + if (m_xAccess.is() && m_nPos < m_aNames.getLength()) + aRes = m_xAccess->getByName(m_aNames.getConstArray()[m_nPos++]); + + if (m_xAccess.is() && m_nPos >= m_aNames.getLength()) + { + impl_stopDisposeListening(); + m_xAccess.clear(); + } + + if (!aRes.hasValue()) // es gibt kein Element mehr + throw starcontainer::NoSuchElementException(); + + return aRes; +} + +//------------------------------------------------------------------------------ +void SAL_CALL OEnumerationByName::disposing(const starlang::EventObject& aEvent) + throw(staruno::RuntimeException) +{ + ::osl::ResettableMutexGuard aLock(m_aLock); + + if (aEvent.Source == m_xAccess) + m_xAccess.clear(); +} + +//------------------------------------------------------------------------------ +void OEnumerationByName::impl_startDisposeListening() +{ + ::osl::ResettableMutexGuard aLock(m_aLock); + + if (m_bListening) + return; + + ++m_refCount; + staruno::Reference< starlang::XComponent > xDisposable(m_xAccess, staruno::UNO_QUERY); + if (xDisposable.is()) + { + xDisposable->addEventListener(this); + m_bListening = sal_True; + } + --m_refCount; +} + +//------------------------------------------------------------------------------ +void OEnumerationByName::impl_stopDisposeListening() +{ + ::osl::ResettableMutexGuard aLock(m_aLock); + + if (!m_bListening) + return; + + ++m_refCount; + staruno::Reference< starlang::XComponent > xDisposable(m_xAccess, staruno::UNO_QUERY); + if (xDisposable.is()) + { + xDisposable->removeEventListener(this); + m_bListening = sal_False; + } + --m_refCount; +} + +//================================================================== +//= OEnumerationByIndex +//================================================================== +//------------------------------------------------------------------------------ +OEnumerationByIndex::OEnumerationByIndex(const staruno::Reference< starcontainer::XIndexAccess >& _rxAccess) + :m_nPos(0) + ,m_xAccess(_rxAccess) + ,m_bListening(sal_False) +{ + impl_startDisposeListening(); +} + +//------------------------------------------------------------------------------ +OEnumerationByIndex::~OEnumerationByIndex() +{ + impl_stopDisposeListening(); +} + +//------------------------------------------------------------------------------ +sal_Bool SAL_CALL OEnumerationByIndex::hasMoreElements( ) throw(staruno::RuntimeException) +{ + ::osl::ResettableMutexGuard aLock(m_aLock); + + if (m_xAccess.is() && m_xAccess->getCount() > m_nPos) + return sal_True; + + if (m_xAccess.is()) + { + impl_stopDisposeListening(); + m_xAccess.clear(); + } + + return sal_False; +} + +//------------------------------------------------------------------------------ +staruno::Any SAL_CALL OEnumerationByIndex::nextElement( ) + throw(starcontainer::NoSuchElementException, starlang::WrappedTargetException, staruno::RuntimeException) +{ + ::osl::ResettableMutexGuard aLock(m_aLock); + + staruno::Any aRes; + if (m_xAccess.is()) + { + aRes = m_xAccess->getByIndex(m_nPos++); + if (m_nPos >= m_xAccess->getCount()) + { + impl_stopDisposeListening(); + m_xAccess.clear(); + } + } + + if (!aRes.hasValue()) // es gibt kein Element mehr + throw starcontainer::NoSuchElementException(); + return aRes; +} + +//------------------------------------------------------------------------------ +void SAL_CALL OEnumerationByIndex::disposing(const starlang::EventObject& aEvent) + throw(staruno::RuntimeException) +{ + ::osl::ResettableMutexGuard aLock(m_aLock); + + if (aEvent.Source == m_xAccess) + m_xAccess.clear(); +} + +//------------------------------------------------------------------------------ +void OEnumerationByIndex::impl_startDisposeListening() +{ + ::osl::ResettableMutexGuard aLock(m_aLock); + + if (m_bListening) + return; + + ++m_refCount; + staruno::Reference< starlang::XComponent > xDisposable(m_xAccess, staruno::UNO_QUERY); + if (xDisposable.is()) + { + xDisposable->addEventListener(this); + m_bListening = sal_True; + } + --m_refCount; +} + +//------------------------------------------------------------------------------ +void OEnumerationByIndex::impl_stopDisposeListening() +{ + ::osl::ResettableMutexGuard aLock(m_aLock); + + if (!m_bListening) + return; + + ++m_refCount; + staruno::Reference< starlang::XComponent > xDisposable(m_xAccess, staruno::UNO_QUERY); + if (xDisposable.is()) + { + xDisposable->removeEventListener(this); + m_bListening = sal_False; + } + --m_refCount; +} + +//================================================================== +//= OAnyEnumeration +//================================================================== + +//------------------------------------------------------------------------------ +OAnyEnumeration::OAnyEnumeration(const staruno::Sequence< staruno::Any >& lItems) + :m_nPos(0) + ,m_lItems(lItems) +{ +} + +//------------------------------------------------------------------------------ +OAnyEnumeration::~OAnyEnumeration() +{ +} + +//------------------------------------------------------------------------------ +sal_Bool SAL_CALL OAnyEnumeration::hasMoreElements( ) throw(staruno::RuntimeException) +{ + ::osl::ResettableMutexGuard aLock(m_aLock); + + return (m_lItems.getLength() > m_nPos); +} + +//------------------------------------------------------------------------------ +staruno::Any SAL_CALL OAnyEnumeration::nextElement( ) + throw(starcontainer::NoSuchElementException, starlang::WrappedTargetException, staruno::RuntimeException) +{ + if ( ! hasMoreElements()) + throw starcontainer::NoSuchElementException(); + + ::osl::ResettableMutexGuard aLock(m_aLock); + sal_Int32 nPos = m_nPos; + ++m_nPos; + return m_lItems[nPos]; +} + +//......................................................................... +} // namespace comphelper +//......................................................................... + + diff --git a/comphelper/source/container/makefile.mk b/comphelper/source/container/makefile.mk new file mode 100644 index 000000000000..97a066f9802a --- /dev/null +++ b/comphelper/source/container/makefile.mk @@ -0,0 +1,55 @@ +#************************************************************************* +# +# 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=container + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES=\ + $(SLO)$/namecontainer.obj \ + $(SLO)$/enumhelper.obj \ + $(SLO)$/container.obj \ + $(SLO)$/containermultiplexer.obj \ + $(SLO)$/IndexedPropertyValuesContainer.obj \ + $(SLO)$/embeddedobjectcontainer.obj \ + $(SLO)$/NamedPropertyValuesContainer.obj \ + $(SLO)$/enumerablemap.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/comphelper/source/container/namecontainer.cxx b/comphelper/source/container/namecontainer.cxx new file mode 100644 index 000000000000..7239a8d573dc --- /dev/null +++ b/comphelper/source/container/namecontainer.cxx @@ -0,0 +1,211 @@ +/************************************************************************* + * + * 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/namecontainer.hxx> +#include <cppuhelper/implbase1.hxx> +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <comphelper/stl_types.hxx> + +DECLARE_STL_USTRINGACCESS_MAP( ::com::sun::star::uno::Any, SvGenericNameContainerMapImpl ); + +namespace comphelper +{ + class NameContainerImpl + { + public: + osl::Mutex maMutex; + }; + + /** this is the base helper class for NameContainer thats also declared in this header. */ + class NameContainer : public ::cppu::WeakImplHelper1< ::com::sun::star::container::XNameContainer >, private NameContainerImpl + { + public: + NameContainer( ::com::sun::star::uno::Type aType ); + virtual ~NameContainer(); + + // XNameContainer + virtual void SAL_CALL insertByName( const ::rtl::OUString& aName, const ::com::sun::star::uno::Any& aElement ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::ElementExistException, + ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeByName( const ::rtl::OUString& Name ) + throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException); + + // XNameReplace + virtual void SAL_CALL replaceByName( const ::rtl::OUString& aName, const ::com::sun::star::uno::Any& aElement ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XNameAccess + virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) + throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames( ) + throw(::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) + throw(::com::sun::star::uno::RuntimeException); + + // XElementAccess + virtual sal_Bool SAL_CALL hasElements( ) + throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Type SAL_CALL getElementType( ) + throw(::com::sun::star::uno::RuntimeException); + + private: + SvGenericNameContainerMapImpl maProperties; + const ::com::sun::star::uno::Type maType; + }; +} + +using namespace ::comphelper; +using namespace ::osl; +using namespace ::rtl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + + +NameContainer::NameContainer( ::com::sun::star::uno::Type aType ) +: maType( aType ) +{ +} + +NameContainer::~NameContainer() +{ +} + +// XNameContainer +void SAL_CALL NameContainer::insertByName( const rtl::OUString& aName, const Any& aElement ) + throw(IllegalArgumentException, ElementExistException, + WrappedTargetException, RuntimeException) +{ + MutexGuard aGuard( maMutex ); + + if( maProperties.find( aName ) != maProperties.end() ) + throw ElementExistException(); + + if( aElement.getValueType() != maType ) + throw IllegalArgumentException(); + + maProperties.insert( SvGenericNameContainerMapImpl::value_type(aName,aElement)); +} + +void SAL_CALL NameContainer::removeByName( const ::rtl::OUString& Name ) + throw(NoSuchElementException, WrappedTargetException, + RuntimeException) +{ + MutexGuard aGuard( maMutex ); + + SvGenericNameContainerMapImpl::iterator aIter = maProperties.find( Name ); + if( aIter == maProperties.end() ) + throw NoSuchElementException(); + + maProperties.erase( aIter ); +} + +// XNameReplace + +void SAL_CALL NameContainer::replaceByName( const ::rtl::OUString& aName, const Any& aElement ) + throw(IllegalArgumentException, NoSuchElementException, + WrappedTargetException, RuntimeException) +{ + MutexGuard aGuard( maMutex ); + + SvGenericNameContainerMapImpl::iterator aIter( maProperties.find( aName ) ); + if( aIter == maProperties.end() ) + throw NoSuchElementException(); + + if( aElement.getValueType() != maType ) + throw IllegalArgumentException(); + + (*aIter).second = aElement; +} + +// XNameAccess + +Any SAL_CALL NameContainer::getByName( const ::rtl::OUString& aName ) + throw(NoSuchElementException, WrappedTargetException, + RuntimeException) +{ + MutexGuard aGuard( maMutex ); + + SvGenericNameContainerMapImpl::iterator aIter = maProperties.find( aName ); + if( aIter == maProperties.end() ) + throw NoSuchElementException(); + + return (*aIter).second; +} + +Sequence< ::rtl::OUString > SAL_CALL NameContainer::getElementNames( ) + throw(RuntimeException) +{ + MutexGuard aGuard( maMutex ); + + SvGenericNameContainerMapImpl::iterator aIter = maProperties.begin(); + const SvGenericNameContainerMapImpl::iterator aEnd = maProperties.end(); + + Sequence< rtl::OUString > aNames( maProperties.size() ); + rtl::OUString* pNames = aNames.getArray(); + + while( aIter != aEnd ) + { + *pNames++ = (*aIter++).first; + } + + return aNames; +} + +sal_Bool SAL_CALL NameContainer::hasByName( const ::rtl::OUString& aName ) + throw(RuntimeException) +{ + MutexGuard aGuard( maMutex ); + + SvGenericNameContainerMapImpl::iterator aIter = maProperties.find( aName ); + return aIter != maProperties.end(); +} + +sal_Bool SAL_CALL NameContainer::hasElements( ) + throw(RuntimeException) +{ + MutexGuard aGuard( maMutex ); + + return !maProperties.empty(); +} + +Type SAL_CALL NameContainer::getElementType() + throw( RuntimeException ) +{ + return maType; +} + +Reference< XNameContainer > comphelper::NameContainer_createInstance( Type aType ) +{ + return (XNameContainer*) new NameContainer( aType ); +} diff --git a/comphelper/source/eventattachermgr/eventattachermgr.cxx b/comphelper/source/eventattachermgr/eventattachermgr.cxx new file mode 100644 index 000000000000..bf217f75c8db --- /dev/null +++ b/comphelper/source/eventattachermgr/eventattachermgr.cxx @@ -0,0 +1,1036 @@ +/************************************************************************* + * + * 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 <deque> + +#if defined( OS2 ) || defined( UNX ) +#include <wchar.h> +#endif +#include <osl/mutex.hxx> +#ifndef _VOS_DIAGNOSE_HXX_ +#include <vos/diagnose.hxx> +#endif +#include <vos/macros.hxx> +#include <comphelper/eventattachermgr.hxx> +#include <com/sun/star/beans/XIntrospection.hpp> +#include <com/sun/star/io/XObjectInputStream.hpp> +#include <com/sun/star/io/XPersistObject.hpp> +#include <com/sun/star/io/XObjectOutputStream.hpp> +#include <com/sun/star/io/XMarkableStream.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/reflection/XIdlClass.hpp> +#include <com/sun/star/reflection/XIdlReflection.hpp> +#include <com/sun/star/reflection/XIdlMethod.hpp> +#include <com/sun/star/script/XTypeConverter.hpp> +#include <com/sun/star/script/XEngineListener.hpp> +#include <com/sun/star/script/XEventAttacher.hpp> +#include <com/sun/star/script/XEventAttacherManager.hpp> +#include <com/sun/star/script/XScriptListener.hpp> +#include <cppuhelper/weak.hxx> +#include <cppuhelper/interfacecontainer.hxx> +#include <cppuhelper/implbase1.hxx> +#include <cppuhelper/implbase2.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::io; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::script; +using namespace com::sun::star::reflection; +using namespace cppu; +using namespace osl; +using namespace rtl; + +namespace comphelper +{ + +//----------------------------------------------------------------------------- +struct AttachedObject_Impl +{ + Reference< XInterface > xTarget; + Sequence< Reference< XEventListener > > aAttachedListenerSeq; + Any aHelper; + + bool operator<( const AttachedObject_Impl & ) const; + bool operator==( const AttachedObject_Impl & ) const; +}; + +struct AttacherIndex_Impl +{ +#ifdef DEQUE_OK + ::std::deque< ScriptEventDescriptor > aEventList; +#else + Sequence< ScriptEventDescriptor > aEventList; +#endif + ::std::deque< AttachedObject_Impl > aObjList; + + bool operator<( const AttacherIndex_Impl & ) const; + bool operator==( const AttacherIndex_Impl & ) const; +}; + +#if 0 +bool AttachedObject_Impl::operator<( const AttachedObject_Impl & r ) const +{ + VOS_ENSHURE( FALSE, "not implemented" ); + return FALSE; + return this < &r; +} + +bool AttachedObject_Impl::operator==( const AttachedObject_Impl & r ) const +{ + VOS_ENSHURE( FALSE, "not implemented" ); + return this == &r; +} + +bool AttacherIndex_Impl::operator<( const AttacherIndex_Impl & r ) const +{ + VOS_ENSHURE( FALSE, "not implemented" ); + return this < &r; +} +bool AttacherIndex_Impl::operator==( const AttacherIndex_Impl & r ) const +{ + VOS_ENSHURE( FALSE, "not implemented" ); + return this == &r; +} +#endif + +//----------------------------------------------------------------------------- +class ImplEventAttacherManager + : public WeakImplHelper2< XEventAttacherManager, XPersistObject > +{ + friend class AttacherAllListener_Impl; + ::std::deque< AttacherIndex_Impl > aIndex; + Mutex aLock; + // Container fuer die ScriptListener + OInterfaceContainerHelper aScriptListeners; + // EventAttacher-Instanz + Reference< XEventAttacher > xAttacher; + Reference< XMultiServiceFactory > mxSMgr; + Reference< XIdlReflection > mxCoreReflection; + Reference< XIntrospection > mxIntrospection; + Reference< XTypeConverter > xConverter; + sal_Int16 nVersion; +public: + ImplEventAttacherManager( const Reference< XIntrospection > & rIntrospection, + const Reference< XMultiServiceFactory > rSMgr ); + ~ImplEventAttacherManager(); + + // Methoden von XEventAttacherManager + virtual void SAL_CALL registerScriptEvent(sal_Int32 Index, const ScriptEventDescriptor& ScriptEvent) + throw( IllegalArgumentException, RuntimeException ); + virtual void SAL_CALL registerScriptEvents(sal_Int32 Index, const Sequence< ScriptEventDescriptor >& ScriptEvents) + throw( IllegalArgumentException, RuntimeException ); + virtual void SAL_CALL revokeScriptEvent(sal_Int32 Index, const OUString& ListenerType, const OUString& EventMethod, const OUString& removeListenerParam) + throw( IllegalArgumentException, RuntimeException ); + virtual void SAL_CALL revokeScriptEvents(sal_Int32 Index) + throw( IllegalArgumentException, RuntimeException ); + virtual void SAL_CALL insertEntry(sal_Int32 Index) + throw( IllegalArgumentException, RuntimeException ); + virtual void SAL_CALL removeEntry(sal_Int32 Index) + throw( IllegalArgumentException, RuntimeException ); + virtual Sequence< ScriptEventDescriptor > SAL_CALL getScriptEvents(sal_Int32 Index) + throw( IllegalArgumentException, RuntimeException ); + virtual void SAL_CALL attach(sal_Int32 Index, const Reference< XInterface >& Object, const Any& Helper) + throw( IllegalArgumentException, ServiceNotRegisteredException, RuntimeException ); + virtual void SAL_CALL detach(sal_Int32 nIndex, const Reference< XInterface >& xObject) + throw( IllegalArgumentException, RuntimeException ); + virtual void SAL_CALL addScriptListener(const Reference< XScriptListener >& aListener) + throw( IllegalArgumentException, RuntimeException ); + virtual void SAL_CALL removeScriptListener(const Reference< XScriptListener >& Listener) + throw( IllegalArgumentException, RuntimeException ); + + // Methoden von XPersistObject + virtual OUString SAL_CALL getServiceName(void) throw( RuntimeException ); + virtual void SAL_CALL write(const Reference< XObjectOutputStream >& OutStream) throw( IOException, RuntimeException ); + virtual void SAL_CALL read(const Reference< XObjectInputStream >& InStream) throw( IOException, RuntimeException ); + +private: + Reference< XIdlReflection > getReflection() throw( Exception ); + + /** checks if <arg>_nIndex</arg> is a valid index, throws an <type>IllegalArgumentException</type> if not + @param _nIndex + the index to check + @return + the iterator pointing to the position indicated by the index + */ + ::std::deque<AttacherIndex_Impl>::iterator implCheckIndex( sal_Int32 _nIndex ) SAL_THROW ( ( IllegalArgumentException ) ); +}; + +//======================================================================== +//======================================================================== +//======================================================================== + +// Implementation eines EventAttacher-bezogenen AllListeners, der +// nur einzelne Events an einen allgemeinen AllListener weiterleitet +class AttacherAllListener_Impl : public WeakImplHelper1< XAllListener > +{ + ImplEventAttacherManager* mpManager; + Reference< XEventAttacherManager > xManager; + OUString aScriptType; + OUString aScriptCode; + sal_Int16 nVersion; + + void convertToEventReturn( Any & rRet, const Type & rRetType ) + throw( CannotConvertException ); +public: + AttacherAllListener_Impl( ImplEventAttacherManager* pManager_, const OUString &rScriptType_, + const OUString & rScriptCode_ ); + + // Methoden von XAllListener + virtual void SAL_CALL firing(const AllEventObject& Event) throw( RuntimeException ); + virtual Any SAL_CALL approveFiring(const AllEventObject& Event) throw( InvocationTargetException, RuntimeException ); + + // Methoden von XEventListener + virtual void SAL_CALL disposing(const EventObject& Source) throw( RuntimeException ); +}; + +//======================================================================== +AttacherAllListener_Impl::AttacherAllListener_Impl +( + ImplEventAttacherManager* pManager_, + const OUString & rScriptType_, + const OUString & rScriptCode_ +) + : mpManager( pManager_ ) + , xManager( pManager_ ) + , aScriptType( rScriptType_ ) + , aScriptCode( rScriptCode_ ) + , nVersion( 2 ) +{ +} + + +//======================================================================== +// Methoden von XAllListener +void SAL_CALL AttacherAllListener_Impl::firing(const AllEventObject& Event) + throw( RuntimeException ) +{ + ScriptEvent aScriptEvent; + aScriptEvent.Source = (OWeakObject *)mpManager; // get correct XInterface + aScriptEvent.ListenerType = Event.ListenerType; + aScriptEvent.MethodName = Event.MethodName; + aScriptEvent.Arguments = Event.Arguments; + aScriptEvent.Helper = Event.Helper; + aScriptEvent.ScriptType = aScriptType; + aScriptEvent.ScriptCode = aScriptCode; + + // ueber alle Listener iterieren und Events senden + OInterfaceIteratorHelper aIt( mpManager->aScriptListeners ); + while( aIt.hasMoreElements() ) + ((XScriptListener *)aIt.next())->firing( aScriptEvent ); +} + +//======================================================================== +// Convert to the standard event return +void AttacherAllListener_Impl::convertToEventReturn( Any & rRet, const Type & rRetType ) + throw( CannotConvertException ) +{ + // no return value? Set to the specified values + if( rRet.getValueType().getTypeClass() == TypeClass_VOID ) + { + switch( rRetType.getTypeClass() ) + { + case TypeClass_INTERFACE: + { + rRet <<= Reference< XInterface >(); + } + break; + + case TypeClass_BOOLEAN: + rRet <<= sal_True; + break; + + case TypeClass_STRING: + rRet <<= OUString(); + break; + + case TypeClass_FLOAT: rRet <<= float(0); break; + case TypeClass_DOUBLE: rRet <<= double(0.0); break; + case TypeClass_BYTE: rRet <<= sal_uInt8(0); break; + case TypeClass_SHORT: rRet <<= sal_Int16( 0 ); break; + case TypeClass_LONG: rRet <<= sal_Int32( 0 ); break; + case TypeClass_UNSIGNED_SHORT: rRet <<= sal_uInt16( 0 ); break; + case TypeClass_UNSIGNED_LONG: rRet <<= sal_uInt32( 0 ); break; + + default: + OSL_ASSERT(false); + break; + } + } + else if( !rRet.getValueType().equals( rRetType ) ) + { + if( mpManager->xConverter.is() ) + rRet = mpManager->xConverter->convertTo( rRet, rRetType ); + else + throw CannotConvertException(); + } +} + +//======================================================================== +// Methoden von XAllListener +Any SAL_CALL AttacherAllListener_Impl::approveFiring( const AllEventObject& Event ) + throw( InvocationTargetException, RuntimeException ) +{ + ScriptEvent aScriptEvent; + aScriptEvent.Source = (OWeakObject *)mpManager; // get correct XInterface + aScriptEvent.ListenerType = Event.ListenerType; + aScriptEvent.MethodName = Event.MethodName; + aScriptEvent.Arguments = Event.Arguments; + aScriptEvent.Helper = Event.Helper; + aScriptEvent.ScriptType = aScriptType; + aScriptEvent.ScriptCode = aScriptCode; + + Any aRet; + // ueber alle Listener iterieren und Events senden + OInterfaceIteratorHelper aIt( mpManager->aScriptListeners ); + while( aIt.hasMoreElements() ) + { + aRet = ((XScriptListener *)aIt.next())->approveFiring( aScriptEvent ); + try + { + Reference< XIdlClass > xListenerType = mpManager->getReflection()-> + forName( Event.ListenerType.getTypeName() ); + Reference< XIdlMethod > xMeth = xListenerType->getMethod( Event.MethodName ); + if( xMeth.is() ) + { + Reference< XIdlClass > xRetType = xMeth->getReturnType(); + Type aRetType(xRetType->getTypeClass(), xRetType->getName()); + convertToEventReturn( aRet, aRetType ); + } + + switch( aRet.getValueType().getTypeClass() ) + { + case TypeClass_INTERFACE: + { + // Interface not null, return + Reference< XInterface > x; + aRet >>= x; + if( x.is() ) + return aRet; + } + break; + + case TypeClass_BOOLEAN: + // FALSE -> Return + if( !(*(sal_Bool*)aRet.getValue()) ) + return aRet; + break; + + case TypeClass_STRING: + // none empty string -> return + if( ((OUString*)aRet.getValue())->getLength() > 0 ) + return aRet; + break; + + // none zero number -> return + case TypeClass_FLOAT: if( *((float*)aRet.getValue()) ) return aRet; break; + case TypeClass_DOUBLE: if( *((double*)aRet.getValue()) ) return aRet; break; + case TypeClass_BYTE: if( *((sal_uInt8*)aRet.getValue()) ) return aRet; break; + case TypeClass_SHORT: if( *((sal_Int16*)aRet.getValue()) ) return aRet; break; + case TypeClass_LONG: if( *((sal_Int32*)aRet.getValue()) ) return aRet; break; + case TypeClass_UNSIGNED_SHORT: if( *((sal_uInt16*)aRet.getValue()) ) return aRet; break; + case TypeClass_UNSIGNED_LONG: if( *((sal_uInt32*)aRet.getValue()) ) return aRet; break; + + default: + OSL_ASSERT(false); + break; + } + } + catch( CannotConvertException& ) + { + // silent ignore conversions errors from a script call + Reference< XIdlClass > xListenerType = mpManager->getReflection()-> + forName( Event.ListenerType.getTypeName() ); + Reference< XIdlMethod > xMeth = xListenerType->getMethod( Event.MethodName ); + if( xMeth.is() ) + { + Reference< XIdlClass > xRetType = xMeth->getReturnType(); + Type aRetType(xRetType->getTypeClass(), xRetType->getName()); + aRet.clear(); + convertToEventReturn( aRet, aRetType ); + } + } + } + return aRet; +} + +//======================================================================== +// Methoden von XEventListener +void SAL_CALL AttacherAllListener_Impl::disposing(const EventObject& ) + throw( RuntimeException ) +{ + // It is up to the container to release the object +} + + +//======================================================================== +//======================================================================== +//======================================================================== + +// Create-Methode fuer EventAttacherManager +Reference< XEventAttacherManager > createEventAttacherManager( const Reference< XIntrospection > & rIntrospection, + const Reference< XMultiServiceFactory > & rSMgr ) + throw( Exception ) +{ + return new ImplEventAttacherManager( rIntrospection, rSMgr ); +} + +// Create-Methode fuer EventAttacherManager +Reference< XEventAttacherManager > createEventAttacherManager( const Reference< XMultiServiceFactory > & rSMgr ) + throw( Exception ) +{ + if ( rSMgr.is() ) + { + Reference< XInterface > xIFace( rSMgr->createInstance( OUString::createFromAscii("com.sun.star.beans.Introspection") ) ); + if ( xIFace.is() ) + { + Reference< XIntrospection > xIntrospection( xIFace, UNO_QUERY); + return new ImplEventAttacherManager( xIntrospection, rSMgr ); + } + } + + return Reference< XEventAttacherManager >(); +} + +//----------------------------------------------------------------------------- +ImplEventAttacherManager::ImplEventAttacherManager( const Reference< XIntrospection > & rIntrospection, + const Reference< XMultiServiceFactory > rSMgr ) + : aScriptListeners( aLock ) + , mxSMgr( rSMgr ) + , mxIntrospection( rIntrospection ) +{ + if ( rSMgr.is() ) + { + Reference< XInterface > xIFace( rSMgr->createInstance( OUString::createFromAscii("com.sun.star.script.EventAttacher") ) ); + if ( xIFace.is() ) + { + xAttacher = Reference< XEventAttacher >::query( xIFace ); + } + xIFace = rSMgr->createInstance( OUString::createFromAscii("com.sun.star.script.Converter") ); + if ( xIFace.is() ) + { + xConverter = Reference< XTypeConverter >::query( xIFace ); + } + } + + Reference< XInitialization > xInit( xAttacher, UNO_QUERY ); + if( xInit.is() ) + { + Sequence< Any > Arguments( 1 ); + Arguments[0] <<= rIntrospection; + xInit->initialize( Arguments ); + } +} + +//----------------------------------------------------------------------------- +ImplEventAttacherManager::~ImplEventAttacherManager() +{ +} + +Reference< XIdlReflection > ImplEventAttacherManager::getReflection() throw( Exception ) +{ + Guard< Mutex > aGuard( aLock ); + // Haben wir den Service schon? Sonst anlegen + if( !mxCoreReflection.is() ) + { + Reference< XInterface > xIFace( mxSMgr->createInstance( OUString::createFromAscii("com.sun.star.reflection.CoreReflection") ) ); + mxCoreReflection = Reference< XIdlReflection >( xIFace, UNO_QUERY); + } + return mxCoreReflection; +} + + +//----------------------------------------------------------------------------- +::std::deque<AttacherIndex_Impl>::iterator ImplEventAttacherManager::implCheckIndex( sal_Int32 _nIndex ) SAL_THROW ( ( IllegalArgumentException ) ) +{ + if (_nIndex < 0) + throw IllegalArgumentException(); + + ::std::deque<AttacherIndex_Impl>::iterator aIt = aIndex.begin(); + for ( sal_Int32 i = 0; (i < _nIndex) && (aIt != aIndex.end()); ++i, ++aIt ) + ; + + if( aIt == aIndex.end() ) + throw IllegalArgumentException(); + + return aIt; +} + +//----------------------------------------------------------------------------- +void detachAll_Impl +( + ImplEventAttacherManager * pMgr, + sal_Int32 nIdx, + ::std::deque< AttachedObject_Impl > & rList +) +{ + ::std::deque< AttachedObject_Impl >::iterator aObjIt = rList.begin(); + ::std::deque< AttachedObject_Impl >::iterator aObjEnd = rList.end(); + while( aObjIt != aObjEnd ) + { + pMgr->detach( nIdx, (*aObjIt).xTarget ); + aObjIt++; + } +} + +//----------------------------------------------------------------------------- +void attachAll_Impl +( + ImplEventAttacherManager * pMgr, + sal_Int32 nIdx, + ::std::deque< AttachedObject_Impl > & rList +) +{ + ::std::deque< AttachedObject_Impl >::iterator aObjIt = rList.begin(); + ::std::deque< AttachedObject_Impl >::iterator aObjEnd = rList.end(); + while( aObjIt != aObjEnd ) + { + pMgr->attach( nIdx, (*aObjIt).xTarget, (*aObjIt).aHelper ); + aObjIt++; + } +} + +//----------------------------------------------------------------------------- +//*** Methoden von XEventAttacherManager *** +void SAL_CALL ImplEventAttacherManager::registerScriptEvent +( + sal_Int32 nIndex, + const ScriptEventDescriptor& ScriptEvent +) + throw( IllegalArgumentException, RuntimeException ) +{ + Guard< Mutex > aGuard( aLock ); + + // Index pruefen und Array anpassen + ::std::deque<AttacherIndex_Impl>::iterator aIt = implCheckIndex( nIndex ); + + ::std::deque< AttachedObject_Impl > aList = (*aIt).aObjList; + + ScriptEventDescriptor aEvt = ScriptEvent; + const sal_Unicode* pLastDot = aEvt.ListenerType.getStr(); + pLastDot += rtl_ustr_lastIndexOfChar( pLastDot, '.' ); + if( pLastDot ) + aEvt.ListenerType = pLastDot +1; +#ifdef DEQUE_OK + (*aIt).aEventList.push_back( aEvt ); +#else + (*aIt).aEventList.realloc( (*aIt).aEventList.getLength() +1 ); + (*aIt).aEventList.getArray()[(*aIt).aEventList.getLength() -1] = aEvt; +#endif + + // register new new Event + ::std::deque< AttachedObject_Impl >::iterator aObjIt = (*aIt).aObjList.begin(); + ::std::deque< AttachedObject_Impl >::iterator aObjEnd = (*aIt).aObjList.end(); + while( aObjIt != aObjEnd ) + { + // resize + sal_Int32 nPos = (*aObjIt).aAttachedListenerSeq.getLength(); + (*aObjIt).aAttachedListenerSeq.realloc( nPos + 1 ); + Reference< XEventListener > * pArray = (*aObjIt).aAttachedListenerSeq.getArray(); + + Reference< XAllListener > xAll = + new AttacherAllListener_Impl( this, ScriptEvent.ScriptType, ScriptEvent.ScriptCode ); + try + { + pArray[nPos] = xAttacher->attachSingleEventListener( (*aObjIt).xTarget, xAll, + (*aObjIt).aHelper, ScriptEvent.ListenerType, + ScriptEvent.AddListenerParam, ScriptEvent.EventMethod ); + } + catch( Exception& ) + { + } + + aObjIt++; + } +} + +//----------------------------------------------------------------------------- +void SAL_CALL ImplEventAttacherManager::registerScriptEvents +( + sal_Int32 nIndex, + const Sequence< ScriptEventDescriptor >& ScriptEvents +) + throw( IllegalArgumentException, RuntimeException ) +{ + Guard< Mutex > aGuard( aLock ); + + // Index pruefen und Array anpassen + ::std::deque<AttacherIndex_Impl>::iterator aIt = implCheckIndex( nIndex ); + + ::std::deque< AttachedObject_Impl > aList = (*aIt).aObjList; + detachAll_Impl( this, nIndex, aList ); + + const ScriptEventDescriptor* pArray = ScriptEvents.getConstArray(); + sal_Int32 nLen = ScriptEvents.getLength(); + for( sal_Int32 i = 0 ; i < nLen ; i++ ) + registerScriptEvent( nIndex, pArray[ i ] ); + + attachAll_Impl( this, nIndex, aList ); +} + +//----------------------------------------------------------------------------- +void SAL_CALL ImplEventAttacherManager::revokeScriptEvent +( + sal_Int32 nIndex, + const OUString& ListenerType, + const OUString& EventMethod, + const OUString& ToRemoveListenerParam +) + throw( IllegalArgumentException, RuntimeException ) +{ + Guard< Mutex > aGuard( aLock ); + + ::std::deque<AttacherIndex_Impl>::iterator aIt = implCheckIndex( nIndex ); + + ::std::deque< AttachedObject_Impl > aList = (*aIt).aObjList; + detachAll_Impl( this, nIndex, aList ); + + OUString aLstType = ListenerType; + const sal_Unicode * pLastDot = aLstType.getStr(); + pLastDot += rtl_ustr_lastIndexOfChar( pLastDot, '.' ); + if( pLastDot ) + aLstType = pLastDot +1; + +#ifdef DEQUE_OK + ::std::deque< ScriptEventDescriptor >::iterator aEvtIt = (*aIt).aEventList.begin(); + ::std::deque< ScriptEventDescriptor >::iterator aEvtEnd = (*aIt).aEventList.end(); + while( aEvtIt != aEvtEnd ) + { + if( aLstType == (*aEvtIt).ListenerType + && EventMethod == (*aEvtIt).EventMethod + && ToRemoveListenerParam == (*aEvtIt).AddListenerParam ) + { + (*aIt).aEventList.erase( aEvtIt ); + break; + } + + aEvtIt++; + } +#else + Sequence< ScriptEventDescriptor >& rEventList = (*aIt).aEventList; + + ScriptEventDescriptor* pEventList = rEventList.getArray(); + const ScriptEventDescriptor* pEventListEnd = pEventList + rEventList.getLength(); + for( ; pEventList < pEventListEnd; ++pEventList ) + { + if ( (aLstType == pEventList->ListenerType ) + && (EventMethod == pEventList->EventMethod ) + && (ToRemoveListenerParam == pEventList->AddListenerParam) + ) + { + ScriptEventDescriptor* pMoveTo = pEventList; + const ScriptEventDescriptor* pMoveFrom = pMoveTo + 1; + while (pMoveFrom < pEventListEnd) + { + *pMoveTo++ = *pMoveFrom++; + } + rEventList.realloc( rEventList.getLength() - 1 ); + break; + } + } +#endif + attachAll_Impl( this, nIndex, aList ); +} + +//----------------------------------------------------------------------------- +void SAL_CALL ImplEventAttacherManager::revokeScriptEvents(sal_Int32 nIndex ) + throw( IllegalArgumentException, RuntimeException ) +{ + Guard< Mutex > aGuard( aLock ); + ::std::deque<AttacherIndex_Impl>::iterator aIt = implCheckIndex( nIndex ); + + ::std::deque< AttachedObject_Impl > aList = (*aIt).aObjList; + detachAll_Impl( this, nIndex, aList ); +#ifdef DEQUE_OK + (*aIt).aEventList = ::std::deque< ScriptEventDescriptor >(); +#else + (*aIt).aEventList.realloc( 0 ); +#endif + attachAll_Impl( this, nIndex, aList ); +} + +//----------------------------------------------------------------------------- +void SAL_CALL ImplEventAttacherManager::insertEntry(sal_Int32 nIndex) + throw( IllegalArgumentException, RuntimeException ) +{ + Guard< Mutex > aGuard( aLock ); + if( nIndex < 0 ) + throw IllegalArgumentException(); + +// ::std::deque<AttacherIndex_Impl>::iterator aIt = aIndex.begin(); +// while( nIndex-- ) +// aIt++; + + if ( static_cast< ::std::deque< AttacherIndex_Impl >::size_type>(nIndex) >= aIndex.size() ) + aIndex.resize(nIndex+1); + + AttacherIndex_Impl aTmp; + aIndex.insert( aIndex.begin() + nIndex, aTmp ); +} + +//----------------------------------------------------------------------------- +void SAL_CALL ImplEventAttacherManager::removeEntry(sal_Int32 nIndex) + throw( IllegalArgumentException, RuntimeException ) +{ + Guard< Mutex > aGuard( aLock ); + ::std::deque<AttacherIndex_Impl>::iterator aIt = implCheckIndex( nIndex ); + + ::std::deque< AttachedObject_Impl > aList = (*aIt).aObjList; + detachAll_Impl( this, nIndex, aList ); + aIndex.erase( aIt ); +} + +//----------------------------------------------------------------------------- +Sequence< ScriptEventDescriptor > SAL_CALL ImplEventAttacherManager::getScriptEvents(sal_Int32 nIndex) + throw( IllegalArgumentException, RuntimeException ) +{ + Guard< Mutex > aGuard( aLock ); + ::std::deque<AttacherIndex_Impl>::iterator aIt = implCheckIndex( nIndex ); + +#ifdef DEQUE_OK + Sequence< ScriptEventDescriptor > aSeq( (*aIt).aEventList.size() ); + ScriptEventDescriptor * pArray = aSeq.getArray(); + + ::std::deque< ScriptEventDescriptor >::iterator aEvtIt = (*aIt).aEventList.begin(); + ::std::deque< ScriptEventDescriptor >::iterator aEvtEnd = (*aIt).aEventList.end(); + sal_Int32 i = 0; + while( aEvtIt != aEvtEnd ) + { + pArray[i++] = *aEvtIt; + aEvtIt++; + } + return aSeq; +#else + return (*aIt).aEventList; +#endif +} + +//----------------------------------------------------------------------------- +void SAL_CALL ImplEventAttacherManager::attach(sal_Int32 nIndex, const Reference< XInterface >& xObject, const Any & Helper) + throw( IllegalArgumentException, ServiceNotRegisteredException, RuntimeException ) +{ + Guard< Mutex > aGuard( aLock ); + if( nIndex < 0 || !xObject.is() ) + throw IllegalArgumentException(); + + if( static_cast< ::std::deque< AttacherIndex_Impl >::size_type>(nIndex) >= aIndex.size() ) + { + // alte Dateien lesen + if( nVersion == 1 ) + { + insertEntry( nIndex ); + attach( nIndex, xObject, Helper ); + return; + } + else + throw IllegalArgumentException(); + } + + ::std::deque< AttacherIndex_Impl >::iterator aCurrentPosition = aIndex.begin() + nIndex; + + AttachedObject_Impl aTmp; + aTmp.xTarget = xObject; + aTmp.aHelper = Helper; + aCurrentPosition->aObjList.push_back( aTmp ); + + //::std::deque< AttachedObject_Impl >::iterator aObjIt = (*aIt).aObjList.back(); + AttachedObject_Impl & rCurObj = aCurrentPosition->aObjList.back(); +#ifdef DEQUE_OK + rCurObj.aAttachedListenerSeq = Sequence< Reference< XEventListener > >( aCurrentPosition->aEventList.size() ); +#else + rCurObj.aAttachedListenerSeq = Sequence< Reference< XEventListener > >( aCurrentPosition->aEventList.getLength() ); +#endif + Reference< XEventListener > * pArray = rCurObj.aAttachedListenerSeq.getArray(); + +#ifdef DEQUE_OK + ::std::deque< ScriptEventDescriptor >::iterator aEvtIt = aCurrentPosition->aEventList.begin(); + ::std::deque< ScriptEventDescriptor >::iterator aEvtEnd = aCurrentPosition->aEventList.end(); + sal_Int32 i = 0; + while( aEvtIt != aEvtEnd ) + { + Reference< XAllListener > xAll = + new AttacherAllListener_Impl( this, (*aEvtIt).ScriptType, (*aEvtIt).ScriptCode ); + Reference< XEventListener > xAdapter; + try + { + xAdapter = xAttacher->attachSingleEventListener( rCurObj.xTarget, xAll, + rCurObj.aHelper, (*aEvtIt).ScriptType, + (*aEvtIt).AddListenerParam, (*aEvtIt).EventMethod ); + } + catch( Exception& ) + { + } + + pArray[i++] = xAdapter; + aEvtIt++; + } +#else + sal_Int32 nLen = aCurrentPosition->aEventList.getLength(); + ScriptEventDescriptor * pEL = aCurrentPosition->aEventList.getArray(); + for(sal_Int32 i = 0; i < nLen; ++i ) + { + Reference< XAllListener > xAll = + new AttacherAllListener_Impl( this, pEL[i].ScriptType, pEL[i].ScriptCode ); + Reference< XEventListener > xAdapter; + try + { + xAdapter = xAttacher->attachSingleEventListener( rCurObj.xTarget, xAll, + rCurObj.aHelper, pEL[i].ListenerType, + pEL[i].AddListenerParam, pEL[i].EventMethod ); + } + catch( Exception& ) + { + } + + pArray[i] = xAdapter; + } +#endif +} + +//----------------------------------------------------------------------------- +void SAL_CALL ImplEventAttacherManager::detach(sal_Int32 nIndex, const Reference< XInterface >& xObject) + throw( IllegalArgumentException, RuntimeException ) +{ + Guard< Mutex > aGuard( aLock ); + //return; + if( nIndex < 0 || static_cast< ::std::deque< AttacherIndex_Impl >::size_type>(nIndex) >= aIndex.size() || !xObject.is() ) + throw IllegalArgumentException(); + + ::std::deque< AttacherIndex_Impl >::iterator aCurrentPosition = aIndex.begin() + nIndex; + ::std::deque< AttachedObject_Impl >::iterator aObjIt = aCurrentPosition->aObjList.begin(); + ::std::deque< AttachedObject_Impl >::iterator aObjEnd = aCurrentPosition->aObjList.end(); + while( aObjIt != aObjEnd ) + { + if( (*aObjIt).xTarget == xObject ) + { + Reference< XEventListener > * pArray = (*aObjIt).aAttachedListenerSeq.getArray(); +#ifdef DEQUE_OK + + ::std::deque< ScriptEventDescriptor >::iterator aEvtIt = aCurrentPosition->aEventList.begin(); + ::std::deque< ScriptEventDescriptor >::iterator aEvtEnd = aCurrentPosition->aEventList.end(); + sal_Int32 i = 0; + while( aEvtIt != aEvtEnd ) + { + if( pArray[i].is() ) + { + try + { + xAttacher->removeListener( (*aObjIt).xTarget, (*aEvtIt).ListenerType, + (*aEvtIt).AddListenerParam, pArray[i] ); + } + catch( Exception& ) + { + } + } + i++; + aEvtIt++; + } +#else + sal_Int32 nLen = aCurrentPosition->aEventList.getLength(); + ScriptEventDescriptor * pEL = aCurrentPosition->aEventList.getArray(); + for( sal_Int32 i = 0; i < nLen; i++ ) + { + if( pArray[i].is() ) + { + try + { + xAttacher->removeListener( (*aObjIt).xTarget, pEL[i].ListenerType, + pEL[i].AddListenerParam, pArray[i] ); + } + catch( Exception& ) + { + } + } + } +#endif + aCurrentPosition->aObjList.erase( aObjIt ); + break; + } + aObjIt++; + } +} + +void SAL_CALL ImplEventAttacherManager::addScriptListener(const Reference< XScriptListener >& aListener) + throw( IllegalArgumentException, RuntimeException ) +{ + Guard< Mutex > aGuard( aLock ); + aScriptListeners.addInterface( aListener ); +} + +void SAL_CALL ImplEventAttacherManager::removeScriptListener(const Reference< XScriptListener >& aListener) + throw( IllegalArgumentException, RuntimeException ) +{ + Guard< Mutex > aGuard( aLock ); + aScriptListeners.removeInterface( aListener ); +} + + +// Methoden von XPersistObject +OUString SAL_CALL ImplEventAttacherManager::getServiceName(void) + throw( RuntimeException ) +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uno.script.EventAttacherManager") ); +} + +void SAL_CALL ImplEventAttacherManager::write(const Reference< XObjectOutputStream >& OutStream) + throw( IOException, RuntimeException ) +{ + Guard< Mutex > aGuard( aLock ); + // Ohne XMarkableStream laeuft nichts + Reference< XMarkableStream > xMarkStream( OutStream, UNO_QUERY ); + if( !xMarkStream.is() ) + return; + + // Version schreiben + OutStream->writeShort( 2 ); + + // Position fuer Laenge merken + sal_Int32 nObjLenMark = xMarkStream->createMark(); + OutStream->writeLong( 0L ); + + OutStream->writeLong( aIndex.size() ); + + // Sequences schreiben + ::std::deque<AttacherIndex_Impl>::iterator aIt = aIndex.begin(); + ::std::deque<AttacherIndex_Impl>::iterator aEnd = aIndex.end(); + while( aIt != aEnd ) + { +#ifdef DEQUE_OK + // Laenge der Sequence und alle Descriptoren schreiben + OutStream->writeLong( (*aIt).aEventList.size() ); + ::std::deque< ScriptEventDescriptor >::iterator aEvtIt = (*aIt).aEventList.begin(); + ::std::deque< ScriptEventDescriptor >::iterator aEvtEnd = (*aIt).aEventList.end(); + while( aEvtIt != aEvtEnd ) + { + const ScriptEventDescriptor& rDesc = (*aEvtIt); + OutStream->writeUTF( rDesc.ListenerType ); + OutStream->writeUTF( rDesc.EventMethod ); + OutStream->writeUTF( rDesc.AddListenerParam ); + OutStream->writeUTF( rDesc.ScriptType ); + OutStream->writeUTF( rDesc.ScriptCode ); + + aEvtIt++; + } +#else + sal_Int32 nLen = (*aIt).aEventList.getLength(); + // Laenge der Sequence und alle Descriptoren schreiben + OutStream->writeLong( nLen ); + ScriptEventDescriptor * pEL = (*aIt).aEventList.getArray(); + for( sal_Int32 i = 0; i < nLen; i++ ) + { + const ScriptEventDescriptor& rDesc = pEL[i]; + OutStream->writeUTF( rDesc.ListenerType ); + OutStream->writeUTF( rDesc.EventMethod ); + OutStream->writeUTF( rDesc.AddListenerParam ); + OutStream->writeUTF( rDesc.ScriptType ); + OutStream->writeUTF( rDesc.ScriptCode ); + } +#endif + aIt++; + } + + // Die jetzt bekannte Laenge eintragen + sal_Int32 nObjLen = xMarkStream->offsetToMark( nObjLenMark ) -4; + xMarkStream->jumpToMark( nObjLenMark ); + OutStream->writeLong( nObjLen ); + xMarkStream->jumpToFurthest(); + xMarkStream->deleteMark( nObjLenMark ); +} + +void SAL_CALL ImplEventAttacherManager::read(const Reference< XObjectInputStream >& InStream) + throw( IOException, RuntimeException ) +{ + Guard< Mutex > aGuard( aLock ); + // Ohne XMarkableStream laeuft nichts + Reference< XMarkableStream > xMarkStream( InStream, UNO_QUERY ); + if( !xMarkStream.is() ) + return; + + // Version lesen + nVersion = InStream->readShort(); + + // Zunaechst kommen die Daten gemaess Version 1, + // muss auch bei hoeheren Versionen beibehalten werden + sal_Int32 nLen = InStream->readLong(); + + // Position fuer Vergleichszwecke + sal_Int32 nObjLenMark = xMarkStream->createMark(); + + // Anzahl der zu lesenden Sequences + sal_Int32 nItemCount = InStream->readLong(); + + for( sal_Int32 i = 0 ; i < nItemCount ; i++ ) + { + insertEntry( i ); + // Laenge der Sequence lesen + sal_Int32 nSeqLen = InStream->readLong(); + + // Sequence anlegen und Descriptoren lesen + Sequence< ScriptEventDescriptor > aSEDSeq( nSeqLen ); + ScriptEventDescriptor* pArray = aSEDSeq.getArray(); + for( sal_Int32 j = 0 ; j < nSeqLen ; j++ ) + { + ScriptEventDescriptor& rDesc = pArray[ j ]; + rDesc.ListenerType = InStream->readUTF(); + rDesc.EventMethod = InStream->readUTF(); + rDesc.AddListenerParam = InStream->readUTF(); + rDesc.ScriptType = InStream->readUTF(); + rDesc.ScriptCode = InStream->readUTF(); + } + registerScriptEvents( i, aSEDSeq ); + } + + // Haben wir die angegebene Laenge gelesen? + sal_Int32 nRealLen = xMarkStream->offsetToMark( nObjLenMark ); + if( nRealLen != nLen ) + { + // Nur wenn die StreamVersion > 1 ist und noch Daten folgen, kann das + // Ganze richtig sein. Sonst ist etwas voellig daneben gegangen. + if( nRealLen > nLen || nVersion == 1 ) + { + VOS_ENSHURE( sal_False, "ImplEventAttacherManager::read(): Fatal Error, wrong object length" ); + } + else + { + // TODO: Pruefen, ob Zwischen-Speicherung der Daten sinnvoll sein koennte + + // Vorerst einfach nur Skippen + sal_Int32 nSkipCount = nLen - nRealLen; + InStream->skipBytes( nSkipCount ); + } + } + xMarkStream->jumpToFurthest(); + xMarkStream->deleteMark( nObjLenMark ); +} + +} // namesapce comphelper + + diff --git a/comphelper/source/eventattachermgr/makefile.mk b/comphelper/source/eventattachermgr/makefile.mk new file mode 100644 index 000000000000..26aca0467d7d --- /dev/null +++ b/comphelper/source/eventattachermgr/makefile.mk @@ -0,0 +1,50 @@ +#************************************************************************* +# +# 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=evtattmgr + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings common for the whole project ----- + + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES= $(SLO)$/eventattachermgr.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/comphelper/source/inc/comphelper_module.hxx b/comphelper/source/inc/comphelper_module.hxx new file mode 100644 index 000000000000..ea2fc7eeb4eb --- /dev/null +++ b/comphelper/source/inc/comphelper_module.hxx @@ -0,0 +1,43 @@ +/************************************************************************* + * 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_COMPHELPER_MODULE_HXX +#define COMPHELPER_COMPHELPER_MODULE_HXX + +#include "comphelper/componentmodule.hxx" + +//........................................................................ +namespace comphelper { namespace module +{ +//........................................................................ + + DECLARE_COMPONENT_MODULE( ComphelperModule, ComphelperModuleClient ) + +//........................................................................ +} } // namespace comphelper::module +//........................................................................ + +#endif // COMPHELPER_COMPHELPER_MODULE_HXX diff --git a/comphelper/source/misc/SelectionMultiplex.cxx b/comphelper/source/misc/SelectionMultiplex.cxx new file mode 100644 index 000000000000..d61dee3f29f0 --- /dev/null +++ b/comphelper/source/misc/SelectionMultiplex.cxx @@ -0,0 +1,174 @@ +/************************************************************************* + * + * 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/SelectionMultiplex.hxx> +#include <osl/diagnose.h> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::view; + +//======================================================================== +//= OSelectionChangeListener +//======================================================================== +//------------------------------------------------------------------------ +OSelectionChangeListener::~OSelectionChangeListener() +{ + if (m_pAdapter) + m_pAdapter->dispose(); +} + +//------------------------------------------------------------------ +void OSelectionChangeListener::_disposing(const EventObject&) throw( RuntimeException) +{ + // nothing to do here +} + +//------------------------------------------------------------------ +void OSelectionChangeListener::disposeAdapter() +{ + if ( m_pAdapter ) + m_pAdapter->dispose(); + + // will automatically set a new adapter + OSL_ENSURE( !m_pAdapter, "OSelectionChangeListener::disposeAdapter: what did dispose do?" ); +} + +//------------------------------------------------------------------ +void OSelectionChangeListener::setAdapter(OSelectionChangeMultiplexer* 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(); + } +} + +//======================================================================== +//= OSelectionChangeMultiplexer +//======================================================================== +//------------------------------------------------------------------ +OSelectionChangeMultiplexer::OSelectionChangeMultiplexer(OSelectionChangeListener* _pListener, const Reference< XSelectionSupplier>& _rxSet, sal_Bool _bAutoReleaseSet) + :m_xSet(_rxSet) + ,m_pListener(_pListener) + ,m_nLockCount(0) + ,m_bListening(sal_False) + ,m_bAutoSetRelease(_bAutoReleaseSet) +{ + m_pListener->setAdapter(this); + osl_incrementInterlockedCount(&m_refCount); + { + Reference< XSelectionChangeListener> xPreventDelete(this); + m_xSet->addSelectionChangeListener(xPreventDelete); + } + osl_decrementInterlockedCount(&m_refCount); +} + +//------------------------------------------------------------------ +OSelectionChangeMultiplexer::~OSelectionChangeMultiplexer() +{ +} + +//------------------------------------------------------------------ +void OSelectionChangeMultiplexer::lock() +{ + ++m_nLockCount; +} + +//------------------------------------------------------------------ +void OSelectionChangeMultiplexer::unlock() +{ + --m_nLockCount; +} + +//------------------------------------------------------------------ +void OSelectionChangeMultiplexer::dispose() +{ + if (m_bListening) + { + Reference< XSelectionChangeListener> xPreventDelete(this); + + m_xSet->removeSelectionChangeListener(xPreventDelete); + + m_pListener->setAdapter(NULL); + + m_pListener = NULL; + m_bListening = sal_False; + + if (m_bAutoSetRelease) + m_xSet = NULL; + } +} + +// XEventListener +//------------------------------------------------------------------ +void SAL_CALL OSelectionChangeMultiplexer::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; +} + +// XSelectionChangeListener +//------------------------------------------------------------------ +void SAL_CALL OSelectionChangeMultiplexer::selectionChanged( const EventObject& _rEvent ) throw( RuntimeException) +{ + if (m_pListener && !locked()) + m_pListener->_selectionChanged(_rEvent); +} +//......................................................................... +} +//......................................................................... + diff --git a/comphelper/source/misc/accessiblecomponenthelper.cxx b/comphelper/source/misc/accessiblecomponenthelper.cxx new file mode 100644 index 000000000000..5fb86f3f7b1d --- /dev/null +++ b/comphelper/source/misc/accessiblecomponenthelper.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/accessiblecomponenthelper.hxx> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::accessibility; + + //===================================================================== + //= OCommonAccessibleComponent + //===================================================================== + //--------------------------------------------------------------------- + OCommonAccessibleComponent::OCommonAccessibleComponent( ) + { + } + + //--------------------------------------------------------------------- + OCommonAccessibleComponent::OCommonAccessibleComponent( IMutex* _pExternalLock ) + :OAccessibleContextHelper( _pExternalLock ) + { + } + + //--------------------------------------------------------------------- + OCommonAccessibleComponent::~OCommonAccessibleComponent( ) + { + forgetExternalLock(); + // this ensures that the lock, which may be already destroyed as part of the derivee, + // is not used anymore + } + + //-------------------------------------------------------------------- + sal_Bool SAL_CALL OCommonAccessibleComponent::containsPoint( const Point& _rPoint ) throw (RuntimeException) + { + OExternalLockGuard aGuard( this ); + Rectangle aBounds( implGetBounds() ); + return ( _rPoint.X >= 0 ) + && ( _rPoint.Y >= 0 ) + && ( _rPoint.X < aBounds.Width ) + && ( _rPoint.Y < aBounds.Height ); + } + + //-------------------------------------------------------------------- + Point SAL_CALL OCommonAccessibleComponent::getLocation( ) throw (RuntimeException) + { + OExternalLockGuard aGuard( this ); + Rectangle aBounds( implGetBounds() ); + return Point( aBounds.X, aBounds.Y ); + } + + //-------------------------------------------------------------------- + Point SAL_CALL OCommonAccessibleComponent::getLocationOnScreen( ) throw (RuntimeException) + { + OExternalLockGuard aGuard( this ); + Rectangle aBounds( implGetBounds() ); + + Point aScreenLoc( 0, 0 ); + + Reference< XAccessibleComponent > xParentComponent( implGetParentContext(), UNO_QUERY ); + OSL_ENSURE( xParentComponent.is(), "OCommonAccessibleComponent::getLocationOnScreen: no parent component!" ); + if ( xParentComponent.is() ) + { + Point aParentScreenLoc( xParentComponent->getLocationOnScreen() ); + Point aOwnRelativeLoc( getLocation() ); + aScreenLoc.X = aParentScreenLoc.X + aOwnRelativeLoc.X; + aScreenLoc.Y = aParentScreenLoc.Y + aOwnRelativeLoc.Y; + } + + return aScreenLoc; + } + + //-------------------------------------------------------------------- + Size SAL_CALL OCommonAccessibleComponent::getSize( ) throw (RuntimeException) + { + OExternalLockGuard aGuard( this ); + Rectangle aBounds( implGetBounds() ); + return Size( aBounds.Width, aBounds.Height ); + } + + //-------------------------------------------------------------------- + Rectangle SAL_CALL OCommonAccessibleComponent::getBounds( ) throw (RuntimeException) + { + OExternalLockGuard aGuard( this ); + return implGetBounds(); + } + + //===================================================================== + //= OAccessibleComponentHelper + //===================================================================== + //--------------------------------------------------------------------- + OAccessibleComponentHelper::OAccessibleComponentHelper( ) + { + } + + //--------------------------------------------------------------------- + OAccessibleComponentHelper::OAccessibleComponentHelper( IMutex* _pExternalLock ) + :OCommonAccessibleComponent( _pExternalLock ) + { + } + + //-------------------------------------------------------------------- + IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleComponentHelper, OCommonAccessibleComponent, OAccessibleComponentHelper_Base ) + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleComponentHelper, OCommonAccessibleComponent, OAccessibleComponentHelper_Base ) + // (order matters: the first is the class name, the second is the class doing the ref counting) + + //-------------------------------------------------------------------- + sal_Bool SAL_CALL OAccessibleComponentHelper::containsPoint( const Point& _rPoint ) throw (RuntimeException) + { + return OCommonAccessibleComponent::containsPoint( _rPoint ); + } + + //-------------------------------------------------------------------- + Point SAL_CALL OAccessibleComponentHelper::getLocation( ) throw (RuntimeException) + { + return OCommonAccessibleComponent::getLocation( ); + } + + //-------------------------------------------------------------------- + Point SAL_CALL OAccessibleComponentHelper::getLocationOnScreen( ) throw (RuntimeException) + { + return OCommonAccessibleComponent::getLocationOnScreen( ); + } + + //-------------------------------------------------------------------- + Size SAL_CALL OAccessibleComponentHelper::getSize( ) throw (RuntimeException) + { + return OCommonAccessibleComponent::getSize( ); + } + + //-------------------------------------------------------------------- + Rectangle SAL_CALL OAccessibleComponentHelper::getBounds( ) throw (RuntimeException) + { + return OCommonAccessibleComponent::getBounds( ); + } + + //===================================================================== + //= OAccessibleExtendedComponentHelper + //===================================================================== + //--------------------------------------------------------------------- + OAccessibleExtendedComponentHelper::OAccessibleExtendedComponentHelper( ) + { + } + + //--------------------------------------------------------------------- + OAccessibleExtendedComponentHelper::OAccessibleExtendedComponentHelper( IMutex* _pExternalLock ) + :OCommonAccessibleComponent( _pExternalLock ) + { + } + + //-------------------------------------------------------------------- + IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleExtendedComponentHelper, OCommonAccessibleComponent, OAccessibleExtendedComponentHelper_Base ) + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleExtendedComponentHelper, OCommonAccessibleComponent, OAccessibleExtendedComponentHelper_Base ) + // (order matters: the first is the class name, the second is the class doing the ref counting) + + //-------------------------------------------------------------------- + sal_Bool SAL_CALL OAccessibleExtendedComponentHelper::containsPoint( const Point& _rPoint ) throw (RuntimeException) + { + return OCommonAccessibleComponent::containsPoint( _rPoint ); + } + + //-------------------------------------------------------------------- + Point SAL_CALL OAccessibleExtendedComponentHelper::getLocation( ) throw (RuntimeException) + { + return OCommonAccessibleComponent::getLocation( ); + } + + //-------------------------------------------------------------------- + Point SAL_CALL OAccessibleExtendedComponentHelper::getLocationOnScreen( ) throw (RuntimeException) + { + return OCommonAccessibleComponent::getLocationOnScreen( ); + } + + //-------------------------------------------------------------------- + Size SAL_CALL OAccessibleExtendedComponentHelper::getSize( ) throw (RuntimeException) + { + return OCommonAccessibleComponent::getSize( ); + } + + //-------------------------------------------------------------------- + Rectangle SAL_CALL OAccessibleExtendedComponentHelper::getBounds( ) throw (RuntimeException) + { + return OCommonAccessibleComponent::getBounds( ); + } + +//......................................................................... +} // namespace comphelper +//......................................................................... + + diff --git a/comphelper/source/misc/accessiblecontexthelper.cxx b/comphelper/source/misc/accessiblecontexthelper.cxx new file mode 100644 index 000000000000..2e0281848e8c --- /dev/null +++ b/comphelper/source/misc/accessiblecontexthelper.cxx @@ -0,0 +1,356 @@ +/************************************************************************* + * + * 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/accessiblecontexthelper.hxx> +#include <comphelper/accessibleeventbuffer.hxx> +#include <osl/diagnose.h> +#include <cppuhelper/weakref.hxx> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <comphelper/accessibleeventnotifier.hxx> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::accessibility; + + //===================================================================== + //= OContextHelper_Impl + //===================================================================== + /** implementation class for OAccessibleContextHelper. No own thread safety! + */ + class OContextHelper_Impl + { + private: + OAccessibleContextHelper* m_pAntiImpl; // the owning instance + IMutex* m_pExternalLock; // the optional additional external lock + + ::cppu::OInterfaceContainerHelper* m_pEventListeners; + WeakReference< XAccessible > m_aCreator; // the XAccessible which created our XAccessibleContext + + AccessibleEventNotifier::TClientId m_nClientId; + + public: + inline Reference< XAccessible > getCreator( ) const { return m_aCreator; } + inline void setCreator( const Reference< XAccessible >& _rAcc ); + + inline IMutex* getExternalLock( ) { return m_pExternalLock; } + inline void setExternalLock( IMutex* _pLock ) { m_pExternalLock = _pLock; } + + inline AccessibleEventNotifier::TClientId + getClientId() const { return m_nClientId; } + inline void setClientId( const AccessibleEventNotifier::TClientId _nId ) + { m_nClientId = _nId; } + + public: + OContextHelper_Impl( OAccessibleContextHelper* _pAntiImpl ) + :m_pAntiImpl( _pAntiImpl ) + ,m_pExternalLock( NULL ) + ,m_pEventListeners( NULL ) + ,m_nClientId( 0 ) + { + } + }; + + //--------------------------------------------------------------------- + inline void OContextHelper_Impl::setCreator( const Reference< XAccessible >& _rAcc ) + { + m_aCreator = _rAcc; + } + + //===================================================================== + //= OAccessibleContextHelper + //===================================================================== + //--------------------------------------------------------------------- + OAccessibleContextHelper::OAccessibleContextHelper( ) + :OAccessibleContextHelper_Base( GetMutex() ) + ,m_pImpl( NULL ) + { + m_pImpl = new OContextHelper_Impl( this ); + } + + //--------------------------------------------------------------------- + OAccessibleContextHelper::OAccessibleContextHelper( IMutex* _pExternalLock ) + :OAccessibleContextHelper_Base( GetMutex() ) + ,m_pImpl( NULL ) + { + m_pImpl = new OContextHelper_Impl( this ); + m_pImpl->setExternalLock( _pExternalLock ); + } + + //--------------------------------------------------------------------- + void OAccessibleContextHelper::forgetExternalLock() + { + m_pImpl->setExternalLock( NULL ); + } + + //--------------------------------------------------------------------- + OAccessibleContextHelper::~OAccessibleContextHelper( ) + { + forgetExternalLock(); + // this ensures that the lock, which may be already destroyed as part of the derivee, + // is not used anymore + + ensureDisposed(); + + delete m_pImpl; + m_pImpl = NULL; + } + + //--------------------------------------------------------------------- + IMutex* OAccessibleContextHelper::getExternalLock( ) + { + return m_pImpl->getExternalLock(); + } + + //--------------------------------------------------------------------- + void SAL_CALL OAccessibleContextHelper::disposing() + { + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + + if ( m_pImpl->getClientId( ) ) + { + AccessibleEventNotifier::revokeClientNotifyDisposing( m_pImpl->getClientId( ), *this ); + m_pImpl->setClientId( 0 ); + } + } + + //--------------------------------------------------------------------- + void SAL_CALL OAccessibleContextHelper::addEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException) + { + OMutexGuard aGuard( getExternalLock() ); + // don't use the OContextEntryGuard - it will throw an exception if we're not alive + // anymore, while the most recent specification for XComponent states that we should + // silently ignore the call in such a situation + if ( !isAlive() ) + { + if ( _rxListener.is() ) + _rxListener->disposing( EventObject( *this ) ); + return; + } + + if ( _rxListener.is() ) + { + if ( !m_pImpl->getClientId( ) ) + m_pImpl->setClientId( AccessibleEventNotifier::registerClient( ) ); + + AccessibleEventNotifier::addEventListener( m_pImpl->getClientId( ), _rxListener ); + } + } + + //--------------------------------------------------------------------- + void SAL_CALL OAccessibleContextHelper::removeEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException) + { + OMutexGuard aGuard( getExternalLock() ); + // don't use the OContextEntryGuard - it will throw an exception if we're not alive + // anymore, while the most recent specification for XComponent states that we should + // silently ignore the call in such a situation + if ( !isAlive() ) + return; + + if ( _rxListener.is() ) + { + sal_Int32 nListenerCount = AccessibleEventNotifier::removeEventListener( m_pImpl->getClientId( ), _rxListener ); + if ( !nListenerCount ) + { + // no listeners anymore + // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client), + // and at least to us not firing any events anymore, in case somebody calls + // NotifyAccessibleEvent, again + AccessibleEventNotifier::revokeClient( m_pImpl->getClientId( ) ); + m_pImpl->setClientId( 0 ); + } + } + } + + //--------------------------------------------------------------------- + void SAL_CALL OAccessibleContextHelper::NotifyAccessibleEvent( const sal_Int16 _nEventId, + const Any& _rOldValue, const Any& _rNewValue ) + { + if ( !m_pImpl->getClientId( ) ) + // if we don't have a client id for the notifier, then we don't have listeners, then + // we don't need to notify anything + return; + + // build an event object + AccessibleEventObject aEvent; + aEvent.Source = *this; + aEvent.EventId = _nEventId; + aEvent.OldValue = _rOldValue; + aEvent.NewValue = _rNewValue; + + // let the notifier handle this event + AccessibleEventNotifier::addEvent( m_pImpl->getClientId( ), aEvent ); + } + + //--------------------------------------------------------------------- + void SAL_CALL OAccessibleContextHelper::BufferAccessibleEvent( const sal_Int16 _nEventId, + const Any& _rOldValue, const Any& _rNewValue, + AccessibleEventBuffer & _rBuffer ) + { + // TODO: this whole method (as well as the class AccessibleEventBuffer) should be removed + // The reasons why they have been introduces id that we needed to collect a set of events + // before notifying them alltogether (after releasing our mutex). With the other + // NotifyAccessibleEvent being asynchronous now, this should not be necessary anymore + // - clients could use the other version now. + + // copy our current listeners + Sequence< Reference< XInterface > > aListeners; + if ( m_pImpl->getClientId( ) ) + aListeners = AccessibleEventNotifier::getEventListeners( m_pImpl->getClientId( ) ); + + if ( aListeners.getLength() ) + { + AccessibleEventObject aEvent; + aEvent.Source = *this; + OSL_ENSURE( aEvent.Source.is(), "OAccessibleContextHelper::BufferAccessibleEvent: invalid creator!" ); + aEvent.EventId = _nEventId; + aEvent.OldValue = _rOldValue; + aEvent.NewValue = _rNewValue; + + _rBuffer.addEvent( aEvent, aListeners ); + } + } + + //--------------------------------------------------------------------- + sal_Bool OAccessibleContextHelper::isAlive() const + { + return !GetBroadcastHelper().bDisposed && !GetBroadcastHelper().bInDispose; + } + + //--------------------------------------------------------------------- + void OAccessibleContextHelper::ensureAlive() const SAL_THROW( ( DisposedException ) ) + { + if( !isAlive() ) + throw DisposedException(); + } + + //--------------------------------------------------------------------- + void OAccessibleContextHelper::ensureDisposed( ) + { + if ( !GetBroadcastHelper().bDisposed ) + { + OSL_ENSURE( 0 == m_refCount, "OAccessibleContextHelper::ensureDisposed: this method _has_ to be called from without your dtor only!" ); + acquire(); + dispose(); + } + } + + //--------------------------------------------------------------------- + void OAccessibleContextHelper::lateInit( const Reference< XAccessible >& _rxAccessible ) + { + m_pImpl->setCreator( _rxAccessible ); + } + + //--------------------------------------------------------------------- + Reference< XAccessible > OAccessibleContextHelper::getAccessibleCreator( ) const + { + return m_pImpl->getCreator(); + } + + //--------------------------------------------------------------------- + sal_Int32 SAL_CALL OAccessibleContextHelper::getAccessibleIndexInParent( ) throw (RuntimeException) + { + OExternalLockGuard aGuard( this ); + + // -1 for child not found/no parent (according to specification) + sal_Int32 nRet = -1; + + try + { + + Reference< XAccessibleContext > xParentContext( implGetParentContext() ); + + // iterate over parent's children and search for this object + if ( xParentContext.is() ) + { + // our own XAccessible for comparing with the children of our parent + Reference< XAccessible > xCreator( m_pImpl->getCreator() ); + + OSL_ENSURE( xCreator.is(), "OAccessibleContextHelper::getAccessibleIndexInParent: invalid creator!" ); + // two ideas why this could be NULL: + // * nobody called our late ctor (init), so we never had a creator at all -> bad + // * the creator is already dead. In this case, we should have been disposed, and + // never survived the above OContextEntryGuard. + // in all other situations the creator should be non-NULL + + if ( xCreator.is() ) + { + sal_Int32 nChildCount = xParentContext->getAccessibleChildCount(); + for ( sal_Int32 nChild = 0; ( nChild < nChildCount ) && ( -1 == nRet ); ++nChild ) + { + Reference< XAccessible > xChild( xParentContext->getAccessibleChild( nChild ) ); + if ( xChild.get() == xCreator.get() ) + nRet = nChild; + } + } + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "OAccessibleContextHelper::getAccessibleIndexInParent: caught an exception!" ); + } + + return nRet; + } + + //--------------------------------------------------------------------- + Locale SAL_CALL OAccessibleContextHelper::getLocale( ) throw (IllegalAccessibleComponentStateException, RuntimeException) + { + // simply ask the parent + Reference< XAccessible > xParent = getAccessibleParent(); + Reference< XAccessibleContext > xParentContext; + if ( xParent.is() ) + xParentContext = xParent->getAccessibleContext(); + + if ( !xParentContext.is() ) + throw IllegalAccessibleComponentStateException( ::rtl::OUString(), *this ); + + return xParentContext->getLocale(); + } + + //--------------------------------------------------------------------- + Reference< XAccessibleContext > OAccessibleContextHelper::implGetParentContext() SAL_THROW( ( RuntimeException ) ) + { + Reference< XAccessible > xParent = getAccessibleParent(); + Reference< XAccessibleContext > xParentContext; + if ( xParent.is() ) + xParentContext = xParent->getAccessibleContext(); + return xParentContext; + } + +//......................................................................... +} // namespace comphelper +//......................................................................... + + diff --git a/comphelper/source/misc/accessibleeventbuffer.cxx b/comphelper/source/misc/accessibleeventbuffer.cxx new file mode 100644 index 000000000000..50c61d59b9e6 --- /dev/null +++ b/comphelper/source/misc/accessibleeventbuffer.cxx @@ -0,0 +1,110 @@ +/************************************************************************* + * + * 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/accessibleeventbuffer.hxx" + +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "com/sun/star/uno/XInterface.hpp" +#include "com/sun/star/accessibility/AccessibleEventObject.hpp" +#include "com/sun/star/accessibility/XAccessibleEventListener.hpp" +#include "osl/diagnose.h" +#include "rtl/textenc.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" + +namespace css = ::com::sun::star; + +using comphelper::AccessibleEventBuffer; + +struct AccessibleEventBuffer::Entry +{ + inline Entry(::css::accessibility::AccessibleEventObject const & rEvent, + ::css::uno::Sequence< ::css::uno::Reference< + ::css::uno::XInterface > > const & rListeners): + m_aEvent(rEvent), m_aListeners(rListeners) {} + + ::css::accessibility::AccessibleEventObject m_aEvent; + + ::css::uno::Sequence< + ::css::uno::Reference< ::css::uno::XInterface > > m_aListeners; +}; + +AccessibleEventBuffer::AccessibleEventBuffer() +{} + +AccessibleEventBuffer::AccessibleEventBuffer( + AccessibleEventBuffer const & rOther): + m_aEntries(rOther.m_aEntries) +{} + +AccessibleEventBuffer::~AccessibleEventBuffer() +{} + +AccessibleEventBuffer +AccessibleEventBuffer::operator =(AccessibleEventBuffer const & rOther) +{ + m_aEntries = rOther.m_aEntries; + return *this; +} + +void AccessibleEventBuffer::addEvent( + ::css::accessibility::AccessibleEventObject const & rEvent, + ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > + const & rListeners) +{ + m_aEntries.push_back(Entry(rEvent, rListeners)); +} + +void AccessibleEventBuffer::sendEvents() const +{ + for (Entries::const_iterator aIt(m_aEntries.begin()); + aIt != m_aEntries.end(); ++aIt) + for (::sal_Int32 i = 0; i < aIt->m_aListeners.getLength(); ++i) + { + ::css::uno::Reference< + ::css::accessibility::XAccessibleEventListener > xListener( + aIt->m_aListeners[i], ::css::uno::UNO_QUERY); + if (xListener.is()) + try + { + xListener->notifyEvent(aIt->m_aEvent); + } + catch (::css::uno::RuntimeException & rEx) + { + OSL_TRACE( + "comphelper::AccessibleEventBuffer::sendEvents:" + " caught %s\n", + ::rtl::OUStringToOString( + rEx.Message, RTL_TEXTENCODING_UTF8).getStr()); + } + } +} diff --git a/comphelper/source/misc/accessibleeventnotifier.cxx b/comphelper/source/misc/accessibleeventnotifier.cxx new file mode 100644 index 000000000000..421fb9868d73 --- /dev/null +++ b/comphelper/source/misc/accessibleeventnotifier.cxx @@ -0,0 +1,259 @@ +/************************************************************************* + * + * 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/accessibleeventnotifier.hxx> +#include <osl/diagnose.h> +#include <rtl/instance.hxx> +#include <comphelper/guarding.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::accessibility; +using namespace ::comphelper; + +//===================================================================== +//= AccessibleEventNotifier +//===================================================================== +//--------------------------------------------------------------------- +namespace +{ + struct lclMutex + : public rtl::Static< ::osl::Mutex, lclMutex > {}; + struct Clients + : public rtl::Static< AccessibleEventNotifier::ClientMap, Clients > {}; +} + +//......................................................................... +namespace comphelper +{ +//......................................................................... + + //--------------------------------------------------------------------- + AccessibleEventNotifier::TClientId AccessibleEventNotifier::generateId() + { + TClientId nBiggestUsedId = 0; + TClientId nFreeId = 0; + + // look through all registered clients until we find a "gap" in the ids + + // Note that the following relies on the fact the elements in the map are traveled with + // ascending keys (aka client ids) + AccessibleEventNotifier::ClientMap &rClients = Clients::get(); + for ( ClientMap::const_iterator aLookup = rClients.begin(); + aLookup != rClients.end(); + ++aLookup + ) + { + TClientId nCurrent = aLookup->first; + OSL_ENSURE( nCurrent > nBiggestUsedId, "AccessibleEventNotifier::generateId: map is expected to be sorted ascending!" ); + + if ( nCurrent - nBiggestUsedId > 1 ) + { // found a "gap" + nFreeId = nBiggestUsedId + 1; + break; + } + + nBiggestUsedId = nCurrent; + } + + if ( !nFreeId ) + nFreeId = nBiggestUsedId + 1; + + OSL_ENSURE( rClients.end() == rClients.find( nFreeId ), + "AccessibleEventNotifier::generateId: algorithm broken!" ); + + return nFreeId; + } + + //--------------------------------------------------------------------- + AccessibleEventNotifier::TClientId AccessibleEventNotifier::registerClient( ) + { + ::osl::MutexGuard aGuard( lclMutex::get() ); + + // generate a new client id + TClientId nNewClientId = generateId( ); + + // the event listeners for the new client + EventListeners* pNewListeners = new EventListeners( lclMutex::get() ); + // note that we're using our own mutex here, so the listener containers for all + // our clients share this same mutex. + // this is a reminiscense to the days where the notifier was asynchronous. Today this is + // completely nonsense, and potentially slowing down the Office me thinks ... + + // add the client + Clients::get().insert( ClientMap::value_type( nNewClientId, pNewListeners ) ); + + // outta here + return nNewClientId; + } + + //--------------------------------------------------------------------- + sal_Bool AccessibleEventNotifier::implLookupClient( const TClientId _nClient, ClientMap::iterator& _rPos ) + { + // look up this client + AccessibleEventNotifier::ClientMap &rClients = Clients::get(); + _rPos = rClients.find( _nClient ); + OSL_ENSURE( rClients.end() != _rPos, "AccessibleEventNotifier::implLookupClient: invalid client id (did you register your client?)!" ); + + return ( rClients.end() != _rPos ); + } + + //--------------------------------------------------------------------- + void AccessibleEventNotifier::revokeClient( const TClientId _nClient ) + { + ::osl::MutexGuard aGuard( lclMutex::get() ); + + ClientMap::iterator aClientPos; + if ( !implLookupClient( _nClient, aClientPos ) ) + // already asserted in implLookupClient + return; + + // remove it from the clients map + delete aClientPos->second; + Clients::get().erase( aClientPos ); + } + + //--------------------------------------------------------------------- + void AccessibleEventNotifier::revokeClientNotifyDisposing( const TClientId _nClient, + const Reference< XInterface >& _rxEventSource ) SAL_THROW( ( ) ) + { + ::osl::MutexGuard aGuard( lclMutex::get() ); + + ClientMap::iterator aClientPos; + if ( !implLookupClient( _nClient, aClientPos ) ) + // already asserted in implLookupClient + return; + + // notify the "disposing" event for this client + EventObject aDisposalEvent; + aDisposalEvent.Source = _rxEventSource; + + // notify the listeners + EventListeners* pListeners = aClientPos->second; + + // we do not need the entry in the clients map anymore + // (do this before actually notifying, because some client implementations have re-entrance + // problems and call into revokeClient while we are notifying from hereing) + Clients::get().erase( aClientPos ); + + // now really do the notification + pListeners->disposeAndClear( aDisposalEvent ); + delete pListeners; + + } + + //--------------------------------------------------------------------- + sal_Int32 AccessibleEventNotifier::addEventListener( + const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) ) + { + ::osl::MutexGuard aGuard( lclMutex::get() ); + + ClientMap::iterator aClientPos; + if ( !implLookupClient( _nClient, aClientPos ) ) + // already asserted in implLookupClient + return 0; + + if ( _rxListener.is() ) + aClientPos->second->addInterface( _rxListener ); + + return aClientPos->second->getLength(); + } + + //--------------------------------------------------------------------- + sal_Int32 AccessibleEventNotifier::removeEventListener( + const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) ) + { + ::osl::MutexGuard aGuard( lclMutex::get() ); + + ClientMap::iterator aClientPos; + if ( !implLookupClient( _nClient, aClientPos ) ) + // already asserted in implLookupClient + return 0; + + if ( _rxListener.is() ) + aClientPos->second->removeInterface( _rxListener ); + + return aClientPos->second->getLength(); + } + + //--------------------------------------------------------------------- + Sequence< Reference< XInterface > > AccessibleEventNotifier::getEventListeners( const TClientId _nClient ) SAL_THROW( ( ) ) + { + Sequence< Reference< XInterface > > aListeners; + + ::osl::MutexGuard aGuard( lclMutex::get() ); + + ClientMap::iterator aClientPos; + if ( implLookupClient( _nClient, aClientPos ) ) + aListeners = aClientPos->second->getElements(); + + return aListeners; + } + + //--------------------------------------------------------------------- + void AccessibleEventNotifier::addEvent( const TClientId _nClient, const AccessibleEventObject& _rEvent ) SAL_THROW( ( ) ) + { + Sequence< Reference< XInterface > > aListeners; + + // --- <mutex lock> ------------------------------- + { + ::osl::MutexGuard aGuard( lclMutex::get() ); + + ClientMap::iterator aClientPos; + if ( !implLookupClient( _nClient, aClientPos ) ) + // already asserted in implLookupClient + return; + + // since we're synchronous, again, we want to notify immediately + aListeners = aClientPos->second->getElements(); + } + // --- </mutex lock> ------------------------------ + + // default handling: loop through all listeners, and notify them + const Reference< XInterface >* pListeners = aListeners.getConstArray(); + const Reference< XInterface >* pListenersEnd = pListeners + aListeners.getLength(); + while ( pListeners != pListenersEnd ) + { + try + { + static_cast< XAccessibleEventListener* >( pListeners->get() )->notifyEvent( _rEvent ); + } + catch( const Exception& ) + { + // no assertion, because a broken access remote bridge or something like this + // can cause this exception + } + ++pListeners; + } + } + +//......................................................................... +} // namespace comphelper +//......................................................................... + diff --git a/comphelper/source/misc/accessiblekeybindinghelper.cxx b/comphelper/source/misc/accessiblekeybindinghelper.cxx new file mode 100644 index 000000000000..d3c22071bfd8 --- /dev/null +++ b/comphelper/source/misc/accessiblekeybindinghelper.cxx @@ -0,0 +1,114 @@ +/************************************************************************* + * + * 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" + +// includes -------------------------------------------------------------- +#include <comphelper/accessiblekeybindinghelper.hxx> + + +//.............................................................................. +namespace comphelper +{ +//.............................................................................. + + using namespace ::com::sun::star; // MT 04/2003: was ::drafts::com::sun::star - otherwise to many changes + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::accessibility; + + //============================================================================== + // OAccessibleKeyBindingHelper + //============================================================================== + + OAccessibleKeyBindingHelper::OAccessibleKeyBindingHelper() + { + } + + // ----------------------------------------------------------------------------- + + OAccessibleKeyBindingHelper::OAccessibleKeyBindingHelper( const OAccessibleKeyBindingHelper& rHelper ) + : cppu::WeakImplHelper1<XAccessibleKeyBinding>( rHelper ) + , m_aKeyBindings( rHelper.m_aKeyBindings ) + { + } + + // ----------------------------------------------------------------------------- + + OAccessibleKeyBindingHelper::~OAccessibleKeyBindingHelper() + { + } + + // ----------------------------------------------------------------------------- + + void OAccessibleKeyBindingHelper::AddKeyBinding( const Sequence< awt::KeyStroke >& rKeyBinding ) throw (RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + m_aKeyBindings.push_back( rKeyBinding ); + } + + // ----------------------------------------------------------------------------- + + void OAccessibleKeyBindingHelper::AddKeyBinding( const awt::KeyStroke& rKeyStroke ) throw (RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + Sequence< awt::KeyStroke > aSeq(1); + aSeq[0] = rKeyStroke; + m_aKeyBindings.push_back( aSeq ); + } + + // ----------------------------------------------------------------------------- + // XAccessibleKeyBinding + // ----------------------------------------------------------------------------- + + sal_Int32 OAccessibleKeyBindingHelper::getAccessibleKeyBindingCount() throw (RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return m_aKeyBindings.size(); + } + + // ----------------------------------------------------------------------------- + + Sequence< awt::KeyStroke > OAccessibleKeyBindingHelper::getAccessibleKeyBinding( sal_Int32 nIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( nIndex < 0 || nIndex >= (sal_Int32)m_aKeyBindings.size() ) + throw IndexOutOfBoundsException(); + + return m_aKeyBindings[nIndex]; + } + + // ----------------------------------------------------------------------------- + +//.............................................................................. +} // namespace comphelper +//.............................................................................. diff --git a/comphelper/source/misc/accessibleselectionhelper.cxx b/comphelper/source/misc/accessibleselectionhelper.cxx new file mode 100644 index 000000000000..8e31410b337e --- /dev/null +++ b/comphelper/source/misc/accessibleselectionhelper.cxx @@ -0,0 +1,192 @@ +/************************************************************************* + * + * 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/accessibleselectionhelper.hxx> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::accessibility; + + //===================================================================== + //= OCommonAccessibleSelection + //===================================================================== + //--------------------------------------------------------------------- + OCommonAccessibleSelection::OCommonAccessibleSelection( ) + { + } + + //-------------------------------------------------------------------- + void SAL_CALL OCommonAccessibleSelection::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + implSelect( nChildIndex, sal_True ); + } + + //-------------------------------------------------------------------- + sal_Bool SAL_CALL OCommonAccessibleSelection::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + return( implIsSelected( nChildIndex ) ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OCommonAccessibleSelection::clearAccessibleSelection( ) throw (RuntimeException) + { + implSelect( ACCESSIBLE_SELECTION_CHILD_ALL, sal_False ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OCommonAccessibleSelection::selectAllAccessibleChildren( ) throw (RuntimeException) + { + implSelect( ACCESSIBLE_SELECTION_CHILD_ALL, sal_True ); + } + + //-------------------------------------------------------------------- + sal_Int32 SAL_CALL OCommonAccessibleSelection::getSelectedAccessibleChildCount( ) throw (RuntimeException) + { + sal_Int32 nRet = 0; + Reference< XAccessibleContext > xParentContext( implGetAccessibleContext() ); + + OSL_ENSURE( xParentContext.is(), "OCommonAccessibleSelection::getSelectedAccessibleChildCount: no parent context!" ); + + if( xParentContext.is() ) + { + for( sal_Int32 i = 0, nChildCount = xParentContext->getAccessibleChildCount(); i < nChildCount; i++ ) + if( implIsSelected( i ) ) + ++nRet; + } + + return( nRet ); + } + + //-------------------------------------------------------------------- + Reference< XAccessible > SAL_CALL OCommonAccessibleSelection::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + Reference< XAccessible > xRet; + Reference< XAccessibleContext > xParentContext( implGetAccessibleContext() ); + + OSL_ENSURE( xParentContext.is(), "OCommonAccessibleSelection::getSelectedAccessibleChildCount: no parent context!" ); + + if( xParentContext.is() ) + { + for( sal_Int32 i = 0, nChildCount = xParentContext->getAccessibleChildCount(), nPos = 0; ( i < nChildCount ) && !xRet.is(); i++ ) + if( implIsSelected( i ) && ( nPos++ == nSelectedChildIndex ) ) + xRet = xParentContext->getAccessibleChild( i ); + } + + return( xRet ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OCommonAccessibleSelection::deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + implSelect( nSelectedChildIndex, sal_False ); + } + + //===================================================================== + //= OAccessibleSelectionHelper + //===================================================================== + //--------------------------------------------------------------------- + OAccessibleSelectionHelper::OAccessibleSelectionHelper( ) + { + } + + //-------------------------------------------------------------------- + OAccessibleSelectionHelper::OAccessibleSelectionHelper( IMutex* _pExternalLock ) : OAccessibleComponentHelper(_pExternalLock) + { + } + + //-------------------------------------------------------------------- + IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleSelectionHelper, OAccessibleComponentHelper, OAccessibleSelectionHelper_Base ) + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleSelectionHelper, OAccessibleComponentHelper, OAccessibleSelectionHelper_Base ) + // (order matters: the first is the class name, the second is the class doing the ref counting) + + //-------------------------------------------------------------------- + Reference< XAccessibleContext > OAccessibleSelectionHelper::implGetAccessibleContext() throw ( RuntimeException ) + { + return( this ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OAccessibleSelectionHelper::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + OExternalLockGuard aGuard( this ); + OCommonAccessibleSelection::selectAccessibleChild( nChildIndex ); + } + + //-------------------------------------------------------------------- + sal_Bool SAL_CALL OAccessibleSelectionHelper::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + OExternalLockGuard aGuard( this ); + return( OCommonAccessibleSelection::isAccessibleChildSelected( nChildIndex ) ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OAccessibleSelectionHelper::clearAccessibleSelection( ) throw (RuntimeException) + { + OExternalLockGuard aGuard( this ); + OCommonAccessibleSelection::clearAccessibleSelection(); + } + + //-------------------------------------------------------------------- + void SAL_CALL OAccessibleSelectionHelper::selectAllAccessibleChildren( ) throw (RuntimeException) + { + OExternalLockGuard aGuard( this ); + OCommonAccessibleSelection::selectAllAccessibleChildren(); + } + + //-------------------------------------------------------------------- + sal_Int32 SAL_CALL OAccessibleSelectionHelper::getSelectedAccessibleChildCount( ) throw (RuntimeException) + { + OExternalLockGuard aGuard( this ); + return( OCommonAccessibleSelection::getSelectedAccessibleChildCount() ); + } + + //-------------------------------------------------------------------- + Reference< XAccessible > SAL_CALL OAccessibleSelectionHelper::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + OExternalLockGuard aGuard( this ); + return( OCommonAccessibleSelection::getSelectedAccessibleChild( nSelectedChildIndex ) ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OAccessibleSelectionHelper::deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + OExternalLockGuard aGuard( this ); + OCommonAccessibleSelection::deselectAccessibleChild( nSelectedChildIndex ); + } + +//......................................................................... +} // namespace comphelper +//......................................................................... + diff --git a/comphelper/source/misc/accessibletexthelper.cxx b/comphelper/source/misc/accessibletexthelper.cxx new file mode 100644 index 000000000000..e3247cae5b60 --- /dev/null +++ b/comphelper/source/misc/accessibletexthelper.cxx @@ -0,0 +1,915 @@ +/************************************************************************* + * + * 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" + +// includes -------------------------------------------------------------- +#include <comphelper/accessibletexthelper.hxx> +#include <com/sun/star/accessibility/AccessibleTextType.hpp> +#include <com/sun/star/i18n/CharacterIteratorMode.hpp> +#ifndef _COM_SUN_STAR_TEXT_WORDTYPE_HPP_ +#include <com/sun/star/i18n/WordType.hpp> +#endif +#include <com/sun/star/i18n/KCharacterType.hpp> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/accessibility/TextSegment.hpp> + +#include <algorithm> + +//.............................................................................. +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 namespace ::com::sun::star::accessibility; + + //============================================================================== + // OCommonAccessibleText + //============================================================================== + + OCommonAccessibleText::OCommonAccessibleText() + { + } + + // ----------------------------------------------------------------------------- + + OCommonAccessibleText::~OCommonAccessibleText() + { + } + + // ----------------------------------------------------------------------------- + + Reference < i18n::XBreakIterator > OCommonAccessibleText::implGetBreakIterator() + { + if ( !m_xBreakIter.is() ) + { + Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + if ( xMSF.is() ) + { + m_xBreakIter = Reference< i18n::XBreakIterator > + ( xMSF->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.BreakIterator" ) ) ), UNO_QUERY ); + } + } + + return m_xBreakIter; + } + + // ----------------------------------------------------------------------------- + + Reference < i18n::XCharacterClassification > OCommonAccessibleText::implGetCharacterClassification() + { + if ( !m_xCharClass.is() ) + { + Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + if ( xMSF.is() ) + { + m_xCharClass = Reference< i18n::XCharacterClassification > + ( xMSF->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.CharacterClassification" ) ) ), UNO_QUERY ); + } + } + + return m_xCharClass; + } + + // ----------------------------------------------------------------------------- + + sal_Bool OCommonAccessibleText::implIsValidBoundary( i18n::Boundary& rBoundary, sal_Int32 nLength ) + { + return ( rBoundary.startPos >= 0 ) && ( rBoundary.startPos < nLength ) && ( rBoundary.endPos >= 0 ) && ( rBoundary.endPos <= nLength ); + } + + // ----------------------------------------------------------------------------- + + sal_Bool OCommonAccessibleText::implIsValidIndex( sal_Int32 nIndex, sal_Int32 nLength ) + { + return ( nIndex >= 0 ) && ( nIndex < nLength ); + } + + // ----------------------------------------------------------------------------- + + sal_Bool OCommonAccessibleText::implIsValidRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex, sal_Int32 nLength ) + { + return ( nStartIndex >= 0 ) && ( nStartIndex <= nLength ) && ( nEndIndex >= 0 ) && ( nEndIndex <= nLength ); + } + + // ----------------------------------------------------------------------------- + + void OCommonAccessibleText::implGetGlyphBoundary( i18n::Boundary& rBoundary, sal_Int32 nIndex ) + { + ::rtl::OUString sText( implGetText() ); + + if ( implIsValidIndex( nIndex, sText.getLength() ) ) + { + Reference < i18n::XBreakIterator > xBreakIter = implGetBreakIterator(); + if ( xBreakIter.is() ) + { + sal_Int32 nCount = 1; + sal_Int32 nDone; + sal_Int32 nStartIndex = xBreakIter->previousCharacters( sText, nIndex, implGetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nDone ); + if ( nDone != 0 ) + nStartIndex = xBreakIter->nextCharacters( sText, nStartIndex, implGetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nDone ); + sal_Int32 nEndIndex = xBreakIter->nextCharacters( sText, nStartIndex, implGetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nDone ); + if ( nDone != 0 ) + { + rBoundary.startPos = nStartIndex; + rBoundary.endPos = nEndIndex; + } + } + } + else + { + rBoundary.startPos = nIndex; + rBoundary.endPos = nIndex; + } + } + + // ----------------------------------------------------------------------------- + + sal_Bool OCommonAccessibleText::implGetWordBoundary( i18n::Boundary& rBoundary, sal_Int32 nIndex ) + { + sal_Bool bWord = sal_False; + ::rtl::OUString sText( implGetText() ); + + if ( implIsValidIndex( nIndex, sText.getLength() ) ) + { + Reference < i18n::XBreakIterator > xBreakIter = implGetBreakIterator(); + if ( xBreakIter.is() ) + { + rBoundary = xBreakIter->getWordBoundary( sText, nIndex, implGetLocale(), i18n::WordType::ANY_WORD, sal_True ); + + // it's a word, if the first character is an alpha-numeric character + Reference< i18n::XCharacterClassification > xCharClass = implGetCharacterClassification(); + if ( xCharClass.is() ) + { + sal_Int32 nType = xCharClass->getCharacterType( sText, rBoundary.startPos, implGetLocale() ); + if ( ( nType & ( i18n::KCharacterType::LETTER | i18n::KCharacterType::DIGIT ) ) != 0 ) + bWord = sal_True; + } + } + } + else + { + rBoundary.startPos = nIndex; + rBoundary.endPos = nIndex; + } + + return bWord; + } + + // ----------------------------------------------------------------------------- + + void OCommonAccessibleText::implGetSentenceBoundary( i18n::Boundary& rBoundary, sal_Int32 nIndex ) + { + ::rtl::OUString sText( implGetText() ); + + if ( implIsValidIndex( nIndex, sText.getLength() ) ) + { + Locale aLocale = implGetLocale(); + Reference < i18n::XBreakIterator > xBreakIter = implGetBreakIterator(); + if ( xBreakIter.is() ) + { + rBoundary.endPos = xBreakIter->endOfSentence( sText, nIndex, aLocale ); + rBoundary.startPos = xBreakIter->beginOfSentence( sText, rBoundary.endPos, aLocale ); + } + } + else + { + rBoundary.startPos = nIndex; + rBoundary.endPos = nIndex; + } + } + + // ----------------------------------------------------------------------------- + + void OCommonAccessibleText::implGetParagraphBoundary( i18n::Boundary& rBoundary, sal_Int32 nIndex ) + { + ::rtl::OUString sText( implGetText() ); + + if ( implIsValidIndex( nIndex, sText.getLength() ) ) + { + rBoundary.startPos = 0; + rBoundary.endPos = sText.getLength(); + + sal_Int32 nFound = sText.lastIndexOf( (sal_Unicode)'\n', nIndex ); + if ( nFound != -1 ) + rBoundary.startPos = nFound + 1; + + nFound = sText.indexOf( (sal_Unicode)'\n', nIndex ); + if ( nFound != -1 ) + rBoundary.endPos = nFound + 1; + } + else + { + rBoundary.startPos = nIndex; + rBoundary.endPos = nIndex; + } + } + + // ----------------------------------------------------------------------------- + + void OCommonAccessibleText::implGetLineBoundary( i18n::Boundary& rBoundary, sal_Int32 nIndex ) + { + ::rtl::OUString sText( implGetText() ); + sal_Int32 nLength = sText.getLength(); + + if ( implIsValidIndex( nIndex, nLength ) || nIndex == nLength ) + { + rBoundary.startPos = 0; + rBoundary.endPos = nLength; + } + else + { + rBoundary.startPos = nIndex; + rBoundary.endPos = nIndex; + } + } + + // ----------------------------------------------------------------------------- + + sal_Unicode OCommonAccessibleText::getCharacter( sal_Int32 nIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + ::rtl::OUString sText( implGetText() ); + + if ( !implIsValidIndex( nIndex, sText.getLength() ) ) + throw IndexOutOfBoundsException(); + + return sText.getStr()[nIndex]; + } + + // ----------------------------------------------------------------------------- + + sal_Int32 OCommonAccessibleText::getCharacterCount() throw (RuntimeException) + { + return implGetText().getLength(); + } + + // ----------------------------------------------------------------------------- + + ::rtl::OUString OCommonAccessibleText::getSelectedText() throw (RuntimeException) + { + ::rtl::OUString sText; + sal_Int32 nStartIndex; + sal_Int32 nEndIndex; + + implGetSelection( nStartIndex, nEndIndex ); + + try + { + sText = getTextRange( nStartIndex, nEndIndex ); + } + catch ( IndexOutOfBoundsException& ) + { + } + + return sText; + } + + // ----------------------------------------------------------------------------- + + sal_Int32 OCommonAccessibleText::getSelectionStart() throw (RuntimeException) + { + sal_Int32 nStartIndex; + sal_Int32 nEndIndex; + + implGetSelection( nStartIndex, nEndIndex ); + + return nStartIndex; + } + + // ----------------------------------------------------------------------------- + + sal_Int32 OCommonAccessibleText::getSelectionEnd() throw (RuntimeException) + { + sal_Int32 nStartIndex; + sal_Int32 nEndIndex; + + implGetSelection( nStartIndex, nEndIndex ); + + return nEndIndex; + } + + // ----------------------------------------------------------------------------- + + ::rtl::OUString OCommonAccessibleText::getText() throw (RuntimeException) + { + return implGetText(); + } + + // ----------------------------------------------------------------------------- + + ::rtl::OUString OCommonAccessibleText::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + ::rtl::OUString sText( implGetText() ); + + if ( !implIsValidRange( nStartIndex, nEndIndex, sText.getLength() ) ) + throw IndexOutOfBoundsException(); + + sal_Int32 nMinIndex = ::std::min( nStartIndex, nEndIndex ); + sal_Int32 nMaxIndex = ::std::max( nStartIndex, nEndIndex ); + + return sText.copy( nMinIndex, nMaxIndex - nMinIndex ); + } + + // ----------------------------------------------------------------------------- + + TextSegment OCommonAccessibleText::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException) + { + ::rtl::OUString sText( implGetText() ); + sal_Int32 nLength = sText.getLength(); + + if ( !implIsValidIndex( nIndex, nLength ) && nIndex != nLength ) + throw IndexOutOfBoundsException(); + + i18n::Boundary aBoundary; + TextSegment aResult; + aResult.SegmentStart = -1; + aResult.SegmentEnd = -1; + + switch ( aTextType ) + { + case AccessibleTextType::CHARACTER: + { + if ( implIsValidIndex( nIndex, nLength ) ) + { + aResult.SegmentText = sText.copy( nIndex, 1 ); + aResult.SegmentStart = nIndex; + aResult.SegmentEnd = nIndex+1; + } + } + break; + case AccessibleTextType::GLYPH: + { + // get glyph at index + implGetGlyphBoundary( aBoundary, nIndex ); + if ( implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + break; + case AccessibleTextType::WORD: + { + // get word at index + sal_Bool bWord = implGetWordBoundary( aBoundary, nIndex ); + if ( bWord && implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + break; + case AccessibleTextType::SENTENCE: + { + // get sentence at index + implGetSentenceBoundary( aBoundary, nIndex ); + if ( implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + break; + case AccessibleTextType::PARAGRAPH: + { + // get paragraph at index + implGetParagraphBoundary( aBoundary, nIndex ); + if ( implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + break; + case AccessibleTextType::LINE: + { + // get line at index + implGetLineBoundary( aBoundary, nIndex ); + if ( implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + break; + case AccessibleTextType::ATTRIBUTE_RUN: + { + // TODO: implGetAttributeRunBoundary() (incompatible!) + + aResult.SegmentText = sText; + aResult.SegmentStart = 0; + aResult.SegmentEnd = nLength; + } + break; + default: + { + // unknown text type + } + } + + return aResult; + } + + // ----------------------------------------------------------------------------- + + TextSegment OCommonAccessibleText::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException) + { + ::rtl::OUString sText( implGetText() ); + sal_Int32 nLength = sText.getLength(); + + if ( !implIsValidIndex( nIndex, nLength ) && nIndex != nLength ) + throw IndexOutOfBoundsException(); + + i18n::Boundary aBoundary; + TextSegment aResult; + aResult.SegmentStart = -1; + aResult.SegmentEnd = -1; + + switch ( aTextType ) + { + case AccessibleTextType::CHARACTER: + { + if ( implIsValidIndex( nIndex - 1, nLength ) ) + { + aResult.SegmentText = sText.copy( nIndex - 1, 1 ); + aResult.SegmentStart = nIndex-1; + aResult.SegmentEnd = nIndex; + } + } + break; + case AccessibleTextType::GLYPH: + { + // get glyph at index + implGetGlyphBoundary( aBoundary, nIndex ); + // get previous glyph + if ( aBoundary.startPos > 0 ) + { + implGetGlyphBoundary( aBoundary, aBoundary.startPos - 1 ); + if ( implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + } + break; + case AccessibleTextType::WORD: + { + // get word at index + implGetWordBoundary( aBoundary, nIndex ); + // get previous word + sal_Bool bWord = sal_False; + while ( !bWord && aBoundary.startPos > 0 ) + bWord = implGetWordBoundary( aBoundary, aBoundary.startPos - 1 ); + if ( bWord && implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + break; + case AccessibleTextType::SENTENCE: + { + // get sentence at index + implGetSentenceBoundary( aBoundary, nIndex ); + // get previous sentence + if ( aBoundary.startPos > 0 ) + { + implGetSentenceBoundary( aBoundary, aBoundary.startPos - 1 ); + if ( implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + } + break; + case AccessibleTextType::PARAGRAPH: + { + // get paragraph at index + implGetParagraphBoundary( aBoundary, nIndex ); + // get previous paragraph + if ( aBoundary.startPos > 0 ) + { + implGetParagraphBoundary( aBoundary, aBoundary.startPos - 1 ); + if ( implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + } + break; + case AccessibleTextType::LINE: + { + // get line at index + implGetLineBoundary( aBoundary, nIndex ); + // get previous line + if ( aBoundary.startPos > 0 ) + { + implGetLineBoundary( aBoundary, aBoundary.startPos - 1 ); + if ( implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + } + break; + case AccessibleTextType::ATTRIBUTE_RUN: + { + // TODO: implGetAttributeRunBoundary() (incompatible!) + } + break; + default: + { + // unknown text type + } + } + + return aResult; + } + + // ----------------------------------------------------------------------------- + + TextSegment OCommonAccessibleText::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException) + { + ::rtl::OUString sText( implGetText() ); + sal_Int32 nLength = sText.getLength(); + + if ( !implIsValidIndex( nIndex, nLength ) && nIndex != nLength ) + throw IndexOutOfBoundsException(); + + i18n::Boundary aBoundary; + TextSegment aResult; + aResult.SegmentStart = -1; + aResult.SegmentEnd = -1; + + switch ( aTextType ) + { + case AccessibleTextType::CHARACTER: + { + if ( implIsValidIndex( nIndex + 1, nLength ) ) + { + aResult.SegmentText = sText.copy( nIndex + 1, 1 ); + aResult.SegmentStart = nIndex+1; + aResult.SegmentEnd = nIndex+2; + } + } + break; + case AccessibleTextType::GLYPH: + { + // get glyph at index + implGetGlyphBoundary( aBoundary, nIndex ); + // get next glyph + if ( aBoundary.endPos < nLength ) + { + implGetGlyphBoundary( aBoundary, aBoundary.endPos ); + if ( implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + } + break; + case AccessibleTextType::WORD: + { + // get word at index + implGetWordBoundary( aBoundary, nIndex ); + // get next word + sal_Bool bWord = sal_False; + while ( !bWord && aBoundary.endPos < nLength ) + bWord = implGetWordBoundary( aBoundary, aBoundary.endPos ); + if ( bWord && implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + break; + case AccessibleTextType::SENTENCE: + { + // get sentence at index + implGetSentenceBoundary( aBoundary, nIndex ); + // get next sentence + sal_Int32 nEnd = aBoundary.endPos; + sal_Int32 nI = aBoundary.endPos; + sal_Bool bFound = sal_False; + while ( !bFound && ++nI < nLength ) + { + implGetSentenceBoundary( aBoundary, nI ); + bFound = ( aBoundary.endPos > nEnd ); + } + if ( bFound && implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + break; + case AccessibleTextType::PARAGRAPH: + { + // get paragraph at index + implGetParagraphBoundary( aBoundary, nIndex ); + // get next paragraph + if ( aBoundary.endPos < nLength ) + { + implGetParagraphBoundary( aBoundary, aBoundary.endPos ); + if ( implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + } + break; + case AccessibleTextType::LINE: + { + // get line at index + implGetLineBoundary( aBoundary, nIndex ); + // get next line + if ( aBoundary.endPos < nLength ) + { + implGetLineBoundary( aBoundary, aBoundary.endPos ); + if ( implIsValidBoundary( aBoundary, nLength ) ) + { + aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); + aResult.SegmentStart = aBoundary.startPos; + aResult.SegmentEnd = aBoundary.endPos; + } + } + } + break; + case AccessibleTextType::ATTRIBUTE_RUN: + { + // TODO: implGetAttributeRunBoundary() (incompatible!) + } + break; + default: + { + // unknown text type + } + } + + return aResult; + } + + // ----------------------------------------------------------------------------- + bool OCommonAccessibleText::implInitTextChangedEvent( + const rtl::OUString& rOldString, + const rtl::OUString& rNewString, + ::com::sun::star::uno::Any& rDeleted, + ::com::sun::star::uno::Any& rInserted) // throw() + { + sal_uInt32 nLenOld = rOldString.getLength(); + sal_uInt32 nLenNew = rNewString.getLength(); + + // equal + if ((0 == nLenOld) && (0 == nLenNew)) + return false; + + TextSegment aDeletedText; + TextSegment aInsertedText; + + aDeletedText.SegmentStart = -1; + aDeletedText.SegmentEnd = -1; + aInsertedText.SegmentStart = -1; + aInsertedText.SegmentEnd = -1; + + // insert only + if ((0 == nLenOld) && (nLenNew > 0)) + { + aInsertedText.SegmentStart = 0; + aInsertedText.SegmentEnd = nLenNew; + aInsertedText.SegmentText = rNewString.copy( aInsertedText.SegmentStart, aInsertedText.SegmentEnd - aInsertedText.SegmentStart ); + + rInserted <<= aInsertedText; + return true; + } + + // delete only + if ((nLenOld > 0) && (0 == nLenNew)) + { + aDeletedText.SegmentStart = 0; + aDeletedText.SegmentEnd = nLenOld; + aDeletedText.SegmentText = rOldString.copy( aDeletedText.SegmentStart, aDeletedText.SegmentEnd - aDeletedText.SegmentStart ); + + rDeleted <<= aDeletedText; + return true; + } + + const sal_Unicode* pFirstDiffOld = rOldString.getStr(); + const sal_Unicode* pLastDiffOld = rOldString.getStr() + nLenOld; + const sal_Unicode* pFirstDiffNew = rNewString.getStr(); + const sal_Unicode* pLastDiffNew = rNewString.getStr() + nLenNew; + + // find first difference + while ((*pFirstDiffOld == *pFirstDiffNew) && + (pFirstDiffOld < pLastDiffOld) && + (pFirstDiffNew < pLastDiffNew)) + { + pFirstDiffOld++; + pFirstDiffNew++; + } + + // equality test + if ((0 == *pFirstDiffOld) && (0 == *pFirstDiffNew)) + return false; + + // find last difference + while ( ( pLastDiffOld > pFirstDiffOld) && + ( pLastDiffNew > pFirstDiffNew) && + (pLastDiffOld[-1] == pLastDiffNew[-1])) + { + pLastDiffOld--; + pLastDiffNew--; + } + + if (pFirstDiffOld < pLastDiffOld) + { + aDeletedText.SegmentStart = pFirstDiffOld - rOldString.getStr(); + aDeletedText.SegmentEnd = pLastDiffOld - rOldString.getStr(); + aDeletedText.SegmentText = rOldString.copy( aDeletedText.SegmentStart, aDeletedText.SegmentEnd - aDeletedText.SegmentStart ); + + rDeleted <<= aDeletedText; + } + + if (pFirstDiffNew < pLastDiffNew) + { + aInsertedText.SegmentStart = pFirstDiffNew - rNewString.getStr(); + aInsertedText.SegmentEnd = pLastDiffNew - rNewString.getStr(); + aInsertedText.SegmentText = rNewString.copy( aInsertedText.SegmentStart, aInsertedText.SegmentEnd - aInsertedText.SegmentStart ); + + rInserted <<= aInsertedText; + } + return true; + } + + //============================================================================== + // OAccessibleTextHelper + //============================================================================== + + OAccessibleTextHelper::OAccessibleTextHelper() + { + } + + // ----------------------------------------------------------------------------- + + OAccessibleTextHelper::OAccessibleTextHelper( IMutex* _pExternalLock ) + :OAccessibleExtendedComponentHelper( _pExternalLock ) + { + } + + // ----------------------------------------------------------------------------- + // XInterface + // ----------------------------------------------------------------------------- + + IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleTextHelper, OAccessibleExtendedComponentHelper, OAccessibleTextHelper_Base ) + + // ----------------------------------------------------------------------------- + // XTypeProvider + // ----------------------------------------------------------------------------- + + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleTextHelper, OAccessibleExtendedComponentHelper, OAccessibleTextHelper_Base ) + + // ----------------------------------------------------------------------------- + // XAccessibleText + // ----------------------------------------------------------------------------- + + sal_Unicode OAccessibleTextHelper::getCharacter( sal_Int32 nIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + OExternalLockGuard aGuard( this ); + + return OCommonAccessibleText::getCharacter( nIndex ); + } + + // ----------------------------------------------------------------------------- + + sal_Int32 OAccessibleTextHelper::getCharacterCount() throw (RuntimeException) + { + OExternalLockGuard aGuard( this ); + + return OCommonAccessibleText::getCharacterCount(); + } + + // ----------------------------------------------------------------------------- + + ::rtl::OUString OAccessibleTextHelper::getSelectedText() throw (RuntimeException) + { + OExternalLockGuard aGuard( this ); + + return OCommonAccessibleText::getSelectedText(); + } + + // ----------------------------------------------------------------------------- + + sal_Int32 OAccessibleTextHelper::getSelectionStart() throw (RuntimeException) + { + OExternalLockGuard aGuard( this ); + + return OCommonAccessibleText::getSelectionStart(); + } + + // ----------------------------------------------------------------------------- + + sal_Int32 OAccessibleTextHelper::getSelectionEnd() throw (RuntimeException) + { + OExternalLockGuard aGuard( this ); + + return OCommonAccessibleText::getSelectionEnd(); + } + + // ----------------------------------------------------------------------------- + + ::rtl::OUString OAccessibleTextHelper::getText() throw (RuntimeException) + { + OExternalLockGuard aGuard( this ); + + return OCommonAccessibleText::getText(); + } + + // ----------------------------------------------------------------------------- + + ::rtl::OUString OAccessibleTextHelper::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + OExternalLockGuard aGuard( this ); + + return OCommonAccessibleText::getTextRange( nStartIndex, nEndIndex ); + } + + // ----------------------------------------------------------------------------- + + TextSegment OAccessibleTextHelper::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException) + { + OExternalLockGuard aGuard( this ); + + return OCommonAccessibleText::getTextAtIndex( nIndex, aTextType ); + } + + // ----------------------------------------------------------------------------- + + TextSegment OAccessibleTextHelper::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException) + { + OExternalLockGuard aGuard( this ); + + return OCommonAccessibleText::getTextBeforeIndex( nIndex, aTextType ); + } + + // ----------------------------------------------------------------------------- + + TextSegment OAccessibleTextHelper::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException) + { + OExternalLockGuard aGuard( this ); + + return OCommonAccessibleText::getTextBehindIndex( nIndex, aTextType ); + } + + // ----------------------------------------------------------------------------- + +//.............................................................................. +} // namespace comphelper +//.............................................................................. diff --git a/comphelper/source/misc/accessiblewrapper.cxx b/comphelper/source/misc/accessiblewrapper.cxx new file mode 100644 index 000000000000..0ed694856b97 --- /dev/null +++ b/comphelper/source/misc/accessiblewrapper.cxx @@ -0,0 +1,683 @@ +/************************************************************************* + * + * 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/accessiblewrapper.hxx" +#include <com/sun/star/reflection/XProxyFactory.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> + +#include <algorithm> + +using namespace ::comphelper; +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +//............................................................................. +namespace comphelper +{ +//............................................................................. + + //========================================================================= + //= OWrappedAccessibleChildrenManager + //========================================================================= + //-------------------------------------------------------------------- + struct RemoveEventListener + : public ::std::unary_function< AccessibleMap::value_type, void > + { + private: + Reference< XEventListener > m_xListener; + + public: + RemoveEventListener( const Reference< XEventListener >& _rxListener ) + :m_xListener( _rxListener ) + { + } + + void operator()( const AccessibleMap::value_type& _rMapEntry ) const + { + Reference< XComponent > xComp( _rMapEntry.first, UNO_QUERY ); + if ( xComp.is() ) + xComp->removeEventListener( m_xListener ); + } + }; + + //-------------------------------------------------------------------- + struct DisposeMappedChild + : public ::std::unary_function< AccessibleMap::value_type, void > + { + void operator()( const AccessibleMap::value_type& _rMapEntry ) const + { + Reference< XComponent > xContextComponent; + if ( _rMapEntry.second.is() ) + xContextComponent = xContextComponent.query( _rMapEntry.second->getAccessibleContext() ); + if ( xContextComponent.is() ) + xContextComponent->dispose(); + } + }; + + //------------------------------------------------------------------------- + OWrappedAccessibleChildrenManager::OWrappedAccessibleChildrenManager( const Reference< XMultiServiceFactory >& _rxORB ) + :m_xORB( _rxORB ) + ,m_bTransientChildren( sal_True ) + { + } + + //------------------------------------------------------------------------- + OWrappedAccessibleChildrenManager::~OWrappedAccessibleChildrenManager( ) + { + } + + //------------------------------------------------------------------------- + void OWrappedAccessibleChildrenManager::setTransientChildren( sal_Bool _bSet ) + { + m_bTransientChildren = _bSet; + } + + //------------------------------------------------------------------------- + void OWrappedAccessibleChildrenManager::setOwningAccessible( const Reference< XAccessible >& _rxAcc ) + { + OSL_ENSURE( !m_aOwningAccessible.get().is(), "OWrappedAccessibleChildrenManager::setOwningAccessible: to be called only once!" ); + m_aOwningAccessible = WeakReference< XAccessible >( _rxAcc ); + } + + //------------------------------------------------------------------------- + void OWrappedAccessibleChildrenManager::removeFromCache( const Reference< XAccessible >& _rxKey ) + { + AccessibleMap::iterator aRemovedPos = m_aChildrenMap.find( _rxKey ); + if ( m_aChildrenMap.end() != aRemovedPos ) + { // it was cached + // remove ourself as event listener + RemoveEventListener aOperator( this ); + aOperator( *aRemovedPos ); + // and remove the entry from the map + m_aChildrenMap.erase( aRemovedPos ); + } + } + + //------------------------------------------------------------------------- + void OWrappedAccessibleChildrenManager::invalidateAll( ) + { + // remove as event listener from the map elements + ::std::for_each( m_aChildrenMap.begin(), m_aChildrenMap.end(), RemoveEventListener( this ) ); + // clear the map + AccessibleMap aMap; + m_aChildrenMap.swap( aMap ); + } + + //------------------------------------------------------------------------- + Reference< XAccessible > OWrappedAccessibleChildrenManager::getAccessibleWrapperFor( + const Reference< XAccessible >& _rxKey, sal_Bool _bCreate ) + { + Reference< XAccessible > xValue; + + if( !_rxKey.is() ) + { + // fprintf( stderr, "It was this path that was crashing stuff\n" ); + return xValue; + } + + // do we have this child in the cahce? + AccessibleMap::const_iterator aPos = m_aChildrenMap.find( _rxKey ); + if ( m_aChildrenMap.end() != aPos ) + { + xValue = aPos->second; + } + else if ( _bCreate ) + { // not found in the cache, and allowed to create + // -> new wrapper + xValue = new OAccessibleWrapper( m_xORB, _rxKey, (Reference< XAccessible >)m_aOwningAccessible ); + + // see if we do cache children + if ( !m_bTransientChildren ) + { + if (!m_aChildrenMap.insert( + AccessibleMap::value_type( _rxKey, xValue ) ).second) + { + OSL_ENSURE( + false, + "OWrappedAccessibleChildrenManager::" + "getAccessibleWrapperFor: element was already" + " inserted!" ); + } + + // listen for disposals of inner children - this may happen when the inner context + // is the owner for the inner children (it will dispose these children, and of course + // not our wrapper for these children) + Reference< XComponent > xComp( _rxKey, UNO_QUERY ); + if ( xComp.is() ) + xComp->addEventListener( this ); + } + } + + return xValue; + } + + //------------------------------------------------------------------------- + void OWrappedAccessibleChildrenManager::dispose() + { + // dispose our children + ::std::for_each( m_aChildrenMap.begin(), m_aChildrenMap.end(), RemoveEventListener( this ) ); + ::std::for_each( m_aChildrenMap.begin(), m_aChildrenMap.end(), DisposeMappedChild( ) ); + // clear our children + AccessibleMap aMap; + m_aChildrenMap.swap( aMap ); + } + + //-------------------------------------------------------------------- + void OWrappedAccessibleChildrenManager::implTranslateChildEventValue( const Any& _rInValue, Any& _rOutValue ) + { + _rOutValue.clear(); + Reference< XAccessible > xChild; + if ( _rInValue >>= xChild ) + _rOutValue <<= getAccessibleWrapperFor( xChild, sal_True ); + } + + //------------------------------------------------------------------------- + void OWrappedAccessibleChildrenManager::translateAccessibleEvent( const AccessibleEventObject& _rEvent, AccessibleEventObject& _rTranslatedEvent ) + { + // just in case we can't translate some of the values: + _rTranslatedEvent.NewValue = _rEvent.NewValue; + _rTranslatedEvent.OldValue = _rEvent.OldValue; + + switch ( _rEvent.EventId ) + { + case AccessibleEventId::CHILD: + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED: + case AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED: + case AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED: + case AccessibleEventId::LABEL_FOR_RELATION_CHANGED: + case AccessibleEventId::LABELED_BY_RELATION_CHANGED: + case AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED: + case AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED: + // these are events where both the old and the new value contain child references + implTranslateChildEventValue( _rEvent.OldValue, _rTranslatedEvent.OldValue ); + implTranslateChildEventValue( _rEvent.NewValue, _rTranslatedEvent.NewValue ); + break; + + case AccessibleEventId::NAME_CHANGED: + case AccessibleEventId::DESCRIPTION_CHANGED: + case AccessibleEventId::ACTION_CHANGED: + case AccessibleEventId::STATE_CHANGED: + case AccessibleEventId::BOUNDRECT_CHANGED: + case AccessibleEventId::INVALIDATE_ALL_CHILDREN: + case AccessibleEventId::SELECTION_CHANGED: + case AccessibleEventId::VISIBLE_DATA_CHANGED: + case AccessibleEventId::VALUE_CHANGED: + case AccessibleEventId::MEMBER_OF_RELATION_CHANGED: + case AccessibleEventId::CARET_CHANGED: + case AccessibleEventId::TEXT_CHANGED: + case AccessibleEventId::HYPERTEXT_CHANGED: + case AccessibleEventId::TABLE_CAPTION_CHANGED: + case AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED: + case AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED: + case AccessibleEventId::TABLE_MODEL_CHANGED: + case AccessibleEventId::TABLE_ROW_DESCRIPTION_CHANGED: + case AccessibleEventId::TABLE_ROW_HEADER_CHANGED: + case AccessibleEventId::TABLE_SUMMARY_CHANGED: + // --> PB 2006-03-21 #130798# EventId TEXT_SELECTION_CHANGED was missed + // these Ids are also missed: SUB_WINDOW_OF_RELATION_CHANGED & TEXT_ATTRIBUTE_CHANGED + case AccessibleEventId::TEXT_SELECTION_CHANGED: + // <-- + // nothing to translate + break; + + default: + OSL_ENSURE( sal_False, "OWrappedAccessibleChildrenManager::translateAccessibleEvent: unknown (or unexpected) event id!" ); + break; + } + } + + //------------------------------------------------------------------------- + void OWrappedAccessibleChildrenManager::handleChildNotification( const AccessibleEventObject& _rEvent ) + { + if ( AccessibleEventId::INVALIDATE_ALL_CHILDREN == _rEvent.EventId ) + { // clear our child map + invalidateAll( ); + } + else if ( AccessibleEventId::CHILD == _rEvent.EventId ) + { + // check if the removed or replaced element is cached + Reference< XAccessible > xRemoved; + if ( _rEvent.OldValue >>= xRemoved ) + removeFromCache( xRemoved ); + } + } + + //-------------------------------------------------------------------- + void SAL_CALL OWrappedAccessibleChildrenManager::disposing( const EventObject& _rSource ) throw (RuntimeException) + { + // this should come from one of the inner XAccessible's of our children + Reference< XAccessible > xSource( _rSource.Source, UNO_QUERY ); + AccessibleMap::iterator aDisposedPos = m_aChildrenMap.find( xSource ); +#if OSL_DEBUG_LEVEL > 0 + if ( m_aChildrenMap.end() == aDisposedPos ) + { + OSL_ENSURE( sal_False, + "OWrappedAccessibleChildrenManager::disposing: where did this come from?" ); + // helper for dignostics + Reference< XAccessible > xOwningAccessible( m_aOwningAccessible ); + Reference< XAccessibleContext > xContext; + try + { + if ( xOwningAccessible.is() ) + xContext = xOwningAccessible->getAccessibleContext(); + if ( xContext.is() ) + { + ::rtl::OUString sName = xContext->getAccessibleName(); + ::rtl::OUString sDescription = xContext->getAccessibleDescription(); +// sal_Int32 nPlaceYourBreakpointHere = 0; + } + } + catch( const Exception& /*e*/ ) + { + // silent this, it's only diagnostics which failed + } + } +#endif + if ( m_aChildrenMap.end() != aDisposedPos ) + { + m_aChildrenMap.erase( aDisposedPos ); + } + } + + //========================================================================= + //= OAccessibleWrapper (implementation) + //========================================================================= + //------------------------------------------------------------------------- + OAccessibleWrapper::OAccessibleWrapper( const Reference< XMultiServiceFactory >& _rxORB, + const Reference< XAccessible >& _rxInnerAccessible, const Reference< XAccessible >& _rxParentAccessible ) + :OAccessibleWrapper_Base( ) + ,OComponentProxyAggregation( _rxORB, Reference< XComponent >( _rxInnerAccessible, UNO_QUERY ) ) + ,m_xParentAccessible( _rxParentAccessible ) + ,m_xInnerAccessible( _rxInnerAccessible ) + { + } + + //-------------------------------------------------------------------- + OAccessibleWrapper::~OAccessibleWrapper( ) + { + if ( !m_rBHelper.bDisposed ) + { + acquire(); // to prevent duplicate dtor calls + dispose(); + } + } + + //-------------------------------------------------------------------- + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleWrapper, OComponentProxyAggregation, OAccessibleWrapper_Base ) + IMPLEMENT_FORWARD_REFCOUNT( OAccessibleWrapper, OComponentProxyAggregation ) + + //-------------------------------------------------------------------- + Any OAccessibleWrapper::queryInterface( const Type& _rType ) throw (RuntimeException) + { + // #111089# instead of the inner XAccessible the proxy XAccessible must be returned + Any aReturn = OAccessibleWrapper_Base::queryInterface( _rType ); + if ( !aReturn.hasValue() ) + aReturn = OComponentProxyAggregation::queryInterface( _rType ); + + return aReturn; + } + + //-------------------------------------------------------------------- + Reference< XAccessibleContext > OAccessibleWrapper::getContextNoCreate( ) const + { + return (Reference< XAccessibleContext >)m_aContext; + } + + //-------------------------------------------------------------------- + OAccessibleContextWrapper* OAccessibleWrapper::createAccessibleContext( const Reference< XAccessibleContext >& _rxInnerContext ) + { + return new OAccessibleContextWrapper( getORB(), _rxInnerContext, this, m_xParentAccessible ); + } + + //-------------------------------------------------------------------- + Reference< XAccessibleContext > SAL_CALL OAccessibleWrapper::getAccessibleContext( ) throw (RuntimeException) + { + // see if the context is still alive (we cache it) + Reference< XAccessibleContext > xContext = (Reference< XAccessibleContext >)m_aContext; + if ( !xContext.is() ) + { + // create a new context + Reference< XAccessibleContext > xInnerContext = m_xInnerAccessible->getAccessibleContext( ); + if ( xInnerContext.is() ) + { + xContext = createAccessibleContext( xInnerContext ); + // cache it + m_aContext = WeakReference< XAccessibleContext >( xContext ); + } + } + + return xContext; + } + + //========================================================================= + //= OAccessibleWrapper (implementation) + //========================================================================= + //------------------------------------------------------------------------- + OAccessibleContextWrapperHelper::OAccessibleContextWrapperHelper( + const Reference< XMultiServiceFactory >& _rxORB, + ::cppu::OBroadcastHelper& _rBHelper, + const Reference< XAccessibleContext >& _rxInnerAccessibleContext, + const Reference< XAccessible >& _rxOwningAccessible, + const Reference< XAccessible >& _rxParentAccessible ) + :OComponentProxyAggregationHelper( _rxORB, _rBHelper ) + ,m_xInnerContext( _rxInnerAccessibleContext ) + ,m_xOwningAccessible( _rxOwningAccessible ) + ,m_xParentAccessible( _rxParentAccessible ) + ,m_pChildMapper( NULL ) + { + // initialize the mapper for our children + m_pChildMapper = new OWrappedAccessibleChildrenManager( getORB() ); + m_pChildMapper->acquire(); + + // determine if we're allowed to cache children + Reference< XAccessibleStateSet > xStates( m_xInnerContext->getAccessibleStateSet( ) ); + OSL_ENSURE( xStates.is(), "OAccessibleContextWrapperHelper::OAccessibleContextWrapperHelper: no inner state set!" ); + m_pChildMapper->setTransientChildren( !xStates.is() || xStates->contains( AccessibleStateType::MANAGES_DESCENDANTS) ); + + m_pChildMapper->setOwningAccessible( m_xOwningAccessible ); + } + + //-------------------------------------------------------------------- + void OAccessibleContextWrapperHelper::aggregateProxy( oslInterlockedCount& _rRefCount, ::cppu::OWeakObject& _rDelegator ) + { + Reference< XComponent > xInnerComponent( m_xInnerContext, UNO_QUERY ); + OSL_ENSURE( xInnerComponent.is(), "OComponentProxyAggregation::aggregateProxy: accessible is no XComponent!" ); + if ( xInnerComponent.is() ) + componentAggregateProxyFor( xInnerComponent, _rRefCount, _rDelegator ); + + // add as event listener to the inner context, because we want to multiplex the AccessibleEvents + osl_incrementInterlockedCount( &_rRefCount ); + { + Reference< XAccessibleEventBroadcaster > xBroadcaster( m_xInner, UNO_QUERY ); + if ( xBroadcaster.is() ) + xBroadcaster->addEventListener( this ); + } + osl_decrementInterlockedCount( &_rRefCount ); + } + + //-------------------------------------------------------------------- + OAccessibleContextWrapperHelper::~OAccessibleContextWrapperHelper( ) + { + OSL_ENSURE( m_rBHelper.bDisposed, "OAccessibleContextWrapperHelper::~OAccessibleContextWrapperHelper: you should ensure (in your dtor) that the object is disposed!" ); + + m_pChildMapper->release(); + m_pChildMapper = NULL; + } + + //-------------------------------------------------------------------- + Any SAL_CALL OAccessibleContextWrapperHelper::queryInterface( const Type& _rType ) throw (RuntimeException) + { + Any aReturn = OComponentProxyAggregationHelper::queryInterface( _rType ); + if ( !aReturn.hasValue() ) + aReturn = OAccessibleContextWrapperHelper_Base::queryInterface( _rType ); + return aReturn; + } + + //-------------------------------------------------------------------- + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleContextWrapperHelper, OComponentProxyAggregationHelper, OAccessibleContextWrapperHelper_Base ) + + //-------------------------------------------------------------------- + sal_Int32 SAL_CALL OAccessibleContextWrapperHelper::getAccessibleChildCount( ) throw (RuntimeException) + { + return m_xInnerContext->getAccessibleChildCount(); + } + + //-------------------------------------------------------------------- + Reference< XAccessible > SAL_CALL OAccessibleContextWrapperHelper::getAccessibleChild( sal_Int32 i ) throw (IndexOutOfBoundsException, RuntimeException) + { + // get the child of the wrapped component + Reference< XAccessible > xInnerChild = m_xInnerContext->getAccessibleChild( i ); + return m_pChildMapper->getAccessibleWrapperFor( xInnerChild ); + } + + //-------------------------------------------------------------------- + Reference< XAccessibleRelationSet > SAL_CALL OAccessibleContextWrapperHelper::getAccessibleRelationSet( ) throw (RuntimeException) + { + return m_xInnerContext->getAccessibleRelationSet(); + // TODO: if this relation set would contain relations to siblings, we would normally need + // to wrap them, too .... + } + + //-------------------------------------------------------------------- + void SAL_CALL OAccessibleContextWrapperHelper::notifyEvent( const AccessibleEventObject& _rEvent ) throw (RuntimeException) + { +#if OSL_DEBUG_LEVEL > 0 + if ( AccessibleEventId::STATE_CHANGED == _rEvent.EventId ) + { + sal_Bool bChildTransienceChanged = sal_False; + sal_Int16 nChangeState = 0; + if ( _rEvent.OldValue >>= nChangeState ) + bChildTransienceChanged = bChildTransienceChanged || AccessibleStateType::MANAGES_DESCENDANTS == nChangeState; + if ( _rEvent.NewValue >>= nChangeState ) + bChildTransienceChanged = bChildTransienceChanged || AccessibleStateType::MANAGES_DESCENDANTS == nChangeState; + OSL_ENSURE( !bChildTransienceChanged, "OAccessibleContextWrapperHelper::notifyEvent: MANAGES_DESCENDANTS is not expected to change during runtime!" ); + // if this asserts, then we would need to update our m_bTransientChildren flag here, + // as well as (potentially) our child cache + } +#endif + AccessibleEventObject aTranslatedEvent( _rEvent ); + + { + ::osl::MutexGuard aGuard( m_rBHelper.rMutex ); + + // translate the event + queryInterface( ::getCppuType( static_cast< Reference< XInterface >* >( NULL ) ) ) >>= aTranslatedEvent.Source; + m_pChildMapper->translateAccessibleEvent( _rEvent, aTranslatedEvent ); + + // see if any of these notifications affect our child manager + m_pChildMapper->handleChildNotification( _rEvent ); + + if ( aTranslatedEvent.NewValue == m_xInner ) + aTranslatedEvent.NewValue = makeAny(aTranslatedEvent.Source); + if ( aTranslatedEvent.OldValue == m_xInner ) + aTranslatedEvent.OldValue = makeAny(aTranslatedEvent.Source); + } + + notifyTranslatedEvent( aTranslatedEvent ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OAccessibleContextWrapperHelper::dispose() throw( RuntimeException ) + { + ::osl::MutexGuard aGuard( m_rBHelper.rMutex ); + + // stop multiplexing events + Reference< XAccessibleEventBroadcaster > xBroadcaster( m_xInner, UNO_QUERY ); + OSL_ENSURE( xBroadcaster.is(), "OAccessibleContextWrapperHelper::disposing(): inner context is no broadcaster!" ); + if ( xBroadcaster.is() ) + xBroadcaster->removeEventListener( this ); + + // dispose the child cache/map + m_pChildMapper->dispose(); + + // let the base class dispose the inner component + OComponentProxyAggregationHelper::dispose(); + } + + //-------------------------------------------------------------------- + void SAL_CALL OAccessibleContextWrapperHelper::disposing( const EventObject& _rEvent ) throw (RuntimeException) + { + // simply disambiguate this + OComponentProxyAggregationHelper::disposing( _rEvent ); + } + + //==================================================================== + //= OAccessibleContextWrapper + //==================================================================== + //-------------------------------------------------------------------- + IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleContextWrapper, OAccessibleContextWrapper_CBase, OAccessibleContextWrapperHelper ) + + //-------------------------------------------------------------------- + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleContextWrapper, OAccessibleContextWrapper_CBase, OAccessibleContextWrapperHelper ) + + //-------------------------------------------------------------------- + OAccessibleContextWrapper::OAccessibleContextWrapper( const Reference< XMultiServiceFactory >& _rxORB, + const Reference< XAccessibleContext >& _rxInnerAccessibleContext, const Reference< XAccessible >& _rxOwningAccessible, + const Reference< XAccessible >& _rxParentAccessible ) + :OAccessibleContextWrapper_CBase( m_aMutex ) + ,OAccessibleContextWrapperHelper( _rxORB, rBHelper, _rxInnerAccessibleContext, _rxOwningAccessible, _rxParentAccessible ) + ,m_nNotifierClient( 0 ) + { + aggregateProxy( m_refCount, *this ); + } + + //-------------------------------------------------------------------- + OAccessibleContextWrapper::~OAccessibleContextWrapper() + { + } + + //-------------------------------------------------------------------- + sal_Int32 SAL_CALL OAccessibleContextWrapper::getAccessibleChildCount( ) throw (RuntimeException) + { + return OAccessibleContextWrapperHelper::getAccessibleChildCount(); + } + + //-------------------------------------------------------------------- + Reference< XAccessible > SAL_CALL OAccessibleContextWrapper::getAccessibleChild( sal_Int32 i ) throw (IndexOutOfBoundsException, RuntimeException) + { + return OAccessibleContextWrapperHelper::getAccessibleChild( i ); + } + + //-------------------------------------------------------------------- + Reference< XAccessible > SAL_CALL OAccessibleContextWrapper::getAccessibleParent( ) throw (RuntimeException) + { + return m_xParentAccessible; + } + + //-------------------------------------------------------------------- + sal_Int32 SAL_CALL OAccessibleContextWrapper::getAccessibleIndexInParent( ) throw (RuntimeException) + { + return m_xInnerContext->getAccessibleIndexInParent(); + } + + //-------------------------------------------------------------------- + sal_Int16 SAL_CALL OAccessibleContextWrapper::getAccessibleRole( ) throw (RuntimeException) + { + return m_xInnerContext->getAccessibleRole(); + } + + //-------------------------------------------------------------------- + ::rtl::OUString SAL_CALL OAccessibleContextWrapper::getAccessibleDescription( ) throw (RuntimeException) + { + return m_xInnerContext->getAccessibleDescription(); + } + + //-------------------------------------------------------------------- + ::rtl::OUString SAL_CALL OAccessibleContextWrapper::getAccessibleName( ) throw (RuntimeException) + { + return m_xInnerContext->getAccessibleName(); + } + + //-------------------------------------------------------------------- + Reference< XAccessibleRelationSet > SAL_CALL OAccessibleContextWrapper::getAccessibleRelationSet( ) throw (RuntimeException) + { + return OAccessibleContextWrapperHelper::getAccessibleRelationSet(); + } + + //-------------------------------------------------------------------- + Reference< XAccessibleStateSet > SAL_CALL OAccessibleContextWrapper::getAccessibleStateSet( ) throw (RuntimeException) + { + return m_xInnerContext->getAccessibleStateSet(); + } + + //-------------------------------------------------------------------- + Locale SAL_CALL OAccessibleContextWrapper::getLocale( ) throw (IllegalAccessibleComponentStateException, RuntimeException) + { + return m_xInnerContext->getLocale(); + } + + //-------------------------------------------------------------------- + void OAccessibleContextWrapper::notifyTranslatedEvent( const AccessibleEventObject& _rEvent ) throw (RuntimeException) + { + if ( m_nNotifierClient ) + AccessibleEventNotifier::addEvent( m_nNotifierClient, _rEvent ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OAccessibleContextWrapper::addEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_nNotifierClient ) + m_nNotifierClient = AccessibleEventNotifier::registerClient( ); + AccessibleEventNotifier::addEventListener( m_nNotifierClient, _rxListener ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OAccessibleContextWrapper::removeEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_nNotifierClient ) + { + if ( 0 == AccessibleEventNotifier::removeEventListener( m_nNotifierClient, _rxListener ) ) + { + AccessibleEventNotifier::TClientId nId( m_nNotifierClient ); + m_nNotifierClient = 0; + AccessibleEventNotifier::revokeClient( nId ); + } + } + } + + //-------------------------------------------------------------------- + void SAL_CALL OAccessibleContextWrapper::disposing() throw (RuntimeException) + { + AccessibleEventNotifier::TClientId nClientId( 0 ); + + // --- <mutex lock> ----------------------------------------- + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // prepare notifying our AccessibleListeners + if ( m_nNotifierClient ) + { + nClientId = m_nNotifierClient; + m_nNotifierClient = 0; + } + } + // --- </mutex lock> ----------------------------------------- + + // let the base class do + OAccessibleContextWrapperHelper::dispose(); + + // notify the disposal + if ( nClientId ) + AccessibleEventNotifier::revokeClientNotifyDisposing( nClientId, *this ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OAccessibleContextWrapper::dispose() throw( RuntimeException ) + { + // simply disambiguate + OComponentProxyAggregation_CBase::dispose(); + } + +//............................................................................. +} // namespace accessibility +//............................................................................. diff --git a/comphelper/source/misc/accimplaccess.cxx b/comphelper/source/misc/accimplaccess.cxx new file mode 100644 index 000000000000..e792b9fe43c1 --- /dev/null +++ b/comphelper/source/misc/accimplaccess.cxx @@ -0,0 +1,189 @@ +/************************************************************************* + * + * 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/accimplaccess.hxx> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <cppuhelper/typeprovider.hxx> + +#include <set> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + +#define BITFIELDSIZE ( sizeof( sal_Int64 ) * 8 ) + // maximum number of bits we have in a sal_Int64 + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::lang::XUnoTunnel; + using ::com::sun::star::accessibility::XAccessible; + using ::com::sun::star::accessibility::XAccessibleContext; + + //===================================================================== + //= OAccImpl_Impl + //===================================================================== + struct OAccImpl_Impl + { + Reference< XAccessible > m_xAccParent; + sal_Int64 m_nForeignControlledStates; + }; + + + //===================================================================== + //= OAccessibleImplementationAccess + //===================================================================== + //--------------------------------------------------------------------- + OAccessibleImplementationAccess::OAccessibleImplementationAccess( ) + :m_pImpl( new OAccImpl_Impl ) + { + } + + //--------------------------------------------------------------------- + OAccessibleImplementationAccess::~OAccessibleImplementationAccess( ) + { + delete m_pImpl; + m_pImpl = NULL; + } + + //--------------------------------------------------------------------- + Reference< XAccessible > OAccessibleImplementationAccess::implGetForeignControlledParent( ) const + { + return m_pImpl->m_xAccParent; + } + + //--------------------------------------------------------------------- + void OAccessibleImplementationAccess::setAccessibleParent( const Reference< XAccessible >& _rxAccParent ) + { + m_pImpl->m_xAccParent = _rxAccParent; + } + + //--------------------------------------------------------------------- + sal_Int64 OAccessibleImplementationAccess::implGetForeignControlledStates( ) const + { + return m_pImpl->m_nForeignControlledStates; + } + + //--------------------------------------------------------------------- + void OAccessibleImplementationAccess::setStateBit( const sal_Int16 _nState, const sal_Bool _bSet ) + { + OSL_ENSURE( _nState >= 0 && static_cast< sal_uInt16 >(_nState) < BITFIELDSIZE, "OAccessibleImplementationAccess::setStateBit: no more bits (shutting down the universe now)!" ); + + sal_uInt64 nBitMask( 1 ); + nBitMask <<= _nState; + if ( _bSet ) + m_pImpl->m_nForeignControlledStates |= nBitMask; + else + m_pImpl->m_nForeignControlledStates &= ~nBitMask; + } + + //--------------------------------------------------------------------- + sal_Bool OAccessibleImplementationAccess::setForeignControlledState( const Reference< XAccessibleContext >& _rxComponent, const sal_Int16 _nState, + const sal_Bool _bSet ) + { + OAccessibleImplementationAccess* pImplementation = getImplementation( _rxComponent ); + + if ( pImplementation ) + pImplementation->setStateBit( _nState, _bSet ); + + return ( NULL != pImplementation ); + } + + //--------------------------------------------------------------------- + const Sequence< sal_Int8 >& OAccessibleImplementationAccess::getUnoTunnelImplementationId() + { + static Sequence< sal_Int8 > aId; + if ( !aId.getLength() ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if ( !aId.getLength() ) + { + static ::cppu::OImplementationId aImplId; + // unfortunately, the OImplementationId::getImplementationId returns a copy, not a static reference ... + aId = aImplId.getImplementationId(); + } + } + return aId; + } + + //--------------------------------------------------------------------- + sal_Int64 SAL_CALL OAccessibleImplementationAccess::getSomething( const Sequence< sal_Int8 >& _rIdentifier ) throw (RuntimeException) + { + sal_Int64 nReturn( 0 ); + + if ( ( _rIdentifier.getLength() == 16 ) + && ( 0 == rtl_compareMemory( getUnoTunnelImplementationId().getConstArray(), _rIdentifier.getConstArray(), 16 ) ) + ) + nReturn = reinterpret_cast< sal_Int64 >( this ); + + return nReturn; + } + + //--------------------------------------------------------------------- + OAccessibleImplementationAccess* OAccessibleImplementationAccess::getImplementation( const Reference< XAccessibleContext >& _rxComponent ) + { + OAccessibleImplementationAccess* pImplementation = NULL; + try + { + Reference< XUnoTunnel > xTunnel( _rxComponent, UNO_QUERY ); + if ( xTunnel.is() ) + { + pImplementation = reinterpret_cast< OAccessibleImplementationAccess* >( + xTunnel->getSomething( getUnoTunnelImplementationId() ) ); + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "OAccessibleImplementationAccess::setAccessibleParent: caught an exception while retrieving the implementation!" ); + } + return pImplementation; + } + + //--------------------------------------------------------------------- + sal_Bool OAccessibleImplementationAccess::setAccessibleParent( + const Reference< XAccessibleContext >& _rxComponent, const Reference< XAccessible >& _rxNewParent ) + { + OAccessibleImplementationAccess* pImplementation = getImplementation( _rxComponent ); + + if ( pImplementation ) + pImplementation->setAccessibleParent( _rxNewParent ); + + return ( NULL != pImplementation ); + } + +//......................................................................... +} // namespace comphelper +//......................................................................... + + diff --git a/comphelper/source/misc/anytostring.cxx b/comphelper/source/misc/anytostring.cxx new file mode 100644 index 000000000000..01f282172f18 --- /dev/null +++ b/comphelper/source/misc/anytostring.cxx @@ -0,0 +1,335 @@ +/************************************************************************* + * + * 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/anytostring.hxx" +#include "osl/diagnose.h" +#include "rtl/ustrbuf.hxx" +#include "typelib/typedescription.h" +#include "com/sun/star/lang/XServiceInfo.hpp" + +using namespace ::com::sun::star; + +namespace comphelper { +namespace { + +void appendTypeError( + rtl::OUStringBuffer & buf, typelib_TypeDescriptionReference * typeRef ) +{ + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("<cannot get type description of type ") ); + buf.append( rtl::OUString::unacquired( &typeRef->pTypeName ) ); + buf.append( static_cast< sal_Unicode >('>') ); +} + +inline void appendChar( rtl::OUStringBuffer & buf, sal_Unicode c ) +{ + if (c < ' ' || c > '~') { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\\X") ); + rtl::OUString const s( + rtl::OUString::valueOf( static_cast< sal_Int32 >(c), 16 ) ); + for ( sal_Int32 f = 4 - s.getLength(); f > 0; --f ) + buf.append( static_cast< sal_Unicode >('0') ); + buf.append( s ); + } + else { + buf.append( c ); + } +} + +//------------------------------------------------------------------------------ +void appendValue( rtl::OUStringBuffer & buf, + void const * val, typelib_TypeDescriptionReference * typeRef, + bool prependType ) +{ + if (typeRef->eTypeClass == typelib_TypeClass_VOID) { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("void") ); + return; + } + OSL_ASSERT( val != 0 ); + + if (prependType && + typeRef->eTypeClass != typelib_TypeClass_STRING && + typeRef->eTypeClass != typelib_TypeClass_CHAR && + typeRef->eTypeClass != typelib_TypeClass_BOOLEAN) + { + buf.append( static_cast< sal_Unicode >('(') ); + buf.append( rtl::OUString::unacquired( &typeRef->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(") ") ); + } + + switch (typeRef->eTypeClass) { + case typelib_TypeClass_INTERFACE: { + buf.append( static_cast<sal_Unicode>('@') ); + buf.append( reinterpret_cast< sal_Int64 >( + *static_cast< void * const * >(val) ), 16 ); + uno::Reference< lang::XServiceInfo > xServiceInfo( + *static_cast< uno::XInterface * const * >(val), + uno::UNO_QUERY ); + if (xServiceInfo.is()) { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( + " (ImplementationName = \"") ); + buf.append( xServiceInfo->getImplementationName() ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\")") ); + } + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") ); + typelib_TypeDescription * typeDescr = 0; + typelib_typedescriptionreference_getDescription( &typeDescr, typeRef ); + if (typeDescr == 0 || !typelib_typedescription_complete( &typeDescr )) { + appendTypeError( buf, typeRef ); + } + else { + typelib_CompoundTypeDescription * compType = + reinterpret_cast< typelib_CompoundTypeDescription * >( + typeDescr ); + sal_Int32 nDescr = compType->nMembers; + + if (compType->pBaseTypeDescription) { + appendValue( + buf, val, reinterpret_cast< + typelib_TypeDescription * >( + compType->pBaseTypeDescription)->pWeakRef, false ); + if (nDescr > 0) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") ); + } + + typelib_TypeDescriptionReference ** ppTypeRefs = + compType->ppTypeRefs; + sal_Int32 * memberOffsets = compType->pMemberOffsets; + rtl_uString ** ppMemberNames = compType->ppMemberNames; + + for ( sal_Int32 nPos = 0; nPos < nDescr; ++nPos ) + { + buf.append( ppMemberNames[ nPos ] ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" = ") ); + typelib_TypeDescription * memberType = 0; + TYPELIB_DANGER_GET( &memberType, ppTypeRefs[ nPos ] ); + if (memberType == 0) { + appendTypeError( buf, ppTypeRefs[ nPos ] ); + } + else { + appendValue( buf, + static_cast< char const * >( + val ) + memberOffsets[ nPos ], + memberType->pWeakRef, true ); + TYPELIB_DANGER_RELEASE( memberType ); + } + if (nPos < (nDescr - 1)) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") ); + } + } + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") ); + if (typeDescr != 0) + typelib_typedescription_release( typeDescr ); + break; + } + case typelib_TypeClass_SEQUENCE: { + typelib_TypeDescription * typeDescr = 0; + TYPELIB_DANGER_GET( &typeDescr, typeRef ); + if (typeDescr == 0) { + appendTypeError( buf,typeRef ); + } + else { + typelib_TypeDescriptionReference * elementTypeRef = + reinterpret_cast< + typelib_IndirectTypeDescription * >(typeDescr)->pType; + typelib_TypeDescription * elementTypeDescr = 0; + TYPELIB_DANGER_GET( &elementTypeDescr, elementTypeRef ); + if (elementTypeDescr == 0) + { + appendTypeError( buf, elementTypeRef ); + } + else + { + sal_Int32 nElementSize = elementTypeDescr->nSize; + uno_Sequence * seq = + *static_cast< uno_Sequence * const * >(val); + sal_Int32 nElements = seq->nElements; + + if (nElements > 0) + { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") ); + char const * pElements = seq->elements; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + appendValue( + buf, pElements + (nElementSize * nPos), + elementTypeDescr->pWeakRef, false ); + if (nPos < (nElements - 1)) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") ); + } + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") ); + } + else + { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{}") ); + } + TYPELIB_DANGER_RELEASE( elementTypeDescr ); + } + TYPELIB_DANGER_RELEASE( typeDescr ); + } + break; + } + case typelib_TypeClass_ANY: { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") ); + uno_Any const * pAny = static_cast< uno_Any const * >(val); + appendValue( buf, pAny->pData, pAny->pType, true ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") ); + break; + } + case typelib_TypeClass_TYPE: + buf.append( (*reinterpret_cast< + typelib_TypeDescriptionReference * const * >(val) + )->pTypeName ); + break; + case typelib_TypeClass_STRING: { + buf.append( static_cast< sal_Unicode >('\"') ); + rtl::OUString const & str = rtl::OUString::unacquired( + static_cast< rtl_uString * const * >(val) ); + sal_Int32 len = str.getLength(); + for ( sal_Int32 pos = 0; pos < len; ++pos ) + { + sal_Unicode c = str[ pos ]; + if (c == '\"') + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\\\"") ); + else if (c == '\\') + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\\\\") ); + else + appendChar( buf, c ); + } + buf.append( static_cast< sal_Unicode >('\"') ); + break; + } + case typelib_TypeClass_ENUM: { + typelib_TypeDescription * typeDescr = 0; + typelib_typedescriptionreference_getDescription( &typeDescr, typeRef ); + if (typeDescr == 0 || !typelib_typedescription_complete( &typeDescr )) { + appendTypeError( buf, typeRef ); + } + else + { + sal_Int32 * pValues = + reinterpret_cast< typelib_EnumTypeDescription * >( + typeDescr )->pEnumValues; + sal_Int32 nPos = reinterpret_cast< typelib_EnumTypeDescription * >( + typeDescr )->nEnumValues; + while (nPos--) + { + if (pValues[ nPos ] == *static_cast< int const * >(val)) + break; + } + if (nPos >= 0) + { + buf.append( reinterpret_cast< typelib_EnumTypeDescription * >( + typeDescr )->ppEnumNames[ nPos ] ); + } + else + { + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("?unknown enum value?") ); + } + } + if (typeDescr != 0) + typelib_typedescription_release( typeDescr ); + break; + } + case typelib_TypeClass_BOOLEAN: + if (*static_cast< sal_Bool const * >(val) != sal_False) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("true") ); + else + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("false") ); + break; + case typelib_TypeClass_CHAR: { + buf.append( static_cast< sal_Unicode >('\'') ); + sal_Unicode c = *static_cast< sal_Unicode const * >(val); + if (c == '\'') + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\\\'") ); + else if (c == '\\') + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\\\\") ); + else + appendChar( buf, c ); + buf.append( static_cast< sal_Unicode >('\'') ); + break; + } + case typelib_TypeClass_FLOAT: + buf.append( *static_cast< float const * >(val) ); + break; + case typelib_TypeClass_DOUBLE: + buf.append( *static_cast< double const * >(val) ); + break; + case typelib_TypeClass_BYTE: + buf.append( static_cast< sal_Int32 >( + *static_cast< sal_Int8 const * >(val) ) ); + break; + case typelib_TypeClass_SHORT: + buf.append( static_cast< sal_Int32 >( + *static_cast< sal_Int16 const * >(val) ) ); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + buf.append( static_cast< sal_Int32 >( + *static_cast< sal_uInt16 const * >(val) ) ); + break; + case typelib_TypeClass_LONG: + buf.append( *static_cast< sal_Int32 const * >(val) ); + break; + case typelib_TypeClass_UNSIGNED_LONG: + buf.append( static_cast< sal_Int64 >( + *static_cast< sal_uInt32 const * >(val) ) ); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + buf.append( *static_cast< sal_Int64 const * >(val) ); + break; +// case typelib_TypeClass_UNION: +// case typelib_TypeClass_ARRAY: +// case typelib_TypeClass_UNKNOWN: +// case typelib_TypeClass_SERVICE: +// case typelib_TypeClass_MODULE: + default: + buf.append( static_cast< sal_Unicode >('?') ); + break; + } +} + +} // anon namespace + +//============================================================================== +rtl::OUString anyToString( uno::Any const & value ) +{ + rtl::OUStringBuffer buf; + appendValue( buf, value.getValue(), value.getValueTypeRef(), true ); + return buf.makeStringAndClear(); +} + +} // namespace comphelper + diff --git a/comphelper/source/misc/asyncnotification.cxx b/comphelper/source/misc/asyncnotification.cxx new file mode 100644 index 000000000000..e8bee632a9b4 --- /dev/null +++ b/comphelper/source/misc/asyncnotification.cxx @@ -0,0 +1,281 @@ +/************************************************************************* + * + * 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/asyncnotification.hxx> +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <osl/conditn.hxx> +#include <comphelper/guarding.hxx> + +#include <deque> +#include <set> +#include <functional> +#include <algorithm> + +//........................................................................ +namespace comphelper +{ +//........................................................................ + + //==================================================================== + //= AnyEvent + //==================================================================== + //-------------------------------------------------------------------- + AnyEvent::AnyEvent() + :m_refCount( 0 ) + { + } + + //-------------------------------------------------------------------- + AnyEvent::~AnyEvent() + { + } + + //-------------------------------------------------------------------- + oslInterlockedCount SAL_CALL AnyEvent::acquire() + { + return osl_incrementInterlockedCount( &m_refCount ); + } + + //-------------------------------------------------------------------- + oslInterlockedCount SAL_CALL AnyEvent::release() + { + if ( 0 == osl_decrementInterlockedCount( &m_refCount ) ) + { + delete this; + return 0; + } + return m_refCount; + } + + //==================================================================== + //= ProcessableEvent + //==================================================================== + struct ProcessableEvent + { + AnyEventRef aEvent; + ::rtl::Reference< IEventProcessor > xProcessor; + + ProcessableEvent( const AnyEventRef& _rEvent, const ::rtl::Reference< IEventProcessor >& _xProcessor ) + :aEvent( _rEvent ) + ,xProcessor( _xProcessor ) + { + } + + ProcessableEvent( const ProcessableEvent& _rRHS ) + :aEvent( _rRHS.aEvent ) + ,xProcessor( _rRHS.xProcessor ) + { + } + + ProcessableEvent& operator=( const ProcessableEvent& _rRHS ) + { + aEvent = _rRHS.aEvent; + xProcessor = _rRHS.xProcessor; + return *this; + } + }; + + //==================================================================== + typedef ::std::deque< ProcessableEvent > EventQueue; + + //==================================================================== + struct EqualProcessor : public ::std::unary_function< ProcessableEvent, bool > + { + const ::rtl::Reference< IEventProcessor >& rProcessor; + EqualProcessor( const ::rtl::Reference< IEventProcessor >& _rProcessor ) :rProcessor( _rProcessor ) { } + + bool operator()( const ProcessableEvent& _rEvent ) + { + return _rEvent.xProcessor.get() == rProcessor.get(); + } + }; + + //==================================================================== + //= EventNotifierImpl + //==================================================================== + struct EventNotifierImpl + { + ::osl::Mutex aMutex; + oslInterlockedCount m_refCount; + ::osl::Condition aPendingActions; + EventQueue aEvents; + ::std::set< ::rtl::Reference< IEventProcessor > > + m_aDeadProcessors; + + EventNotifierImpl() + :m_refCount( 0 ) + { + } + + private: + EventNotifierImpl( const EventNotifierImpl& ); // never implemented + EventNotifierImpl& operator=( const EventNotifierImpl& ); // never implemented + }; + + //==================================================================== + //= AsyncEventNotifier + //==================================================================== + //-------------------------------------------------------------------- + AsyncEventNotifier::AsyncEventNotifier() + :m_pImpl( new EventNotifierImpl ) + { + } + + //-------------------------------------------------------------------- + AsyncEventNotifier::~AsyncEventNotifier() + { + } + + //-------------------------------------------------------------------- + void AsyncEventNotifier::removeEventsForProcessor( const ::rtl::Reference< IEventProcessor >& _xProcessor ) + { + ::osl::MutexGuard aGuard( m_pImpl->aMutex ); + + // remove all events for this processor + ::std::remove_if( m_pImpl->aEvents.begin(), m_pImpl->aEvents.end(), EqualProcessor( _xProcessor ) ); + + // and just in case that an event for exactly this processor has just been + // popped from the queue, but not yet processed: remember it: + m_pImpl->m_aDeadProcessors.insert( _xProcessor ); + } + + //-------------------------------------------------------------------- + void SAL_CALL AsyncEventNotifier::terminate() + { + ::osl::MutexGuard aGuard( m_pImpl->aMutex ); + + // remember the termination request + AsyncEventNotifier_TBASE::terminate(); + + // awake the thread + m_pImpl->aPendingActions.set(); + } + + //-------------------------------------------------------------------- + void AsyncEventNotifier::addEvent( const AnyEventRef& _rEvent, const ::rtl::Reference< IEventProcessor >& _xProcessor ) + { + ::osl::MutexGuard aGuard( m_pImpl->aMutex ); + + OSL_TRACE( "AsyncEventNotifier(%p): adding %p\n", this, _rEvent.get() ); + // remember this event + m_pImpl->aEvents.push_back( ProcessableEvent( _rEvent, _xProcessor ) ); + + // awake the thread + m_pImpl->aPendingActions.set(); + } + + //-------------------------------------------------------------------- + void AsyncEventNotifier::run() + { + acquire(); + + // keep us alive, in case we're terminated in the mid of the following + ::rtl::Reference< AsyncEventNotifier > xKeepAlive( this ); + + do + { + AnyEventRef aNextEvent; + ::rtl::Reference< IEventProcessor > xNextProcessor; + + ::osl::ClearableMutexGuard aGuard( m_pImpl->aMutex ); + while ( m_pImpl->aEvents.size() > 0 ) + { + ProcessableEvent aEvent( m_pImpl->aEvents.front() ); + aNextEvent = aEvent.aEvent; + xNextProcessor = aEvent.xProcessor; + m_pImpl->aEvents.pop_front(); + + OSL_TRACE( "AsyncEventNotifier(%p): popping %p\n", this, aNextEvent.get() ); + + if ( !aNextEvent.get() ) + continue; + + // process the event, but only if it's processor did not die inbetween + ::std::set< ::rtl::Reference< IEventProcessor > >::iterator deadPos = m_pImpl->m_aDeadProcessors.find( xNextProcessor ); + if ( deadPos != m_pImpl->m_aDeadProcessors.end() ) + { + m_pImpl->m_aDeadProcessors.erase( xNextProcessor ); + xNextProcessor.clear(); + OSL_TRACE( "AsyncEventNotifier(%p): removing %p\n", this, aNextEvent.get() ); + } + + // if there was a termination request (->terminate), respect it + if ( !schedule() ) + return; + + { + ::comphelper::MutexRelease aReleaseOnce( m_pImpl->aMutex ); + if ( xNextProcessor.get() ) + xNextProcessor->processEvent( *aNextEvent.get() ); + } + } + + // if there was a termination request (->terminate), respect it + if ( !schedule() ) + return; + + // wait for new events to process + aGuard.clear(); + m_pImpl->aPendingActions.reset(); + m_pImpl->aPendingActions.wait(); + } + while ( sal_True ); + } + + //-------------------------------------------------------------------- + void SAL_CALL AsyncEventNotifier::onTerminated() + { + AsyncEventNotifier_TBASE::onTerminated(); + // when we were started (->run), we aquired ourself. Release this now + // that we were finally terminated + release(); + } + + //-------------------------------------------------------------------- + oslInterlockedCount SAL_CALL AsyncEventNotifier::acquire() + { + return osl_incrementInterlockedCount( &m_pImpl->m_refCount ); + } + + //-------------------------------------------------------------------- + oslInterlockedCount SAL_CALL AsyncEventNotifier::release() + { + if ( 0 == osl_decrementInterlockedCount( &m_pImpl->m_refCount ) ) + { + delete this; + return 0; + } + return m_pImpl->m_refCount; + } + +//........................................................................ +} // namespace comphelper +//........................................................................ + diff --git a/comphelper/source/misc/comphelper_module.cxx b/comphelper/source/misc/comphelper_module.cxx new file mode 100644 index 000000000000..5f423691592a --- /dev/null +++ b/comphelper/source/misc/comphelper_module.cxx @@ -0,0 +1,41 @@ +/************************************************************************* + * 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_module.hxx" + +//........................................................................ +namespace comphelper { namespace module +{ +//........................................................................ + + IMPLEMENT_COMPONENT_MODULE( ComphelperModule ); + +//........................................................................ +} } // namespace comphelper::module +//........................................................................ diff --git a/comphelper/source/misc/comphelper_services.cxx b/comphelper/source/misc/comphelper_services.cxx new file mode 100644 index 000000000000..b46dcea68ba7 --- /dev/null +++ b/comphelper/source/misc/comphelper_services.cxx @@ -0,0 +1,79 @@ +/************************************************************************* + * 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_module.hxx" + +//-------------------------------------------------------------------- +extern void createRegistryInfo_OPropertyBag(); +extern void createRegistryInfo_SequenceOutputStream(); +extern void createRegistryInfo_SequenceInputStream(); +extern void createRegistryInfo_UNOMemoryStream(); +extern void createRegistryInfo_IndexedPropertyValuesContainer(); +extern void createRegistryInfo_NamedPropertyValuesContainer(); +extern void createRegistryInfo_AnyCompareFactory(); +extern void createRegistryInfo_OfficeInstallationDirectories(); +extern void createRegistryInfo_OInstanceLocker(); +extern void createRegistryInfo_Map(); +extern void createRegistryInfo_OSimpleLogRing(); +extern void createRegistryInfo_OOfficeRestartManager(); + +//........................................................................ +namespace comphelper { namespace module +{ +//........................................................................ + + static void initializeModule() + { + static bool bInitialized( false ); + if ( !bInitialized ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if ( !bInitialized ) + { + createRegistryInfo_OPropertyBag(); + createRegistryInfo_SequenceOutputStream(); + createRegistryInfo_SequenceInputStream(); + createRegistryInfo_UNOMemoryStream(); + createRegistryInfo_IndexedPropertyValuesContainer(); + createRegistryInfo_NamedPropertyValuesContainer(); + createRegistryInfo_AnyCompareFactory(); + createRegistryInfo_OfficeInstallationDirectories(); + createRegistryInfo_OInstanceLocker(); + createRegistryInfo_Map(); + createRegistryInfo_OSimpleLogRing(); + createRegistryInfo_OOfficeRestartManager(); + } + } + } + +//........................................................................ +} } // namespace comphelper::module +//........................................................................ + +IMPLEMENT_COMPONENT_LIBRARY_API( ::comphelper::module::ComphelperModule, ::comphelper::module::initializeModule ) diff --git a/comphelper/source/misc/componentbase.cxx b/comphelper/source/misc/componentbase.cxx new file mode 100644 index 000000000000..657c2c6a5972 --- /dev/null +++ b/comphelper/source/misc/componentbase.cxx @@ -0,0 +1,74 @@ +/************************************************************************* + * 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/componentbase.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/lang/NotInitializedException.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +/** === end UNO includes === **/ + +//........................................................................ +namespace comphelper +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::lang::NotInitializedException; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + /** === end UNO using === **/ + + //==================================================================== + //= ComponentBase + //==================================================================== + //-------------------------------------------------------------------- + void ComponentBase::impl_checkDisposed_throw() const + { + if ( m_rBHelper.bDisposed ) + throw DisposedException( ::rtl::OUString(), getComponent() ); + } + + //-------------------------------------------------------------------- + void ComponentBase::impl_checkInitialized_throw() const + { + if ( !m_bInitialized ) + throw NotInitializedException( ::rtl::OUString(), getComponent() ); + } + + //-------------------------------------------------------------------- + Reference< XInterface > ComponentBase::getComponent() const + { + return NULL; + } + +//........................................................................ +} // namespace comphelper +//........................................................................ diff --git a/comphelper/source/misc/componentcontext.cxx b/comphelper/source/misc/componentcontext.cxx new file mode 100644 index 000000000000..0f9ddad5d2f5 --- /dev/null +++ b/comphelper/source/misc/componentcontext.cxx @@ -0,0 +1,151 @@ +/************************************************************************* + * + * 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/componentcontext.hxx> + +/** === begin UNO includes === **/ +#include <com/sun/star/lang/NullPointerException.hpp> +#include <com/sun/star/lang/ServiceNotRegisteredException.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +/** === end UNO includes === **/ + +//........................................................................ +namespace comphelper +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::lang::NullPointerException; + using ::com::sun::star::lang::ServiceNotRegisteredException; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::lang::XMultiServiceFactory; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Sequence; + /** === end UNO using === **/ + + //==================================================================== + //= ComponentContext + //==================================================================== + //-------------------------------------------------------------------- + ComponentContext::ComponentContext( const Reference< XComponentContext >& _rxContext ) + :m_xContext( _rxContext ) + { + if ( m_xContext.is() ) + m_xORB = m_xContext->getServiceManager(); + if ( !m_xORB.is() ) + throw NullPointerException(); + } + + //------------------------------------------------------------------------ + ComponentContext::ComponentContext( const Reference< XMultiServiceFactory >& _rxLegacyFactory ) + { + if ( !_rxLegacyFactory.is() ) + throw NullPointerException(); + + try + { + Reference< XPropertySet > xFactoryProperties( _rxLegacyFactory, UNO_QUERY_THROW ); + m_xContext = Reference< XComponentContext >( + xFactoryProperties->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) ), + UNO_QUERY ); + } + catch( const RuntimeException& ) { throw; } + catch( const Exception& ) + { + throw RuntimeException(); + } + + if ( m_xContext.is() ) + m_xORB = m_xContext->getServiceManager(); + if ( !m_xORB.is() ) + throw NullPointerException(); + } + + //------------------------------------------------------------------------ + Any ComponentContext::getContextValueByName( const ::rtl::OUString& _rName ) const + { + Any aReturn; + try + { + aReturn = m_xContext->getValueByName( _rName ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "ComponentContext::getContextValueByName: caught an exception!" ); + } + return aReturn; + } + + //------------------------------------------------------------------------ + Reference< XInterface > ComponentContext::createComponent( const ::rtl::OUString& _rServiceName ) const + { + Reference< XInterface > xComponent( + m_xORB->createInstanceWithContext( _rServiceName, m_xContext ) + ); + if ( !xComponent.is() ) + throw ServiceNotRegisteredException( _rServiceName, NULL ); + return xComponent; + } + + //------------------------------------------------------------------------ + Reference< XInterface > ComponentContext::createComponentWithArguments( const ::rtl::OUString& _rServiceName, const Sequence< Any >& _rArguments ) const + { + Reference< XInterface > xComponent( + m_xORB->createInstanceWithArgumentsAndContext( _rServiceName, _rArguments, m_xContext ) + ); + if ( !xComponent.is() ) + throw ServiceNotRegisteredException( _rServiceName, NULL ); + return xComponent; + } + + //------------------------------------------------------------------------ + Reference< XInterface > ComponentContext::getSingleton( const ::rtl::OUString& _rInstanceName ) const + { + ::rtl::OUString sKey( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/singletons/" ) ) ); + sKey += _rInstanceName; + return Reference< XInterface >( getContextValueByName( sKey ), UNO_QUERY ); + } + + //------------------------------------------------------------------------ + Reference< XMultiServiceFactory > ComponentContext::getLegacyServiceFactory() const + { + return Reference< XMultiServiceFactory >( m_xORB, UNO_QUERY_THROW ); + } + +//........................................................................ +} // namespace comphelper +//........................................................................ + diff --git a/comphelper/source/misc/componentmodule.cxx b/comphelper/source/misc/componentmodule.cxx new file mode 100644 index 000000000000..63893d0f6d0d --- /dev/null +++ b/comphelper/source/misc/componentmodule.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" +#include <comphelper/componentmodule.hxx> + +/** === begin UNO includes === **/ +/** === end UNO includes === **/ +#include <comphelper/sequence.hxx> +#include <osl/diagnose.h> + +#include <vector> + +//........................................................................ +namespace comphelper +{ +//........................................................................ + + using namespace ::cppu; + /** === being UNO using === **/ + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::lang::XMultiServiceFactory; + using ::com::sun::star::registry::XRegistryKey; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::XInterface; + /** === end UNO using === **/ + + typedef ::std::vector< ComponentDescription > ComponentDescriptions; + + //========================================================================= + //= OModuleImpl + //========================================================================= + /** implementation for <type>OModule</type>. not threadsafe, has to be guarded by it's owner + */ + class OModuleImpl + { + public: + ComponentDescriptions m_aRegisteredComponents; + + OModuleImpl(); + ~OModuleImpl(); + }; + + //------------------------------------------------------------------------- + OModuleImpl::OModuleImpl() + { + } + + //------------------------------------------------------------------------- + OModuleImpl::~OModuleImpl() + { + } + + //========================================================================= + //= OModule + //========================================================================= + //------------------------------------------------------------------------- + OModule::OModule() + :m_nClients( 0 ) + ,m_pImpl( new OModuleImpl ) + { + } + + OModule::~OModule() {} + + //------------------------------------------------------------------------- + void OModule::registerClient( OModule::ClientAccess ) + { + ::osl::MutexGuard aGuard(m_aMutex); + if ( 1 == osl_incrementInterlockedCount( &m_nClients ) ) + onFirstClient(); + } + + //------------------------------------------------------------------------- + void OModule::revokeClient( OModule::ClientAccess ) + { + ::osl::MutexGuard aGuard(m_aMutex); + if ( 0 == osl_decrementInterlockedCount( &m_nClients ) ) + onLastClient(); + } + + //-------------------------------------------------------------------------- + void OModule::onFirstClient() + { + } + + //-------------------------------------------------------------------------- + void OModule::onLastClient() + { + } + + //-------------------------------------------------------------------------- + void OModule::registerImplementation( const ComponentDescription& _rComp ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_pImpl ) + throw RuntimeException(); + + m_pImpl->m_aRegisteredComponents.push_back( _rComp ); + } + + //-------------------------------------------------------------------------- + void OModule::registerImplementation( const ::rtl::OUString& _rImplementationName, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rServiceNames, + ::cppu::ComponentFactoryFunc _pCreateFunction, FactoryInstantiation _pFactoryFunction ) + { + ComponentDescription aComponent( _rImplementationName, _rServiceNames, ::rtl::OUString(), _pCreateFunction, _pFactoryFunction ); + registerImplementation( aComponent ); + } + + //-------------------------------------------------------------------------- + sal_Bool OModule::writeComponentInfos( void* pServiceManager, void* pRegistryKey ) + { + Reference< XMultiServiceFactory > xFactory( static_cast< XMultiServiceFactory* >( pServiceManager ) ); + Reference< XRegistryKey > xRegistryKey( static_cast< XRegistryKey* >( pRegistryKey ) ); + return writeComponentInfos( xFactory, xRegistryKey ); + } + + //-------------------------------------------------------------------------- + sal_Bool OModule::writeComponentInfos( + const Reference< XMultiServiceFactory >& /*_rxServiceManager*/, + const Reference< XRegistryKey >& _rxRootKey ) + { + OSL_ENSURE( _rxRootKey.is(), "OModule::writeComponentInfos: invalid argument!" ); + + ::rtl::OUString sRootKey( "/", 1, RTL_TEXTENCODING_ASCII_US ); + + for ( ComponentDescriptions::const_iterator component = m_pImpl->m_aRegisteredComponents.begin(); + component != m_pImpl->m_aRegisteredComponents.end(); + ++component + ) + { + ::rtl::OUString sMainKeyName( sRootKey ); + sMainKeyName += component->sImplementationName; + sMainKeyName += ::rtl::OUString::createFromAscii( "/UNO/SERVICES" ); + + try + { + Reference< XRegistryKey > xNewKey( _rxRootKey->createKey( sMainKeyName ) ); + + const ::rtl::OUString* pService = component->aSupportedServices.getConstArray(); + const ::rtl::OUString* pServiceEnd = component->aSupportedServices.getConstArray() + component->aSupportedServices.getLength(); + for ( ; pService != pServiceEnd; ++pService ) + xNewKey->createKey( *pService ); + + if ( component->sSingletonName.getLength() ) + { + OSL_ENSURE( component->aSupportedServices.getLength() == 1, "OModule::writeComponentInfos: singletons should support exactly one service, shouldn't they?" ); + + ::rtl::OUString sSingletonKeyName( sRootKey ); + sSingletonKeyName += component->sImplementationName; + sSingletonKeyName += ::rtl::OUString::createFromAscii( "/UNO/SINGLETONS/" ); + sSingletonKeyName += component->sSingletonName; + + xNewKey = _rxRootKey->createKey( sSingletonKeyName ); + xNewKey->setStringValue( component->aSupportedServices[ 0 ] ); + } + } + catch( Exception& ) + { + OSL_ASSERT( "OModule::writeComponentInfos: something went wrong while creating the keys!" ); + return sal_False; + } + } + + return sal_True; + } + + //-------------------------------------------------------------------------- + void* OModule::getComponentFactory( const sal_Char* _pImplementationName, void* _pServiceManager, void* /*_pRegistryKey*/ ) + { + Reference< XInterface > xFactory( getComponentFactory( + ::rtl::OUString::createFromAscii( _pImplementationName ), + Reference< XMultiServiceFactory >( static_cast< XMultiServiceFactory* >( _pServiceManager ) ) + ) ); + return xFactory.get(); + } + + //-------------------------------------------------------------------------- + Reference< XInterface > OModule::getComponentFactory( const ::rtl::OUString& _rImplementationName, + const Reference< XMultiServiceFactory >& /* _rxServiceManager */ ) + { + Reference< XInterface > xReturn; + + for ( ComponentDescriptions::const_iterator component = m_pImpl->m_aRegisteredComponents.begin(); + component != m_pImpl->m_aRegisteredComponents.end(); + ++component + ) + { + if ( component->sImplementationName == _rImplementationName ) + { + xReturn = component->pFactoryCreationFunc( + component->pComponentCreationFunc, + component->sImplementationName, + component->aSupportedServices, + NULL + ); + if ( xReturn.is() ) + { + xReturn->acquire(); + return xReturn.get(); + } + } + } + + return NULL; + } + +//........................................................................ +} // namespace comphelper +//........................................................................ diff --git a/comphelper/source/misc/configurationhelper.cxx b/comphelper/source/misc/configurationhelper.cxx new file mode 100644 index 000000000000..b78d39217d90 --- /dev/null +++ b/comphelper/source/misc/configurationhelper.cxx @@ -0,0 +1,207 @@ +/************************************************************************* + * + * 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" + +//_______________________________________________ +// includes +#include <comphelper/configurationhelper.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +//_______________________________________________ +// namespace + +namespace comphelper{ + +namespace css = ::com::sun::star; + +//_______________________________________________ +// definitions + +//----------------------------------------------- +css::uno::Reference< css::uno::XInterface > ConfigurationHelper::openConfig(const css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR , + const ::rtl::OUString& sPackage, + sal_Int32 eMode ) +{ + css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider( + xSMGR->createInstance(::rtl::OUString::createFromAscii("com.sun.star.configuration.ConfigurationProvider")), css::uno::UNO_QUERY_THROW); + + ::comphelper::SequenceAsVector< css::uno::Any > lParams; + css::beans::PropertyValue aParam ; + + // set root path + aParam.Name = ::rtl::OUString::createFromAscii("nodepath"); + aParam.Value <<= sPackage; + lParams.push_back(css::uno::makeAny(aParam)); + + // enable all locales mode + if ((eMode & ConfigurationHelper::E_ALL_LOCALES)==ConfigurationHelper::E_ALL_LOCALES) + { + aParam.Name = ::rtl::OUString::createFromAscii("locale"); + aParam.Value <<= ::rtl::OUString::createFromAscii("*"); + lParams.push_back(css::uno::makeAny(aParam)); + } + + // enable lazy writing + sal_Bool bLazy = ((eMode & ConfigurationHelper::E_LAZY_WRITE)==ConfigurationHelper::E_LAZY_WRITE); + aParam.Name = ::rtl::OUString::createFromAscii("lazywrite"); + aParam.Value = css::uno::makeAny(bLazy); + lParams.push_back(css::uno::makeAny(aParam)); + + // open it + css::uno::Reference< css::uno::XInterface > xCFG; + + sal_Bool bReadOnly = ((eMode & ConfigurationHelper::E_READONLY)==ConfigurationHelper::E_READONLY); + if (bReadOnly) + xCFG = xConfigProvider->createInstanceWithArguments( + ::rtl::OUString::createFromAscii("com.sun.star.configuration.ConfigurationAccess"), + lParams.getAsConstList()); + else + xCFG = xConfigProvider->createInstanceWithArguments( + ::rtl::OUString::createFromAscii("com.sun.star.configuration.ConfigurationUpdateAccess"), + lParams.getAsConstList()); + + return xCFG; +} + +//----------------------------------------------- +css::uno::Any ConfigurationHelper::readRelativeKey(const css::uno::Reference< css::uno::XInterface > xCFG , + const ::rtl::OUString& sRelPath, + const ::rtl::OUString& sKey ) +{ + css::uno::Reference< css::container::XHierarchicalNameAccess > xAccess(xCFG, css::uno::UNO_QUERY_THROW); + + css::uno::Reference< css::beans::XPropertySet > xProps; + xAccess->getByHierarchicalName(sRelPath) >>= xProps; + if (!xProps.is()) + { + ::rtl::OUStringBuffer sMsg(256); + sMsg.appendAscii("The requested path \""); + sMsg.append (sRelPath ); + sMsg.appendAscii("\" does not exists." ); + + throw css::container::NoSuchElementException( + sMsg.makeStringAndClear(), + css::uno::Reference< css::uno::XInterface >()); + } + return xProps->getPropertyValue(sKey); +} + +//----------------------------------------------- +void ConfigurationHelper::writeRelativeKey(const css::uno::Reference< css::uno::XInterface > xCFG , + const ::rtl::OUString& sRelPath, + const ::rtl::OUString& sKey , + const css::uno::Any& aValue ) +{ + css::uno::Reference< css::container::XHierarchicalNameAccess > xAccess(xCFG, css::uno::UNO_QUERY_THROW); + + css::uno::Reference< css::beans::XPropertySet > xProps; + xAccess->getByHierarchicalName(sRelPath) >>= xProps; + if (!xProps.is()) + { + ::rtl::OUStringBuffer sMsg(256); + sMsg.appendAscii("The requested path \""); + sMsg.append (sRelPath ); + sMsg.appendAscii("\" does not exists." ); + + throw css::container::NoSuchElementException( + sMsg.makeStringAndClear(), + css::uno::Reference< css::uno::XInterface >()); + } + xProps->setPropertyValue(sKey, aValue); +} + +//----------------------------------------------- +css::uno::Reference< css::uno::XInterface > ConfigurationHelper::makeSureSetNodeExists(const css::uno::Reference< css::uno::XInterface > xCFG , + const ::rtl::OUString& sRelPathToSet, + const ::rtl::OUString& sSetNode ) +{ + css::uno::Reference< css::container::XHierarchicalNameAccess > xAccess(xCFG, css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::container::XNameAccess > xSet; + xAccess->getByHierarchicalName(sRelPathToSet) >>= xSet; + if (!xSet.is()) + { + ::rtl::OUStringBuffer sMsg(256); + sMsg.appendAscii("The requested path \""); + sMsg.append (sRelPathToSet ); + sMsg.appendAscii("\" does not exists." ); + + throw css::container::NoSuchElementException( + sMsg.makeStringAndClear(), + css::uno::Reference< css::uno::XInterface >()); + } + + css::uno::Reference< css::uno::XInterface > xNode; + if (xSet->hasByName(sSetNode)) + xSet->getByName(sSetNode) >>= xNode; + else + { + css::uno::Reference< css::lang::XSingleServiceFactory > xNodeFactory(xSet, css::uno::UNO_QUERY_THROW); + xNode = xNodeFactory->createInstance(); + css::uno::Reference< css::container::XNameContainer > xSetReplace(xSet, css::uno::UNO_QUERY_THROW); + xSetReplace->insertByName(sSetNode, css::uno::makeAny(xNode)); + } + + return xNode; +} + +//----------------------------------------------- +css::uno::Any ConfigurationHelper::readDirectKey(const css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR , + const ::rtl::OUString& sPackage, + const ::rtl::OUString& sRelPath, + const ::rtl::OUString& sKey , + sal_Int32 eMode ) +{ + css::uno::Reference< css::uno::XInterface > xCFG = ConfigurationHelper::openConfig(xSMGR, sPackage, eMode); + return ConfigurationHelper::readRelativeKey(xCFG, sRelPath, sKey); +} + +//----------------------------------------------- +void ConfigurationHelper::writeDirectKey(const css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR , + const ::rtl::OUString& sPackage, + const ::rtl::OUString& sRelPath, + const ::rtl::OUString& sKey , + const css::uno::Any& aValue , + sal_Int32 eMode ) +{ + css::uno::Reference< css::uno::XInterface > xCFG = ConfigurationHelper::openConfig(xSMGR, sPackage, eMode); + ConfigurationHelper::writeRelativeKey(xCFG, sRelPath, sKey, aValue); + ConfigurationHelper::flush(xCFG); +} + +//----------------------------------------------- +void ConfigurationHelper::flush(const css::uno::Reference< css::uno::XInterface >& xCFG) +{ + css::uno::Reference< css::util::XChangesBatch > xBatch(xCFG, css::uno::UNO_QUERY_THROW); + xBatch->commitChanges(); +} + +} // namespace comphelper diff --git a/comphelper/source/misc/docpasswordhelper.cxx b/comphelper/source/misc/docpasswordhelper.cxx new file mode 100644 index 000000000000..37941352ae28 --- /dev/null +++ b/comphelper/source/misc/docpasswordhelper.cxx @@ -0,0 +1,380 @@ +/*********************************************************************** + * + * 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/docpasswordhelper.hxx" +#include <com/sun/star/task/XInteractionHandler.hpp> +#include "comphelper/mediadescriptor.hxx" + +#include <osl/time.h> +#include <rtl/digest.h> +#include <rtl/random.h> + +using ::rtl::OUString; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_SET_THROW; +using ::com::sun::star::task::PasswordRequestMode; +using ::com::sun::star::task::PasswordRequestMode_PASSWORD_ENTER; +using ::com::sun::star::task::PasswordRequestMode_PASSWORD_REENTER; +using ::com::sun::star::task::XInteractionHandler; +using ::com::sun::star::task::XInteractionRequest; + +using namespace ::com::sun::star; + +namespace comphelper { + +// ============================================================================ + +static uno::Sequence< sal_Int8 > GeneratePBKDF2Hash( const ::rtl::OUString& aPassword, const uno::Sequence< sal_Int8 >& aSalt, sal_Int32 nCount, sal_Int32 nHashLength ) +{ + uno::Sequence< sal_Int8 > aResult; + + if ( aPassword.getLength() && aSalt.getLength() && nCount && nHashLength ) + { + ::rtl::OString aBytePass = ::rtl::OUStringToOString( aPassword, RTL_TEXTENCODING_UTF8 ); + aResult.realloc( 16 ); + rtl_digest_PBKDF2( reinterpret_cast < sal_uInt8 * > ( aResult.getArray() ), + aResult.getLength(), + reinterpret_cast < const sal_uInt8 * > ( aBytePass.getStr() ), + aBytePass.getLength(), + reinterpret_cast < const sal_uInt8 * > ( aSalt.getConstArray() ), + aSalt.getLength(), + nCount ); + } + + return aResult; +} + +// ============================================================================ + +IDocPasswordVerifier::~IDocPasswordVerifier() +{ +} + +// ============================================================================ +uno::Sequence< beans::PropertyValue > DocPasswordHelper::GenerateNewModifyPasswordInfo( const ::rtl::OUString& aPassword ) +{ + uno::Sequence< beans::PropertyValue > aResult; + + uno::Sequence< sal_Int8 > aSalt( 16 ); + sal_Int32 nCount = 1024; + + TimeValue aTime; + osl_getSystemTime( &aTime ); + rtlRandomPool aRandomPool = rtl_random_createPool (); + rtl_random_addBytes ( aRandomPool, &aTime, 8 ); + + rtl_random_getBytes ( aRandomPool, aSalt.getArray(), 16 ); + + uno::Sequence< sal_Int8 > aNewHash = GeneratePBKDF2Hash( aPassword, aSalt, nCount, 16 ); + if ( aNewHash.getLength() ) + { + aResult.realloc( 4 ); + aResult[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "algorithm-name" ) ); + aResult[0].Value <<= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PBKDF2" ) ); + aResult[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "salt" ) ); + aResult[1].Value <<= aSalt; + aResult[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "iteration-count" ) ); + aResult[2].Value <<= nCount; + aResult[3].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "hash" ) ); + aResult[3].Value <<= aNewHash; + } + + // Clean up random pool memory + rtl_random_destroyPool ( aRandomPool ); + + return aResult; +} + +// ============================================================================ +sal_Bool DocPasswordHelper::IsModifyPasswordCorrect( const ::rtl::OUString& aPassword, const uno::Sequence< beans::PropertyValue >& aInfo ) +{ + sal_Bool bResult = sal_False; + if ( aPassword.getLength() && aInfo.getLength() ) + { + ::rtl::OUString sAlgorithm; + uno::Sequence< sal_Int8 > aSalt; + uno::Sequence< sal_Int8 > aHash; + sal_Int32 nCount = 0; + + for ( sal_Int32 nInd = 0; nInd < aInfo.getLength(); nInd++ ) + { + if ( aInfo[nInd].Name.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "algorithm-name" ) ) ) ) + aInfo[nInd].Value >>= sAlgorithm; + else if ( aInfo[nInd].Name.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "salt" ) ) ) ) + aInfo[nInd].Value >>= aSalt; + else if ( aInfo[nInd].Name.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "iteration-count" ) ) ) ) + aInfo[nInd].Value >>= nCount; + else if ( aInfo[nInd].Name.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "hash" ) ) ) ) + aInfo[nInd].Value >>= aHash; + } + + if ( sAlgorithm.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PBKDF2" ) ) ) + && aSalt.getLength() && nCount > 0 && aHash.getLength() ) + { + uno::Sequence< sal_Int8 > aNewHash = GeneratePBKDF2Hash( aPassword, aSalt, nCount, aHash.getLength() ); + for ( sal_Int32 nInd = 0; nInd < aNewHash.getLength() && nInd < aHash.getLength() && aNewHash[nInd] == aHash[nInd]; nInd ++ ) + { + if ( nInd == aNewHash.getLength() - 1 && nInd == aHash.getLength() - 1 ) + bResult = sal_True; + } + } + } + + return bResult; +} + +// ============================================================================ +sal_uInt32 DocPasswordHelper::GetWordHashAsUINT32( + const ::rtl::OUString& aUString ) +{ + static sal_uInt16 pInitialCode[] = { + 0xE1F0, // 1 + 0x1D0F, // 2 + 0xCC9C, // 3 + 0x84C0, // 4 + 0x110C, // 5 + 0x0E10, // 6 + 0xF1CE, // 7 + 0x313E, // 8 + 0x1872, // 9 + 0xE139, // 10 + 0xD40F, // 11 + 0x84F9, // 12 + 0x280C, // 13 + 0xA96A, // 14 + 0x4EC3 // 15 + }; + + static sal_uInt16 pEncryptionMatrix[15][7] = { + { 0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09}, // last-14 + { 0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF}, // last-13 + { 0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0}, // last-12 + { 0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40}, // last-11 + { 0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5}, // last-10 + { 0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A}, // last-9 + { 0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9}, // last-8 + { 0x47D3, 0x8FA6, 0x8FA6, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0}, // last-7 + { 0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC}, // last-6 + { 0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10}, // last-5 + { 0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168}, // last-4 + { 0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C}, // last-3 + { 0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD}, // last-2 + { 0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC}, // last-1 + { 0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4} // last + }; + + sal_uInt32 nResult = 0; + sal_uInt32 nLen = aUString.getLength(); + + if ( nLen ) + { + if ( nLen > 15 ) + nLen = 15; + + sal_uInt16 nHighResult = pInitialCode[nLen - 1]; + sal_uInt16 nLowResult = 0; + + const sal_Unicode* pStr = aUString.getStr(); + for ( sal_uInt32 nInd = 0; nInd < nLen; nInd++ ) + { + // NO Encoding during conversion! + // The specification says that the low byte should be used in case it is not NULL + char nHighChar = (char)( pStr[nInd] >> 8 ); + char nLowChar = (char)( pStr[nInd] & 0xFF ); + char nChar = nLowChar ? nLowChar : nHighChar; + + for ( int nMatrixInd = 0; nMatrixInd < 7; ++nMatrixInd ) + { + if ( ( nChar & ( 1 << nMatrixInd ) ) != 0 ) + nHighResult = nHighResult ^ pEncryptionMatrix[15 - nLen + nInd][nMatrixInd]; + } + + nLowResult = ( ( ( nLowResult >> 14 ) & 0x0001 ) | ( ( nLowResult << 1 ) & 0x7FFF ) ) ^ nChar; + } + + nLowResult = (sal_uInt16)( ( ( ( nLowResult >> 14 ) & 0x001 ) | ( ( nLowResult << 1 ) & 0x7FF ) ) ^ nLen ^ 0xCE4B ); + + nResult = ( nHighResult << 16 ) | nLowResult; + } + + return nResult; +} + +// ============================================================================ +Sequence< sal_Int8 > DocPasswordHelper::GetWordHashAsSequence( + const ::rtl::OUString& aUString ) +{ + sal_uInt32 nHash = GetWordHashAsUINT32( aUString ); + Sequence< sal_Int8 > aResult( 4 ); + aResult[0] = ( nHash >> 24 ); + aResult[1] = ( ( nHash >> 16 ) & 0xFF ); + aResult[2] = ( ( nHash >> 8 ) & 0xFF ); + aResult[3] = ( nHash & 0xFF ); + + return aResult; +} + +// ============================================================================ +sal_uInt16 DocPasswordHelper::GetXLHashAsUINT16( + const ::rtl::OUString& aUString, + rtl_TextEncoding nEnc ) +{ + sal_uInt16 nResult = 0; + + ::rtl::OString aString = ::rtl::OUStringToOString( aUString, nEnc ); + + if ( aString.getLength() && aString.getLength() <= SAL_MAX_UINT16 ) + { + for ( sal_Int32 nInd = aString.getLength() - 1; nInd >= 0; nInd-- ) + { + nResult = ( ( nResult >> 14 ) & 0x01 ) | ( ( nResult << 1 ) & 0x7FFF ); + nResult ^= aString.getStr()[nInd]; + } + + nResult = ( ( nResult >> 14 ) & 0x01 ) | ( ( nResult << 1 ) & 0x7FFF ); + nResult ^= ( 0x8000 | ( 'N' << 8 ) | 'K' ); + nResult ^= aString.getLength(); + } + + return nResult; +} + +// ============================================================================ +Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence( + const ::rtl::OUString& aUString, + rtl_TextEncoding nEnc ) +{ + sal_uInt16 nHash = GetXLHashAsUINT16( aUString, nEnc ); + Sequence< sal_Int8 > aResult( 2 ); + aResult[0] = ( nHash >> 8 ); + aResult[1] = ( nHash & 0xFF ); + + return aResult; +} + +// ============================================================================ + +/*static*/ OUString DocPasswordHelper::requestAndVerifyDocPassword( + IDocPasswordVerifier& rVerifier, + const OUString& rMediaPassword, + const Reference< XInteractionHandler >& rxInteractHandler, + const OUString& rDocumentName, + DocPasswordRequestType eRequestType, + const ::std::vector< OUString >* pDefaultPasswords, + bool* pbIsDefaultPassword ) +{ + OUString aPassword; + DocPasswordVerifierResult eResult = DocPasswordVerifierResult_WRONG_PASSWORD; + + // first, try provided default passwords + if( pbIsDefaultPassword ) + *pbIsDefaultPassword = false; + if( pDefaultPasswords ) + { + for( ::std::vector< OUString >::const_iterator aIt = pDefaultPasswords->begin(), aEnd = pDefaultPasswords->end(); (eResult == DocPasswordVerifierResult_WRONG_PASSWORD) && (aIt != aEnd); ++aIt ) + { + aPassword = *aIt; + OSL_ENSURE( aPassword.getLength() > 0, "DocPasswordHelper::requestAndVerifyDocPassword - unexpected empty default password" ); + if( aPassword.getLength() > 0 ) + { + eResult = rVerifier.verifyPassword( aPassword ); + if( pbIsDefaultPassword ) + *pbIsDefaultPassword = eResult == DocPasswordVerifierResult_OK; + } + } + } + + // try media password (skip, if result is OK or ABORT) + if( eResult == DocPasswordVerifierResult_WRONG_PASSWORD ) + { + aPassword = rMediaPassword; + if( aPassword.getLength() > 0 ) + eResult = rVerifier.verifyPassword( aPassword ); + } + + // request a password (skip, if result is OK or ABORT) + if( (eResult == DocPasswordVerifierResult_WRONG_PASSWORD) && rxInteractHandler.is() ) try + { + PasswordRequestMode eRequestMode = PasswordRequestMode_PASSWORD_ENTER; + while( eResult == DocPasswordVerifierResult_WRONG_PASSWORD ) + { + DocPasswordRequest* pRequest = new DocPasswordRequest( eRequestType, eRequestMode, rDocumentName ); + Reference< XInteractionRequest > xRequest( pRequest ); + rxInteractHandler->handle( xRequest ); + if( pRequest->isPassword() ) + { + aPassword = pRequest->getPassword(); + if( aPassword.getLength() > 0 ) + eResult = rVerifier.verifyPassword( aPassword ); + } + else + { + eResult = DocPasswordVerifierResult_ABORT; + } + eRequestMode = PasswordRequestMode_PASSWORD_REENTER; + } + } + catch( Exception& ) + { + } + + return (eResult == DocPasswordVerifierResult_OK) ? aPassword : OUString(); +} + +/*static*/ OUString DocPasswordHelper::requestAndVerifyDocPassword( + IDocPasswordVerifier& rVerifier, + MediaDescriptor& rMediaDesc, + DocPasswordRequestType eRequestType, + const ::std::vector< OUString >* pDefaultPasswords ) +{ + OUString aMediaPassword = rMediaDesc.getUnpackedValueOrDefault( + MediaDescriptor::PROP_PASSWORD(), OUString() ); + Reference< XInteractionHandler > xInteractHandler = rMediaDesc.getUnpackedValueOrDefault( + MediaDescriptor::PROP_INTERACTIONHANDLER(), Reference< XInteractionHandler >() ); + OUString aDocumentName = rMediaDesc.getUnpackedValueOrDefault( + MediaDescriptor::PROP_URL(), OUString() ); + + bool bIsDefaultPassword = false; + OUString aPassword = requestAndVerifyDocPassword( + rVerifier, aMediaPassword, xInteractHandler, aDocumentName, eRequestType, pDefaultPasswords, &bIsDefaultPassword ); + + // insert valid password into media descriptor (but not a default password) + if( (aPassword.getLength() > 0) && !bIsDefaultPassword ) + rMediaDesc[ MediaDescriptor::PROP_PASSWORD() ] <<= aPassword; + + return aPassword; +} + +// ============================================================================ + +} // namespace comphelper + diff --git a/comphelper/source/misc/docpasswordrequest.cxx b/comphelper/source/misc/docpasswordrequest.cxx new file mode 100644 index 000000000000..17cdb0ae2d92 --- /dev/null +++ b/comphelper/source/misc/docpasswordrequest.cxx @@ -0,0 +1,194 @@ +/************************************************************************* + * + * 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/docpasswordrequest.hxx" +#include <com/sun/star/task/DocumentMSPasswordRequest2.hpp> +#include <com/sun/star/task/DocumentPasswordRequest2.hpp> +#include <com/sun/star/task/XInteractionAbort.hpp> +#include <com/sun/star/task/XInteractionPassword2.hpp> + +using ::rtl::OUString; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Type; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::task::InteractionClassification_QUERY; +using ::com::sun::star::task::DocumentMSPasswordRequest2; +using ::com::sun::star::task::DocumentPasswordRequest2; +using ::com::sun::star::task::PasswordRequestMode; +using ::com::sun::star::task::XInteractionAbort; +using ::com::sun::star::task::XInteractionContinuation; +using ::com::sun::star::task::XInteractionPassword2; +using ::com::sun::star::task::XInteractionRequest; + +namespace comphelper { + +// ============================================================================ + +class AbortContinuation : public ::cppu::WeakImplHelper1< XInteractionAbort > +{ +public: + inline explicit AbortContinuation() : mbSelected( false ) {} + + inline sal_Bool isSelected() const { return mbSelected; } + inline void reset() { mbSelected = false; } + + virtual void SAL_CALL select() throw( RuntimeException ) { mbSelected = true; } + +private: + sal_Bool mbSelected; +}; + +// ============================================================================ + +class PasswordContinuation : public ::cppu::WeakImplHelper1< XInteractionPassword2 > +{ +public: + inline explicit PasswordContinuation() : mbReadOnly( sal_False ), mbSelected( sal_False ) {} + + inline sal_Bool isSelected() const { return mbSelected; } + inline void reset() { mbSelected = sal_False; } + + virtual void SAL_CALL select() throw( RuntimeException ) { mbSelected = sal_True; } + + virtual void SAL_CALL setPassword( const OUString& rPass ) throw( RuntimeException ) { maPassword = rPass; } + virtual OUString SAL_CALL getPassword() throw( RuntimeException ) { return maPassword; } + + virtual void SAL_CALL setPasswordToModify( const OUString& rPass ) throw( RuntimeException ) { maModifyPassword = rPass; } + virtual OUString SAL_CALL getPasswordToModify() throw( RuntimeException ) { return maModifyPassword; } + + virtual void SAL_CALL setRecommendReadOnly( sal_Bool bReadOnly ) throw( RuntimeException ) { mbReadOnly = bReadOnly; } + virtual sal_Bool SAL_CALL getRecommendReadOnly() throw( RuntimeException ) { return mbReadOnly; } + +private: + OUString maPassword; + OUString maModifyPassword; + sal_Bool mbReadOnly; + sal_Bool mbSelected; +}; + +// ============================================================================ + +DocPasswordRequest::DocPasswordRequest( DocPasswordRequestType eType, + PasswordRequestMode eMode, const OUString& rDocumentName, sal_Bool bPasswordToModify ) +: mpAbort( NULL ) +, mpPassword( NULL ) +, mbPasswordToModify( bPasswordToModify ) +{ + switch( eType ) + { + case DocPasswordRequestType_STANDARD: + { + DocumentPasswordRequest2 aRequest( OUString(), Reference< XInterface >(), + InteractionClassification_QUERY, eMode, rDocumentName, bPasswordToModify ); + maRequest <<= aRequest; + } + break; + case DocPasswordRequestType_MS: + { + DocumentMSPasswordRequest2 aRequest( OUString(), Reference< XInterface >(), + InteractionClassification_QUERY, eMode, rDocumentName, bPasswordToModify ); + maRequest <<= aRequest; + } + break; + /* no 'default', so compilers will complain about missing + implementation of a new enum value. */ + } + + maContinuations.realloc( 2 ); + maContinuations[ 0 ].set( mpAbort = new AbortContinuation ); + maContinuations[ 1 ].set( mpPassword = new PasswordContinuation ); +} + +DocPasswordRequest::~DocPasswordRequest() +{ +} + +/*uno::*/Any SAL_CALL DocPasswordRequest::queryInterface( const /*uno::*/Type& rType ) throw (RuntimeException) +{ + return ::cppu::queryInterface ( rType, + // OWeakObject interfaces + dynamic_cast< XInterface* > ( (XInteractionRequest *) this ), + static_cast< XWeak* > ( this ), + // my own interfaces + static_cast< XInteractionRequest* > ( this ) ); +} + +void SAL_CALL DocPasswordRequest::acquire( ) throw () +{ + OWeakObject::acquire(); +} + +void SAL_CALL DocPasswordRequest::release( ) throw () +{ + OWeakObject::release(); +} + +sal_Bool DocPasswordRequest::isAbort() const +{ + return mpAbort->isSelected(); +} + +sal_Bool DocPasswordRequest::isPassword() const +{ + return mpPassword->isSelected(); +} + +OUString DocPasswordRequest::getPassword() const +{ + return mpPassword->getPassword(); +} + +OUString DocPasswordRequest::getPasswordToModify() const +{ + return mpPassword->getPasswordToModify(); +} + +sal_Bool DocPasswordRequest::getRecommendReadOnly() const +{ + return mpPassword->getRecommendReadOnly(); +} + +Any SAL_CALL DocPasswordRequest::getRequest() throw( RuntimeException ) +{ + return maRequest; +} + +Sequence< Reference< XInteractionContinuation > > SAL_CALL DocPasswordRequest::getContinuations() throw( RuntimeException ) +{ + return maContinuations; +} + +// ============================================================================ + +} // namespace comphelper + diff --git a/comphelper/source/misc/documentinfo.cxx b/comphelper/source/misc/documentinfo.cxx new file mode 100644 index 000000000000..aee3a8e005a6 --- /dev/null +++ b/comphelper/source/misc/documentinfo.cxx @@ -0,0 +1,197 @@ +/************************************************************************* + * + * 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/documentinfo.hxx" +#include "comphelper/namedvaluecollection.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/frame/XTitle.hpp> +/** === end UNO includes === **/ + +#include <cppuhelper/exc_hlp.hxx> + +#include <osl/diagnose.h> +#include <osl/thread.h> + +#include <boost/current_function.hpp> + +//........................................................................ +namespace comphelper { +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::frame::XTitle; + using ::com::sun::star::frame::XController; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::document::XDocumentPropertiesSupplier; + using ::com::sun::star::document::XDocumentProperties; + using ::com::sun::star::frame::XStorable; + using ::com::sun::star::beans::XPropertySetInfo; + using ::com::sun::star::frame::XTitle; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::frame::XFrame; + /** === end UNO using === **/ + + //==================================================================== + //= helper + //==================================================================== + namespace + { + ::rtl::OUString lcl_getTitle( const Reference< XInterface >& _rxComponent ) + { + Reference< XTitle > xTitle( _rxComponent, UNO_QUERY ); + if ( xTitle.is() ) + return xTitle->getTitle(); + return ::rtl::OUString(); + } + } + + //==================================================================== + //= DocumentInfo + //==================================================================== + //-------------------------------------------------------------------- + ::rtl::OUString DocumentInfo::getDocumentTitle( const Reference< XModel >& _rxDocument ) + { + ::rtl::OUString sTitle; + + if ( !_rxDocument.is() ) + return sTitle; + + ::rtl::OUString sDocURL; + try + { + // 1. ask the model and the controller for their XTitle::getTitle + sTitle = lcl_getTitle( _rxDocument ); + if ( sTitle.getLength() ) + return sTitle; + + Reference< XController > xController( _rxDocument->getCurrentController() ); + sTitle = lcl_getTitle( xController ); + if ( sTitle.getLength() ) + return sTitle; + + // work around a problem with embedded objects, which sometimes return + // private:object as URL + sDocURL = _rxDocument->getURL(); + if ( sDocURL.matchAsciiL( "private:", 8 ) ) + sDocURL = ::rtl::OUString(); + + // 2. if the document is not saved, yet, check the frame title + if ( sDocURL.getLength() == 0 ) + { + Reference< XFrame > xFrame; + if ( xController.is() ) + xFrame.set( xController->getFrame() ); + sTitle = lcl_getTitle( xFrame ); + if ( sTitle.getLength() ) + return sTitle; + } + + // 3. try the UNO DocumentInfo + Reference< XDocumentPropertiesSupplier > xDPS( _rxDocument, UNO_QUERY ); + if ( xDPS.is() ) + { + Reference< XDocumentProperties > xDocProps ( + xDPS->getDocumentProperties(), UNO_QUERY_THROW ); + OSL_ENSURE(xDocProps.is(), "no DocumentProperties"); + sTitle = xDocProps->getTitle(); + if ( sTitle.getLength() ) + return sTitle; + } + + // 4. try model arguments + NamedValueCollection aModelArgs( _rxDocument->getArgs() ); + sTitle = aModelArgs.getOrDefault( "Title", sTitle ); + if ( sTitle.getLength() ) + return sTitle; + + // 5. try the last segment of the document URL + // this formerly was an INetURLObject::getName( LAST_SEGMENT, true, DECODE_WITH_CHARSET ), + // but since we moved this code to comphelper, we do not have access to an INetURLObject anymore + // This heuristics here should be sufficient - finally, we will get an UNO title API in a not + // too distant future (hopefully), then this complete class is superfluous) + if ( sDocURL.getLength() == 0 ) + { + Reference< XStorable > xDocStorable( _rxDocument, UNO_QUERY_THROW ); + sDocURL = xDocStorable->getLocation(); + } + sal_Int32 nLastSepPos = sDocURL.lastIndexOf( '/' ); + if ( ( nLastSepPos != -1 ) && ( nLastSepPos == sDocURL.getLength() - 1 ) ) + { + sDocURL = sDocURL.copy( 0, nLastSepPos ); + nLastSepPos = sDocURL.lastIndexOf( '/' ); + } + sTitle = sDocURL.copy( nLastSepPos + 1 ); + + if ( sTitle.getLength() != 0 ) + return sTitle; + + // 5. + // <-- #i88104# (05-16-08) TKR: use the new XTitle Interface to get the Title --> + + Reference< XTitle > xTitle( _rxDocument, UNO_QUERY ); + if ( xTitle.is() ) + { + if ( xTitle->getTitle().getLength() != 0 ) + return xTitle->getTitle(); + } + } + catch ( const Exception& ) + { + ::com::sun::star::uno::Any caught( ::cppu::getCaughtException() ); + ::rtl::OString sMessage( "caught an exception!" ); + sMessage += "\ntype : "; + sMessage += ::rtl::OString( caught.getValueTypeName().getStr(), caught.getValueTypeName().getLength(), osl_getThreadTextEncoding() ); + sMessage += "\nmessage: "; + ::com::sun::star::uno::Exception exception; + caught >>= exception; + sMessage += ::rtl::OString( exception.Message.getStr(), exception.Message.getLength(), osl_getThreadTextEncoding() ); + sMessage += "\nin function:\n"; + sMessage += BOOST_CURRENT_FUNCTION; + sMessage += "\n"; + OSL_ENSURE( false, sMessage ); + } + + return sTitle; + } + +//........................................................................ +} // namespace comphelper +//........................................................................ diff --git a/comphelper/source/misc/documentiologring.cxx b/comphelper/source/misc/documentiologring.cxx new file mode 100644 index 000000000000..5f07f8058fb3 --- /dev/null +++ b/comphelper/source/misc/documentiologring.cxx @@ -0,0 +1,179 @@ +/************************************************************************* + * + * 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/frame/DoubleInitializationException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +#include <comphelper_module.hxx> + +#include "documentiologring.hxx" + +using namespace ::com::sun::star; + +namespace comphelper +{ + +// ---------------------------------------------------------- +OSimpleLogRing::OSimpleLogRing( const uno::Reference< uno::XComponentContext >& /*xContext*/ ) +: m_aMessages( SIMPLELOGRING_SIZE ) +, m_bInitialized( sal_False ) +, m_bFull( sal_False ) +, m_nPos( 0 ) +{ +} + +// ---------------------------------------------------------- +OSimpleLogRing::~OSimpleLogRing() +{ +} + +// ---------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OSimpleLogRing::getSupportedServiceNames_static() +{ + uno::Sequence< rtl::OUString > aResult( 1 ); + aResult[0] = getServiceName_static(); + return aResult; +} + +// ---------------------------------------------------------- +::rtl::OUString SAL_CALL OSimpleLogRing::getImplementationName_static() +{ + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.logging.SimpleLogRing" ) ); +} + +// ---------------------------------------------------------- +::rtl::OUString SAL_CALL OSimpleLogRing::getSingletonName_static() +{ + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.logging.DocumentIOLogRing" ) ); +} + +// ---------------------------------------------------------- +::rtl::OUString SAL_CALL OSimpleLogRing::getServiceName_static() +{ + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.logging.SimpleLogRing" ) ); +} + +// ---------------------------------------------------------- +uno::Reference< uno::XInterface > SAL_CALL OSimpleLogRing::Create( const uno::Reference< uno::XComponentContext >& rxContext ) +{ + return static_cast< cppu::OWeakObject* >( new OSimpleLogRing( rxContext ) ); +} + +// XSimpleLogRing +// ---------------------------------------------------------- +void SAL_CALL OSimpleLogRing::logString( const ::rtl::OUString& aMessage ) throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + m_aMessages[m_nPos] = aMessage; + if ( ++m_nPos >= m_aMessages.getLength() ) + { + m_nPos = 0; + m_bFull = sal_True; + } + + // if used once then default initialized + m_bInitialized = sal_True; +} + +// ---------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OSimpleLogRing::getCollectedLog() throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + sal_Int32 nResLen = m_bFull ? m_aMessages.getLength() : m_nPos; + sal_Int32 nStart = m_bFull ? m_nPos : 0; + uno::Sequence< ::rtl::OUString > aResult( nResLen ); + + for ( sal_Int32 nInd = 0; nInd < nResLen; nInd++ ) + aResult[nInd] = m_aMessages[ ( nStart + nInd ) % m_aMessages.getLength() ]; + + // if used once then default initialized + m_bInitialized = sal_True; + + return aResult; +} + +// XInitialization +// ---------------------------------------------------------- +void SAL_CALL OSimpleLogRing::initialize( const uno::Sequence< uno::Any >& aArguments ) throw (uno::Exception, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_bInitialized ) + throw frame::DoubleInitializationException(); + + if ( !m_refCount ) + throw uno::RuntimeException(); // the object must be refcounted already! + + sal_Int32 nLen = 0; + if ( aArguments.getLength() == 1 && ( aArguments[0] >>= nLen ) && nLen ) + m_aMessages.realloc( nLen ); + else + throw lang::IllegalArgumentException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Nonnull size is expected as the first argument!" ) ), + uno::Reference< uno::XInterface >(), + 0 ); + + m_bInitialized = sal_True; +} + +// XServiceInfo +// ---------------------------------------------------------- +::rtl::OUString SAL_CALL OSimpleLogRing::getImplementationName() throw (uno::RuntimeException) +{ + return getImplementationName_static(); +} + +// ---------------------------------------------------------- +::sal_Bool SAL_CALL OSimpleLogRing::supportsService( const ::rtl::OUString& aServiceName ) throw (uno::RuntimeException) +{ + const uno::Sequence< rtl::OUString > & aSupportedNames = getSupportedServiceNames_static(); + for ( sal_Int32 nInd = 0; nInd < aSupportedNames.getLength(); nInd++ ) + { + if ( aSupportedNames[ nInd ].equals( aServiceName ) ) + return sal_True; + } + + return sal_False; +} + +// ---------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OSimpleLogRing::getSupportedServiceNames() throw (uno::RuntimeException) +{ + return getSupportedServiceNames_static(); +} + +} // namespace comphelper + +void createRegistryInfo_OSimpleLogRing() +{ + static ::comphelper::module::OAutoRegistration< ::comphelper::OSimpleLogRing > aAutoRegistration; + static ::comphelper::module::OSingletonRegistration< ::comphelper::OSimpleLogRing > aSingletonRegistration; +} diff --git a/comphelper/source/misc/documentiologring.hxx b/comphelper/source/misc/documentiologring.hxx new file mode 100644 index 000000000000..f9626ffe5d62 --- /dev/null +++ b/comphelper/source/misc/documentiologring.hxx @@ -0,0 +1,88 @@ +/************************************************************************* + * + * 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 __DOCUMENTIOLOGRING_HXX_ +#define __DOCUMENTIOLOGRING_HXX_ + +#include <com/sun/star/logging/XSimpleLogRing.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XInitialization.hpp> + +#include <osl/mutex.hxx> +#include <cppuhelper/implbase3.hxx> + +#define SIMPLELOGRING_SIZE 256 + +namespace comphelper +{ + +class OSimpleLogRing : public ::cppu::WeakImplHelper3< ::com::sun::star::logging::XSimpleLogRing, + ::com::sun::star::lang::XInitialization, + ::com::sun::star::lang::XServiceInfo > +{ + ::osl::Mutex m_aMutex; + ::com::sun::star::uno::Sequence< ::rtl::OUString > m_aMessages; + + sal_Bool m_bInitialized; + sal_Bool m_bFull; + sal_Int32 m_nPos; + +public: + OSimpleLogRing( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& xContext ); + virtual ~OSimpleLogRing(); + + static ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL + getSupportedServiceNames_static(); + + static ::rtl::OUString SAL_CALL getImplementationName_static(); + + static ::rtl::OUString SAL_CALL getSingletonName_static(); + + static ::rtl::OUString SAL_CALL getServiceName_static(); + + 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 >& rxContext ); + +// XSimpleLogRing + virtual void SAL_CALL logString( const ::rtl::OUString& aMessage ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getCollectedLog() throw (::com::sun::star::uno::RuntimeException); + +// 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); + +}; + +} // namespace comphelper + +#endif + diff --git a/comphelper/source/misc/evtlistenerhlp.cxx b/comphelper/source/misc/evtlistenerhlp.cxx new file mode 100644 index 000000000000..6511b9a9ecf7 --- /dev/null +++ b/comphelper/source/misc/evtlistenerhlp.cxx @@ -0,0 +1,52 @@ +/************************************************************************* + * + * 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/evtlistenerhlp.hxx" + +namespace comphelper +{ + OEventListenerHelper::OEventListenerHelper(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener>& + _rxListener) : m_xListener(_rxListener) + { + } + void SAL_CALL OEventListenerHelper::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(::com::sun::star::uno::RuntimeException) + { + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener> xRef = m_xListener; + if(xRef.is()) + xRef->disposing(Source); + } +} + + + + + + + + diff --git a/comphelper/source/misc/evtmethodhelper.cxx b/comphelper/source/misc/evtmethodhelper.cxx new file mode 100755 index 000000000000..e91adee3912b --- /dev/null +++ b/comphelper/source/misc/evtmethodhelper.cxx @@ -0,0 +1,77 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: evtlistenerhlp.cxx,v $ + * $Revision$ + * + * 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/evtmethodhelper.hxx" +#include "cppuhelper/typeprovider.hxx" + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Type; + +namespace comphelper +{ + + Sequence< ::rtl::OUString> getEventMethodsForType(const Type& type) + { + typelib_InterfaceTypeDescription *pType=0; + type.getDescription( (typelib_TypeDescription**)&pType); + + if(!pType) + return Sequence< ::rtl::OUString>(); + + Sequence< ::rtl::OUString> aNames(pType->nMembers); + ::rtl::OUString* pNames = aNames.getArray(); + for(sal_Int32 i=0;i<pType->nMembers;i++,++pNames) + { + // the decription reference + typelib_TypeDescriptionReference* pMemberDescriptionReference = pType->ppMembers[i]; + // the description for the reference + typelib_TypeDescription* pMemberDescription = NULL; + typelib_typedescriptionreference_getDescription(&pMemberDescription, pMemberDescriptionReference); + if (pMemberDescription) + { + typelib_InterfaceMemberTypeDescription* pRealMemberDescription = + reinterpret_cast<typelib_InterfaceMemberTypeDescription*>(pMemberDescription); + *pNames = pRealMemberDescription->pMemberName; + } + } + typelib_typedescription_release( (typelib_TypeDescription *)pType ); + return aNames; + } + +} + + + + + + + diff --git a/comphelper/source/misc/ihwrapnofilter.cxx b/comphelper/source/misc/ihwrapnofilter.cxx new file mode 100644 index 000000000000..1cbd1f09f4c6 --- /dev/null +++ b/comphelper/source/misc/ihwrapnofilter.cxx @@ -0,0 +1,117 @@ +/************************************************************************* +* + * 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. + * +************************************************************************/ + +#include "precompiled_comphelper.hxx" + +#include "comphelper/ihwrapnofilter.hxx" +#include <com/sun/star/document/NoSuchFilterRequest.hpp> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + + using namespace ::com::sun::star; + + //---------------------------------------------------------------------------------------------------- + OIHWrapNoFilterDialog::OIHWrapNoFilterDialog( uno::Reference< task::XInteractionHandler > xInteraction ) + :m_xInter( xInteraction ) + { + } + + OIHWrapNoFilterDialog::~OIHWrapNoFilterDialog() + { + } + + //---------------------------------------------------------------------------------------------------- + uno::Sequence< ::rtl::OUString > SAL_CALL OIHWrapNoFilterDialog::impl_staticGetSupportedServiceNames() + { + uno::Sequence< ::rtl::OUString > aRet(1); + aRet[0] = ::rtl::OUString::createFromAscii("com.sun.star.task.InteractionHandlerWrapper"); + return aRet; + } + + ::rtl::OUString SAL_CALL OIHWrapNoFilterDialog::impl_staticGetImplementationName() + { + return ::rtl::OUString::createFromAscii("com.sun.star.comp.task.InteractionHandlerWrapper"); + } + + //---------------------------------------------------------------------------------------------------- + // XInteractionHandler + //---------------------------------------------------------------------------------------------------- + void SAL_CALL OIHWrapNoFilterDialog::handle( const uno::Reference< task::XInteractionRequest >& xRequest) + throw( com::sun::star::uno::RuntimeException ) + { + if( !m_xInter.is() ) + return; + + uno::Any aRequest = xRequest->getRequest(); + document::NoSuchFilterRequest aNoSuchFilterRequest; + if ( aRequest >>= aNoSuchFilterRequest ) + return; + else + m_xInter->handle( xRequest ); + } + + //---------------------------------------------------------------------------------------------------- + // XInitialization + //---------------------------------------------------------------------------------------------------- + void SAL_CALL OIHWrapNoFilterDialog::initialize( const uno::Sequence< uno::Any >& ) + throw ( uno::Exception, + uno::RuntimeException, + frame::DoubleInitializationException ) + { + } + + //---------------------------------------------------------------------------------------------------- + // XServiceInfo + //---------------------------------------------------------------------------------------------------- + + ::rtl::OUString SAL_CALL OIHWrapNoFilterDialog::getImplementationName() + throw ( uno::RuntimeException ) + { + return impl_staticGetImplementationName(); + } + + ::sal_Bool SAL_CALL OIHWrapNoFilterDialog::supportsService( const ::rtl::OUString& ServiceName ) + throw ( uno::RuntimeException ) + { + uno::Sequence< ::rtl::OUString > aSeq = impl_staticGetSupportedServiceNames(); + + for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) + if ( ServiceName.compareTo( aSeq[nInd] ) == 0 ) + return sal_True; + + return sal_False; + } + + uno::Sequence< ::rtl::OUString > SAL_CALL OIHWrapNoFilterDialog::getSupportedServiceNames() + throw ( uno::RuntimeException ) + { + return impl_staticGetSupportedServiceNames(); + } +} diff --git a/comphelper/source/misc/instancelocker.cxx b/comphelper/source/misc/instancelocker.cxx new file mode 100644 index 000000000000..c147217f1e7f --- /dev/null +++ b/comphelper/source/misc/instancelocker.cxx @@ -0,0 +1,512 @@ +/************************************************************************* + * + * 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_module.hxx" + +#include <com/sun/star/util/XCloseBroadcaster.hpp> +#include <com/sun/star/util/XCloseable.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/frame/XDesktop.hpp> +#include <com/sun/star/frame/DoubleInitializationException.hpp> +#include <com/sun/star/frame/DoubleInitializationException.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include "instancelocker.hxx" + +using namespace ::com::sun::star; + + +// ==================================================================== +// OInstanceLocker +// ==================================================================== + +// -------------------------------------------------------- +OInstanceLocker::OInstanceLocker( const uno::Reference< uno::XComponentContext >& xContext ) +: m_xContext( xContext ) +, m_pLockListener( NULL ) +, m_pListenersContainer( NULL ) +, m_bDisposed( sal_False ) +, m_bInitialized( sal_False ) +{ +} + +// -------------------------------------------------------- +OInstanceLocker::~OInstanceLocker() +{ + if ( !m_bDisposed ) + { + m_refCount++; // to call dispose + try { + dispose(); + } + catch ( uno::RuntimeException& ) + {} + } + + if ( m_pListenersContainer ) + { + delete m_pListenersContainer; + m_pListenersContainer = NULL; + } +} + +// XComponent +// -------------------------------------------------------- +void SAL_CALL OInstanceLocker::dispose() + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( m_bDisposed ) + throw lang::DisposedException(); + + lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) ); + if ( m_pListenersContainer ) + m_pListenersContainer->disposeAndClear( aSource ); + + if ( m_xLockListener.is() ) + { + if ( m_pLockListener ) + { + m_pLockListener->Dispose(); + m_pLockListener = NULL; + } + m_xLockListener = uno::Reference< uno::XInterface >(); + } + + m_bDisposed = sal_True; +} + +// -------------------------------------------------------- +void SAL_CALL OInstanceLocker::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_bDisposed ) + throw lang::DisposedException(); // TODO + + if ( !m_pListenersContainer ) + m_pListenersContainer = new ::cppu::OInterfaceContainerHelper( m_aMutex ); + + m_pListenersContainer->addInterface( xListener ); +} + +// -------------------------------------------------------- +void SAL_CALL OInstanceLocker::removeEventListener( const uno::Reference< lang::XEventListener >& xListener ) + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_pListenersContainer ) + m_pListenersContainer->removeInterface( xListener ); +} + +// XInitialization +// -------------------------------------------------------- +void SAL_CALL OInstanceLocker::initialize( const uno::Sequence< uno::Any >& aArguments ) + throw (uno::Exception, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_bInitialized ) + throw frame::DoubleInitializationException(); + + if ( m_bDisposed ) + throw lang::DisposedException(); // TODO + + if ( !m_refCount ) + throw uno::RuntimeException(); // the object must be refcounted already! + + uno::Reference< uno::XInterface > xInstance; + uno::Reference< embed::XActionsApproval > xApproval; + sal_Int32 nModes = 0; + + try + { + sal_Int32 nLen = aArguments.getLength(); + if ( nLen < 2 || nLen > 3 ) + throw lang::IllegalArgumentException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Wrong count of parameters!" ) ), + uno::Reference< uno::XInterface >(), + 0 ); + + if ( !( aArguments[0] >>= xInstance ) || !xInstance.is() ) + throw lang::IllegalArgumentException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Nonempty reference is expected as the first argument!" ) ), + uno::Reference< uno::XInterface >(), + 0 ); + + if ( + !( aArguments[1] >>= nModes ) || + ( + !( nModes & embed::Actions::PREVENT_CLOSE ) && + !( nModes & embed::Actions::PREVENT_TERMINATION ) + ) + ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("The correct modes set is expected as the second argument!" ) ), + uno::Reference< uno::XInterface >(), + 0 ); + } + + if ( nLen == 3 && !( aArguments[2] >>= xApproval ) ) + throw lang::IllegalArgumentException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("If the third argument is provided, it must be XActionsApproval implementation!" ) ), + uno::Reference< uno::XInterface >(), + 0 ); + + m_pLockListener = new OLockListener( uno::Reference< lang::XComponent > ( static_cast< lang::XComponent* >( this ) ), + xInstance, + nModes, + xApproval ); + m_xLockListener = uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( m_pLockListener ) ); + m_pLockListener->Init(); + } + catch( uno::Exception& ) + { + dispose(); + throw; + } + + m_bInitialized = sal_True; +} + + +// XServiceInfo +// -------------------------------------------------------- +::rtl::OUString SAL_CALL OInstanceLocker::getImplementationName( ) + throw (uno::RuntimeException) +{ + return getImplementationName_static(); +} + +// -------------------------------------------------------- +::sal_Bool SAL_CALL OInstanceLocker::supportsService( const ::rtl::OUString& ServiceName ) + throw (uno::RuntimeException) +{ + uno::Sequence< ::rtl::OUString > aSeq = getSupportedServiceNames(); + + for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) + if ( ServiceName.compareTo( aSeq[nInd] ) == 0 ) + return sal_True; + + return sal_False; +} + +// -------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OInstanceLocker::getSupportedServiceNames() + throw (uno::RuntimeException) +{ + return getSupportedServiceNames_static(); +} + +// Static methods +// -------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OInstanceLocker::getSupportedServiceNames_static() +{ + const rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.embed.InstanceLocker" ) ); + return uno::Sequence< rtl::OUString >( &aServiceName, 1 ); +} + +// -------------------------------------------------------- +::rtl::OUString SAL_CALL OInstanceLocker::getImplementationName_static() +{ + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.embed.InstanceLocker" ) ); +} + +// -------------------------------------------------------- +uno::Reference< uno::XInterface > SAL_CALL OInstanceLocker::Create( + const uno::Reference< uno::XComponentContext >& rxContext ) +{ + return static_cast< cppu::OWeakObject * >( new OInstanceLocker( rxContext ) ); +} + + + +// ==================================================================== +// OLockListener +// ==================================================================== + +// -------------------------------------------------------- +OLockListener::OLockListener( const uno::WeakReference< lang::XComponent >& xWrapper, + const uno::Reference< uno::XInterface >& xInstance, + sal_Int32 nMode, + const uno::Reference< embed::XActionsApproval > xApproval ) +: m_xInstance( xInstance ) +, m_xApproval( xApproval ) +, m_xWrapper( xWrapper ) +, m_bDisposed( sal_False ) +, m_bInitialized( sal_False ) +, m_nMode( nMode ) +{ +} + +// -------------------------------------------------------- +OLockListener::~OLockListener() +{ +} + +// -------------------------------------------------------- +void OLockListener::Dispose() +{ + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + + if ( m_bDisposed ) + return; + + if ( m_nMode & embed::Actions::PREVENT_CLOSE ) + { + try + { + uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY ); + if ( xCloseBroadcaster.is() ) + xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) ); + + uno::Reference< util::XCloseable > xCloseable( m_xInstance, uno::UNO_QUERY ); + if ( xCloseable.is() ) + xCloseable->close( sal_True ); + } + catch( uno::Exception& ) + {} + } + + if ( m_nMode & embed::Actions::PREVENT_TERMINATION ) + { + try + { + uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW ); + xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) ); + } + catch( uno::Exception& ) + {} + } + + m_xInstance = uno::Reference< uno::XInterface >(); + m_bDisposed = sal_True; +} + +// XEventListener +// -------------------------------------------------------- +void SAL_CALL OLockListener::disposing( const lang::EventObject& aEvent ) + throw (uno::RuntimeException) +{ + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + + // object is disposed + if ( aEvent.Source == m_xInstance ) + { + // the object does not listen for anything any more + m_nMode = 0; + + // dispose the wrapper; + uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY ); + aGuard.clear(); + if ( xComponent.is() ) + { + try { xComponent->dispose(); } + catch( uno::Exception& ){} + } + } +} + + +// XCloseListener +// -------------------------------------------------------- +void SAL_CALL OLockListener::queryClosing( const lang::EventObject& aEvent, sal_Bool ) + throw (util::CloseVetoException, uno::RuntimeException) +{ + // GetsOwnership parameter is always ignored, the user of the service must close the object always + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + if ( !m_bDisposed && aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_CLOSE ) ) + { + try + { + uno::Reference< embed::XActionsApproval > xApprove = m_xApproval; + + // unlock the mutex here + aGuard.clear(); + + if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_CLOSE ) ) + throw util::CloseVetoException(); + } + catch( util::CloseVetoException& ) + { + // rethrow this exception + throw; + } + catch( uno::Exception& ) + { + // no action should be done + } + } +} + +// -------------------------------------------------------- +void SAL_CALL OLockListener::notifyClosing( const lang::EventObject& aEvent ) + throw (uno::RuntimeException) +{ + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + + // object is closed, no reason to listen + if ( aEvent.Source == m_xInstance ) + { + uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( aEvent.Source, uno::UNO_QUERY ); + if ( xCloseBroadcaster.is() ) + { + xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) ); + m_nMode &= ~embed::Actions::PREVENT_CLOSE; + if ( !m_nMode ) + { + // dispose the wrapper; + uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY ); + aGuard.clear(); + if ( xComponent.is() ) + { + try { xComponent->dispose(); } + catch( uno::Exception& ){} + } + } + } + } +} + + +// XTerminateListener +// -------------------------------------------------------- +void SAL_CALL OLockListener::queryTermination( const lang::EventObject& aEvent ) + throw (frame::TerminationVetoException, uno::RuntimeException) +{ + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + if ( aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_TERMINATION ) ) + { + try + { + uno::Reference< embed::XActionsApproval > xApprove = m_xApproval; + + // unlock the mutex here + aGuard.clear(); + + if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_TERMINATION ) ) + throw frame::TerminationVetoException(); + } + catch( frame::TerminationVetoException& ) + { + // rethrow this exception + throw; + } + catch( uno::Exception& ) + { + // no action should be done + } + } +} + +// -------------------------------------------------------- +void SAL_CALL OLockListener::notifyTermination( const lang::EventObject& aEvent ) + throw (uno::RuntimeException) +{ + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + + // object is terminated, no reason to listen + if ( aEvent.Source == m_xInstance ) + { + uno::Reference< frame::XDesktop > xDesktop( aEvent.Source, uno::UNO_QUERY ); + if ( xDesktop.is() ) + { + try + { + xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) ); + m_nMode &= ~embed::Actions::PREVENT_TERMINATION; + if ( !m_nMode ) + { + // dispose the wrapper; + uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY ); + aGuard.clear(); + if ( xComponent.is() ) + { + try { xComponent->dispose(); } + catch( uno::Exception& ){} + } + } + } + catch( uno::Exception& ) + {} + } + } +} + + +// XInitialization +// -------------------------------------------------------- +sal_Bool OLockListener::Init() +{ + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + + if ( m_bDisposed || m_bInitialized ) + return sal_False; + + try + { + if ( m_nMode & embed::Actions::PREVENT_CLOSE ) + { + uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY_THROW ); + xCloseBroadcaster->addCloseListener( static_cast< util::XCloseListener* >( this ) ); + } + + if ( m_nMode & embed::Actions::PREVENT_TERMINATION ) + { + uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW ); + xDesktop->addTerminateListener( static_cast< frame::XTerminateListener* >( this ) ); + } + } + catch( uno::Exception& ) + { + // dispose the wrapper; + uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY ); + aGuard.clear(); + if ( xComponent.is() ) + { + try { xComponent->dispose(); } + catch( uno::Exception& ){} + } + + throw; + } + + m_bInitialized = sal_True; + + return sal_True; +} + +void createRegistryInfo_OInstanceLocker() +{ + static ::comphelper::module::OAutoRegistration< OInstanceLocker > aAutoRegistration; +} diff --git a/comphelper/source/misc/instancelocker.hxx b/comphelper/source/misc/instancelocker.hxx new file mode 100644 index 000000000000..73800e3cee6f --- /dev/null +++ b/comphelper/source/misc/instancelocker.hxx @@ -0,0 +1,133 @@ +/************************************************************************* + * + * 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 __INSTANCELOCKER_HXX_ +#define __INSTANCELOCKER_HXX_ + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/util/XCloseListener.hpp> +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/embed/XActionsApproval.hpp> +#include <com/sun/star/embed/Actions.hpp> +#include <cppuhelper/weakref.hxx> +#include <osl/mutex.hxx> +#include <cppuhelper/implbase3.hxx> +#include <cppuhelper/implbase2.hxx> +#include <cppuhelper/interfacecontainer.h> + + +class OLockListener; + +// the service is implemented as a wrapper to be able to die by refcount +// the disposing mechanics is required for java related scenarios +class OInstanceLocker : public ::cppu::WeakImplHelper3< ::com::sun::star::lang::XComponent, + ::com::sun::star::lang::XInitialization, + ::com::sun::star::lang::XServiceInfo > +{ + ::osl::Mutex m_aMutex; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > m_xContext; + + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xLockListener; + OLockListener* m_pLockListener; + + ::cppu::OInterfaceContainerHelper* m_pListenersContainer; // list of listeners + + sal_Bool m_bDisposed; + sal_Bool m_bInitialized; + +public: + OInstanceLocker( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& xContext ); + ~OInstanceLocker(); + + static ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL + getSupportedServiceNames_static(); + + static ::rtl::OUString SAL_CALL getImplementationName_static(); + + 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 >& rxContext ); + +// XComponent + virtual void SAL_CALL dispose() throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& aListener ) throw (::com::sun::star::uno::RuntimeException); + +// 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); + +}; + + +class OLockListener : public ::cppu::WeakImplHelper2< ::com::sun::star::util::XCloseListener, + ::com::sun::star::frame::XTerminateListener > +{ + ::osl::Mutex m_aMutex; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xInstance; + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XActionsApproval > m_xApproval; + + ::com::sun::star::uno::WeakReference< ::com::sun::star::lang::XComponent > m_xWrapper; + + sal_Bool m_bDisposed; + sal_Bool m_bInitialized; + + sal_Int32 m_nMode; + +public: + OLockListener( const ::com::sun::star::uno::WeakReference< ::com::sun::star::lang::XComponent >& xWrapper, + const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& xInstance, + sal_Int32 nMode, + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XActionsApproval > xApproval ); + + ~OLockListener(); + + sal_Bool Init(); + void Dispose(); + +// XEventListener + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); + +// XCloseListener + virtual void SAL_CALL queryClosing( const ::com::sun::star::lang::EventObject& Source, sal_Bool GetsOwnership ) throw (::com::sun::star::util::CloseVetoException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL notifyClosing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); + +// XTerminateListener + virtual void SAL_CALL queryTermination( const ::com::sun::star::lang::EventObject& Event ) throw (::com::sun::star::frame::TerminationVetoException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL notifyTermination( const ::com::sun::star::lang::EventObject& Event ) throw (::com::sun::star::uno::RuntimeException); + +}; + +#endif + diff --git a/comphelper/source/misc/interaction.cxx b/comphelper/source/misc/interaction.cxx new file mode 100644 index 000000000000..c97f879581e4 --- /dev/null +++ b/comphelper/source/misc/interaction.cxx @@ -0,0 +1,99 @@ +/************************************************************************* + * + * 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/interaction.hxx> +#include <osl/diagnose.h> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::task; + + //========================================================================= + //= OInteractionPassword + //========================================================================= + //-------------------------------------------------------------------- + void SAL_CALL OInteractionPassword::setPassword( const ::rtl::OUString& _Password ) throw (RuntimeException) + { + m_sPassword = _Password;; + } + + //-------------------------------------------------------------------- + ::rtl::OUString SAL_CALL OInteractionPassword::getPassword( ) throw (RuntimeException) + { + return m_sPassword; + } + + //========================================================================= + //= OInteractionRequest + //========================================================================= + //------------------------------------------------------------------------- + OInteractionRequest::OInteractionRequest(const Any& _rRequestDescription) + :m_aRequest(_rRequestDescription) + { + } + + //------------------------------------------------------------------------- + void OInteractionRequest::addContinuation(const Reference< XInteractionContinuation >& _rxContinuation) + { + OSL_ENSURE(_rxContinuation.is(), "OInteractionRequest::addContinuation: invalid argument!"); + if (_rxContinuation.is()) + { + sal_Int32 nOldLen = m_aContinuations.getLength(); + m_aContinuations.realloc(nOldLen + 1); + m_aContinuations[nOldLen] = _rxContinuation; + } + } + + //------------------------------------------------------------------------- + void OInteractionRequest::clearContinuations() + { + m_aContinuations.realloc(0); + } + + //------------------------------------------------------------------------- + Any SAL_CALL OInteractionRequest::getRequest( ) throw(RuntimeException) + { + return m_aRequest; + } + + //------------------------------------------------------------------------- + Sequence< Reference< XInteractionContinuation > > SAL_CALL OInteractionRequest::getContinuations( ) throw(RuntimeException) + { + return m_aContinuations; + } + +//......................................................................... +} // namespace comphelper +//......................................................................... + + diff --git a/comphelper/source/misc/legacysingletonfactory.cxx b/comphelper/source/misc/legacysingletonfactory.cxx new file mode 100644 index 000000000000..cfc1793e7db2 --- /dev/null +++ b/comphelper/source/misc/legacysingletonfactory.cxx @@ -0,0 +1,197 @@ +/************************************************************************* + * + * 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/legacysingletonfactory.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +/** === end UNO includes === **/ + +#include <cppuhelper/implbase2.hxx> + +#include <algorithm> + +//........................................................................ +namespace comphelper +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::lang::XSingleComponentFactory; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::lang::XServiceInfo; + using ::com::sun::star::lang::XInitialization; + /** === end UNO using === **/ + + //==================================================================== + //= LegacySingletonFactory + //==================================================================== + typedef ::cppu::WeakImplHelper2 < XServiceInfo + , XSingleComponentFactory + > LegacySingletonFactory_Base; + + class COMPHELPER_DLLPRIVATE LegacySingletonFactory : public LegacySingletonFactory_Base + { + public: + LegacySingletonFactory( + ::cppu::ComponentFactoryFunc _componentFactoryFunc, const ::rtl::OUString& _rImplementationName, + const Sequence< ::rtl::OUString >& _rServiceNames, rtl_ModuleCount* _pModCount + ); + + // 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); + + // XSingleComponentFactory + virtual Reference< XInterface > SAL_CALL createInstanceWithContext( const Reference< XComponentContext >& Context ) throw (Exception, RuntimeException); + virtual Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext( const Sequence< Any >& Arguments, const Reference< XComponentContext >& Context ) throw (Exception, RuntimeException); + + protected: + ~LegacySingletonFactory(); + + private: + /** creates m_xInstance, returns whether it actually was created (<TRUE/>) or existed before (<FALSE/> + */ + bool impl_nts_ensureInstance( const Reference< XComponentContext >& _rxContext ); + + private: + ::osl::Mutex m_aMutex; + ::cppu::ComponentFactoryFunc m_componentFactoryFunc; + ::rtl::OUString m_sImplementationName; + Sequence< ::rtl::OUString > m_aServiceNames; + rtl_ModuleCount* m_pModuleCount; + Reference< XInterface > m_xTheInstance; + }; + + //-------------------------------------------------------------------- + LegacySingletonFactory::LegacySingletonFactory( ::cppu::ComponentFactoryFunc _componentFactoryFunc, const ::rtl::OUString& _rImplementationName, + const Sequence< ::rtl::OUString >& _rServiceNames, rtl_ModuleCount* _pModCount ) + :m_componentFactoryFunc ( _componentFactoryFunc ) + ,m_sImplementationName ( _rImplementationName ) + ,m_aServiceNames ( _rServiceNames ) + ,m_pModuleCount ( _pModCount ) + ,m_xTheInstance ( ) + { + if ( m_pModuleCount ) + m_pModuleCount->acquire( m_pModuleCount ); + } + + //-------------------------------------------------------------------- + LegacySingletonFactory::~LegacySingletonFactory() + { + if ( m_pModuleCount ) + m_pModuleCount->release( m_pModuleCount ); + } + + //-------------------------------------------------------------------- + ::rtl::OUString SAL_CALL LegacySingletonFactory::getImplementationName( ) throw (RuntimeException) + { + return m_sImplementationName; + } + + //-------------------------------------------------------------------- + ::sal_Bool SAL_CALL LegacySingletonFactory::supportsService( const ::rtl::OUString& _rServiceName ) throw (RuntimeException) + { + Sequence< ::rtl::OUString > aServices( getSupportedServiceNames() ); + 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 LegacySingletonFactory::getSupportedServiceNames( ) throw (RuntimeException) + { + return m_aServiceNames; + } + + //-------------------------------------------------------------------- + bool LegacySingletonFactory::impl_nts_ensureInstance( const Reference< XComponentContext >& _rxContext ) + { + if ( m_xTheInstance.is() ) + return false; + + m_xTheInstance = (*m_componentFactoryFunc)( _rxContext ); + if ( !m_xTheInstance.is() ) + throw RuntimeException(); + + return true; // true -> "was newly created" + } + + //-------------------------------------------------------------------- + Reference< XInterface > SAL_CALL LegacySingletonFactory::createInstanceWithContext( const Reference< XComponentContext >& _rxContext ) throw (Exception, RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + impl_nts_ensureInstance( _rxContext ); + + return m_xTheInstance; + } + + //-------------------------------------------------------------------- + Reference< XInterface > SAL_CALL LegacySingletonFactory::createInstanceWithArgumentsAndContext( const Sequence< Any >& _rArguments, const Reference< XComponentContext >& _rxContext ) throw (Exception, RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !impl_nts_ensureInstance( _rxContext ) ) + throw RuntimeException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Instance already created before, unable to initialize it." ) ), + *this + ); + + Reference< XInitialization > xInit( m_xTheInstance, UNO_QUERY_THROW ); + xInit->initialize( _rArguments ); + + return m_xTheInstance; + } + + //==================================================================== + //= createLegacySingletonFactory + //==================================================================== + Reference< XSingleComponentFactory > createLegacySingletonFactory( + ::cppu::ComponentFactoryFunc _componentFactoryFunc, const ::rtl::OUString& _rImplementationName, + const Sequence< ::rtl::OUString >& _rServiceNames, rtl_ModuleCount* _pModCount ) + { + return new LegacySingletonFactory( _componentFactoryFunc, _rImplementationName, _rServiceNames, _pModCount ); + } + + +//........................................................................ +} // namespace comphelper +//........................................................................ diff --git a/comphelper/source/misc/listenernotification.cxx b/comphelper/source/misc/listenernotification.cxx new file mode 100644 index 000000000000..a9a14a0b9b72 --- /dev/null +++ b/comphelper/source/misc/listenernotification.cxx @@ -0,0 +1,127 @@ +/************************************************************************* + * + * 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/listenernotification.hxx> + +/** === begin UNO includes === **/ +#include <com/sun/star/lang/DisposedException.hpp> +/** === end UNO includes === **/ + +//........................................................................ +namespace comphelper +{ +//........................................................................ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + + //==================================================================== + //= OListenerContainer + //==================================================================== + //-------------------------------------------------------------------- + OListenerContainer::OListenerContainer( ::osl::Mutex& _rMutex ) + :m_aListeners( _rMutex ) + { + } + + OListenerContainer::~OListenerContainer() {} + + //-------------------------------------------------------------------- + void OListenerContainer::impl_addListener( const Reference< XEventListener >& _rxListener ) + { + OSL_PRECOND( _rxListener.is(), "OListenerContainer::impl_addListener: a NULL listener?!" ); + if ( _rxListener.is() ) + m_aListeners.addInterface( _rxListener ); + } + + //-------------------------------------------------------------------- + void OListenerContainer::impl_removeListener( const Reference< XEventListener >& _rxListener ) + { +#if OSL_DEBUG_LEVEL > 0 + ::cppu::OInterfaceIteratorHelper aIter( m_aListeners ); + bool bFound = false; + while ( aIter.hasMoreElements() && !bFound ) + { + bFound = ( Reference< XInterface >( aIter.next() ) == _rxListener ); + } + OSL_ENSURE( bFound, "OListenerContainer::impl_removeListener: sure your listener handling is correct? The given listener is not registered!" ); +#endif + m_aListeners.removeInterface( _rxListener ); + } + + //-------------------------------------------------------------------- + void OListenerContainer::disposing( const EventObject& _rEventSource ) + { + m_aListeners.disposeAndClear( _rEventSource ); + } + + //-------------------------------------------------------------------- + void OListenerContainer::clear() + { + m_aListeners.clear(); + } + + //-------------------------------------------------------------------- + bool OListenerContainer::impl_notify( const EventObject& _rEvent ) SAL_THROW(( Exception )) + { + ::cppu::OInterfaceIteratorHelper aIter( m_aListeners ); + bool bCancelled = false; + while ( aIter.hasMoreElements() && !bCancelled ) + { + Reference< XEventListener > xListener( static_cast< XEventListener* >( aIter.next() ) ); + if ( !xListener.is() ) + continue; + + try + { + bCancelled = !implNotify( xListener, _rEvent ); + } + catch( const DisposedException& e ) + { + // DisposedExceptions from the listener might indicate a + // broken connection to a different environment. + + OSL_ENSURE( e.Context.is(), "OListenerContainer::impl_notify: caught dispose exception with empty Context field" ); + + // If the exception stems from the listener then remove it + // from the list of listeners. If the Context field of the + // exception is empty this is interpreted to indicate the + // listener as well. + if ( e.Context == xListener || !e.Context.is() ) + aIter.remove(); + } + } + + return !bCancelled; + } + +//........................................................................ +} // namespace comphelper +//........................................................................ + diff --git a/comphelper/source/misc/locale.cxx b/comphelper/source/misc/locale.cxx new file mode 100644 index 000000000000..53c53f1c3c48 --- /dev/null +++ b/comphelper/source/misc/locale.cxx @@ -0,0 +1,683 @@ +/************************************************************************* + * + * 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/locale.hxx> + +//_______________________________________________ +// includes +#include <rtl/ustrbuf.hxx> + +//_______________________________________________ +// namespace + +namespace comphelper{ + +//----------------------------------------------- +const sal_Unicode Locale::SEPERATOR_LC = (sal_Unicode)'-'; +const sal_Unicode Locale::SEPERATOR_CV = (sal_Unicode)'_'; +const sal_Unicode Locale::SEPERATOR_CV_LINUX = (sal_Unicode)'.'; + +//----------------------------------------------- +const Locale Locale::X_DEFAULT() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("x"), + ::rtl::OUString::createFromAscii("default")); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::EN() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("en"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::EN_US() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("en"), + ::rtl::OUString::createFromAscii("US")); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::DE_DE() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("de"), + ::rtl::OUString::createFromAscii("DE")); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::DE_CH() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("de"), + ::rtl::OUString::createFromAscii("CH")); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::DE_AT() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("de"), + ::rtl::OUString::createFromAscii("AT")); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::AR() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("ar"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::CA() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("ca"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::CS() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("cs"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::DA() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("da"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::EL() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("el"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::ES() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("es"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::FI() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("fi"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::FR() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("fr"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::HE() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("he"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::HI_IN() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("hi"), + ::rtl::OUString::createFromAscii("IN")); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::HU() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("hu"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::IT() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("it"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::JA() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("ja"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::KO() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("ko"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::NL() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("nl"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::PL() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("pl"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::PT() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("pt"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::PT_BR() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("pt"), + ::rtl::OUString::createFromAscii("BR")); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::RU() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("ru"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::SK() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("sk"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::SL() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("sl"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::SV() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("sv"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::TH() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("th"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::TR() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("tr"), + ::rtl::OUString()); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::X_COMMENT() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("x"), + ::rtl::OUString::createFromAscii("comment")); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::X_TRANSLATE() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("x"), + ::rtl::OUString::createFromAscii("translate")); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::X_NOTRANSLATE() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("x"), + ::rtl::OUString::createFromAscii("notranslate")); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::ZH_CN() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("zh"), + ::rtl::OUString::createFromAscii("CN")); + return aLocale; +} + +//----------------------------------------------- +const Locale Locale::ZH_TW() +{ + static Locale aLocale( + ::rtl::OUString::createFromAscii("zh"), + ::rtl::OUString::createFromAscii("TW")); + return aLocale; +} + +//----------------------------------------------- +Locale::Locale(const ::rtl::OUString& sISO) + throw(Locale::MalFormedLocaleException) +{ + fromISO(sISO); +} + +//----------------------------------------------- +Locale::Locale(const ::rtl::OUString& sLanguage, + const ::rtl::OUString& sCountry , + const ::rtl::OUString& sVariant ) +{ + // Use set methods to check values too! + setLanguage(sLanguage); + setCountry (sCountry ); + setVariant (sVariant ); +} + +//----------------------------------------------- +Locale::Locale() +{ + // Initialize instance ... otherwhise user will + // may be get exceptions if he e.g. copy this instance ... + (*this) = X_NOTRANSLATE(); +} + +//----------------------------------------------- +Locale::Locale(const Locale& aCopy) +{ + (*this) = aCopy; // recycle assign operator +} + +//----------------------------------------------- +::rtl::OUString Locale::getLanguage() const +{ + return m_sLanguage; +} + +//----------------------------------------------- +::rtl::OUString Locale::getCountry() const +{ + return m_sCountry; +} + +//----------------------------------------------- +::rtl::OUString Locale::getVariant() const +{ + return m_sVariant; +} + +//----------------------------------------------- +void Locale::setLanguage(const ::rtl::OUString& sLanguage) +{ + m_sLanguage = sLanguage; +} + +//----------------------------------------------- +void Locale::setCountry(const ::rtl::OUString& sCountry) +{ + m_sCountry = sCountry; +} + +//----------------------------------------------- +void Locale::setVariant(const ::rtl::OUString& sVariant) +{ + m_sVariant = sVariant; +} + +//----------------------------------------------- +/* Attention: Use own interface methods to set the + different parts of this locale. Because the + check the incoming value and throw an exception + automaticly ... + */ +void Locale::fromISO(const ::rtl::OUString& sISO) + throw(Locale::MalFormedLocaleException) +{ + m_sLanguage = ::rtl::OUString(); + m_sCountry = ::rtl::OUString(); + m_sVariant = ::rtl::OUString(); + + ::rtl::OUString sParser(sISO); + sParser.trim(); + + sal_Int32 nStart = 0; + sal_Int32 nEnd = 0; + + // extract language part + nEnd = sParser.indexOf(SEPERATOR_LC, nStart); + if (nEnd<0) + { + setLanguage(sParser); + return; + } + setLanguage(sParser.copy(nStart, nEnd-nStart)); + nStart = nEnd+1; + + // extract country + nEnd = sParser.indexOf(SEPERATOR_CV, nStart); + if (nEnd<0) + nEnd = sParser.indexOf(SEPERATOR_CV_LINUX, nStart); + if (nEnd<0) + { + setCountry(sParser.copy(nStart, sParser.getLength()-nStart)); + return; + } + nStart = nEnd+1; + + // extract variant + setVariant(sParser.copy(nStart, sParser.getLength()-nStart)); +} + +//----------------------------------------------- +::rtl::OUString Locale::toISO() const +{ + ::rtl::OUStringBuffer sISO(64); + + sISO.append(m_sLanguage); + if (m_sCountry.getLength()) + { + sISO.append(SEPERATOR_LC); + sISO.append(m_sCountry); + + if (m_sVariant.getLength()) + { + sISO.append(SEPERATOR_CV); + sISO.append(m_sVariant); + } + } + + return sISO.makeStringAndClear(); +} + +//----------------------------------------------- +sal_Bool Locale::equals(const Locale& aComparable) const +{ + return ( + m_sLanguage.equals(aComparable.m_sLanguage) && + m_sCountry.equals (aComparable.m_sCountry ) && + m_sVariant.equals (aComparable.m_sVariant ) + ); +} + +//----------------------------------------------- +sal_Bool Locale::similar(const Locale& aComparable) const +{ + return (m_sLanguage.equals(aComparable.m_sLanguage)); +} + +//----------------------------------------------- +::std::vector< ::rtl::OUString >::const_iterator Locale::getFallback(const ::std::vector< ::rtl::OUString >& lISOList , + const ::rtl::OUString& sReferenceISO) + throw(Locale::MalFormedLocaleException) +{ + Locale aReference(sReferenceISO); + + // Note: The same language or "en"/"en-US" should be preferred as fallback. + // On the other side some localized variables doesnt use localzation in real. + // May be the use a "fix" value only ... marked as X-DEFAULT or X-NOTRANSLATE. + // At least it can be discussed, if any language is a valid fallback ... + // But in case some office functionality depends on that (that means real functionality instead + // of pure UI descriptions) we should do anything, so it can work. + + ::std::vector< ::rtl::OUString >::const_iterator pSimilar = lISOList.end(); + ::std::vector< ::rtl::OUString >::const_iterator pEN_US = lISOList.end(); + ::std::vector< ::rtl::OUString >::const_iterator pEN = lISOList.end(); + ::std::vector< ::rtl::OUString >::const_iterator pXDefault = lISOList.end(); + ::std::vector< ::rtl::OUString >::const_iterator pXNoTranslate = lISOList.end(); + ::std::vector< ::rtl::OUString >::const_iterator pAny = lISOList.end(); + + ::std::vector< ::rtl::OUString >::const_iterator pIt; + for ( pIt = lISOList.begin(); + pIt != lISOList.end() ; + ++pIt ) + { + Locale aCheck(*pIt); + // found Locale, which match with 100% => return it + if (aCheck.equals(aReference)) + return pIt; + + // found similar Locale => safe it as possible fallback + if ( + (pSimilar == lISOList.end()) && + (aCheck.similar(aReference)) + ) + { + pSimilar = pIt; + } + else + // found en-US => safe it as fallback + if ( + (pEN_US == lISOList.end()) && + (aCheck.equals(EN_US()) ) + ) + { + pEN_US = pIt; + } + else + // found en[-XX] => safe it as fallback + if ( + (pEN == lISOList.end() ) && + (aCheck.similar(EN_US())) + ) + { + pEN = pIt; + } + else + // found an explicit default value(!) => safe it as fallback + if ( + (pXDefault == lISOList.end()) && + (aCheck.equals(X_DEFAULT()) ) + ) + { + pXDefault = pIt; + } + else + // found an implicit default value(!) => safe it as fallback + if ( + (pXNoTranslate == lISOList.end()) && + (aCheck.equals(X_NOTRANSLATE()) ) + ) + { + pXNoTranslate = pIt; + } + else + // safe the first locale, which isn't an explicit fallback + // as "last possible fallback" + if (pAny == lISOList.end()) + pAny = pIt; + } + + if (pSimilar != lISOList.end()) + return pSimilar; + + if (pEN_US != lISOList.end()) + return pEN_US; + + if (pEN != lISOList.end()) + return pEN; + + if (pXDefault != lISOList.end()) + return pXDefault; + + if (pXNoTranslate != lISOList.end()) + return pXNoTranslate; + + if (pAny != lISOList.end()) + return pAny; + + return lISOList.end(); +} + +//----------------------------------------------- +sal_Bool Locale::getFallback(Locale& aLocale) +{ + // a) + // this was our last fallback! + // break any further calls to this method ... + if (aLocale.equals(X_NOTRANSLATE())) + return sal_False; + + // b) + // switch from X_DEFAULT to X_NOTRANSLATE + // next time we will go to a) + if (aLocale.equals(X_DEFAULT())) + { + aLocale = X_NOTRANSLATE(); + return sal_True; + } + + // c) + // switch from EN to X_DEFAULT + // next time we will go to b) + if (aLocale.equals(EN())) + { + aLocale = X_DEFAULT(); + return sal_True; + } + + // d) remove country from incoming locale + // e.g. "de-DE" => "de" or "en-US" => "en"! + if (aLocale.getCountry().getLength()) + { + aLocale.setCountry(::rtl::OUString()); + return sal_True; + } + + // e) "en-US" possible? + if (!aLocale.equals(EN_US())) + { + aLocale = EN_US(); + return sal_True; + } + + // f) no more fallbacks + return sal_False; +} + +//----------------------------------------------- +void Locale::operator=(const Locale& rCopy) +{ + // Take over these values without checking ... + // They was already checked if the copy was constructed + // and must be valid now! + m_sLanguage = rCopy.m_sLanguage; + m_sCountry = rCopy.m_sCountry; + m_sVariant = rCopy.m_sVariant; +} + +//----------------------------------------------- +sal_Bool Locale::operator==(const Locale& aComparable) const +{ + return equals(aComparable); +} + +//----------------------------------------------- +sal_Bool Locale::operator!=(const Locale& aComparable) const +{ + return !equals(aComparable); +} + +} // namespace comphelper + diff --git a/comphelper/source/misc/logging.cxx b/comphelper/source/misc/logging.cxx new file mode 100644 index 000000000000..445f2cbe6c14 --- /dev/null +++ b/comphelper/source/misc/logging.cxx @@ -0,0 +1,405 @@ +/************************************************************************* + * + * 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/logging.hxx> +#include <comphelper/componentcontext.hxx> + +/** === begin UNO includes === **/ +#include <com/sun/star/logging/LoggerPool.hpp> +#include <com/sun/star/logging/LogLevel.hpp> +#include <com/sun/star/resource/XResourceBundle.hpp> +#include <com/sun/star/resource/XResourceBundleLoader.hpp> +/** === end UNO includes === **/ + +#include <rtl/ustrbuf.hxx> + +//........................................................................ +namespace comphelper +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::logging::XLoggerPool; + using ::com::sun::star::logging::LoggerPool; + using ::com::sun::star::logging::XLogger; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::logging::XLogHandler; + using ::com::sun::star::resource::XResourceBundle; + using ::com::sun::star::resource::XResourceBundleLoader; + /** === end UNO using === **/ + namespace LogLevel = ::com::sun::star::logging::LogLevel; + + //==================================================================== + //= EventLogger_Impl - declaration + //==================================================================== + class EventLogger_Impl + { + private: + ::comphelper::ComponentContext m_aContext; + ::rtl::OUString m_sLoggerName; + Reference< XLogger > m_xLogger; + + public: + EventLogger_Impl( const Reference< XComponentContext >& _rxContext, const ::rtl::OUString& _rLoggerName ) + :m_aContext( _rxContext ) + ,m_sLoggerName( _rLoggerName ) + { + impl_createLogger_nothrow(); + } + + inline bool isValid() const { return m_xLogger.is(); } + inline const ::rtl::OUString& getName() const { return m_sLoggerName; } + inline const Reference< XLogger >& getLogger() const { return m_xLogger; } + inline const ::comphelper::ComponentContext& getContext() const { return m_aContext; } + + private: + void impl_createLogger_nothrow(); + }; + + //==================================================================== + //= EventLogger_Impl - implementation + //==================================================================== + //-------------------------------------------------------------------- + void EventLogger_Impl::impl_createLogger_nothrow() + { + try + { + Reference< XLoggerPool > xPool( LoggerPool::get( m_aContext.getUNOContext() ), UNO_QUERY_THROW ); + if ( m_sLoggerName.getLength() ) + m_xLogger = xPool->getNamedLogger( m_sLoggerName ); + else + m_xLogger = xPool->getDefaultLogger(); + } + catch( const Exception& e ) + { + (void)e; + OSL_ENSURE( false, "EventLogger_Impl::impl_createLogger_nothrow: caught an exception!" ); + } + } + + //==================================================================== + //= EventLogger + //==================================================================== + //-------------------------------------------------------------------- + EventLogger::EventLogger( const Reference< XComponentContext >& _rxContext, const ::rtl::OUString& _rLoggerName ) + :m_pImpl( new EventLogger_Impl( _rxContext, _rLoggerName ) ) + { + } + + //-------------------------------------------------------------------- + EventLogger::EventLogger( const Reference< XComponentContext >& _rxContext, const sal_Char* _pAsciiLoggerName ) + :m_pImpl( new EventLogger_Impl( _rxContext, ::rtl::OUString::createFromAscii( _pAsciiLoggerName ) ) ) + { + } + + //-------------------------------------------------------------------- + EventLogger::~EventLogger() + { + } + + //-------------------------------------------------------------------- + const ::rtl::OUString& EventLogger::getName() const + { + return m_pImpl->getName(); + } + + //-------------------------------------------------------------------- + sal_Int32 EventLogger::getLogLevel() const + { + try + { + if ( m_pImpl->isValid() ) + return m_pImpl->getLogger()->getLevel(); + } + catch( const Exception& e ) + { + (void)e; + OSL_ENSURE( false, "EventLogger::getLogLevel: caught an exception!" ); + } + + return LogLevel::OFF; + } + + //-------------------------------------------------------------------- + void EventLogger::setLogLevel( const sal_Int32 _nLogLevel ) const + { + try + { + if ( m_pImpl->isValid() ) + m_pImpl->getLogger()->setLevel( _nLogLevel ); + } + catch( const Exception& e ) + { + (void)e; + OSL_ENSURE( false, "EventLogger::setLogLevel: caught an exception!" ); + } + } + + //-------------------------------------------------------------------- + bool EventLogger::isLoggable( const sal_Int32 _nLogLevel ) const + { + if ( !m_pImpl->isValid() ) + return false; + + try + { + return m_pImpl->getLogger()->isLoggable( _nLogLevel ); + } + catch( const Exception& e ) + { + (void)e; + OSL_ENSURE( false, "EventLogger::isLoggable: caught an exception!" ); + } + + return false; + } + + //-------------------------------------------------------------------- + bool EventLogger::addLogHandler( const Reference< XLogHandler >& _rxLogHandler ) + { + try + { + if ( m_pImpl->isValid() ) + { + m_pImpl->getLogger()->addLogHandler( _rxLogHandler ); + return true; + } + } + catch( const Exception& e ) + { + (void)e; + OSL_ENSURE( false, "EventLogger::addLogHandler: caught an exception!" ); + } + return false; + } + + //-------------------------------------------------------------------- + bool EventLogger::removeLogHandler( const Reference< XLogHandler >& _rxLogHandler ) + { + try + { + if ( m_pImpl->isValid() ) + { + m_pImpl->getLogger()->removeLogHandler( _rxLogHandler ); + return true; + } + } + catch( const Exception& e ) + { + (void)e; + OSL_ENSURE( false, "EventLogger::removeLogHandler: caught an exception!" ); + } + return false; + } + + //-------------------------------------------------------------------- + namespace + { + void lcl_replaceParameter( ::rtl::OUString& _inout_Message, const ::rtl::OUString& _rPlaceHolder, const ::rtl::OUString& _rReplacement ) + { + sal_Int32 nPlaceholderPosition = _inout_Message.indexOf( _rPlaceHolder ); + OSL_ENSURE( nPlaceholderPosition >= 0, "lcl_replaceParameter: placeholder not found!" ); + if ( nPlaceholderPosition < 0 ) + return; + + _inout_Message = _inout_Message.replaceAt( nPlaceholderPosition, _rPlaceHolder.getLength(), _rReplacement ); + } + } + + //-------------------------------------------------------------------- + bool EventLogger::impl_log( const sal_Int32 _nLogLevel, + const sal_Char* _pSourceClass, const sal_Char* _pSourceMethod, const ::rtl::OUString& _rMessage, + const OptionalString& _rArgument1, const OptionalString& _rArgument2, + const OptionalString& _rArgument3, const OptionalString& _rArgument4, + const OptionalString& _rArgument5, const OptionalString& _rArgument6 ) const + { + // (if ::rtl::OUString had an indexOfAscii, we could save those ugly statics ...) + static ::rtl::OUString sPH1( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "$1$" ) ) ); + static ::rtl::OUString sPH2( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "$2$" ) ) ); + static ::rtl::OUString sPH3( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "$3$" ) ) ); + static ::rtl::OUString sPH4( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "$4$" ) ) ); + static ::rtl::OUString sPH5( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "$5$" ) ) ); + static ::rtl::OUString sPH6( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "$6$" ) ) ); + + ::rtl::OUString sMessage( _rMessage ); + if ( !!_rArgument1 ) + lcl_replaceParameter( sMessage, sPH1, *_rArgument1 ); + + if ( !!_rArgument2 ) + lcl_replaceParameter( sMessage, sPH2, *_rArgument2 ); + + if ( !!_rArgument3 ) + lcl_replaceParameter( sMessage, sPH3, *_rArgument3 ); + + if ( !!_rArgument4 ) + lcl_replaceParameter( sMessage, sPH4, *_rArgument4 ); + + if ( !!_rArgument5 ) + lcl_replaceParameter( sMessage, sPH5, *_rArgument5 ); + + if ( !!_rArgument6 ) + lcl_replaceParameter( sMessage, sPH6, *_rArgument6 ); + + try + { + Reference< XLogger > xLogger( m_pImpl->getLogger() ); + OSL_PRECOND( xLogger.is(), "EventLogger::impl_log: should never be called without a logger!" ); + if ( _pSourceClass && _pSourceMethod ) + { + xLogger->logp( + _nLogLevel, + ::rtl::OUString::createFromAscii( _pSourceClass ), + ::rtl::OUString::createFromAscii( _pSourceMethod ), + sMessage + ); + } + else + { + xLogger->log( _nLogLevel, sMessage ); + } + } + catch( const Exception& e ) + { + (void)e; + OSL_ENSURE( false, "EventLogger::impl_log: caught an exception!" ); + } + + return false; + } + + //==================================================================== + //= ResourceBasedEventLogger_Data + //==================================================================== + struct ResourceBasedEventLogger_Data + { + /// the base name of the resource bundle + ::rtl::OUString sBundleBaseName; + /// did we already attempt to load the bundle? + bool bBundleLoaded; + /// the lazily loaded bundle + Reference< XResourceBundle > xBundle; + + ResourceBasedEventLogger_Data() + :sBundleBaseName() + ,bBundleLoaded( false ) + ,xBundle() + { + } + }; + + //-------------------------------------------------------------------- + bool lcl_loadBundle_nothrow( const ComponentContext& _rContext, ResourceBasedEventLogger_Data& _rLoggerData ) + { + if ( _rLoggerData.bBundleLoaded ) + return _rLoggerData.xBundle.is(); + + // no matter what happens below, don't attempt creation ever again + _rLoggerData.bBundleLoaded = true; + + try + { + Reference< XResourceBundleLoader > xLoader( _rContext.getSingleton( "com.sun.star.resource.OfficeResourceLoader" ), UNO_QUERY_THROW ); + _rLoggerData.xBundle = Reference< XResourceBundle >( xLoader->loadBundle_Default( _rLoggerData.sBundleBaseName ), UNO_QUERY_THROW ); + } + catch( const Exception& e ) + { + (void)e; + OSL_ENSURE( false, "lcl_loadBundle_nothrow: caught an exception!" ); + } + + return _rLoggerData.xBundle.is(); + } + + //-------------------------------------------------------------------- + ::rtl::OUString lcl_loadString_nothrow( const Reference< XResourceBundle >& _rxBundle, const sal_Int32 _nMessageResID ) + { + OSL_PRECOND( _rxBundle.is(), "lcl_loadString_nothrow: this will crash!" ); + ::rtl::OUString sMessage; + try + { + ::rtl::OUStringBuffer aBuffer; + aBuffer.appendAscii( "string:" ); + aBuffer.append( _nMessageResID ); + OSL_VERIFY( _rxBundle->getDirectElement( aBuffer.makeStringAndClear() ) >>= sMessage ); + } + catch( const Exception& e ) + { + (void)e; + OSL_ENSURE( false, "lcl_loadString_nothrow: caught an exception!" ); + } + return sMessage; + } + + //==================================================================== + //= ResourceBasedEventLogger + //==================================================================== + //-------------------------------------------------------------------- + ResourceBasedEventLogger::ResourceBasedEventLogger( const Reference< XComponentContext >& _rxContext, const ::rtl::OUString& _rResourceBundleBaseName, + const ::rtl::OUString& _rLoggerName ) + :EventLogger( _rxContext, _rLoggerName ) + ,m_pData( new ResourceBasedEventLogger_Data ) + { + m_pData->sBundleBaseName = _rResourceBundleBaseName; + } + + //-------------------------------------------------------------------- + ResourceBasedEventLogger::ResourceBasedEventLogger( const Reference< XComponentContext >& _rxContext, const sal_Char* _pResourceBundleBaseName, + const sal_Char* _pAsciiLoggerName ) + :EventLogger( _rxContext, _pAsciiLoggerName ) + ,m_pData( new ResourceBasedEventLogger_Data ) + { + m_pData->sBundleBaseName = ::rtl::OUString::createFromAscii( _pResourceBundleBaseName ); + } + + //-------------------------------------------------------------------- + ::rtl::OUString ResourceBasedEventLogger::impl_loadStringMessage_nothrow( const sal_Int32 _nMessageResID ) const + { + ::rtl::OUString sMessage; + if ( lcl_loadBundle_nothrow( m_pImpl->getContext(), *m_pData ) ) + sMessage = lcl_loadString_nothrow( m_pData->xBundle, _nMessageResID ); + if ( sMessage.getLength() == 0 ) + { + ::rtl::OUStringBuffer aBuffer; + aBuffer.appendAscii( "<invalid event resource: '" ); + aBuffer.append( m_pData->sBundleBaseName ); + aBuffer.appendAscii( ":" ); + aBuffer.append( _nMessageResID ); + aBuffer.appendAscii( "'>" ); + sMessage = aBuffer.makeStringAndClear(); + } + return sMessage; + } + +//........................................................................ +} // namespace comphelper +//........................................................................ diff --git a/comphelper/source/misc/makefile.mk b/comphelper/source/misc/makefile.mk new file mode 100644 index 000000000000..cecba554b332 --- /dev/null +++ b/comphelper/source/misc/makefile.mk @@ -0,0 +1,101 @@ +#************************************************************************* +# +# 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=..$/.. +PRJNAME=comphelper +TARGET=misc + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES= \ + $(SLO)$/accessiblecomponenthelper.obj \ + $(SLO)$/accessiblecontexthelper.obj \ + $(SLO)$/accessibleeventbuffer.obj \ + $(SLO)$/accessibleeventnotifier.obj \ + $(SLO)$/accessiblekeybindinghelper.obj \ + $(SLO)$/accessibleselectionhelper.obj \ + $(SLO)$/accessibletexthelper.obj \ + $(SLO)$/accessiblewrapper.obj \ + $(SLO)$/accimplaccess.obj \ + $(SLO)$/anytostring.obj \ + $(SLO)$/asyncnotification.obj \ + $(SLO)$/componentcontext.obj \ + $(SLO)$/componentmodule.obj \ + $(SLO)$/configurationhelper.obj \ + $(SLO)$/docpasswordhelper.obj \ + $(SLO)$/docpasswordrequest.obj \ + $(SLO)$/documentinfo.obj \ + $(SLO)$/evtmethodhelper.obj \ + $(SLO)$/documentiologring.obj \ + $(SLO)$/evtlistenerhlp.obj \ + $(SLO)$/ihwrapnofilter.obj \ + $(SLO)$/instancelocker.obj \ + $(SLO)$/interaction.obj \ + $(SLO)$/legacysingletonfactory.obj \ + $(SLO)$/listenernotification.obj \ + $(SLO)$/locale.obj \ + $(SLO)$/logging.obj \ + $(SLO)$/mediadescriptor.obj \ + $(SLO)$/mimeconfighelper.obj \ + $(SLO)$/namedvaluecollection.obj \ + $(SLO)$/numberedcollection.obj \ + $(SLO)$/numbers.obj \ + $(SLO)$/officeresourcebundle.obj \ + $(SLO)$/officerestartmanager.obj \ + $(SLO)$/proxyaggregation.obj \ + $(SLO)$/querydeep.obj \ + $(SLO)$/regpathhelper.obj \ + $(SLO)$/scopeguard.obj \ + $(SLO)$/SelectionMultiplex.obj \ + $(SLO)$/sequenceashashmap.obj \ + $(SLO)$/sequence.obj \ + $(SLO)$/servicedecl.obj \ + $(SLO)$/serviceinfohelper.obj \ + $(SLO)$/sharedmutex.obj \ + $(SLO)$/synchronousdispatch.obj \ + $(SLO)$/storagehelper.obj \ + $(SLO)$/string.obj \ + $(SLO)$/types.obj \ + $(SLO)$/uieventslogger.obj \ + $(SLO)$/weakeventlistener.obj \ + $(SLO)$/weak.obj \ + $(SLO)$/comphelper_module.obj \ + $(SLO)$/comphelper_services.obj \ + $(SLO)$/componentbase.obj \ + $(SLO)$/stillreadwriteinteraction.obj \ + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/comphelper/source/misc/mediadescriptor.cxx b/comphelper/source/misc/mediadescriptor.cxx new file mode 100644 index 000000000000..9e02afe8c56c --- /dev/null +++ b/comphelper/source/misc/mediadescriptor.cxx @@ -0,0 +1,868 @@ +/************************************************************************* + * + * 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/mediadescriptor.hxx> +#include <comphelper/stillreadwriteinteraction.hxx> + +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/ucb/InteractiveIOException.hpp> +#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp> +#include <com/sun/star/ucb/CommandFailedException.hpp> +#include <com/sun/star/task/XInteractionAbort.hpp> +#include <com/sun/star/uri/XUriReferenceFactory.hpp> +#include <com/sun/star/uri/XUriReference.hpp> +#include <com/sun/star/ucb/PostCommandArgument2.hpp> +#include <com/sun/star/container/XNameAccess.hpp> + +#include <ucbhelper/interceptedinteraction.hxx> +#include <ucbhelper/content.hxx> +#include <ucbhelper/commandenvironment.hxx> +#include <ucbhelper/activedatasink.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/configurationhelper.hxx> + +#include <rtl/ustrbuf.hxx> + +//_______________________________________________ +// namespace + +namespace comphelper{ + +namespace css = ::com::sun::star; + +//_______________________________________________ +// definitions + +/*----------------------------------------------- + 10.03.2004 07:35 +-----------------------------------------------*/ +const ::rtl::OUString& MediaDescriptor::PROP_ABORTED() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Aborted")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_ASTEMPLATE() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("AsTemplate")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_CHARACTERSET() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("CharacterSet")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_COMPONENTDATA() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("ComponentData")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_DEEPDETECTION() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("DeepDetection")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_DETECTSERVICE() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("DetectService")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_DOCUMENTSERVICE() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("DocumentService")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_EXTENSION() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Extension")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_FILENAME() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("FileName")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_FILTERNAME() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("FilterName")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_FILTEROPTIONS() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("FilterOptions")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_FORMAT() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Format")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_FRAME() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Frame")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_FRAMENAME() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("FrameName")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_HIDDEN() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Hidden")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_INPUTSTREAM() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("InputStream")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_INTERACTIONHANDLER() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("InteractionHandler")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_JUMPMARK() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("JumpMark")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_MACROEXECUTIONMODE() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("MacroExecutionMode")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_MEDIATYPE() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("MediaType")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_MINIMIZED() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Minimized")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_NOAUTOSAVE() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("NoAutoSave")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_OPENNEWVIEW() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("OpenNewView")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_OUTPUTSTREAM() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("OutputStream")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_PATTERN() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Pattern")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_POSSIZE() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("PosSize")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_POSTDATA() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("PostData")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_POSTSTRING() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("PostString")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_PREVIEW() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Preview")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_READONLY() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("ReadOnly")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_REFERRER() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Referer")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_SILENT() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Silent")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_STATUSINDICATOR() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("StatusIndicator")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_STREAM() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Stream")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_STREAMFOROUTPUT() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("StreamForOutput")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_TEMPLATENAME() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("TemplateName")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_TEMPLATEREGIONNAME() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("TemplateRegionName")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_TYPENAME() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("TypeName")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_UCBCONTENT() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("UCBContent")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_UPDATEDOCMODE() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("UpdateDocMode")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_URL() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("URL")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_VERSION() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Version")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_VIEWID() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("ViewId")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_REPAIRPACKAGE() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("RepairPackage")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_DOCUMENTTITLE() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("DocumentTitle")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_MODEL() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Model")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_PASSWORD() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Password")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_TITLE() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Title")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_SALVAGEDFILE() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("SalvagedFile")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_VIEWONLY() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("ViewOnly")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_DOCUMENTBASEURL() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("DocumentBaseURL")); + return sProp; +} + +const ::rtl::OUString& MediaDescriptor::PROP_VIEWCONTROLLERNAME() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("ViewControllerName")); + return sProp; +} +/*----------------------------------------------- + 10.03.2004 08:09 +-----------------------------------------------*/ +MediaDescriptor::MediaDescriptor() + : SequenceAsHashMap() +{ +} + +/*----------------------------------------------- + 10.03.2004 08:09 +-----------------------------------------------*/ +MediaDescriptor::MediaDescriptor(const css::uno::Any& aSource) + : SequenceAsHashMap(aSource) +{ +} + +/*----------------------------------------------- + 10.03.2004 08:09 +-----------------------------------------------*/ +MediaDescriptor::MediaDescriptor(const css::uno::Sequence< css::beans::PropertyValue >& lSource) + : SequenceAsHashMap(lSource) +{ +} + +/*----------------------------------------------- + 10.03.2004 08:09 +-----------------------------------------------*/ +MediaDescriptor::MediaDescriptor(const css::uno::Sequence< css::beans::NamedValue >& lSource) + : SequenceAsHashMap(lSource) +{ +} + +/*----------------------------------------------- + 18.11.2004 13:37 +-----------------------------------------------*/ +sal_Bool MediaDescriptor::isStreamReadOnly() const +{ + static ::rtl::OUString CONTENTSCHEME_FILE = ::rtl::OUString::createFromAscii("file"); + static ::rtl::OUString CONTENTPROP_ISREADONLY = ::rtl::OUString::createFromAscii("IsReadOnly"); + static sal_Bool READONLY_FALLBACK = sal_False; + + sal_Bool bReadOnly = READONLY_FALLBACK; + + // check for explicit readonly state + const_iterator pIt = find(MediaDescriptor::PROP_READONLY()); + if (pIt != end()) + { + pIt->second >>= bReadOnly; + return bReadOnly; + } + + // streams based on post data are readonly by definition + pIt = find(MediaDescriptor::PROP_POSTDATA()); + if (pIt != end()) + return sal_True; + + // A XStream capsulate XInputStream and XOutputStream ... + // If it exists - the file must be open in read/write mode! + pIt = find(MediaDescriptor::PROP_STREAM()); + if (pIt != end()) + return sal_False; + + // Only file system content provider is able to provide XStream + // so for this content impossibility to create XStream triggers + // switch to readonly mode. + try + { + css::uno::Reference< css::ucb::XContent > xContent = getUnpackedValueOrDefault(MediaDescriptor::PROP_UCBCONTENT(), css::uno::Reference< css::ucb::XContent >()); + if (xContent.is()) + { + css::uno::Reference< css::ucb::XContentIdentifier > xId(xContent->getIdentifier(), css::uno::UNO_QUERY); + ::rtl::OUString aScheme; + if (xId.is()) + aScheme = xId->getContentProviderScheme(); + + if (aScheme.equalsIgnoreAsciiCase(CONTENTSCHEME_FILE)) + bReadOnly = sal_True; + else + { + ::ucbhelper::Content aContent(xContent, css::uno::Reference< css::ucb::XCommandEnvironment >()); + aContent.getPropertyValue(CONTENTPROP_ISREADONLY) >>= bReadOnly; + } + } + } + catch(const css::uno::RuntimeException& exRun) + { throw exRun; } + catch(const css::uno::Exception&) + {} + + return bReadOnly; +} + +// ---------------------------------------------------------------------------- + +css::uno::Any MediaDescriptor::getComponentDataEntry( const ::rtl::OUString& rName ) const +{ + SequenceAsHashMap aCompDataMap( getUnpackedValueOrDefault( PROP_COMPONENTDATA(), ComponentDataSequence() ) ); + SequenceAsHashMap::iterator aIt = aCompDataMap.find( rName ); + return (aIt == aCompDataMap.end()) ? css::uno::Any() : aIt->second; +} + +void MediaDescriptor::setComponentDataEntry( const ::rtl::OUString& rName, const css::uno::Any& rValue ) +{ + if( rValue.hasValue() ) + { + // get or craete the 'ComponentData' property entry + css::uno::Any& rCompDataAny = operator[]( PROP_COMPONENTDATA() ); + // check type, insert the value + OSL_ENSURE( !rCompDataAny.hasValue() || rCompDataAny.has< ComponentDataSequence >(), + "MediaDescriptor::setComponentDataEntry - incompatible 'ComponentData' property in media descriptor" ); + if( !rCompDataAny.hasValue() || rCompDataAny.has< ComponentDataSequence >() ) + { + // insert or overwrite the passed value + SequenceAsHashMap aCompDataMap( rCompDataAny ); + aCompDataMap[ rName ] = rValue; + // write back the sequence (sal_False = use NamedValue instead of PropertyValue) + rCompDataAny = aCompDataMap.getAsConstAny( sal_False ); + } + } + else + { + // if an empty Any is passed, clear the entry + clearComponentDataEntry( rName ); + } +} + +void MediaDescriptor::clearComponentDataEntry( const ::rtl::OUString& rName ) +{ + SequenceAsHashMap::iterator aPropertyIter = find( PROP_COMPONENTDATA() ); + if( aPropertyIter != end() ) + { + OSL_ENSURE( aPropertyIter->second.has< ComponentDataSequence >(), + "MediaDescriptor::clearComponentDataEntry - incompatible 'ComponentData' property in media descriptor" ); + if( aPropertyIter->second.has< ComponentDataSequence >() ) + { + // remove the value with the passed name + SequenceAsHashMap aCompDataMap( aPropertyIter->second ); + aCompDataMap.erase( rName ); + // write back the sequence, or remove it completely if it is empty + if( aCompDataMap.empty() ) + erase( aPropertyIter ); + else + aPropertyIter->second = aCompDataMap.getAsConstAny( sal_False ); + } + } +} + +/*----------------------------------------------- + 10.03.2004 09:02 +-----------------------------------------------*/ +sal_Bool MediaDescriptor::addInputStream() +{ + return impl_addInputStream( sal_True ); +} + +/*-----------------------------------------------*/ +sal_Bool MediaDescriptor::addInputStreamOwnLock() +{ + // Own lock file implementation + + sal_Bool bUseLock = sal_True; // the system file locking is used per default + try + { + + css::uno::Reference< css::uno::XInterface > xCommonConfig = ::comphelper::ConfigurationHelper::openConfig( + ::comphelper::getProcessServiceFactory(), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common" ) ), + ::comphelper::ConfigurationHelper::E_STANDARD ); + if ( !xCommonConfig.is() ) + throw css::uno::RuntimeException(); + + ::comphelper::ConfigurationHelper::readRelativeKey( + xCommonConfig, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Misc/" ) ), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseDocumentSystemFileLocking" ) ) ) >>= bUseLock; + } + catch( const css::uno::Exception& ) + { + } + + return impl_addInputStream( bUseLock ); +} + +/*-----------------------------------------------*/ +sal_Bool MediaDescriptor::impl_addInputStream( sal_Bool bLockFile ) +{ + // check for an already existing stream item first + const_iterator pIt = find(MediaDescriptor::PROP_INPUTSTREAM()); + if (pIt != end()) + return sal_True; + + try + { + // No stream available - create a new one + // a) data comes as PostData ... + pIt = find(MediaDescriptor::PROP_POSTDATA()); + if (pIt != end()) + { + const css::uno::Any& rPostData = pIt->second; + css::uno::Reference< css::io::XInputStream > xPostData; + rPostData >>= xPostData; + + return impl_openStreamWithPostData( xPostData ); + } + + // b) ... or we must get it from the given URL + ::rtl::OUString sURL = getUnpackedValueOrDefault(MediaDescriptor::PROP_URL(), ::rtl::OUString()); + if (!sURL.getLength()) + throw css::uno::Exception( + ::rtl::OUString::createFromAscii("Found no URL."), + css::uno::Reference< css::uno::XInterface >()); + + // Parse URL! Only the main part has to be used further. E.g. a jumpmark can make trouble + ::rtl::OUString sNormalizedURL = impl_normalizeURL( sURL ); + return impl_openStreamWithURL( sNormalizedURL, bLockFile ); + } +#if OSL_DEBUG_LEVEL>0 + catch(const css::uno::Exception& ex) + { + ::rtl::OUStringBuffer sMsg(256); + sMsg.appendAscii("Invalid MediaDescriptor detected:\n"); + sMsg.append (ex.Message ); + OSL_ENSURE(sal_False, ::rtl::OUStringToOString(sMsg.makeStringAndClear(), RTL_TEXTENCODING_UTF8).getStr()); + } +#else + catch(const css::uno::Exception&) + {} +#endif + + return sal_False; +} + +/*----------------------------------------------- + 25.03.2004 12:38 +-----------------------------------------------*/ +sal_Bool MediaDescriptor::impl_openStreamWithPostData( const css::uno::Reference< css::io::XInputStream >& _rxPostData ) + throw(::com::sun::star::uno::RuntimeException) +{ + if ( !_rxPostData.is() ) + throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("Found invalid PostData."), + css::uno::Reference< css::uno::XInterface >(), 1); + + // PostData can't be used in read/write mode! + (*this)[MediaDescriptor::PROP_READONLY()] <<= sal_True; + + // prepare the environment + css::uno::Reference< css::task::XInteractionHandler > xInteraction = getUnpackedValueOrDefault( + MediaDescriptor::PROP_INTERACTIONHANDLER(), + css::uno::Reference< css::task::XInteractionHandler >()); + css::uno::Reference< css::ucb::XProgressHandler > xProgress; + ::ucbhelper::CommandEnvironment* pCommandEnv = new ::ucbhelper::CommandEnvironment(xInteraction, xProgress); + css::uno::Reference< css::ucb::XCommandEnvironment > xCommandEnv(static_cast< css::ucb::XCommandEnvironment* >(pCommandEnv), css::uno::UNO_QUERY); + + // media type + ::rtl::OUString sMediaType = getUnpackedValueOrDefault(MediaDescriptor::PROP_MEDIATYPE(), ::rtl::OUString()); + if (!sMediaType.getLength()) + { + sMediaType = ::rtl::OUString::createFromAscii("application/x-www-form-urlencoded"); + (*this)[MediaDescriptor::PROP_MEDIATYPE()] <<= sMediaType; + } + + // url + ::rtl::OUString sURL( getUnpackedValueOrDefault( PROP_URL(), ::rtl::OUString() ) ); + + css::uno::Reference< css::io::XInputStream > xResultStream; + try + { + // seek PostData stream to the beginning + css::uno::Reference< css::io::XSeekable > xSeek( _rxPostData, css::uno::UNO_QUERY ); + if ( xSeek.is() ) + xSeek->seek( 0 ); + + // a content for the URL + ::ucbhelper::Content aContent( sURL, xCommandEnv ); + + // use post command + css::ucb::PostCommandArgument2 aPostArgument; + aPostArgument.Source = _rxPostData; + css::uno::Reference< css::io::XActiveDataSink > xSink( new ucbhelper::ActiveDataSink ); + aPostArgument.Sink = xSink; + aPostArgument.MediaType = sMediaType; + aPostArgument.Referer = getUnpackedValueOrDefault( PROP_REFERRER(), ::rtl::OUString() ); + + ::rtl::OUString sCommandName( RTL_CONSTASCII_USTRINGPARAM( "post" ) ); + aContent.executeCommand( sCommandName, css::uno::makeAny( aPostArgument ) ); + + // get result + xResultStream = xSink->getInputStream(); + } + catch( const css::uno::Exception& ) + { + } + + // success? + if ( !xResultStream.is() ) + { + OSL_ENSURE( false, "no valid reply to the HTTP-Post" ); + return sal_False; + } + + (*this)[MediaDescriptor::PROP_INPUTSTREAM()] <<= xResultStream; + return sal_True; +} + +/*-----------------------------------------------*/ + +/*----------------------------------------------- + 25.03.2004 12:29 +-----------------------------------------------*/ +sal_Bool MediaDescriptor::impl_openStreamWithURL( const ::rtl::OUString& sURL, sal_Bool bLockFile ) + throw(::com::sun::star::uno::RuntimeException) +{ + // prepare the environment + css::uno::Reference< css::task::XInteractionHandler > xOrgInteraction = getUnpackedValueOrDefault( + MediaDescriptor::PROP_INTERACTIONHANDLER(), + css::uno::Reference< css::task::XInteractionHandler >()); + + StillReadWriteInteraction* pInteraction = new StillReadWriteInteraction(xOrgInteraction); + css::uno::Reference< css::task::XInteractionHandler > xInteraction(static_cast< css::task::XInteractionHandler* >(pInteraction), css::uno::UNO_QUERY); + + css::uno::Reference< css::ucb::XProgressHandler > xProgress; + ::ucbhelper::CommandEnvironment* pCommandEnv = new ::ucbhelper::CommandEnvironment(xInteraction, xProgress); + css::uno::Reference< css::ucb::XCommandEnvironment > xCommandEnv(static_cast< css::ucb::XCommandEnvironment* >(pCommandEnv), css::uno::UNO_QUERY); + + // try to create the content + // no content -> no stream => return immediatly with FALSE + ::ucbhelper::Content aContent; + css::uno::Reference< css::ucb::XContent > xContent; + try + { + aContent = ::ucbhelper::Content(sURL, xCommandEnv); + xContent = aContent.get(); + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::ucb::ContentCreationException&) + { return sal_False; } // TODO error handling + catch(const css::uno::Exception&) + { return sal_False; } // TODO error handling + + // try to open the file in read/write mode + // (if its allowed to do so). + // But handle errors in a "hidden mode". Because + // we try it readonly later - if read/write isnt an option. + css::uno::Reference< css::io::XStream > xStream ; + css::uno::Reference< css::io::XInputStream > xInputStream; + + sal_Bool bReadOnly = sal_False; + sal_Bool bModeRequestedExplicitly = sal_False; + const_iterator pIt = find(MediaDescriptor::PROP_READONLY()); + if (pIt != end()) + { + pIt->second >>= bReadOnly; + bModeRequestedExplicitly = sal_True; + } + + if ( !bReadOnly && bLockFile ) + { + try + { + // TODO: use "special" still interaction to supress error messages + xStream = aContent.openWriteableStream(); + if (xStream.is()) + xInputStream = xStream->getInputStream(); + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception&) + { + // ignore exception, if reason was problem reasoned on + // open it in WRITEABLE mode! Then we try it READONLY + // later a second time. + // All other errors must be handled as real error an + // break this method. + if (!pInteraction->wasWriteError() || bModeRequestedExplicitly) + return sal_False; + xStream.clear(); + xInputStream.clear(); + } + } + + // If opening of the stream in read/write mode wasnt allowed + // or failed by an error - we must try it in readonly mode. + if (!xInputStream.is()) + { + rtl::OUString aScheme; + + try + { + css::uno::Reference< css::ucb::XContentIdentifier > xContId( + aContent.get().is() ? aContent.get()->getIdentifier() : 0 ); + + if ( xContId.is() ) + aScheme = xContId->getContentProviderScheme(); + + // Only file system content provider is able to provide XStream + // so for this content impossibility to create XStream triggers + // switch to readonly mode in case of opening with locking on + if( bLockFile && aScheme.equalsIgnoreAsciiCaseAscii( "file" ) ) + bReadOnly = sal_True; + else + { + sal_Bool bRequestReadOnly = bReadOnly; + aContent.getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) ) ) >>= bReadOnly; + if ( bReadOnly && !bRequestReadOnly && bModeRequestedExplicitly ) + return sal_False; // the document is explicitly requested with WRITEABLE mode + } + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception&) + { /* no error handling if IsReadOnly property does not exist for UCP */ } + + if ( bReadOnly ) + (*this)[MediaDescriptor::PROP_READONLY()] <<= bReadOnly; + + pInteraction->resetInterceptions(); + pInteraction->resetErrorStates(); + try + { + // all the contents except file-URLs should be opened as usual + if ( bLockFile || !aScheme.equalsIgnoreAsciiCaseAscii( "file" ) ) + xInputStream = aContent.openStream(); + else + xInputStream = aContent.openStreamNoLock(); + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception&) + { return sal_False; } + } + + // add streams to the descriptor + if (xContent.is()) + (*this)[MediaDescriptor::PROP_UCBCONTENT()] <<= xContent; + if (xStream.is()) + (*this)[MediaDescriptor::PROP_STREAM()] <<= xStream; + if (xInputStream.is()) + (*this)[MediaDescriptor::PROP_INPUTSTREAM()] <<= xInputStream; + + // At least we need an input stream. The r/w stream is optional ... + return xInputStream.is(); +} + +/*----------------------------------------------- + 10.09.2004 10:51 +-----------------------------------------------*/ +::rtl::OUString MediaDescriptor::impl_normalizeURL(const ::rtl::OUString& sURL) +{ + /* Remove Jumpmarks (fragments) of an URL only here. + They are not part of any URL and as a result may be + no ucb content can be created then. + On the other side arguments must exists ... because + they are part of an URL. + + Do not use the URLTransformer service here. Because + it parses the URL in another way. It's main part isnt enough + and it's complete part contains the jumpmark (fragment) parameter ... + */ + static ::rtl::OUString SERVICENAME_URIREFERENCEFACTORY = ::rtl::OUString::createFromAscii("com.sun.star.uri.UriReferenceFactory"); + + try + { + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = ::comphelper::getProcessServiceFactory(); + css::uno::Reference< css::uri::XUriReferenceFactory > xUriFactory(xSMGR->createInstance(SERVICENAME_URIREFERENCEFACTORY), css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::uri::XUriReference > xUriRef = xUriFactory->parse(sURL); + if (xUriRef.is()) + { + xUriRef->clearFragment(); + return xUriRef->getUriReference(); + } + } + catch(const css::uno::RuntimeException& exRun) + { throw exRun; } + catch(const css::uno::Exception&) + {} + + // If an error ocurred ... return the original URL. + // It's a try .-) + return sURL; +} + +} // namespace comphelper + diff --git a/comphelper/source/misc/mimeconfighelper.cxx b/comphelper/source/misc/mimeconfighelper.cxx new file mode 100644 index 000000000000..b677c977739e --- /dev/null +++ b/comphelper/source/misc/mimeconfighelper.cxx @@ -0,0 +1,805 @@ +/************************************************************************* + * + * 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/beans/PropertyValue.hpp> +#include <com/sun/star/container/XContainerQuery.hpp> +#include <com/sun/star/document/XTypeDetection.hpp> + +#include <comphelper/fileformat.h> +#include <comphelper/mimeconfighelper.hxx> +#include <comphelper/classids.hxx> +#include <comphelper/sequenceashashmap.hxx> + + +using namespace ::com::sun::star; +using namespace comphelper; + +//----------------------------------------------------------------------- +MimeConfigurationHelper::MimeConfigurationHelper( const uno::Reference< lang::XMultiServiceFactory >& xFactory ) +: m_xFactory( xFactory ) +{ + if ( !m_xFactory.is() ) + throw uno::RuntimeException(); +} + +//----------------------------------------------------------------------- +::rtl::OUString MimeConfigurationHelper::GetStringClassIDRepresentation( const uno::Sequence< sal_Int8 >& aClassID ) +{ + ::rtl::OUString aResult; + + if ( aClassID.getLength() == 16 ) + { + for ( sal_Int32 nInd = 0; nInd < aClassID.getLength(); nInd++ ) + { + if ( nInd == 4 || nInd == 6 || nInd == 8 || nInd == 10 ) + aResult += ::rtl::OUString::createFromAscii( "-" ); + + sal_Int32 nDigit1 = (sal_Int32)( (sal_uInt8)aClassID[nInd] / 16 ); + sal_Int32 nDigit2 = (sal_uInt8)aClassID[nInd] % 16; + aResult += ::rtl::OUString::valueOf( nDigit1, 16 ); + aResult += ::rtl::OUString::valueOf( nDigit2, 16 ); + } + } + + return aResult; +} + +//----------------------------------------------------------------------- +sal_uInt8 GetDigit_Impl( sal_Char aChar ) +{ + if ( aChar >= '0' && aChar <= '9' ) + return aChar - '0'; + else if ( aChar >= 'a' && aChar <= 'f' ) + return aChar - 'a' + 10; + else if ( aChar >= 'A' && aChar <= 'F' ) + return aChar - 'A' + 10; + else + return 16; +} + +//----------------------------------------------------------------------- +uno::Sequence< sal_Int8 > MimeConfigurationHelper::GetSequenceClassIDRepresentation( const ::rtl::OUString& aClassID ) +{ + sal_Int32 nLength = aClassID.getLength(); + if ( nLength == 36 ) + { + ::rtl::OString aCharClassID = ::rtl::OUStringToOString( aClassID, RTL_TEXTENCODING_ASCII_US ); + const sal_Char* pString = aCharClassID.getStr(); + if ( pString ) + { + uno::Sequence< sal_Int8 > aResult( 16 ); + + sal_Int32 nStrPointer = 0; + sal_Int32 nSeqInd = 0; + while( nSeqInd < 16 && nStrPointer + 1 < nLength ) + { + sal_uInt8 nDigit1 = GetDigit_Impl( pString[nStrPointer++] ); + sal_uInt8 nDigit2 = GetDigit_Impl( pString[nStrPointer++] ); + + if ( nDigit1 > 15 || nDigit2 > 15 ) + break; + + aResult[nSeqInd++] = (sal_Int8)( nDigit1 * 16 + nDigit2 ); + + if ( nStrPointer < nLength && pString[nStrPointer] == '-' ) + nStrPointer++; + } + + if ( nSeqInd == 16 && nStrPointer == nLength ) + return aResult; + } + } + + return uno::Sequence< sal_Int8 >(); +} + +//----------------------------------------------------------------------- +uno::Reference< container::XNameAccess > MimeConfigurationHelper::GetConfigurationByPath( const ::rtl::OUString& aPath ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + uno::Reference< container::XNameAccess > xConfig; + + try + { + if ( !m_xConfigProvider.is() ) + m_xConfigProvider = uno::Reference< lang::XMultiServiceFactory >( + m_xFactory->createInstance( + ::rtl::OUString::createFromAscii( "com.sun.star.configuration.ConfigurationProvider" ) ), + uno::UNO_QUERY_THROW ); + + uno::Sequence< uno::Any > aArgs( 1 ); + beans::PropertyValue aPathProp; + aPathProp.Name = ::rtl::OUString::createFromAscii( "nodepath" ); + aPathProp.Value <<= aPath; + aArgs[0] <<= aPathProp; + + xConfig = uno::Reference< container::XNameAccess >( + m_xConfigProvider->createInstanceWithArguments( + ::rtl::OUString::createFromAscii( "com.sun.star.configuration.ConfigurationAccess" ), + aArgs ), + uno::UNO_QUERY ); + } + catch( uno::Exception& ) + {} + + return xConfig; +} + +//----------------------------------------------------------------------- +uno::Reference< container::XNameAccess > MimeConfigurationHelper::GetObjConfiguration() +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_xObjectConfig.is() ) + m_xObjectConfig = GetConfigurationByPath( + ::rtl::OUString::createFromAscii( "/org.openoffice.Office.Embedding/Objects" ) ); + + return m_xObjectConfig; +} + +//----------------------------------------------------------------------- +uno::Reference< container::XNameAccess > MimeConfigurationHelper::GetVerbsConfiguration() +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_xVerbsConfig.is() ) + m_xVerbsConfig = GetConfigurationByPath( + ::rtl::OUString::createFromAscii( "/org.openoffice.Office.Embedding/Verbs" ) ); + + return m_xVerbsConfig; +} + +//----------------------------------------------------------------------- +uno::Reference< container::XNameAccess > MimeConfigurationHelper::GetMediaTypeConfiguration() +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_xMediaTypeConfig.is() ) + m_xMediaTypeConfig = GetConfigurationByPath( + ::rtl::OUString::createFromAscii( "/org.openoffice.Office.Embedding/MimeTypeClassIDRelations" ) ); + + return m_xMediaTypeConfig; +} +//------------------------------------------------------------------------- +::rtl::OUString MimeConfigurationHelper::GetDocServiceNameFromFilter( const ::rtl::OUString& aFilterName ) +{ + ::rtl::OUString aDocServiceName; + + try + { + uno::Reference< container::XNameAccess > xFilterFactory( + m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ), + uno::UNO_QUERY_THROW ); + + uno::Any aFilterAnyData = xFilterFactory->getByName( aFilterName ); + uno::Sequence< beans::PropertyValue > aFilterData; + if ( aFilterAnyData >>= aFilterData ) + { + for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ ) + if ( aFilterData[nInd].Name.equalsAscii( "DocumentService" ) ) + aFilterData[nInd].Value >>= aDocServiceName; + } + } + catch( uno::Exception& ) + {} + + return aDocServiceName; +} + +//------------------------------------------------------------------------- +::rtl::OUString MimeConfigurationHelper::GetDocServiceNameFromMediaType( const ::rtl::OUString& aMediaType ) +{ + uno::Reference< container::XContainerQuery > xTypeCFG( + m_xFactory->createInstance( + ::rtl::OUString::createFromAscii( "com.sun.star.document.TypeDetection" ) ), + uno::UNO_QUERY ); + + if ( xTypeCFG.is() ) + { + try + { + // make query for all types matching the properties + uno::Sequence < beans::NamedValue > aSeq( 1 ); + aSeq[0].Name = ::rtl::OUString::createFromAscii( "MediaType" ); + aSeq[0].Value <<= aMediaType; + + uno::Reference < container::XEnumeration > xEnum = xTypeCFG->createSubSetEnumerationByProperties( aSeq ); + while ( xEnum->hasMoreElements() ) + { + uno::Sequence< beans::PropertyValue > aType; + if ( xEnum->nextElement() >>= aType ) + { + for ( sal_Int32 nInd = 0; nInd < aType.getLength(); nInd++ ) + { + ::rtl::OUString aFilterName; + if ( aType[nInd].Name.equalsAscii( "PreferredFilter" ) + && ( aType[nInd].Value >>= aFilterName ) && aFilterName.getLength() ) + { + ::rtl::OUString aDocumentName = GetDocServiceNameFromFilter( aFilterName ); + if ( aDocumentName.getLength() ) + return aDocumentName; + } + } + } + } + } + catch( uno::Exception& ) + {} + } + + return ::rtl::OUString(); +} + +//------------------------------------------------------------------------- +sal_Bool MimeConfigurationHelper::GetVerbByShortcut( const ::rtl::OUString& aVerbShortcut, + embed::VerbDescriptor& aDescriptor ) +{ + sal_Bool bResult = sal_False; + + uno::Reference< container::XNameAccess > xVerbsConfig = GetVerbsConfiguration(); + uno::Reference< container::XNameAccess > xVerbsProps; + try + { + if ( xVerbsConfig.is() && ( xVerbsConfig->getByName( aVerbShortcut ) >>= xVerbsProps ) && xVerbsProps.is() ) + { + embed::VerbDescriptor aTempDescr; + if ( ( xVerbsProps->getByName( ::rtl::OUString::createFromAscii( "VerbID" ) ) >>= aTempDescr.VerbID ) + && ( xVerbsProps->getByName( ::rtl::OUString::createFromAscii( "VerbUIName" ) ) >>= aTempDescr.VerbName ) + && ( xVerbsProps->getByName( ::rtl::OUString::createFromAscii( "VerbFlags" ) ) >>= aTempDescr.VerbFlags ) + && ( xVerbsProps->getByName( ::rtl::OUString::createFromAscii( "VerbAttributes" ) ) >>= aTempDescr.VerbAttributes ) ) + { + aDescriptor = aTempDescr; + bResult = sal_True; + } + } + } + catch( uno::Exception& ) + { + } + + return bResult; +} + +//------------------------------------------------------------------------- +uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjPropsFromConfigEntry( + const uno::Sequence< sal_Int8 >& aClassID, + const uno::Reference< container::XNameAccess >& xObjectProps ) +{ + uno::Sequence< beans::NamedValue > aResult; + + if ( aClassID.getLength() == 16 ) + { + try + { + uno::Sequence< ::rtl::OUString > aObjPropNames = xObjectProps->getElementNames(); + + aResult.realloc( aObjPropNames.getLength() + 1 ); + aResult[0].Name = ::rtl::OUString::createFromAscii( "ClassID" ); + aResult[0].Value <<= aClassID; + + for ( sal_Int32 nInd = 0; nInd < aObjPropNames.getLength(); nInd++ ) + { + aResult[nInd + 1].Name = aObjPropNames[nInd]; + + if ( aObjPropNames[nInd].equalsAscii( "ObjectVerbs" ) ) + { + uno::Sequence< ::rtl::OUString > aVerbShortcuts; + if ( xObjectProps->getByName( aObjPropNames[nInd] ) >>= aVerbShortcuts ) + { + uno::Sequence< embed::VerbDescriptor > aVerbDescriptors( aVerbShortcuts.getLength() ); + for ( sal_Int32 nVerbI = 0; nVerbI < aVerbShortcuts.getLength(); nVerbI++ ) + if ( !GetVerbByShortcut( aVerbShortcuts[nVerbI], aVerbDescriptors[nVerbI] ) ) + throw uno::RuntimeException(); + + aResult[nInd+1].Value <<= aVerbDescriptors; + } + else + throw uno::RuntimeException(); + } + else + aResult[nInd+1].Value = xObjectProps->getByName( aObjPropNames[nInd] ); + } + } + catch( uno::Exception& ) + { + aResult.realloc( 0 ); + } + } + + return aResult; +} + +//----------------------------------------------------------------------- +::rtl::OUString MimeConfigurationHelper::GetExplicitlyRegisteredObjClassID( const ::rtl::OUString& aMediaType ) +{ + ::rtl::OUString aStringClassID; + + uno::Reference< container::XNameAccess > xMediaTypeConfig = GetMediaTypeConfiguration(); + try + { + if ( xMediaTypeConfig.is() ) + xMediaTypeConfig->getByName( aMediaType ) >>= aStringClassID; + } + catch( uno::Exception& ) + { + } + + return aStringClassID; + +} + +//----------------------------------------------------------------------- +uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByStringClassID( + const ::rtl::OUString& aStringClassID ) +{ + uno::Sequence< beans::NamedValue > aObjProps; + + uno::Sequence< sal_Int8 > aClassID = GetSequenceClassIDRepresentation( aStringClassID ); + if ( ClassIDsEqual( aClassID, GetSequenceClassID( SO3_DUMMY_CLASSID ) ) ) + { + aObjProps.realloc(2); + aObjProps[0].Name = ::rtl::OUString::createFromAscii("ObjectFactory"); + aObjProps[0].Value <<= ::rtl::OUString::createFromAscii("com.sun.star.embed.OOoSpecialEmbeddedObjectFactory"); + aObjProps[1].Name = ::rtl::OUString::createFromAscii("ClassID"); + aObjProps[1].Value <<= aClassID; + return aObjProps; + } + + if ( aClassID.getLength() == 16 ) + { + uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration(); + uno::Reference< container::XNameAccess > xObjectProps; + try + { + // TODO/LATER: allow to provide ClassID string in any format, only digits are counted + if ( xObjConfig.is() && ( xObjConfig->getByName( aStringClassID.toAsciiUpperCase() ) >>= xObjectProps ) && xObjectProps.is() ) + aObjProps = GetObjPropsFromConfigEntry( aClassID, xObjectProps ); + } + catch( uno::Exception& ) + { + } + } + + return aObjProps; +} + +//----------------------------------------------------------------------- +uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByClassID( + const uno::Sequence< sal_Int8 >& aClassID ) +{ + uno::Sequence< beans::NamedValue > aObjProps; + if ( ClassIDsEqual( aClassID, GetSequenceClassID( SO3_DUMMY_CLASSID ) ) ) + { + aObjProps.realloc(2); + aObjProps[0].Name = ::rtl::OUString::createFromAscii("ObjectFactory"); + aObjProps[0].Value <<= ::rtl::OUString::createFromAscii("com.sun.star.embed.OOoSpecialEmbeddedObjectFactory"); + aObjProps[1].Name = ::rtl::OUString::createFromAscii("ClassID"); + aObjProps[1].Value <<= aClassID; + } + + ::rtl::OUString aStringClassID = GetStringClassIDRepresentation( aClassID ); + if ( aStringClassID.getLength() ) + { + uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration(); + uno::Reference< container::XNameAccess > xObjectProps; + try + { + if ( xObjConfig.is() && ( xObjConfig->getByName( aStringClassID.toAsciiUpperCase() ) >>= xObjectProps ) && xObjectProps.is() ) + aObjProps = GetObjPropsFromConfigEntry( aClassID, xObjectProps ); + } + catch( uno::Exception& ) + { + } + } + + return aObjProps; +} + +//----------------------------------------------------------------------- +uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByMediaType( const ::rtl::OUString& aMediaType ) +{ + uno::Sequence< beans::NamedValue > aObject = + GetObjectPropsByStringClassID( GetExplicitlyRegisteredObjClassID( aMediaType ) ); + if ( aObject.getLength() ) + return aObject; + + ::rtl::OUString aDocumentName = GetDocServiceNameFromMediaType( aMediaType ); + if ( aDocumentName.getLength() ) + return GetObjectPropsByDocumentName( aDocumentName ); + + return uno::Sequence< beans::NamedValue >(); +} + +//----------------------------------------------------------------------- +uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByFilter( const ::rtl::OUString& aFilterName ) +{ + ::rtl::OUString aDocumentName = GetDocServiceNameFromFilter( aFilterName ); + if ( aDocumentName.getLength() ) + return GetObjectPropsByDocumentName( aDocumentName ); + + return uno::Sequence< beans::NamedValue >(); +} + +//----------------------------------------------------------------------- +uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByDocumentName( const ::rtl::OUString& aDocName ) +{ + if ( aDocName.getLength() ) + { + uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration(); + if ( xObjConfig.is() ) + { + try + { + uno::Sequence< ::rtl::OUString > aClassIDs = xObjConfig->getElementNames(); + for ( sal_Int32 nInd = 0; nInd < aClassIDs.getLength(); nInd++ ) + { + uno::Reference< container::XNameAccess > xObjectProps; + ::rtl::OUString aEntryDocName; + + if ( ( xObjConfig->getByName( aClassIDs[nInd] ) >>= xObjectProps ) && xObjectProps.is() + && ( xObjectProps->getByName( + ::rtl::OUString::createFromAscii( "ObjectDocumentServiceName" ) ) >>= aEntryDocName ) + && aEntryDocName.equals( aDocName ) ) + { + return GetObjPropsFromConfigEntry( GetSequenceClassIDRepresentation( aClassIDs[nInd] ), + xObjectProps ); + } + } + } + catch( uno::Exception& ) + {} + } + } + + return uno::Sequence< beans::NamedValue >(); +} + +//----------------------------------------------------------------------- +::rtl::OUString MimeConfigurationHelper::GetFactoryNameByClassID( const uno::Sequence< sal_Int8 >& aClassID ) +{ + return GetFactoryNameByStringClassID( GetStringClassIDRepresentation( aClassID ) ); +} + +//----------------------------------------------------------------------- +::rtl::OUString MimeConfigurationHelper::GetFactoryNameByStringClassID( const ::rtl::OUString& aStringClassID ) +{ + ::rtl::OUString aResult; + + if ( aStringClassID.getLength() ) + { + uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration(); + uno::Reference< container::XNameAccess > xObjectProps; + try + { + if ( xObjConfig.is() && ( xObjConfig->getByName( aStringClassID.toAsciiUpperCase() ) >>= xObjectProps ) && xObjectProps.is() ) + xObjectProps->getByName( ::rtl::OUString::createFromAscii( "ObjectFactory" ) ) >>= aResult; + } + catch( uno::Exception& ) + { + uno::Sequence< sal_Int8 > aClassID = GetSequenceClassIDRepresentation( aStringClassID ); + if ( ClassIDsEqual( aClassID, GetSequenceClassID( SO3_DUMMY_CLASSID ) ) ) + return ::rtl::OUString::createFromAscii("com.sun.star.embed.OOoSpecialEmbeddedObjectFactory"); + } + } + + return aResult; +} + +//----------------------------------------------------------------------- +::rtl::OUString MimeConfigurationHelper::GetFactoryNameByDocumentName( const ::rtl::OUString& aDocName ) +{ + ::rtl::OUString aResult; + + if ( aDocName.getLength() ) + { + uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration(); + if ( xObjConfig.is() ) + { + try + { + uno::Sequence< ::rtl::OUString > aClassIDs = xObjConfig->getElementNames(); + for ( sal_Int32 nInd = 0; nInd < aClassIDs.getLength(); nInd++ ) + { + uno::Reference< container::XNameAccess > xObjectProps; + ::rtl::OUString aEntryDocName; + + if ( ( xObjConfig->getByName( aClassIDs[nInd] ) >>= xObjectProps ) && xObjectProps.is() + && ( xObjectProps->getByName( + ::rtl::OUString::createFromAscii( "ObjectDocumentServiceName" ) ) >>= aEntryDocName ) + && aEntryDocName.equals( aDocName ) ) + { + xObjectProps->getByName( ::rtl::OUString::createFromAscii( "ObjectFactory" ) ) >>= aResult; + break; + } + } + } + catch( uno::Exception& ) + {} + } + } + + return aResult; +} + + +//----------------------------------------------------------------------- +::rtl::OUString MimeConfigurationHelper::GetFactoryNameByMediaType( const ::rtl::OUString& aMediaType ) +{ + ::rtl::OUString aResult = GetFactoryNameByStringClassID( GetExplicitlyRegisteredObjClassID( aMediaType ) ); + + if ( !aResult.getLength() ) + { + ::rtl::OUString aDocumentName = GetDocServiceNameFromMediaType( aMediaType ); + if ( aDocumentName.getLength() ) + aResult = GetFactoryNameByDocumentName( aDocumentName ); + } + + return aResult; +} + +//----------------------------------------------------------------------- +::rtl::OUString MimeConfigurationHelper::UpdateMediaDescriptorWithFilterName( + uno::Sequence< beans::PropertyValue >& aMediaDescr, + sal_Bool bIgnoreType ) +{ + ::rtl::OUString aFilterName; + + for ( sal_Int32 nInd = 0; nInd < aMediaDescr.getLength(); nInd++ ) + if ( aMediaDescr[nInd].Name.equalsAscii( "FilterName" ) ) + aMediaDescr[nInd].Value >>= aFilterName; + + if ( !aFilterName.getLength() ) + { + // filter name is not specified, so type detection should be done + + uno::Reference< document::XTypeDetection > xTypeDetection( + m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.TypeDetection" ) ), + uno::UNO_QUERY ); + + if ( !xTypeDetection.is() ) + throw uno::RuntimeException(); // TODO + + // typedetection can change the mode, add a stream and so on, thus a copy should be used + uno::Sequence< beans::PropertyValue > aTempMD( aMediaDescr ); + + // get TypeName + ::rtl::OUString aTypeName = xTypeDetection->queryTypeByDescriptor( aTempMD, sal_True ); + + // get FilterName + for ( sal_Int32 nInd = 0; nInd < aTempMD.getLength(); nInd++ ) + if ( aTempMD[nInd].Name.equalsAscii( "FilterName" ) ) + aTempMD[nInd].Value >>= aFilterName; + + if ( aFilterName.getLength() ) + { + sal_Int32 nOldLen = aMediaDescr.getLength(); + aMediaDescr.realloc( nOldLen + 1 ); + aMediaDescr[nOldLen].Name = ::rtl::OUString::createFromAscii( "FilterName" ); + aMediaDescr[ nOldLen ].Value <<= aFilterName; + + } + else if ( aTypeName.getLength() && !bIgnoreType ) + { + uno::Reference< container::XNameAccess > xNameAccess( xTypeDetection, uno::UNO_QUERY ); + uno::Sequence< beans::PropertyValue > aTypes; + + if ( xNameAccess.is() && ( xNameAccess->getByName( aTypeName ) >>= aTypes ) ) + { + for ( sal_Int32 nInd = 0; nInd < aTypes.getLength(); nInd++ ) + { + if ( aTypes[nInd].Name.equalsAscii( "PreferredFilter" ) && ( aTypes[nInd].Value >>= aFilterName ) ) + { + sal_Int32 nOldLen = aMediaDescr.getLength(); + aMediaDescr.realloc( nOldLen + 1 ); + aMediaDescr[nOldLen].Name = ::rtl::OUString::createFromAscii( "FilterName" ); + aMediaDescr[ nOldLen ].Value = aTypes[nInd].Value; + break; + } + } + } + } + } + + return aFilterName; +} + +::rtl::OUString MimeConfigurationHelper::UpdateMediaDescriptorWithFilterName( + uno::Sequence< beans::PropertyValue >& aMediaDescr, + uno::Sequence< beans::NamedValue >& aObject ) +{ + ::rtl::OUString aDocName; + for ( sal_Int32 nInd = 0; nInd < aObject.getLength(); nInd++ ) + if ( aObject[nInd].Name.equalsAscii( "ObjectDocumentServiceName" ) ) + { + aObject[nInd].Value >>= aDocName; + break; + } + + OSL_ENSURE( aDocName.getLength(), "The name must exist at this point!\n" ); + + + sal_Bool bNeedsAddition = sal_True; + for ( sal_Int32 nMedInd = 0; nMedInd < aMediaDescr.getLength(); nMedInd++ ) + if ( aMediaDescr[nMedInd].Name.equalsAscii( "DocumentService" ) ) + { + aMediaDescr[nMedInd].Value <<= aDocName; + bNeedsAddition = sal_False; + break; + } + + if ( bNeedsAddition ) + { + sal_Int32 nOldLen = aMediaDescr.getLength(); + aMediaDescr.realloc( nOldLen + 1 ); + aMediaDescr[nOldLen].Name = ::rtl::OUString::createFromAscii( "DocumentService" ); + aMediaDescr[nOldLen].Value <<= aDocName; + } + + return UpdateMediaDescriptorWithFilterName( aMediaDescr, sal_True ); +} + +sal_Bool MimeConfigurationHelper::AddFilterNameCheckOwnFile( + uno::Sequence< beans::PropertyValue >& aMediaDescr ) +{ + ::rtl::OUString aFilterName = UpdateMediaDescriptorWithFilterName( aMediaDescr, sal_False ); + if ( aFilterName.getLength() ) + { + try + { + uno::Reference< container::XNameAccess > xFilterFactory( + m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ), + uno::UNO_QUERY_THROW ); + + uno::Any aFilterAnyData = xFilterFactory->getByName( aFilterName ); + uno::Sequence< beans::PropertyValue > aFilterData; + if ( aFilterAnyData >>= aFilterData ) + { + for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ ) + if ( aFilterData[nInd].Name.equalsAscii( "Flags" ) ) + { + uno::Any aVal = aFilterData[nInd].Value; + sal_Int32 nFlags = 0; + // check the OWN flag + if ( ( aFilterData[nInd].Value >>= nFlags ) && ( nFlags & 0x20 ) ) + return sal_True; + break; + } + } + } + catch( uno::Exception& ) + {} + } + + return sal_False; +} + +//----------------------------------------------------------- +::rtl::OUString MimeConfigurationHelper::GetDefaultFilterFromServiceName( const ::rtl::OUString& aServiceName, sal_Int32 nVersion ) +{ + rtl::OUString aResult; + + if ( aServiceName.getLength() && nVersion ) + try + { + uno::Reference< container::XContainerQuery > xFilterQuery( + m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ), + uno::UNO_QUERY_THROW ); + + uno::Sequence< beans::NamedValue > aSearchRequest( 2 ); + aSearchRequest[0].Name = ::rtl::OUString::createFromAscii( "DocumentService" ); + aSearchRequest[0].Value <<= aServiceName; + aSearchRequest[1].Name = ::rtl::OUString::createFromAscii( "FileFormatVersion" ); + aSearchRequest[1].Value <<= nVersion; + + uno::Sequence< beans::PropertyValue > aFilterProps; + uno::Reference< container::XEnumeration > xFilterEnum = + xFilterQuery->createSubSetEnumerationByProperties( aSearchRequest ); + + // use the first filter that is found + if ( xFilterEnum.is() ) + while ( xFilterEnum->hasMoreElements() ) + { + uno::Sequence< beans::PropertyValue > aProps; + if ( xFilterEnum->nextElement() >>= aProps ) + { + SequenceAsHashMap aPropsHM( aProps ); + sal_Int32 nFlags = aPropsHM.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "Flags" ), + (sal_Int32)0 ); + + // that should be import, export, own filter and not a template filter ( TemplatePath flag ) + if ( ( ( nFlags & 0x23L ) == 0x23L ) && !( nFlags & 0x10 ) ) + { + // if there are more than one filter the preffered one should be used + // if there is no preffered filter the first one will be used + if ( !aResult.getLength() || ( nFlags & 0x10000000L ) ) + aResult = aPropsHM.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "Name" ), + ::rtl::OUString() ); + if ( nFlags & 0x10000000L ) + break; // the preffered filter was found + } + } + } + } + catch( uno::Exception& ) + {} + + return aResult; +} +//------------------------------------------------------------------------- +sal_Bool MimeConfigurationHelper::ClassIDsEqual( const uno::Sequence< sal_Int8 >& aClassID1, const uno::Sequence< sal_Int8 >& aClassID2 ) +{ + if ( aClassID1.getLength() != aClassID2.getLength() ) + return sal_False; + + for ( sal_Int32 nInd = 0; nInd < aClassID1.getLength(); nInd++ ) + if ( aClassID1[nInd] != aClassID2[nInd] ) + return sal_False; + + return sal_True; +} +//---------------------------------------------- +uno::Sequence< sal_Int8 > MimeConfigurationHelper::GetSequenceClassID( sal_uInt32 n1, sal_uInt16 n2, sal_uInt16 n3, + sal_uInt8 b8, sal_uInt8 b9, sal_uInt8 b10, sal_uInt8 b11, + sal_uInt8 b12, sal_uInt8 b13, sal_uInt8 b14, sal_uInt8 b15 ) +{ + uno::Sequence< sal_Int8 > aResult( 16 ); + aResult[0] = (sal_Int8)( n1 >> 24 ); + aResult[1] = (sal_Int8)( ( n1 << 8 ) >> 24 ); + aResult[2] = (sal_Int8)( ( n1 << 16 ) >> 24 ); + aResult[3] = (sal_Int8)( ( n1 << 24 ) >> 24 ); + aResult[4] = (sal_Int8)( n2 >> 8 ); + aResult[5] = (sal_Int8)( ( n2 << 8 ) >> 8 ); + aResult[6] = (sal_Int8)( n3 >> 8 ); + aResult[7] = (sal_Int8)( ( n3 << 8 ) >> 8 ); + aResult[8] = b8; + aResult[9] = b9; + aResult[10] = b10; + aResult[11] = b11; + aResult[12] = b12; + aResult[13] = b13; + aResult[14] = b14; + aResult[15] = b15; + + return aResult; +} +uno::Sequence<sal_Int8> MimeConfigurationHelper::GetSequenceClassIDFromObjectName(const ::rtl::OUString& _sObjectName) +{ + uno::Sequence<sal_Int8> aClassId; + uno::Reference< container::XNameAccess > xObjectNames = GetConfigurationByPath(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/org.openoffice.Office.Embedding/ObjectNames"))); + uno::Reference< container::XNameAccess > xProps; + if ( xObjectNames.is() && (xObjectNames->getByName(_sObjectName) >>= xProps) && xProps.is() ) + { + ::rtl::OUString sValue; + xProps->getByName(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ClassID"))) >>= sValue; + aClassId = GetSequenceClassIDRepresentation(sValue); + } + return aClassId; +} + diff --git a/comphelper/source/misc/namedvaluecollection.cxx b/comphelper/source/misc/namedvaluecollection.cxx new file mode 100644 index 000000000000..8bab7fa3d7c7 --- /dev/null +++ b/comphelper/source/misc/namedvaluecollection.cxx @@ -0,0 +1,338 @@ +/************************************************************************* + * + * 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/namedvaluecollection.hxx> + +/** === begin UNO includes === **/ +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/beans/PropertyState.hpp> +/** === end UNO includes === **/ + +#include <rtl/ustrbuf.hxx> +#include <rtl/strbuf.hxx> +#include <osl/diagnose.h> + +#include <hash_map> +#include <functional> +#include <algorithm> + +//........................................................................ +namespace comphelper +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::beans::NamedValue; + using ::com::sun::star::uno::Type; + using ::com::sun::star::uno::cpp_acquire; + using ::com::sun::star::uno::cpp_release; + using ::com::sun::star::uno::cpp_queryInterface; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::beans::NamedValue; + using ::com::sun::star::beans::PropertyState_DIRECT_VALUE; + /** === end UNO using === **/ + + //==================================================================== + //= NamedValueCollection_Impl + //==================================================================== + typedef ::std::hash_map< ::rtl::OUString, Any, ::rtl::OUStringHash > NamedValueRepository; + + struct NamedValueCollection_Impl + { + NamedValueRepository aValues; + }; + + //==================================================================== + //= NamedValueCollection + //==================================================================== + //-------------------------------------------------------------------- + NamedValueCollection::NamedValueCollection() + :m_pImpl( new NamedValueCollection_Impl ) + { + } + + //-------------------------------------------------------------------- + NamedValueCollection::NamedValueCollection( const NamedValueCollection& _rCopySource ) + :m_pImpl( new NamedValueCollection_Impl ) + { + *this = _rCopySource; + } + + //-------------------------------------------------------------------- + NamedValueCollection& NamedValueCollection::operator=( const NamedValueCollection& i_rCopySource ) + { + m_pImpl->aValues = i_rCopySource.m_pImpl->aValues; + return *this; + } + + //-------------------------------------------------------------------- + NamedValueCollection::NamedValueCollection( const Any& _rElements ) + :m_pImpl( new NamedValueCollection_Impl ) + { + Sequence< NamedValue > aNamedValues; + Sequence< PropertyValue > aPropertyValues; + NamedValue aNamedValue; + PropertyValue aPropertyValue; + + if ( _rElements >>= aNamedValues ) + impl_assign( aNamedValues ); + else if ( _rElements >>= aPropertyValues ) + impl_assign( aPropertyValues ); + else if ( _rElements >>= aNamedValue ) + impl_assign( Sequence< NamedValue >( &aNamedValue, 1 ) ); + else if ( _rElements >>= aPropertyValue ) + impl_assign( Sequence< PropertyValue >( &aPropertyValue, 1 ) ); + else + OSL_ENSURE( !_rElements.hasValue(), "NamedValueCollection::NamedValueCollection(Any): unsupported type!" ); + } + + //-------------------------------------------------------------------- + NamedValueCollection::NamedValueCollection( const Sequence< Any >& _rArguments ) + :m_pImpl( new NamedValueCollection_Impl ) + { + impl_assign( _rArguments ); + } + + //-------------------------------------------------------------------- + NamedValueCollection::NamedValueCollection( const Sequence< PropertyValue >& _rArguments ) + :m_pImpl( new NamedValueCollection_Impl ) + { + impl_assign( _rArguments ); + } + + //-------------------------------------------------------------------- + NamedValueCollection::NamedValueCollection( const Sequence< NamedValue >& _rArguments ) + :m_pImpl( new NamedValueCollection_Impl ) + { + impl_assign( _rArguments ); + } + + //-------------------------------------------------------------------- + NamedValueCollection::~NamedValueCollection() + { + } + + //-------------------------------------------------------------------- + NamedValueCollection& NamedValueCollection::merge( const NamedValueCollection& _rAdditionalValues, bool _bOverwriteExisting ) + { + for ( NamedValueRepository::const_iterator namedValue = _rAdditionalValues.m_pImpl->aValues.begin(); + namedValue != _rAdditionalValues.m_pImpl->aValues.end(); + ++namedValue + ) + { + if ( _bOverwriteExisting || !impl_has( namedValue->first ) ) + impl_put( namedValue->first, namedValue->second ); + } + + return *this; + } + + //-------------------------------------------------------------------- + size_t NamedValueCollection::size() const + { + return m_pImpl->aValues.size(); + } + + //-------------------------------------------------------------------- + bool NamedValueCollection::empty() const + { + return m_pImpl->aValues.empty(); + } + + //-------------------------------------------------------------------- + void NamedValueCollection::impl_assign( const Sequence< Any >& _rArguments ) + { + { + NamedValueRepository aEmpty; + m_pImpl->aValues.swap( aEmpty ); + } + + PropertyValue aPropertyValue; + NamedValue aNamedValue; + + const Any* pArgument = _rArguments.getConstArray(); + const Any* pArgumentEnd = _rArguments.getConstArray() + _rArguments.getLength(); + for ( ; pArgument != pArgumentEnd; ++pArgument ) + { + if ( *pArgument >>= aPropertyValue ) + m_pImpl->aValues[ aPropertyValue.Name ] = aPropertyValue.Value; + else if ( *pArgument >>= aNamedValue ) + m_pImpl->aValues[ aNamedValue.Name ] = aNamedValue.Value; +#if OSL_DEBUG_LEVEL > 0 + else if ( pArgument->hasValue() ) + { + ::rtl::OStringBuffer message; + message.append( "NamedValueCollection::impl_assign: encountered a value type which I cannot handle:\n" ); + message.append( ::rtl::OUStringToOString( pArgument->getValueTypeName(), RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE( false, message.makeStringAndClear() ); + } +#endif + } + } + + //-------------------------------------------------------------------- + void NamedValueCollection::impl_assign( const Sequence< PropertyValue >& _rArguments ) + { + { + NamedValueRepository aEmpty; + m_pImpl->aValues.swap( aEmpty ); + } + + const PropertyValue* pArgument = _rArguments.getConstArray(); + const PropertyValue* pArgumentEnd = _rArguments.getConstArray() + _rArguments.getLength(); + for ( ; pArgument != pArgumentEnd; ++pArgument ) + m_pImpl->aValues[ pArgument->Name ] = pArgument->Value; + } + + //-------------------------------------------------------------------- + void NamedValueCollection::impl_assign( const Sequence< NamedValue >& _rArguments ) + { + { + NamedValueRepository aEmpty; + m_pImpl->aValues.swap( aEmpty ); + } + + const NamedValue* pArgument = _rArguments.getConstArray(); + const NamedValue* pArgumentEnd = _rArguments.getConstArray() + _rArguments.getLength(); + for ( ; pArgument != pArgumentEnd; ++pArgument ) + m_pImpl->aValues[ pArgument->Name ] = pArgument->Value; + } + + //-------------------------------------------------------------------- + bool NamedValueCollection::get_ensureType( const ::rtl::OUString& _rValueName, void* _pValueLocation, const Type& _rExpectedValueType ) const + { + NamedValueRepository::const_iterator pos = m_pImpl->aValues.find( _rValueName ); + if ( pos != m_pImpl->aValues.end() ) + { + if ( uno_type_assignData( + _pValueLocation, _rExpectedValueType.getTypeLibType(), + const_cast< void* >( pos->second.getValue() ), pos->second.getValueType().getTypeLibType(), + reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ), + reinterpret_cast< uno_AcquireFunc >( cpp_acquire ), + reinterpret_cast< uno_ReleaseFunc >( cpp_release ) + ) ) + // argument exists, and could be extracted + return true; + + // argument exists, but is of wrong type + ::rtl::OUStringBuffer aBuffer; + aBuffer.appendAscii( "Invalid value type for '" ); + aBuffer.append ( _rValueName ); + aBuffer.appendAscii( "'.\nExpected: " ); + aBuffer.append ( _rExpectedValueType.getTypeName() ); + aBuffer.appendAscii( "\nFound: " ); + aBuffer.append ( pos->second.getValueType().getTypeName() ); + throw IllegalArgumentException( aBuffer.makeStringAndClear(), NULL, 0 ); + } + + // argument does not exist + return false; + } + + //-------------------------------------------------------------------- + const Any& NamedValueCollection::impl_get( const ::rtl::OUString& _rValueName ) const + { + NamedValueRepository::const_iterator pos = m_pImpl->aValues.find( _rValueName ); + if ( pos != m_pImpl->aValues.end() ) + return pos->second; + + static Any aEmptyDefault; + return aEmptyDefault; + } + + //-------------------------------------------------------------------- + bool NamedValueCollection::impl_has( const ::rtl::OUString& _rValueName ) const + { + NamedValueRepository::const_iterator pos = m_pImpl->aValues.find( _rValueName ); + return ( pos != m_pImpl->aValues.end() ); + } + + //-------------------------------------------------------------------- + bool NamedValueCollection::impl_put( const ::rtl::OUString& _rValueName, const Any& _rValue ) + { + bool bHas = impl_has( _rValueName ); + m_pImpl->aValues[ _rValueName ] = _rValue; + return bHas; + } + + //-------------------------------------------------------------------- + bool NamedValueCollection::impl_remove( const ::rtl::OUString& _rValueName ) + { + NamedValueRepository::iterator pos = m_pImpl->aValues.find( _rValueName ); + if ( pos == m_pImpl->aValues.end() ) + return false; + m_pImpl->aValues.erase( pos ); + return true; + } + + //-------------------------------------------------------------------- + namespace + { + struct Value2PropertyValue : public ::std::unary_function< NamedValueRepository::value_type, PropertyValue > + { + PropertyValue operator()( const NamedValueRepository::value_type& _rValue ) + { + return PropertyValue( + _rValue.first, 0, _rValue.second, PropertyState_DIRECT_VALUE ); + } + }; + + struct Value2NamedValue : public ::std::unary_function< NamedValueRepository::value_type, NamedValue > + { + NamedValue operator()( const NamedValueRepository::value_type& _rValue ) + { + return NamedValue( _rValue.first, _rValue.second ); + } + }; + } + + //-------------------------------------------------------------------- + sal_Int32 NamedValueCollection::operator >>= ( Sequence< PropertyValue >& _out_rValues ) const + { + _out_rValues.realloc( m_pImpl->aValues.size() ); + ::std::transform( m_pImpl->aValues.begin(), m_pImpl->aValues.end(), _out_rValues.getArray(), Value2PropertyValue() ); + return _out_rValues.getLength(); + } + + //-------------------------------------------------------------------- + sal_Int32 NamedValueCollection::operator >>= ( Sequence< NamedValue >& _out_rValues ) const + { + _out_rValues.realloc( m_pImpl->aValues.size() ); + ::std::transform( m_pImpl->aValues.begin(), m_pImpl->aValues.end(), _out_rValues.getArray(), Value2NamedValue() ); + return _out_rValues.getLength(); + } + +//........................................................................ +} // namespace comphelper +//........................................................................ + diff --git a/comphelper/source/misc/numberedcollection.cxx b/comphelper/source/misc/numberedcollection.cxx new file mode 100644 index 000000000000..11f430a30fba --- /dev/null +++ b/comphelper/source/misc/numberedcollection.cxx @@ -0,0 +1,276 @@ +/************************************************************************* + * + * 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/numberedcollection.hxx> + +//_______________________________________________ +// includes + +#include <com/sun/star/frame/UntitledNumbersConst.hpp> + +//_______________________________________________ +// namespace + +namespace comphelper{ + +namespace css = ::com::sun::star; + +//_______________________________________________ +// definitions + +static const ::rtl::OUString ERRMSG_INVALID_COMPONENT_PARAM = ::rtl::OUString::createFromAscii("NULL as component reference not allowed."); +static const ::rtl::OUString ERRMSG_INVALID_NUMBER_PARAM = ::rtl::OUString::createFromAscii("Special valkud INVALID_NUMBER not allowed as input parameter."); + +//----------------------------------------------- +NumberedCollection::NumberedCollection() + : ::cppu::BaseMutex () + , m_sUntitledPrefix () + , m_lComponents () + , m_xOwner () +{ +} + +//----------------------------------------------- +NumberedCollection::~NumberedCollection() +{ +} + +//----------------------------------------------- +void NumberedCollection::setOwner(const css::uno::Reference< css::uno::XInterface >& xOwner) +{ + // SYNCHRONIZED -> + ::osl::ResettableMutexGuard aLock(m_aMutex); + + m_xOwner = xOwner; + + // <- SYNCHRONIZED +} + +//----------------------------------------------- +void NumberedCollection::setUntitledPrefix(const ::rtl::OUString& sPrefix) +{ + // SYNCHRONIZED -> + ::osl::ResettableMutexGuard aLock(m_aMutex); + + m_sUntitledPrefix = sPrefix; + + // <- SYNCHRONIZED +} + +//----------------------------------------------- +::sal_Int32 SAL_CALL NumberedCollection::leaseNumber(const css::uno::Reference< css::uno::XInterface >& xComponent) + throw (css::lang::IllegalArgumentException, + css::uno::RuntimeException ) +{ + // SYNCHRONIZED -> + ::osl::ResettableMutexGuard aLock(m_aMutex); + + if ( ! xComponent.is ()) + throw css::lang::IllegalArgumentException (ERRMSG_INVALID_COMPONENT_PARAM, m_xOwner.get(), 1); + + long pComponent = (long) xComponent.get (); + TNumberedItemHash::const_iterator pIt = m_lComponents.find (pComponent); + + // a) component already exists - return it's number directly + if (pIt != m_lComponents.end()) + return pIt->second.nNumber; + + // b) component must be added new to this container + + // b1) collection is full - no further components possible + // -> return INVALID_NUMBER + ::sal_Int32 nFreeNumber = impl_searchFreeNumber(); + if (nFreeNumber == css::frame::UntitledNumbersConst::INVALID_NUMBER) + return css::frame::UntitledNumbersConst::INVALID_NUMBER; + + // b2) add component to collection and return its number + TNumberedItem aItem; + aItem.xItem = css::uno::WeakReference< css::uno::XInterface >(xComponent); + aItem.nNumber = nFreeNumber; + m_lComponents[pComponent] = aItem; + + return nFreeNumber; + + // <- SYNCHRONIZED +} + +//----------------------------------------------- +void SAL_CALL NumberedCollection::releaseNumber(::sal_Int32 nNumber) + throw (css::lang::IllegalArgumentException, + css::uno::RuntimeException ) +{ + // SYNCHRONIZED -> + ::osl::ResettableMutexGuard aLock(m_aMutex); + + if (nNumber == css::frame::UntitledNumbersConst::INVALID_NUMBER) + throw css::lang::IllegalArgumentException (ERRMSG_INVALID_NUMBER_PARAM, m_xOwner.get(), 1); + + TDeadItemList lDeadItems; + TNumberedItemHash::iterator pComponent; + + for ( pComponent = m_lComponents.begin (); + pComponent != m_lComponents.end (); + ++pComponent ) + { + const TNumberedItem& rItem = pComponent->second; + const css::uno::Reference< css::uno::XInterface > xItem = rItem.xItem.get(); + + if ( ! xItem.is ()) + { + lDeadItems.push_back(pComponent->first); + continue; + } + + if (rItem.nNumber == nNumber) + { + m_lComponents.erase (pComponent); + break; + } + } + + impl_cleanUpDeadItems(m_lComponents, lDeadItems); + + // <- SYNCHRONIZED +} + +//----------------------------------------------- +void SAL_CALL NumberedCollection::releaseNumberForComponent(const css::uno::Reference< css::uno::XInterface >& xComponent) + throw (css::lang::IllegalArgumentException, + css::uno::RuntimeException ) +{ + // SYNCHRONIZED -> + ::osl::ResettableMutexGuard aLock(m_aMutex); + + if ( ! xComponent.is ()) + throw css::lang::IllegalArgumentException (ERRMSG_INVALID_COMPONENT_PARAM, m_xOwner.get(), 1); + + long pComponent = (long) xComponent.get (); + TNumberedItemHash::iterator pIt = m_lComponents.find (pComponent); + + // a) component exists and will be removed + if (pIt != m_lComponents.end()) + m_lComponents.erase(pIt); + + // else + // b) component does not exists - nothing todo here (ignore request!) + + // <- SYNCHRONIZED +} + +//----------------------------------------------- +::rtl::OUString SAL_CALL NumberedCollection::getUntitledPrefix() + throw (css::uno::RuntimeException) +{ + // SYNCHRONIZED -> + ::osl::ResettableMutexGuard aLock(m_aMutex); + + return m_sUntitledPrefix; + + // <- SYNCHRONIZED +} + +//----------------------------------------------- +/** create an ordered list of all possible numbers ... + e.g. {1,2,3,...,N} Max size of these list will be + current size of component list + 1 . + + "+1" ... because in case all numbers in range 1..n + are in use we need a new number n+1 :-) + + Every item which is already used as unique number + will be removed. At the end a list of e.g. {3,6,...,M} + exists where the first item represent the lowest free + number (in this example 3). + */ +::sal_Int32 NumberedCollection::impl_searchFreeNumber () +{ + // create ordered list of all possible numbers. + ::std::vector< ::sal_Int32 > lPossibleNumbers; + ::sal_Int32 c = (::sal_Int32)m_lComponents.size (); + ::sal_Int32 i = 1; + + // c cant be less then 0 ... otherwhise hash.size() has an error :-) + // But we need at least n+1 numbers here. + c += 1; + + for (i=1; i<=c; ++i) + lPossibleNumbers.push_back (i); + + // SYNCHRONIZED -> + ::osl::ResettableMutexGuard aLock(m_aMutex); + + TDeadItemList lDeadItems; + TNumberedItemHash::const_iterator pComponent; + + for ( pComponent = m_lComponents.begin (); + pComponent != m_lComponents.end (); + ++pComponent ) + { + const TNumberedItem& rItem = pComponent->second; + const css::uno::Reference< css::uno::XInterface > xItem = rItem.xItem.get(); + + if ( ! xItem.is ()) + { + lDeadItems.push_back(pComponent->first); + continue; + } + + ::std::vector< ::sal_Int32 >::iterator pPossible = ::std::find(lPossibleNumbers.begin (), lPossibleNumbers.end (), rItem.nNumber); + if (pPossible != lPossibleNumbers.end ()) + lPossibleNumbers.erase (pPossible); + } + + impl_cleanUpDeadItems(m_lComponents, lDeadItems); + + // a) non free numbers ... return INVALID_NUMBER + if (lPossibleNumbers.size () < 1) + return css::frame::UntitledNumbersConst::INVALID_NUMBER; + + // b) return first free number + return *(lPossibleNumbers.begin ()); + + // <- SYNCHRONIZED +} + +void NumberedCollection::impl_cleanUpDeadItems ( TNumberedItemHash& lItems , + const TDeadItemList& lDeadItems) +{ + TDeadItemList::const_iterator pIt; + + for ( pIt = lDeadItems.begin (); + pIt != lDeadItems.end (); + ++pIt ) + { + const long& rDeadItem = *pIt; + lItems.erase(rDeadItem); + } +} + +} // namespace comphelper diff --git a/comphelper/source/misc/numbers.cxx b/comphelper/source/misc/numbers.cxx new file mode 100644 index 000000000000..06f9f519c318 --- /dev/null +++ b/comphelper/source/misc/numbers.cxx @@ -0,0 +1,150 @@ +/************************************************************************* + * + * 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/numbers.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/Locale.hpp> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + +namespace starbeans = ::com::sun::star::beans; +namespace starlang = ::com::sun::star::lang; + +//------------------------------------------------------------------------------ +sal_Int16 getNumberFormatType(const staruno::Reference<starutil::XNumberFormats>& xFormats, sal_Int32 nKey) +{ + sal_Int16 nReturn(starutil::NumberFormat::UNDEFINED); + if (xFormats.is()) + { + try + { + staruno::Reference<starbeans::XPropertySet> xFormat(xFormats->getByKey(nKey)); + if (xFormat.is()) + xFormat->getPropertyValue(rtl::OUString::createFromAscii("Type")) >>= nReturn; + } + catch(...) + { + OSL_TRACE("getNumberFormatType : invalid key! (maybe created with another formatter ?)"); + } + } + return nReturn; +} + +//------------------------------------------------------------------------------ +sal_Int16 getNumberFormatType(const staruno::Reference<starutil::XNumberFormatter>& xFormatter, sal_Int32 nKey) +{ + OSL_ENSURE(xFormatter.is(), "getNumberFormatType : the formatter isn't valid !"); + staruno::Reference<starutil::XNumberFormatsSupplier> xSupplier( xFormatter->getNumberFormatsSupplier()); + OSL_ENSURE(xSupplier.is(), "getNumberFormatType : the formatter doesn't implement a supplier !"); + staruno::Reference<starutil::XNumberFormats> xFormats( xSupplier->getNumberFormats()); + return getNumberFormatType(xFormats, nKey); +} + +//------------------------------------------------------------------------------ +staruno::Any getNumberFormatDecimals(const staruno::Reference<starutil::XNumberFormats>& xFormats, sal_Int32 nKey) +{ + if (xFormats.is()) + { + try + { + staruno::Reference<starbeans::XPropertySet> xFormat( xFormats->getByKey(nKey)); + if (xFormat.is()) + { + static ::rtl::OUString PROPERTY_DECIMALS = ::rtl::OUString::createFromAscii("Decimals"); + return xFormat->getPropertyValue(PROPERTY_DECIMALS); + } + } + catch(...) + { + OSL_TRACE("getNumberFormatDecimals : invalid key! (may be created with another formatter ?)"); + } + } + return staruno::makeAny((sal_Int16)0); +} + + +//------------------------------------------------------------------------------ +sal_Int32 getStandardFormat( + const staruno::Reference<starutil::XNumberFormatter>& xFormatter, + sal_Int16 nType, + const starlang::Locale& _rLocale) +{ + staruno::Reference<starutil::XNumberFormatsSupplier> xSupplier( xFormatter.is() ? xFormatter->getNumberFormatsSupplier() : staruno::Reference<starutil::XNumberFormatsSupplier>(NULL)); + staruno::Reference<starutil::XNumberFormats> xFormats( xSupplier.is() ? xSupplier->getNumberFormats() : staruno::Reference<starutil::XNumberFormats>(NULL)); + staruno::Reference<starutil::XNumberFormatTypes> xTypes(xFormats, staruno::UNO_QUERY); + OSL_ENSURE(xTypes.is(), "getStandardFormat : no format types !"); + + return xTypes.is() ? xTypes->getStandardFormat(nType, _rLocale) : 0; +} + +//------------------------------------------------------------------------------ +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::beans; + +//------------------------------------------------------------------------------ +Any getNumberFormatProperty( const Reference< XNumberFormatter >& _rxFormatter, sal_Int32 _nKey, const rtl::OUString& _rPropertyName ) +{ + Any aReturn; + + OSL_ENSURE( _rxFormatter.is() && _rPropertyName.getLength(), "getNumberFormatProperty: invalid arguments!" ); + try + { + Reference< XNumberFormatsSupplier > xSupplier; + Reference< XNumberFormats > xFormats; + Reference< XPropertySet > xFormatProperties; + + if ( _rxFormatter.is() ) + xSupplier = _rxFormatter->getNumberFormatsSupplier(); + if ( xSupplier.is() ) + xFormats = xSupplier->getNumberFormats(); + if ( xFormats.is() ) + xFormatProperties = xFormats->getByKey( _nKey ); + + if ( xFormatProperties.is() ) + aReturn = xFormatProperties->getPropertyValue( _rPropertyName ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "::getNumberFormatProperty: caught an exception (did you create the key with another formatter?)!" ); + } + + return aReturn; +} + +//......................................................................... +} // namespace comphelper +//......................................................................... + diff --git a/comphelper/source/misc/officeresourcebundle.cxx b/comphelper/source/misc/officeresourcebundle.cxx new file mode 100644 index 000000000000..cbe5b0dc2659 --- /dev/null +++ b/comphelper/source/misc/officeresourcebundle.cxx @@ -0,0 +1,240 @@ +/************************************************************************* + * + * 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/officeresourcebundle.hxx> + +/** === begin UNO includes === **/ +#include <com/sun/star/resource/XResourceBundle.hpp> +#include <com/sun/star/resource/XResourceBundleLoader.hpp> +#include <com/sun/star/lang/NullPointerException.hpp> +/** === end UNO includes === **/ +#include <osl/mutex.hxx> +#include <osl/diagnose.h> +#include <rtl/ustrbuf.hxx> + +//........................................................................ +namespace comphelper +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using com::sun::star::resource::XResourceBundle; + using com::sun::star::resource::XResourceBundleLoader; + using com::sun::star::resource::MissingResourceException; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::lang::NullPointerException; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::Any; + /** === end UNO using === **/ + + //==================================================================== + //= ResourceBundle_Impl + //==================================================================== + class ResourceBundle_Impl + { + private: + Reference< XComponentContext > m_xContext; + ::rtl::OUString m_sBaseName; + Reference< XResourceBundle > m_xBundle; + bool m_bAttemptedCreate; + mutable ::osl::Mutex m_aMutex; + + public: + ResourceBundle_Impl( const Reference< XComponentContext >& _context, const ::rtl::OUString& _baseName ) + :m_xContext( _context ) + ,m_sBaseName( _baseName ) + ,m_bAttemptedCreate( false ) + { + } + + public: + /** loads the string with the given resource id from the resource bundle + @param _resourceId + the id of the string to load + @return + the requested resource string. If no string with the given id exists in the resource bundle, + an empty string is returned. In a non-product version, an OSL_ENSURE will notify you of this + then. + */ + ::rtl::OUString loadString( sal_Int32 _resourceId ) const; + + /** determines whether the resource bundle has a string with the given id + @param _resourceId + the id of the string whose existence is to be checked + @return + <TRUE/> if and only if a string with the given ID exists in the resource + bundle. + */ + bool hasString( sal_Int32 _resourceId ) const; + + private: + /** loads the bundle represented by the instance + + The method is safe against multiple calls: If a previos call succeeded or failed, the + previous result will be returned, without any other processing. + + @precond + Our mutex is locked. + */ + bool impl_loadBundle_nothrow(); + + /** returns the resource bundle key for a string with a given resource id + */ + static ::rtl::OUString + impl_getStringResourceKey( sal_Int32 _resourceId ); + }; + + //-------------------------------------------------------------------- + ::rtl::OUString ResourceBundle_Impl::impl_getStringResourceKey( sal_Int32 _resourceId ) + { + ::rtl::OUStringBuffer key; + key.appendAscii( "string:" ); + key.append( _resourceId ); + return key.makeStringAndClear(); + } + + //-------------------------------------------------------------------- + ::rtl::OUString ResourceBundle_Impl::loadString( sal_Int32 _resourceId ) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + ::rtl::OUString sString; + + if ( const_cast< ResourceBundle_Impl* >( this )->impl_loadBundle_nothrow() ) + { + try + { + OSL_VERIFY( m_xBundle->getByName( impl_getStringResourceKey( _resourceId ) ) >>= sString ); + } + catch( const Exception& ) + { + OSL_ENSURE( false, "ResourceBundle_Impl::loadString: caught an exception!" ); + } + } + return sString; + } + + //-------------------------------------------------------------------- + bool ResourceBundle_Impl::hasString( sal_Int32 _resourceId ) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + bool has = false; + + if ( const_cast< ResourceBundle_Impl* >( this )->impl_loadBundle_nothrow() ) + { + try + { + has = m_xBundle->hasByName( impl_getStringResourceKey( _resourceId ) ); + } + catch( const Exception& ) + { + OSL_ENSURE( false, "ResourceBundle_Impl::hasString: caught an exception!" ); + } + } + return has; + } + + //-------------------------------------------------------------------- + bool ResourceBundle_Impl::impl_loadBundle_nothrow() + { + if ( m_bAttemptedCreate ) + return m_xBundle.is(); + + m_bAttemptedCreate = true; + + Reference< XResourceBundleLoader > xLoader; + try + { + Any aValue( m_xContext->getValueByName( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "/singletons/com.sun.star.resource.OfficeResourceLoader" ) ) ) ); + OSL_VERIFY( aValue >>= xLoader ); + } + catch( const Exception& ) + { + OSL_ENSURE( false, "ResourceBundle_Impl::impl_loadBundle_nopthrow: could not create the resource loader!" ); + } + + if ( !xLoader.is() ) + return false; + + try + { + m_xBundle = xLoader->loadBundle_Default( m_sBaseName ); + } + catch( const MissingResourceException& ) + { + OSL_ENSURE( false, "ResourceBundle_Impl::impl_loadBundle_nopthrow: missing the given resource bundle!" ); + } + + return m_xBundle.is(); + } + + //==================================================================== + //= OfficeResourceBundle + //==================================================================== + //-------------------------------------------------------------------- + OfficeResourceBundle::OfficeResourceBundle( const Reference< XComponentContext >& _context, const ::rtl::OUString& _bundleBaseName ) + :m_pImpl( new ResourceBundle_Impl( _context, _bundleBaseName ) ) + { + if ( !_context.is() ) + throw NullPointerException(); + } + + //-------------------------------------------------------------------- + OfficeResourceBundle::OfficeResourceBundle( const Reference< XComponentContext >& _context, const sal_Char* _bundleBaseAsciiName ) + :m_pImpl( new ResourceBundle_Impl( _context, ::rtl::OUString::createFromAscii( _bundleBaseAsciiName ) ) ) + { + if ( !_context.is() ) + throw NullPointerException(); + } + + //-------------------------------------------------------------------- + OfficeResourceBundle::~OfficeResourceBundle() + { + } + + //-------------------------------------------------------------------- + ::rtl::OUString OfficeResourceBundle::loadString( sal_Int32 _resourceId ) const + { + return m_pImpl->loadString( _resourceId ); + } + + //-------------------------------------------------------------------- + bool OfficeResourceBundle::hasString( sal_Int32 _resourceId ) const + { + return m_pImpl->hasString( _resourceId ); + } + +//........................................................................ +} // namespace comphelper +//........................................................................ diff --git a/comphelper/source/misc/officerestartmanager.cxx b/comphelper/source/misc/officerestartmanager.cxx new file mode 100644 index 000000000000..974b8d65e7ae --- /dev/null +++ b/comphelper/source/misc/officerestartmanager.cxx @@ -0,0 +1,210 @@ +/************************************************************************* + * + * 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/XMultiComponentFactory.hpp> +#include <com/sun/star/awt/XRequestCallback.hpp> +#include <com/sun/star/frame/XDesktop.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <comphelper_module.hxx> +#include "officerestartmanager.hxx" + +using namespace ::com::sun::star; + +namespace comphelper +{ + +// ---------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OOfficeRestartManager::getSupportedServiceNames_static() +{ + uno::Sequence< rtl::OUString > aResult( 1 ); + aResult[0] = getServiceName_static(); + return aResult; +} + +// ---------------------------------------------------------- +::rtl::OUString SAL_CALL OOfficeRestartManager::getImplementationName_static() +{ + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.task.OfficeRestartManager" ) ); +} + +// ---------------------------------------------------------- +::rtl::OUString SAL_CALL OOfficeRestartManager::getSingletonName_static() +{ + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.task.OfficeRestartManager" ) ); +} + +// ---------------------------------------------------------- +::rtl::OUString SAL_CALL OOfficeRestartManager::getServiceName_static() +{ + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.task.OfficeRestartManager" ) ); +} + +// ---------------------------------------------------------- +uno::Reference< uno::XInterface > SAL_CALL OOfficeRestartManager::Create( const uno::Reference< uno::XComponentContext >& rxContext ) +{ + return static_cast< cppu::OWeakObject* >( new OOfficeRestartManager( rxContext ) ); +} + +// XRestartManager +// ---------------------------------------------------------- +void SAL_CALL OOfficeRestartManager::requestRestart( const uno::Reference< task::XInteractionHandler >& /* xInteractionHandler */ ) + throw (uno::Exception, uno::RuntimeException) +{ + if ( !m_xContext.is() ) + throw uno::RuntimeException(); + + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // if the restart already running there is no need to trigger it again + if ( m_bRestartRequested ) + return; +#ifndef MACOSX + m_bRestartRequested = sal_True; +#endif + // the office is still not initialized, no need to terminate, changing the state is enough + if ( !m_bOfficeInitialized ) + return; + } + + // TODO: use InteractionHandler to report errors + try + { + // register itself as a job that should be executed asynchronously + uno::Reference< lang::XMultiComponentFactory > xFactory( m_xContext->getServiceManager(), uno::UNO_SET_THROW ); + + uno::Reference< awt::XRequestCallback > xRequestCallback( + xFactory->createInstanceWithContext( + ::rtl::OUString::createFromAscii("com.sun.star.awt.AsyncCallback"), + m_xContext ), + uno::UNO_QUERY_THROW ); + + xRequestCallback->addCallback( this, uno::Any() ); + } + catch ( uno::Exception& ) + { + // the try to request restart has failed + m_bRestartRequested = sal_False; + } +} + +// ---------------------------------------------------------- +::sal_Bool SAL_CALL OOfficeRestartManager::isRestartRequested( ::sal_Bool bOfficeInitialized ) + throw (uno::Exception, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( bOfficeInitialized && !m_bOfficeInitialized ) + m_bOfficeInitialized = bOfficeInitialized; + + return m_bRestartRequested; +} + +// XCallback +// ---------------------------------------------------------- +void SAL_CALL OOfficeRestartManager::notify( const uno::Any& /* aData */ ) + throw ( uno::RuntimeException ) +{ + try + { + sal_Bool bSuccess = sal_False; + + if ( m_xContext.is() ) + { + uno::Reference< lang::XMultiComponentFactory > xFactory( m_xContext->getServiceManager(), uno::UNO_SET_THROW ); + uno::Reference< frame::XDesktop > xDesktop( + xFactory->createInstanceWithContext( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.Desktop" ) ), m_xContext ), + uno::UNO_QUERY_THROW ); + + // Turn Quickstarter veto off + uno::Reference< beans::XPropertySet > xPropertySet( xDesktop, uno::UNO_QUERY_THROW ); + ::rtl::OUString aVetoPropName( RTL_CONSTASCII_USTRINGPARAM( "SuspendQuickstartVeto" ) ); + uno::Any aValue; + aValue <<= (sal_Bool)sal_True; + xPropertySet->setPropertyValue( aVetoPropName, aValue ); + + try + { + bSuccess = xDesktop->terminate(); + } catch( uno::Exception& ) + {} + + if ( !bSuccess ) + { + aValue <<= (sal_Bool)sal_False; + xPropertySet->setPropertyValue( aVetoPropName, aValue ); + } + } + + if ( !bSuccess ) + m_bRestartRequested = sal_False; + } + catch( uno::Exception& ) + { + // the try to restart has failed + m_bRestartRequested = sal_False; + } +} + +// XServiceInfo +// ---------------------------------------------------------- +::rtl::OUString SAL_CALL OOfficeRestartManager::getImplementationName() throw (uno::RuntimeException) +{ + return getImplementationName_static(); +} + +// ---------------------------------------------------------- +::sal_Bool SAL_CALL OOfficeRestartManager::supportsService( const ::rtl::OUString& aServiceName ) throw (uno::RuntimeException) +{ + const uno::Sequence< rtl::OUString > & aSupportedNames = getSupportedServiceNames_static(); + for ( sal_Int32 nInd = 0; nInd < aSupportedNames.getLength(); nInd++ ) + { + if ( aSupportedNames[ nInd ].equals( aServiceName ) ) + return sal_True; + } + + return sal_False; +} + +// ---------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OOfficeRestartManager::getSupportedServiceNames() throw (uno::RuntimeException) +{ + return getSupportedServiceNames_static(); +} + +} // namespace comphelper + +void createRegistryInfo_OOfficeRestartManager() +{ + static ::comphelper::module::OAutoRegistration< ::comphelper::OOfficeRestartManager > aAutoRegistration; + static ::comphelper::module::OSingletonRegistration< ::comphelper::OOfficeRestartManager > aSingletonRegistration; +} diff --git a/comphelper/source/misc/officerestartmanager.hxx b/comphelper/source/misc/officerestartmanager.hxx new file mode 100644 index 000000000000..2317d0217060 --- /dev/null +++ b/comphelper/source/misc/officerestartmanager.hxx @@ -0,0 +1,91 @@ +/************************************************************************* + * + * 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 __OFFICESTARTMANAGER_HXX_ +#define __OFFICESTARTMANAGER_HXX_ + +#include <com/sun/star/task/XRestartManager.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/awt/XCallback.hpp> + +#include <osl/mutex.hxx> +#include <cppuhelper/implbase3.hxx> + +namespace comphelper +{ + +class OOfficeRestartManager : public ::cppu::WeakImplHelper3< ::com::sun::star::task::XRestartManager + , ::com::sun::star::awt::XCallback + , ::com::sun::star::lang::XServiceInfo > +{ + ::osl::Mutex m_aMutex; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > m_xContext; + + sal_Bool m_bOfficeInitialized; + sal_Bool m_bRestartRequested; + +public: + OOfficeRestartManager( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& xContext ) + : m_xContext( xContext ) + , m_bOfficeInitialized( sal_False ) + , m_bRestartRequested( sal_False ) + {} + + virtual ~OOfficeRestartManager() + {} + + static ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL + getSupportedServiceNames_static(); + + static ::rtl::OUString SAL_CALL getImplementationName_static(); + + static ::rtl::OUString SAL_CALL getSingletonName_static(); + + static ::rtl::OUString SAL_CALL getServiceName_static(); + + 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 >& rxContext ); + +// XRestartManager + virtual void SAL_CALL requestRestart( const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& xInteractionHandler ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL isRestartRequested( ::sal_Bool bInitialized ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + +// XCallback + virtual void SAL_CALL notify( const ::com::sun::star::uno::Any& aData ) throw (::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); + +}; + +} // namespace comphelper + +#endif + diff --git a/comphelper/source/misc/proxyaggregation.cxx b/comphelper/source/misc/proxyaggregation.cxx new file mode 100644 index 000000000000..1a3dd73930ba --- /dev/null +++ b/comphelper/source/misc/proxyaggregation.cxx @@ -0,0 +1,276 @@ +/************************************************************************* + * + * 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/proxyaggregation.hxx> +#include <com/sun/star/reflection/XProxyFactory.hpp> + +//............................................................................. +namespace comphelper +{ +//............................................................................. + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::reflection; + + //========================================================================= + //= OProxyAggregation + //========================================================================= + //------------------------------------------------------------------------- + OProxyAggregation::OProxyAggregation( const Reference< XMultiServiceFactory >& _rxORB ) + :m_xORB( _rxORB ) + { + } + + //------------------------------------------------------------------------- + void OProxyAggregation::baseAggregateProxyFor( const Reference< XInterface >& _rxComponent, oslInterlockedCount& _rRefCount, + ::cppu::OWeakObject& _rDelegator ) + { + // first a factory for the proxy + Reference< XProxyFactory > xFactory( + m_xORB->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.reflection.ProxyFactory" ) ) ), + UNO_QUERY + ); + OSL_ENSURE( xFactory.is(), "OProxyAggregation::baseAggregateProxyFor: could not create a proxy factory!" ); + + // then the proxy itself + if ( xFactory.is() ) + { + { // i36686 OJ: achieve the desctruction of the tempoary -> otherwise it leads to _rRefCount -= 2 + m_xProxyAggregate = xFactory->createProxy( _rxComponent ); + } + if ( m_xProxyAggregate.is() ) + m_xProxyAggregate->queryAggregation( ::getCppuType( &m_xProxyTypeAccess ) ) >>= m_xProxyTypeAccess; + + // aggregate the proxy + osl_incrementInterlockedCount( &_rRefCount ); + if ( m_xProxyAggregate.is() ) + { + // At this point in time, the proxy has a ref count of exactly two - in m_xControlContextProxy, + // and in m_xProxyTypeAccess. + // Remember to _not_ reset these members unless the delegator of the proxy has been reset, too! + m_xProxyAggregate->setDelegator( _rDelegator ); + } + osl_decrementInterlockedCount( &_rRefCount ); + } + } + + //------------------------------------------------------------------------- + Any SAL_CALL OProxyAggregation::queryAggregation( const Type& _rType ) throw (RuntimeException) + { + return m_xProxyAggregate.is() ? m_xProxyAggregate->queryAggregation( _rType ) : Any(); + } + + //------------------------------------------------------------------------- + Sequence< Type > SAL_CALL OProxyAggregation::getTypes( ) throw (RuntimeException) + { + Sequence< Type > aTypes; + if ( m_xProxyAggregate.is() ) + { + if ( m_xProxyTypeAccess.is() ) + aTypes = m_xProxyTypeAccess->getTypes(); + } + return aTypes; + } + + //------------------------------------------------------------------------- + OProxyAggregation::~OProxyAggregation() + { + if ( m_xProxyAggregate.is() ) + m_xProxyAggregate->setDelegator( NULL ); + m_xProxyAggregate.clear(); + m_xProxyTypeAccess.clear(); + // this should remove the _two_only_ "real" references (means not delegated to + // ourself) to this proxy, and thus delete it + } + + //========================================================================= + //= OComponentProxyAggregationHelper + //========================================================================= + //------------------------------------------------------------------------- + OComponentProxyAggregationHelper::OComponentProxyAggregationHelper( const Reference< XMultiServiceFactory >& _rxORB, + ::cppu::OBroadcastHelper& _rBHelper ) + :OProxyAggregation( _rxORB ) + ,m_rBHelper( _rBHelper ) + { + OSL_ENSURE( _rxORB.is(), "OComponentProxyAggregationHelper::OComponentProxyAggregationHelper: invalid arguments!" ); + } + + //------------------------------------------------------------------------- + void OComponentProxyAggregationHelper::componentAggregateProxyFor( + const Reference< XComponent >& _rxComponent, oslInterlockedCount& _rRefCount, + ::cppu::OWeakObject& _rDelegator ) + { + OSL_ENSURE( _rxComponent.is(), "OComponentProxyAggregationHelper::componentAggregateProxyFor: invalid inner component!" ); + m_xInner = _rxComponent; + + // aggregate a proxy for the object + baseAggregateProxyFor( m_xInner.get(), _rRefCount, _rDelegator ); + + // add as event listener to the inner context, because we want to be notified of disposals + osl_incrementInterlockedCount( &_rRefCount ); + { + if ( m_xInner.is() ) + m_xInner->addEventListener( this ); + } + osl_decrementInterlockedCount( &_rRefCount ); + } + + //------------------------------------------------------------------------- + Any SAL_CALL OComponentProxyAggregationHelper::queryInterface( const Type& _rType ) throw (RuntimeException) + { + Any aReturn( BASE::queryInterface( _rType ) ); + if ( !aReturn.hasValue() ) + aReturn = OProxyAggregation::queryAggregation( _rType ); + return aReturn; + } + + //------------------------------------------------------------------------- + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OComponentProxyAggregationHelper, BASE, OProxyAggregation ) + + //------------------------------------------------------------------------- + OComponentProxyAggregationHelper::~OComponentProxyAggregationHelper( ) + { + OSL_ENSURE( m_rBHelper.bDisposed, "OComponentProxyAggregationHelper::~OComponentProxyAggregationHelper: you should dispose your derived class in the dtor, if necessary!" ); + // if this asserts, add the following to your derived class dtor: + // + // if ( !m_rBHelper.bDisposed ) + // { + // acquire(); // to prevent duplicate dtor calls + // dispose(); + // } + + m_xInner.clear(); + } + + //------------------------------------------------------------------------- + void SAL_CALL OComponentProxyAggregationHelper::disposing( const EventObject& _rSource ) throw (RuntimeException) + { + if ( _rSource.Source == m_xInner ) + { // it's our inner context which is dying -> dispose ourself + if ( !m_rBHelper.bDisposed && !m_rBHelper.bInDispose ) + { // (if necessary only, of course) + dispose(); + } + } + } + + //------------------------------------------------------------------------- + void SAL_CALL OComponentProxyAggregationHelper::dispose() throw( RuntimeException ) + { + ::osl::MutexGuard aGuard( m_rBHelper.rMutex ); + + // dispose our inner context + // before we do this, remove ourself as listener - else in disposing( EventObject ), we + // would dispose ourself a second time + Reference< XComponent > xComp( m_xInner, UNO_QUERY ); + if ( xComp.is() ) + { + xComp->removeEventListener( this ); + xComp->dispose(); + xComp.clear(); + } + } + + //========================================================================= + //= OComponentProxyAggregation + //========================================================================= + //------------------------------------------------------------------------- + OComponentProxyAggregation::OComponentProxyAggregation( const Reference< XMultiServiceFactory >& _rxORB, + const Reference< XComponent >& _rxComponent ) + :OComponentProxyAggregation_CBase( m_aMutex ) + ,OComponentProxyAggregationHelper( _rxORB, rBHelper ) + { + OSL_ENSURE( _rxComponent.is(), "OComponentProxyAggregation::OComponentProxyAggregation: accessible is no XComponent!" ); + if ( _rxComponent.is() ) + componentAggregateProxyFor( _rxComponent, m_refCount, *this ); + } + + //------------------------------------------------------------------------- + OComponentProxyAggregation::~OComponentProxyAggregation() + { + implEnsureDisposeInDtor( ); + } + + //------------------------------------------------------------------------- + IMPLEMENT_FORWARD_XINTERFACE2( OComponentProxyAggregation, OComponentProxyAggregation_CBase, OComponentProxyAggregationHelper ) + + //------------------------------------------------------------------------- + IMPLEMENT_GET_IMPLEMENTATION_ID( OComponentProxyAggregation ) + + //------------------------------------------------------------------------- + Sequence< Type > SAL_CALL OComponentProxyAggregation::getTypes( ) throw (RuntimeException) + { + Sequence< Type > aTypes( OComponentProxyAggregationHelper::getTypes() ); + + // append XComponent, coming from OComponentProxyAggregation_CBase + sal_Int32 nLen = aTypes.getLength(); + aTypes.realloc( nLen + 1 ); + aTypes[ nLen ] = ::getCppuType( static_cast< Reference< XComponent >* >( NULL ) ); + + return aTypes; + } + + //------------------------------------------------------------------------- + void OComponentProxyAggregation::implEnsureDisposeInDtor( ) + { + if ( !rBHelper.bDisposed ) + { + acquire(); // to prevent duplicate dtor calls + dispose(); + } + } + + //-------------------------------------------------------------------- + void SAL_CALL OComponentProxyAggregation::disposing( const EventObject& _rSource ) throw (RuntimeException) + { + // simly disambiguate - this is necessary for MSVC to distinguish + // "disposing( EventObject )" from "disposing()" + OComponentProxyAggregationHelper::disposing( _rSource ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OComponentProxyAggregation::disposing() throw (RuntimeException) + { + // call the dispose-functionality of the base, which will dispose our aggregated component + OComponentProxyAggregationHelper::dispose(); + } + + //-------------------------------------------------------------------- + void SAL_CALL OComponentProxyAggregation::dispose() throw( RuntimeException ) + { + // simply disambiguate + OComponentProxyAggregation_CBase::dispose(); + } + + +//............................................................................. +} // namespace comphelper +//............................................................................. + diff --git a/comphelper/source/misc/querydeep.cxx b/comphelper/source/misc/querydeep.cxx new file mode 100644 index 000000000000..92e475686783 --- /dev/null +++ b/comphelper/source/misc/querydeep.cxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * 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/querydeep.hxx> +#include <typelib/typedescription.h> + +//__________________________________________________________________________________________________ + +sal_Bool comphelper::isDerivedFrom( + const ::com::sun::star::uno::Type & rBaseType, + const ::com::sun::star::uno::Type & rType ) +{ + using namespace ::com::sun::star::uno; + + TypeClass eClass = rBaseType.getTypeClass(); + + if (eClass != TypeClass_INTERFACE) + return sal_False; + + // supported TypeClass - do the types match ? + if (eClass != rType.getTypeClass()) + return sal_False; + + sal_Bool bRet; + + // shortcut for simple case + if (rBaseType == ::getCppuType(static_cast<const Reference< XInterface > *>(0))) + { + bRet = sal_True; + } + else + { + // now ask in cppu (aka typelib) + ::typelib_TypeDescription *pBaseTD = 0, *pTD = 0; + + rBaseType. getDescription(&pBaseTD); + rType. getDescription(&pTD); + + // interfaces are assignable to a base + bRet = ::typelib_typedescription_isAssignableFrom(pBaseTD, pTD); + + ::typelib_typedescription_release(pBaseTD); + ::typelib_typedescription_release(pTD); + } + + return bRet; +} + + + diff --git a/comphelper/source/misc/regpathhelper.cxx b/comphelper/source/misc/regpathhelper.cxx new file mode 100644 index 000000000000..0ac8f0277236 --- /dev/null +++ b/comphelper/source/misc/regpathhelper.cxx @@ -0,0 +1,235 @@ +/************************************************************************* + * + * 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 <stdio.h> +#include <osl/file.hxx> +#include <osl/security.hxx> +#include <osl/thread.h> +#include <vos/process.hxx> +#include <rtl/textenc.h> +#include <rtl/uri.h> +#include <rtl/uri.hxx> + +using namespace vos; +using namespace osl; +using namespace rtl; + +#define PATH_DELEMITTER '/' + +#define USER_REGISTRY_NAME_ENV "STAR_USER_REGISTRY" +#define SYSTEM_REGISTRY_NAME_ENV "STAR_REGISTRY" +#define REGISTRY_SYSTEM_NAME "services.rdb" + +#define REGISTRY_LOCAL_NAME "user60.rdb" + +#ifdef SAL_UNX +#define CONFIG_PATH_PREFIX "." +#else +#define CONFIG_PATH_PREFIX "" +#endif + +namespace comphelper +{ + +/** + @return sal_True, if the office is started in a portal + environment. + sal_False, if the common office is started + */ +static sal_Bool retrievePortalUserDir( OUString *pDirectory ) +{ + OStartupInfo startInfo; + sal_uInt32 nArgs = startInfo.getCommandArgCount(); + sal_Bool bIsPortalUser = sal_False; + OUString sArg; + while( nArgs > 0 ) + { + if ( !startInfo.getCommandArg(--nArgs, sArg) ) + { + if ( sArg.indexOf(OUString::createFromAscii("-userid")) == 0 ) + { + + bIsPortalUser = sal_True; + sal_Int32 nStart = sArg.lastIndexOf( '[' ); + sal_Int32 nEnd = sArg.lastIndexOf( ']' ); + if( -1 == nStart || -1 == nEnd || nEnd < nStart) + { + *pDirectory = OUString(); + } + else + { + OUString aEncHome = sArg.copy( nStart + 1 , nEnd - nStart -1 ); + *pDirectory = rtl::Uri::decode(aEncHome, + rtl_UriDecodeWithCharset, + RTL_TEXTENCODING_UTF8); + } + break; + } + } + } + return bIsPortalUser; +} + + +static OUString getDefaultLocalRegistry() +{ + OUString uBuffer, userRegistryName; + OUString portalUserDir; + + sal_Bool bIsPortalUser = retrievePortalUserDir( &portalUserDir ); + + if ( bIsPortalUser ) + { + if( portalUserDir.getLength() ) + { + FileBase::getFileURLFromSystemPath( portalUserDir , portalUserDir ); + userRegistryName = portalUserDir; + userRegistryName += OUString( RTL_CONSTASCII_USTRINGPARAM( + "/user/" REGISTRY_LOCAL_NAME ) ); + + // Directory creation is probably necessary for bootstrapping a new + // user in the portal environment (the ucb uses this function). + // This should be solved differently, as + // no one expects this function to create anything ... + OUString sSeparator(RTL_CONSTASCII_USTRINGPARAM("/")); + OUString sPath(RTL_CONSTASCII_USTRINGPARAM("file://")); + FileBase::RC retRC = FileBase::E_None; + + sal_Int32 nIndex = 3; + sPath += userRegistryName.getToken(2, '/', nIndex); + while( nIndex != -1 ) + { + sPath += sSeparator; + sPath += userRegistryName.getToken(0, '/', nIndex); + if( nIndex == -1 ) + break; + Directory aDir( sPath ); + if( aDir.open() == FileBase::E_NOENT ) + { + retRC = Directory::create(sPath); + if ( retRC != FileBase::E_None && retRC != FileBase::E_EXIST) + { + return OUString(); + } + } + } + } + } + else /* bIsPortalUser */ + { + ::osl::Security aUserSecurity; + aUserSecurity.getConfigDir( userRegistryName ); + userRegistryName += OUString( RTL_CONSTASCII_USTRINGPARAM( + "/" CONFIG_PATH_PREFIX REGISTRY_LOCAL_NAME ) ); + } + + return userRegistryName; +} + + +OUString getPathToUserRegistry() +{ + OUString userRegistryName; + FILE *f=NULL; + + // search the environment STAR_USER_REGISTRY + OString sBuffer( getenv(USER_REGISTRY_NAME_ENV) ); + if ( sBuffer.getLength() > 0 ) + { + f = fopen( sBuffer.getStr(), "r" ); + + if (f != NULL) + { + fclose(f); + userRegistryName = OStringToOUString( sBuffer, osl_getThreadTextEncoding() ); + } + } + + if ( !userRegistryName.getLength() ) + { + userRegistryName = getDefaultLocalRegistry(); + } + + return userRegistryName; +} + +OUString getPathToSystemRegistry() +{ + OUString uBuffer; + OUString registryBaseName( RTL_CONSTASCII_USTRINGPARAM(REGISTRY_SYSTEM_NAME) ); + OUString systemRegistryName; + FILE *f=NULL; + + // search in the directory of the executable + OStartupInfo info; + if( OStartupInfo::E_None == info.getExecutableFile(uBuffer) ) + { + sal_uInt32 lastIndex = uBuffer.lastIndexOf(PATH_DELEMITTER); + if (lastIndex > 0) + { + uBuffer = uBuffer.copy(0, lastIndex + 1); + } + + uBuffer += registryBaseName; + + if (!FileBase::getSystemPathFromFileURL(uBuffer, systemRegistryName)) + { + OString tmpStr( OUStringToOString(systemRegistryName, osl_getThreadTextEncoding()) ); + f = fopen( tmpStr.getStr(), "r" ); + } + } + + if (f == NULL) + { + // search the environment STAR_REGISTRY + OString tmpStr( getenv(SYSTEM_REGISTRY_NAME_ENV) ); + if ( tmpStr.getLength() > 0 ) + { + f = fopen(tmpStr.getStr(), "r"); + + if (f != NULL) + { + fclose(f); + systemRegistryName = OStringToOUString( tmpStr, osl_getThreadTextEncoding() ); + } else + { + systemRegistryName = OUString(); + } + } + } else + { + fclose(f); + } + + return systemRegistryName; +} + +} + diff --git a/comphelper/source/misc/scopeguard.cxx b/comphelper/source/misc/scopeguard.cxx new file mode 100644 index 000000000000..7ce478d8bea0 --- /dev/null +++ b/comphelper/source/misc/scopeguard.cxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * 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/scopeguard.hxx" +#include "osl/diagnose.h" +#include "com/sun/star/uno/Exception.hpp" + +namespace comphelper { + +ScopeGuard::~ScopeGuard() +{ + if (m_func) + { + if (m_excHandling == IGNORE_EXCEPTIONS) + { + try { + m_func(); + } + catch (com::sun::star::uno::Exception & exc) { + (void) exc; // avoid warning about unused variable + OSL_ENSURE( + false, rtl::OUStringToOString( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "UNO exception occured: ") ) + + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + } + catch (...) { + OSL_ENSURE( false, "unknown exception occured!" ); + } + } + else + { + m_func(); + } + } +} + +void ScopeGuard::dismiss() +{ + m_func.clear(); +} + +} // namespace comphelper + diff --git a/comphelper/source/misc/sequence.cxx b/comphelper/source/misc/sequence.cxx new file mode 100644 index 000000000000..b0d7c4da1587 --- /dev/null +++ b/comphelper/source/misc/sequence.cxx @@ -0,0 +1,103 @@ +/************************************************************************* + * + * 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/sequence.hxx> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + +//------------------------------------------------------------------------------ +staruno::Sequence<sal_Int16> findValue(const staruno::Sequence< ::rtl::OUString >& _rList, const ::rtl::OUString& _rValue, sal_Bool _bOnlyFirst) +{ + sal_Int32 nLength = _rList.getLength(); + + if( _bOnlyFirst ) + { + ////////////////////////////////////////////////////////////////////// + // An welcher Position finde ich den Wert? + sal_Int32 nPos = -1; + const ::rtl::OUString* pTArray = _rList.getConstArray(); + for (sal_Int32 i = 0; i < nLength; ++i, ++pTArray) + { + if( pTArray->equals(_rValue) ) + { + nPos = i; + break; + } + } + + ////////////////////////////////////////////////////////////////////// + // Sequence fuellen + if( nPos>-1 ) + { + staruno::Sequence<sal_Int16> aRetSeq( 1 ); + aRetSeq.getArray()[0] = (sal_Int16)nPos; + + return aRetSeq; + } + + return staruno::Sequence<sal_Int16>(); + + } + else + { + staruno::Sequence<sal_Int16> aRetSeq( nLength ); + sal_Int16* pReturn = aRetSeq.getArray(); + + ////////////////////////////////////////////////////////////////////// + // Wie oft kommt der Wert vor? + const ::rtl::OUString* pTArray = _rList.getConstArray(); + for (sal_Int32 i = 0; i < nLength; ++i, ++pTArray) + { + if( pTArray->equals(_rValue) ) + { + *pReturn = (sal_Int16)i; + ++pReturn; + } + } + + aRetSeq.realloc(pReturn - aRetSeq.getArray()); + + return aRetSeq; + } +} +// ----------------------------------------------------------------------------- +sal_Bool existsValue(const ::rtl::OUString& Value,const staruno::Sequence< ::rtl::OUString >& _aList) +{ + const ::rtl::OUString * pIter = _aList.getConstArray(); + const ::rtl::OUString * pEnd = pIter + _aList.getLength(); + return ::std::find(pIter,pEnd,Value) != pEnd; +} + +//......................................................................... +} // namespace comphelper +//......................................................................... + diff --git a/comphelper/source/misc/sequenceashashmap.cxx b/comphelper/source/misc/sequenceashashmap.cxx new file mode 100644 index 000000000000..a79ffc9037cc --- /dev/null +++ b/comphelper/source/misc/sequenceashashmap.cxx @@ -0,0 +1,400 @@ +/************************************************************************* + * + * 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" + +//_______________________________________________ +// includes +#include <comphelper/sequenceashashmap.hxx> + +//_______________________________________________ +// namespace + +namespace comphelper{ + +namespace css = ::com::sun::star; + +//_______________________________________________ +// definitions + +/*----------------------------------------------- + 04.11.2003 09:29 +-----------------------------------------------*/ +SequenceAsHashMap::SequenceAsHashMap() + : SequenceAsHashMapBase() +{ +} + +/*----------------------------------------------- + 04.11.2003 08:30 +-----------------------------------------------*/ +SequenceAsHashMap::SequenceAsHashMap(const css::uno::Any& aSource) +{ + (*this) << aSource; +} + +//----------------------------------------------- +SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::uno::Any >& lSource) +{ + (*this) << lSource; +} + +/*----------------------------------------------- + 04.11.2003 08:30 +-----------------------------------------------*/ +SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::beans::PropertyValue >& lSource) +{ + (*this) << lSource; +} + +/*----------------------------------------------- + 04.11.2003 08:30 +-----------------------------------------------*/ +SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::beans::NamedValue >& lSource) +{ + (*this) << lSource; +} + +/*----------------------------------------------- + 04.11.2003 09:04 +-----------------------------------------------*/ +SequenceAsHashMap::~SequenceAsHashMap() +{ +} + +/*----------------------------------------------- + 04.11.2003 10:21 +-----------------------------------------------*/ +void SequenceAsHashMap::operator<<(const css::uno::Any& aSource) +{ + // An empty Any reset this instance! + if (!aSource.hasValue()) + { + clear(); + return; + } + + css::uno::Sequence< css::beans::NamedValue > lN; + if (aSource >>= lN) + { + (*this) << lN; + return; + } + + css::uno::Sequence< css::beans::PropertyValue > lP; + if (aSource >>= lP) + { + (*this) << lP; + return; + } + + throw css::beans::IllegalTypeException( + ::rtl::OUString::createFromAscii("Any contains wrong type."), + css::uno::Reference< css::uno::XInterface >()); +} + +//----------------------------------------------- +void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::uno::Any >& lSource) +{ + sal_Int32 c = lSource.getLength(); + sal_Int32 i = 0; + + for (i=0; i<c; ++i) + { + css::beans::PropertyValue lP; + if (lSource[i] >>= lP) + { + if ( + (!lP.Name.getLength()) || + (!lP.Value.hasValue()) + ) + throw css::beans::IllegalTypeException( + ::rtl::OUString::createFromAscii("PropertyValue struct contains no usefull informations."), + css::uno::Reference< css::uno::XInterface >()); + (*this)[lP.Name] = lP.Value; + continue; + } + + css::beans::NamedValue lN; + if (lSource[i] >>= lN) + { + if ( + (!lN.Name.getLength()) || + (!lN.Value.hasValue()) + ) + throw css::beans::IllegalTypeException( + ::rtl::OUString::createFromAscii("NamedValue struct contains no usefull informations."), + css::uno::Reference< css::uno::XInterface >()); + (*this)[lN.Name] = lN.Value; + continue; + } + + // ignore VOID Any ... but reject wrong filled ones! + if (lSource[i].hasValue()) + throw css::beans::IllegalTypeException( + ::rtl::OUString::createFromAscii("Any contains wrong type."), + css::uno::Reference< css::uno::XInterface >()); + } +} + +/*----------------------------------------------- + 04.11.2003 08:30 +-----------------------------------------------*/ +void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::beans::PropertyValue >& lSource) +{ + clear(); + + sal_Int32 c = lSource.getLength(); + const css::beans::PropertyValue* pSource = lSource.getConstArray(); + + for (sal_Int32 i=0; i<c; ++i) + (*this)[pSource[i].Name] = pSource[i].Value; +} + +/*----------------------------------------------- + 04.11.2003 08:30 +-----------------------------------------------*/ +void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::beans::NamedValue >& lSource) +{ + clear(); + + sal_Int32 c = lSource.getLength(); + const css::beans::NamedValue* pSource = lSource.getConstArray(); + + for (sal_Int32 i=0; i<c; ++i) + (*this)[pSource[i].Name] = pSource[i].Value; +} + +/*----------------------------------------------- + 04.11.2003 08:30 +-----------------------------------------------*/ +void SequenceAsHashMap::operator>>(css::uno::Sequence< css::beans::PropertyValue >& lDestination) const +{ + sal_Int32 c = (sal_Int32)size(); + lDestination.realloc(c); + css::beans::PropertyValue* pDestination = lDestination.getArray(); + + sal_Int32 i = 0; + for (const_iterator pThis = begin(); + pThis != end() ; + ++pThis ) + { + pDestination[i].Name = pThis->first ; + pDestination[i].Value = pThis->second; + ++i; + } +} + +/*----------------------------------------------- + 04.11.2003 08:30 +-----------------------------------------------*/ +void SequenceAsHashMap::operator>>(css::uno::Sequence< css::beans::NamedValue >& lDestination) const +{ + sal_Int32 c = (sal_Int32)size(); + lDestination.realloc(c); + css::beans::NamedValue* pDestination = lDestination.getArray(); + + sal_Int32 i = 0; + for (const_iterator pThis = begin(); + pThis != end() ; + ++pThis ) + { + pDestination[i].Name = pThis->first ; + pDestination[i].Value = pThis->second; + ++i; + } +} + +/*----------------------------------------------- + 30.07.2007 14:10 +-----------------------------------------------*/ +const css::uno::Any SequenceAsHashMap::getAsConstAny(::sal_Bool bAsPropertyValueList) const +{ + css::uno::Any aDestination; + if (bAsPropertyValueList) + aDestination = css::uno::makeAny(getAsConstPropertyValueList()); + else + aDestination = css::uno::makeAny(getAsConstNamedValueList()); + return aDestination; +} + +/*----------------------------------------------- + 30.07.2007 14:10 +-----------------------------------------------*/ +const css::uno::Sequence< css::uno::Any > SequenceAsHashMap::getAsConstAnyList(::sal_Bool bAsPropertyValueList) const +{ + ::sal_Int32 i = 0; + ::sal_Int32 c = (::sal_Int32)size(); + css::uno::Sequence< css::uno::Any > lDestination(c); + css::uno::Any* pDestination = lDestination.getArray(); + + for (const_iterator pThis = begin(); + pThis != end() ; + ++pThis ) + { + if (bAsPropertyValueList) + { + css::beans::PropertyValue aProp; + aProp.Name = pThis->first; + aProp.Value = pThis->second; + pDestination[i] = css::uno::makeAny(aProp); + } + else + { + css::beans::NamedValue aProp; + aProp.Name = pThis->first; + aProp.Value = pThis->second; + pDestination[i] = css::uno::makeAny(aProp); + } + + ++i; + } + + return lDestination; +} + +/*----------------------------------------------- + 04.11.2003 08:30 +-----------------------------------------------*/ +const css::uno::Sequence< css::beans::NamedValue > SequenceAsHashMap::getAsConstNamedValueList() const +{ + css::uno::Sequence< css::beans::NamedValue > lReturn; + (*this) >> lReturn; + return lReturn; +} + +/*----------------------------------------------- + 04.11.2003 08:30 +-----------------------------------------------*/ +const css::uno::Sequence< css::beans::PropertyValue > SequenceAsHashMap::getAsConstPropertyValueList() const +{ + css::uno::Sequence< css::beans::PropertyValue > lReturn; + (*this) >> lReturn; + return lReturn; +} + +/*----------------------------------------------- + 07.03.2007 12:45 +-----------------------------------------------*/ +sal_Bool SequenceAsHashMap::match(const SequenceAsHashMap& rCheck) const +{ + const_iterator pCheck; + for ( pCheck = rCheck.begin(); + pCheck != rCheck.end() ; + ++pCheck ) + { + const ::rtl::OUString& sCheckName = pCheck->first; + const css::uno::Any& aCheckValue = pCheck->second; + const_iterator pFound = find(sCheckName); + + if (pFound == end()) + return sal_False; + + const css::uno::Any& aFoundValue = pFound->second; + if (aFoundValue != aCheckValue) + return sal_False; + } + + return sal_True; +} + +/*----------------------------------------------- + 30.07.2007 14:30 +-----------------------------------------------*/ +void SequenceAsHashMap::update(const SequenceAsHashMap& rUpdate) +{ + const_iterator pUpdate; + for ( pUpdate = rUpdate.begin(); + pUpdate != rUpdate.end() ; + ++pUpdate ) + { + const ::rtl::OUString& sName = pUpdate->first; + const css::uno::Any& aValue = pUpdate->second; + + (*this)[sName] = aValue; + } +} + +/*----------------------------------------------- + 04.11.2003 08:30 +-----------------------------------------------*/ +#if OSL_DEBUG_LEVEL > 1 +void SequenceAsHashMap::dbg_dumpToFile(const char* pFileName, + const char* pComment ) const +{ + if (!pFileName || !pComment) + return; + + FILE* pFile = fopen(pFileName, "a"); + if (!pFile) + return; + + ::rtl::OUStringBuffer sBuffer(1000); + sBuffer.appendAscii("\n----------------------------------------\n"); + sBuffer.appendAscii(pComment ); + sBuffer.appendAscii("\n----------------------------------------\n"); + sal_Int32 i = 0; + for (const_iterator pIt = begin(); + pIt != end() ; + ++pIt ) + { + sBuffer.appendAscii("[" ); + sBuffer.append (i++ ); + sBuffer.appendAscii("] " ); + sBuffer.appendAscii("\"" ); + sBuffer.append (pIt->first); + sBuffer.appendAscii("\" = \"" ); + + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xv; + ::rtl::OUString sv; + sal_Int32 nv; + sal_Bool bv; + + if (pIt->second >>= sv) + sBuffer.append(sv); + else + if (pIt->second >>= nv) + sBuffer.append(nv); + else + if (pIt->second >>= bv) + sBuffer.appendAscii(bv ? "true" : "false"); + else + if (pIt->second >>= xv) + sBuffer.appendAscii(xv.is() ? "object" : "null"); + else + sBuffer.appendAscii("???"); + + sBuffer.appendAscii("\"\n"); + } + + fprintf(pFile, ::rtl::OUStringToOString(sBuffer.makeStringAndClear(), RTL_TEXTENCODING_UTF8).getStr()); + fclose(pFile); +} +#endif // OSL_DEBUG_LEVEL > 1 + +} // namespace comphelper diff --git a/comphelper/source/misc/servicedecl.cxx b/comphelper/source/misc/servicedecl.cxx new file mode 100644 index 000000000000..7c3dd169485d --- /dev/null +++ b/comphelper/source/misc/servicedecl.cxx @@ -0,0 +1,196 @@ +/************************************************************************* + * + * 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/servicedecl.hxx" +#include "osl/diagnose.h" +#include "rtl/string.hxx" +#include "rtl/ustrbuf.hxx" +#include "cppuhelper/implbase2.hxx" +#include "comphelper/sequence.hxx" +#include "com/sun/star/lang/XSingleComponentFactory.hpp" +#include <vector> + +using namespace com::sun::star; + +namespace comphelper { +namespace service_decl { + +class ServiceDecl::Factory : + public cppu::WeakImplHelper2<lang::XSingleComponentFactory, + lang::XServiceInfo>, + private boost::noncopyable +{ +public: + explicit Factory( ServiceDecl const& rServiceDecl ) + : m_rServiceDecl(rServiceDecl) {} + + // XServiceInfo: + virtual rtl::OUString SAL_CALL getImplementationName() + throw (uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService( rtl::OUString const& name ) + throw (uno::RuntimeException); + virtual uno::Sequence<rtl::OUString> SAL_CALL getSupportedServiceNames() + throw (uno::RuntimeException); + // XSingleComponentFactory: + virtual uno::Reference<uno::XInterface> SAL_CALL createInstanceWithContext( + uno::Reference<uno::XComponentContext> const& xContext ) + throw (uno::Exception); + virtual uno::Reference<uno::XInterface> SAL_CALL + createInstanceWithArgumentsAndContext( + uno::Sequence<uno::Any> const& args, + uno::Reference<uno::XComponentContext> const& xContext ) + throw (uno::Exception); + +private: + virtual ~Factory(); + + ServiceDecl const& m_rServiceDecl; +}; + +ServiceDecl::Factory::~Factory() +{ +} + +// XServiceInfo: +rtl::OUString ServiceDecl::Factory::getImplementationName() + throw (uno::RuntimeException) +{ + return m_rServiceDecl.getImplementationName(); +} + +sal_Bool ServiceDecl::Factory::supportsService( rtl::OUString const& name ) + throw (uno::RuntimeException) +{ + return m_rServiceDecl.supportsService(name); +} + +uno::Sequence<rtl::OUString> ServiceDecl::Factory::getSupportedServiceNames() + throw (uno::RuntimeException) +{ + return m_rServiceDecl.getSupportedServiceNames(); +} + +// XSingleComponentFactory: +uno::Reference<uno::XInterface> ServiceDecl::Factory::createInstanceWithContext( + uno::Reference<uno::XComponentContext> const& xContext ) + throw (uno::Exception) +{ + return m_rServiceDecl.m_createFunc( + m_rServiceDecl, uno::Sequence<uno::Any>(), xContext ); +} + +uno::Reference<uno::XInterface> +ServiceDecl::Factory::createInstanceWithArgumentsAndContext( + uno::Sequence<uno::Any > const& args, + uno::Reference<uno::XComponentContext> const& xContext ) + throw (uno::Exception) +{ + return m_rServiceDecl.m_createFunc( + m_rServiceDecl, args, xContext ); +} + +bool ServiceDecl::writeInfo( registry::XRegistryKey * xKey ) const +{ + bool bRet = false; + if (xKey != 0) { + rtl::OUStringBuffer buf; + buf.append( static_cast<sal_Unicode>('/') ); + buf.appendAscii( m_pImplName ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("/UNO/SERVICES") ); + try { + uno::Reference<registry::XRegistryKey> const xNewKey( + xKey->createKey( buf.makeStringAndClear() ) ); + + rtl::OString const str(m_pServiceNames); + sal_Int32 nIndex = 0; + do { + rtl::OString const token( str.getToken( 0, m_cDelim, nIndex ) ); + xNewKey->createKey( + rtl::OUString( token.getStr(), token.getLength(), + RTL_TEXTENCODING_ASCII_US ) ); + } + while (nIndex >= 0); + + bRet = true; + } + catch (registry::InvalidRegistryException const&) { + OSL_ENSURE( false, "### InvalidRegistryException!" ); + } + } + return bRet; +} + +void * ServiceDecl::getFactory( sal_Char const* pImplName ) const +{ + if (rtl_str_compare(m_pImplName, pImplName) == 0) { + lang::XSingleComponentFactory * const pFac( new Factory(*this) ); + pFac->acquire(); + return pFac; + } + return 0; +} + +uno::Sequence<rtl::OUString> ServiceDecl::getSupportedServiceNames() const +{ + std::vector<rtl::OUString> vec; + + rtl::OString const str(m_pServiceNames); + sal_Int32 nIndex = 0; + do { + rtl::OString const token( str.getToken( 0, m_cDelim, nIndex ) ); + vec.push_back( rtl::OUString( token.getStr(), token.getLength(), + RTL_TEXTENCODING_ASCII_US ) ); + } + while (nIndex >= 0); + + return comphelper::containerToSequence(vec); +} + +bool ServiceDecl::supportsService( ::rtl::OUString const& name ) const +{ + rtl::OString const str(m_pServiceNames); + sal_Int32 nIndex = 0; + do { + rtl::OString const token( str.getToken( 0, m_cDelim, nIndex ) ); + if (name.equalsAsciiL( token.getStr(), token.getLength() )) + return true; + } + while (nIndex >= 0); + return false; +} + +rtl::OUString ServiceDecl::getImplementationName() const +{ + return rtl::OUString::createFromAscii(m_pImplName); +} + +} // namespace service_decl +} // namespace comphelper + diff --git a/comphelper/source/misc/serviceinfohelper.cxx b/comphelper/source/misc/serviceinfohelper.cxx new file mode 100644 index 000000000000..f2f9da278a06 --- /dev/null +++ b/comphelper/source/misc/serviceinfohelper.cxx @@ -0,0 +1,112 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unoprov.cxx,v $ + * $Revision: 1.72.92.1 $ + * + * 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/serviceinfohelper.hxx" +#include <stdarg.h> + +// ##################################################################### + +namespace comphelper +{ + +/** returns an empty UString(). most times sufficient */ +::rtl::OUString SAL_CALL ServiceInfoHelper::getImplementationName() throw( ::com::sun::star::uno::RuntimeException ) +{ + return ::rtl::OUString(); +} + +/** the base implementation iterates over the service names from <code>getSupportedServiceNames</code> */ +sal_Bool SAL_CALL ServiceInfoHelper::supportsService( const ::rtl::OUString& ServiceName ) throw(::com::sun::star::uno::RuntimeException) +{ + return supportsService( ServiceName, getSupportedServiceNames() ); +} + +sal_Bool SAL_CALL ServiceInfoHelper::supportsService( const ::rtl::OUString& ServiceName, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& SupportedServices ) throw() +{ + const ::rtl::OUString * pArray = SupportedServices.getConstArray(); + for( sal_Int32 i = 0; i < SupportedServices.getLength(); i++ ) + if( pArray[i] == ServiceName ) + return sal_True; + return sal_False; +} + +/** the base implementation has no supported services */ +::com::sun::star::uno::Sequence< ::rtl::OUString > ServiceInfoHelper::getSupportedServiceNames(void) throw( ::com::sun::star::uno::RuntimeException ) +{ + ::com::sun::star::uno::Sequence< ::rtl::OUString> aSeq(0); + return aSeq; +} + +/** this method concatenates the given sequences and returns the result + */ +::com::sun::star::uno::Sequence< ::rtl::OUString > ServiceInfoHelper::concatSequences( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rSeq1, + const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rSeq2 ) throw() +{ + const sal_Int32 nLen1 = rSeq1.getLength(); + const sal_Int32 nLen2 = rSeq2.getLength(); + + ::com::sun::star::uno::Sequence< ::rtl::OUString > aSeq( nLen1 + nLen2 ); + + ::rtl::OUString* pStrings = aSeq.getArray(); + + sal_Int32 nIdx; + const ::rtl::OUString* pStringSrc = rSeq1.getConstArray(); + for( nIdx = 0; nIdx < nLen1; nIdx++ ) + *pStrings++ = *pStringSrc++; + + pStringSrc = rSeq2.getConstArray(); + for( nIdx = 0; nIdx < nLen2; nIdx++ ) + *pStrings++ = *pStringSrc++; + + return aSeq; +} + +/** this method adds a variable number of char pointer to a given Sequence + */ +void ServiceInfoHelper::addToSequence( ::com::sun::star::uno::Sequence< ::rtl::OUString >& rSeq, sal_uInt16 nServices, /* char * */ ... ) throw() +{ + sal_uInt32 nCount = rSeq.getLength(); + + rSeq.realloc( nCount + nServices ); + rtl::OUString* pStrings = rSeq.getArray(); + + va_list marker; + va_start( marker, nServices ); + for( sal_uInt16 i = 0 ; i < nServices; i++ ) + pStrings[nCount++] = rtl::OUString::createFromAscii(va_arg( marker, char*)); + va_end( marker ); +} + +} + + diff --git a/comphelper/source/misc/sharedmutex.cxx b/comphelper/source/misc/sharedmutex.cxx new file mode 100644 index 000000000000..4d3fade030a6 --- /dev/null +++ b/comphelper/source/misc/sharedmutex.cxx @@ -0,0 +1,62 @@ +/************************************************************************* + * 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/sharedmutex.hxx" + +//........................................................................ +namespace comphelper +{ +//........................................................................ + + //======================================================================== + //= SharedMutex + //======================================================================== + //------------------------------------------------------------------------ + SharedMutex::SharedMutex() + :m_pMutexImpl( new ::osl::Mutex ) + { + } + + //------------------------------------------------------------------------ + SharedMutex::SharedMutex( const SharedMutex& _rhs ) + :m_pMutexImpl() + { + *this = _rhs; + } + + //------------------------------------------------------------------------ + SharedMutex& SharedMutex::operator=( const SharedMutex& _rhs ) + { + m_pMutexImpl = _rhs.m_pMutexImpl; + return *this; + } + +//........................................................................ +} // namespace comphelper +//........................................................................ diff --git a/comphelper/source/misc/stillreadwriteinteraction.cxx b/comphelper/source/misc/stillreadwriteinteraction.cxx new file mode 100644 index 000000000000..9054f0754b5e --- /dev/null +++ b/comphelper/source/misc/stillreadwriteinteraction.cxx @@ -0,0 +1,144 @@ +/************************************************************************* +* +* 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/stillreadwriteinteraction.hxx> + +#ifndef __COM_SUN_STAR_UCB_INTERACTIVEIOEXCEPTION_HPP__ +#include <com/sun/star/ucb/InteractiveIOException.hpp> +#endif + +#ifndef __COM_SUN_STAR_TASK_XINTERACTIONABORT_HPP__ +#include <com/sun/star/task/XInteractionAbort.hpp> +#endif + +#ifndef __COM_SUN_STAR_UCB_UNSUPPORTEDDATASINKEXCEPTION_HPP__ +#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp> +#endif + +namespace comphelper{ + + namespace css = ::com::sun::star; + +StillReadWriteInteraction::StillReadWriteInteraction(const css::uno::Reference< css::task::XInteractionHandler >& xHandler) + : m_bUsed (sal_False) + , m_bHandledByMySelf (sal_False) + , m_bHandledByInternalHandler(sal_False) +{ + ::std::vector< ::ucbhelper::InterceptedInteraction::InterceptedRequest > lInterceptions; + ::ucbhelper::InterceptedInteraction::InterceptedRequest aInterceptedRequest; + + aInterceptedRequest.Handle = HANDLE_INTERACTIVEIOEXCEPTION; + aInterceptedRequest.Request <<= css::ucb::InteractiveIOException(); + aInterceptedRequest.Continuation = ::getCppuType(static_cast< css::uno::Reference< css::task::XInteractionAbort >* >(0)); + aInterceptedRequest.MatchExact = sal_False; + lInterceptions.push_back(aInterceptedRequest); + + aInterceptedRequest.Handle = HANDLE_UNSUPPORTEDDATASINKEXCEPTION; + aInterceptedRequest.Request <<= css::ucb::UnsupportedDataSinkException(); + aInterceptedRequest.Continuation = ::getCppuType(static_cast< css::uno::Reference< css::task::XInteractionAbort >* >(0)); + aInterceptedRequest.MatchExact = sal_False; + lInterceptions.push_back(aInterceptedRequest); + + setInterceptedHandler(xHandler); + setInterceptions(lInterceptions); +} + +void StillReadWriteInteraction::resetInterceptions() +{ + setInterceptions(::std::vector< ::ucbhelper::InterceptedInteraction::InterceptedRequest >()); +} + +void StillReadWriteInteraction::resetErrorStates() +{ + m_bUsed = sal_False; + m_bHandledByMySelf = sal_False; + m_bHandledByInternalHandler = sal_False; +} + +sal_Bool StillReadWriteInteraction::wasWriteError() +{ + return (m_bUsed && m_bHandledByMySelf); +} + +ucbhelper::InterceptedInteraction::EInterceptionState StillReadWriteInteraction::intercepted(const ::ucbhelper::InterceptedInteraction::InterceptedRequest& aRequest, + const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionRequest >& xRequest) +{ + // we are used! + m_bUsed = sal_True; + + // check if its a real interception - might some parameters are not the right ones ... + sal_Bool bAbort = sal_False; + switch(aRequest.Handle) + { + case HANDLE_INTERACTIVEIOEXCEPTION: + { + css::ucb::InteractiveIOException exIO; + xRequest->getRequest() >>= exIO; + bAbort = ( + (exIO.Code == css::ucb::IOErrorCode_ACCESS_DENIED ) + || (exIO.Code == css::ucb::IOErrorCode_LOCKING_VIOLATION ) + || (exIO.Code == css::ucb::IOErrorCode_NOT_EXISTING ) +#ifdef MACOSX + // this is a workaround for MAC, on this platform if the file is locked + // the returned error code looks to be wrong + || (exIO.Code == css::ucb::IOErrorCode_GENERAL ) +#endif + ); + } + break; + + case HANDLE_UNSUPPORTEDDATASINKEXCEPTION: + { + bAbort = sal_True; + } + break; + } + + // handle interaction by ourself + if (bAbort) + { + m_bHandledByMySelf = sal_True; + css::uno::Reference< css::task::XInteractionContinuation > xAbort = ::ucbhelper::InterceptedInteraction::extractContinuation( + xRequest->getContinuations(), + ::getCppuType(static_cast< css::uno::Reference< css::task::XInteractionAbort >* >(0))); + if (!xAbort.is()) + return ::ucbhelper::InterceptedInteraction::E_NO_CONTINUATION_FOUND; + xAbort->select(); + return ::ucbhelper::InterceptedInteraction::E_INTERCEPTED; + } + + // Otherwhise use internal handler. + if (m_xInterceptedHandler.is()) + { + m_bHandledByInternalHandler = sal_True; + m_xInterceptedHandler->handle(xRequest); + } + return ::ucbhelper::InterceptedInteraction::E_INTERCEPTED; +} +} diff --git a/comphelper/source/misc/storagehelper.cxx b/comphelper/source/misc/storagehelper.cxx new file mode 100644 index 000000000000..e2557523f674 --- /dev/null +++ b/comphelper/source/misc/storagehelper.cxx @@ -0,0 +1,456 @@ +/************************************************************************* + * + * 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/embed/ElementModes.hpp> +#include <com/sun/star/embed/XEncryptionProtectedSource.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/IllegalTypeException.hpp> + +#include <ucbhelper/content.hxx> + +#include <comphelper/fileformat.h> +#include <comphelper/processfactory.hxx> +#include <comphelper/documentconstants.hxx> + +#include <comphelper/storagehelper.hxx> + + +using namespace ::com::sun::star; + +namespace comphelper { + +// ---------------------------------------------------------------------- +uno::Reference< lang::XSingleServiceFactory > OStorageHelper::GetStorageFactory( + const uno::Reference< lang::XMultiServiceFactory >& xSF ) + throw ( uno::Exception ) +{ + uno::Reference< lang::XMultiServiceFactory > xFactory = xSF.is() ? xSF : ::comphelper::getProcessServiceFactory(); + if ( !xFactory.is() ) + throw uno::RuntimeException(); + + uno::Reference < lang::XSingleServiceFactory > xStorageFactory( + xFactory->createInstance ( ::rtl::OUString::createFromAscii( "com.sun.star.embed.StorageFactory" ) ), + uno::UNO_QUERY ); + + if ( !xStorageFactory.is() ) + throw uno::RuntimeException(); + + return xStorageFactory; +} + +// ---------------------------------------------------------------------- +uno::Reference< lang::XSingleServiceFactory > OStorageHelper::GetFileSystemStorageFactory( + const uno::Reference< lang::XMultiServiceFactory >& xSF ) + throw ( uno::Exception ) +{ + uno::Reference< lang::XMultiServiceFactory > xFactory = xSF.is() ? xSF : ::comphelper::getProcessServiceFactory(); + if ( !xFactory.is() ) + throw uno::RuntimeException(); + + uno::Reference < lang::XSingleServiceFactory > xStorageFactory( + xFactory->createInstance ( ::rtl::OUString::createFromAscii( "com.sun.star.embed.FileSystemStorageFactory" ) ), + uno::UNO_QUERY ); + + if ( !xStorageFactory.is() ) + throw uno::RuntimeException(); + + return xStorageFactory; +} + +// ---------------------------------------------------------------------- +uno::Reference< embed::XStorage > OStorageHelper::GetTemporaryStorage( + const uno::Reference< lang::XMultiServiceFactory >& xFactory ) + throw ( uno::Exception ) +{ + uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstance(), + uno::UNO_QUERY ); + if ( !xTempStorage.is() ) + throw uno::RuntimeException(); + + return xTempStorage; +} + +// ---------------------------------------------------------------------- +uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromURL( + const ::rtl::OUString& aURL, + sal_Int32 nStorageMode, + const uno::Reference< lang::XMultiServiceFactory >& xFactory ) + throw ( uno::Exception ) +{ + uno::Sequence< uno::Any > aArgs( 2 ); + aArgs[0] <<= aURL; + aArgs[1] <<= nStorageMode; + + uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ), + uno::UNO_QUERY ); + if ( !xTempStorage.is() ) + throw uno::RuntimeException(); + + return xTempStorage; +} + +// ---------------------------------------------------------------------- +uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromURL2( + const ::rtl::OUString& aURL, + sal_Int32 nStorageMode, + const uno::Reference< lang::XMultiServiceFactory >& xFactory ) + throw ( uno::Exception ) +{ + uno::Sequence< uno::Any > aArgs( 2 ); + aArgs[0] <<= aURL; + aArgs[1] <<= nStorageMode; + + uno::Reference< lang::XSingleServiceFactory > xFact; + try { + ::ucbhelper::Content aCntnt( aURL, + uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + if (aCntnt.isDocument()) { + xFact = GetStorageFactory( xFactory ); + } else { + xFact = GetFileSystemStorageFactory( xFactory ); + } + } catch (uno::Exception &) { } + + if (!xFact.is()) throw uno::RuntimeException(); + + uno::Reference< embed::XStorage > xTempStorage( + xFact->createInstanceWithArguments( aArgs ), uno::UNO_QUERY ); + if ( !xTempStorage.is() ) + throw uno::RuntimeException(); + + return xTempStorage; +} + +// ---------------------------------------------------------------------- +uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromInputStream( + const uno::Reference < io::XInputStream >& xStream, + const uno::Reference< lang::XMultiServiceFactory >& xFactory ) + throw ( uno::Exception ) +{ + uno::Sequence< uno::Any > aArgs( 2 ); + aArgs[0] <<= xStream; + aArgs[1] <<= embed::ElementModes::READ; + + uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ), + uno::UNO_QUERY ); + if ( !xTempStorage.is() ) + throw uno::RuntimeException(); + + return xTempStorage; +} + +// ---------------------------------------------------------------------- +uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromStream( + const uno::Reference < io::XStream >& xStream, + sal_Int32 nStorageMode, + const uno::Reference< lang::XMultiServiceFactory >& xFactory ) + throw ( uno::Exception ) +{ + uno::Sequence< uno::Any > aArgs( 2 ); + aArgs[0] <<= xStream; + aArgs[1] <<= nStorageMode; + + uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ), + uno::UNO_QUERY ); + if ( !xTempStorage.is() ) + throw uno::RuntimeException(); + + return xTempStorage; +} + +// ---------------------------------------------------------------------- +void OStorageHelper::CopyInputToOutput( + const uno::Reference< io::XInputStream >& xInput, + const uno::Reference< io::XOutputStream >& xOutput ) + throw ( uno::Exception ) +{ + static const sal_Int32 nConstBufferSize = 32000; + + sal_Int32 nRead; + uno::Sequence < sal_Int8 > aSequence ( nConstBufferSize ); + + do + { + nRead = xInput->readBytes ( aSequence, nConstBufferSize ); + if ( nRead < nConstBufferSize ) + { + uno::Sequence < sal_Int8 > aTempBuf ( aSequence.getConstArray(), nRead ); + xOutput->writeBytes ( aTempBuf ); + } + else + xOutput->writeBytes ( aSequence ); + } + while ( nRead == nConstBufferSize ); +} + +// ---------------------------------------------------------------------- +uno::Reference< io::XInputStream > OStorageHelper::GetInputStreamFromURL( + const ::rtl::OUString& aURL, + const uno::Reference< lang::XMultiServiceFactory >& xSF ) + throw ( uno::Exception ) +{ + uno::Reference< lang::XMultiServiceFactory > xFactory = xSF.is() ? xSF : ::comphelper::getProcessServiceFactory(); + if ( !xFactory.is() ) + throw uno::RuntimeException(); + + uno::Reference < ::com::sun::star::ucb::XSimpleFileAccess > xTempAccess( + xFactory->createInstance ( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), + uno::UNO_QUERY ); + + if ( !xTempAccess.is() ) + throw uno::RuntimeException(); + + uno::Reference< io::XInputStream > xInputStream = xTempAccess->openFileRead( aURL ); + if ( !xInputStream.is() ) + throw uno::RuntimeException(); + + return xInputStream; +} + +// ---------------------------------------------------------------------- +void OStorageHelper::SetCommonStoragePassword( + const uno::Reference< embed::XStorage >& xStorage, + const ::rtl::OUString& aPass ) + throw ( uno::Exception ) +{ + uno::Reference< embed::XEncryptionProtectedSource > xEncrSet( xStorage, uno::UNO_QUERY ); + if ( !xEncrSet.is() ) + throw io::IOException(); // TODO + + xEncrSet->setEncryptionPassword( aPass ); +} + +// ---------------------------------------------------------------------- +sal_Int32 OStorageHelper::GetXStorageFormat( + const uno::Reference< embed::XStorage >& xStorage ) + throw ( uno::Exception ) +{ + uno::Reference< beans::XPropertySet > xStorProps( xStorage, uno::UNO_QUERY_THROW ); + + ::rtl::OUString aMediaType; + xStorProps->getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) ) >>= aMediaType; + + sal_Int32 nResult = 0; + + // TODO/LATER: the filter configuration could be used to detect it later, or batter a special service + if ( + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_WRITER_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_WRITER_WEB_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_WRITER_GLOBAL_ASCII) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_DRAW_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_IMPRESS_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_CALC_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_CHART_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_MATH_ASCII ) + ) + { + nResult = SOFFICE_FILEFORMAT_60; + } + else + if ( + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_REPORT_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_REPORT_CHART_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII ) || + aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII ) + ) + { + nResult = SOFFICE_FILEFORMAT_8; + } + else + { + // the mediatype is not known + throw beans::IllegalTypeException(); + } + + return nResult; +} + +// ---------------------------------------------------------------------- +uno::Reference< embed::XStorage > OStorageHelper::GetTemporaryStorageOfFormat( + const ::rtl::OUString& aFormat, + const uno::Reference< lang::XMultiServiceFactory >& xFactory ) + throw ( uno::Exception ) +{ + uno::Reference< lang::XMultiServiceFactory > xFactoryToUse = xFactory.is() ? xFactory : ::comphelper::getProcessServiceFactory(); + if ( !xFactoryToUse.is() ) + throw uno::RuntimeException(); + + uno::Reference< io::XStream > xTmpStream( + xFactoryToUse->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ) ), + uno::UNO_QUERY_THROW ); + + return GetStorageOfFormatFromStream( aFormat, xTmpStream, embed::ElementModes::READWRITE, xFactoryToUse ); +} + +// ---------------------------------------------------------------------- +uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromURL( + const ::rtl::OUString& aFormat, + const ::rtl::OUString& aURL, + sal_Int32 nStorageMode, + const uno::Reference< lang::XMultiServiceFactory >& xFactory, + sal_Bool bRepairStorage ) + throw ( uno::Exception ) +{ + uno::Sequence< beans::PropertyValue > aProps( 1 ); + aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) ); + aProps[0].Value <<= aFormat; + if ( bRepairStorage ) + { + aProps.realloc( 2 ); + aProps[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RepairPackage" ) ); + aProps[1].Value <<= bRepairStorage; + } + + uno::Sequence< uno::Any > aArgs( 3 ); + aArgs[0] <<= aURL; + aArgs[1] <<= nStorageMode; + aArgs[2] <<= aProps; + + uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ), + uno::UNO_QUERY ); + if ( !xTempStorage.is() ) + throw uno::RuntimeException(); + + return xTempStorage; +} + +// ---------------------------------------------------------------------- +uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromInputStream( + const ::rtl::OUString& aFormat, + const uno::Reference < io::XInputStream >& xStream, + const uno::Reference< lang::XMultiServiceFactory >& xFactory, + sal_Bool bRepairStorage ) + throw ( uno::Exception ) +{ + uno::Sequence< beans::PropertyValue > aProps( 1 ); + aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) ); + aProps[0].Value <<= aFormat; + if ( bRepairStorage ) + { + aProps.realloc( 2 ); + aProps[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RepairPackage" ) ); + aProps[1].Value <<= bRepairStorage; + } + + uno::Sequence< uno::Any > aArgs( 3 ); + aArgs[0] <<= xStream; + aArgs[1] <<= embed::ElementModes::READ; + aArgs[2] <<= aProps; + + uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ), + uno::UNO_QUERY ); + if ( !xTempStorage.is() ) + throw uno::RuntimeException(); + + return xTempStorage; +} + +// ---------------------------------------------------------------------- +uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromStream( + const ::rtl::OUString& aFormat, + const uno::Reference < io::XStream >& xStream, + sal_Int32 nStorageMode, + const uno::Reference< lang::XMultiServiceFactory >& xFactory, + sal_Bool bRepairStorage ) + throw ( uno::Exception ) +{ + uno::Sequence< beans::PropertyValue > aProps( 1 ); + aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) ); + aProps[0].Value <<= aFormat; + if ( bRepairStorage ) + { + aProps.realloc( 2 ); + aProps[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RepairPackage" ) ); + aProps[1].Value <<= bRepairStorage; + } + + uno::Sequence< uno::Any > aArgs( 3 ); + aArgs[0] <<= xStream; + aArgs[1] <<= nStorageMode; + aArgs[2] <<= aProps; + + uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ), + uno::UNO_QUERY ); + if ( !xTempStorage.is() ) + throw uno::RuntimeException(); + + return xTempStorage; +} + +// ---------------------------------------------------------------------- +sal_Bool OStorageHelper::IsValidZipEntryFileName( const ::rtl::OUString& aName, sal_Bool bSlashAllowed ) +{ + return IsValidZipEntryFileName( aName.getStr(), aName.getLength(), bSlashAllowed ); +} + +// ---------------------------------------------------------------------- +sal_Bool OStorageHelper::IsValidZipEntryFileName( + const sal_Unicode *pChar, sal_Int32 nLength, sal_Bool bSlashAllowed ) +{ + for ( sal_Int32 i = 0; i < nLength; i++ ) + { + switch ( pChar[i] ) + { + case '\\': + case '?': + case '<': + case '>': + case '\"': + case '|': + case ':': + return sal_False; + case '/': + if ( !bSlashAllowed ) + return sal_False; + break; + default: + if ( pChar[i] < 32 || (pChar[i] >= 0xD800 && pChar[i] <= 0xDFFF) ) + return sal_False; + } + } + return sal_True; +} + +} + diff --git a/comphelper/source/misc/string.cxx b/comphelper/source/misc/string.cxx new file mode 100644 index 000000000000..951baf0be8d2 --- /dev/null +++ b/comphelper/source/misc/string.cxx @@ -0,0 +1,125 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +#include "precompiled_comphelper.hxx" +#include "sal/config.h" + +#include <cstddef> +#include <string.h> +#include <vector> +#include <algorithm> + +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/types.h> + +#include <comphelper/string.hxx> +#include <comphelper/stlunosequence.hxx> +#include <comphelper/stl_types.hxx> + + +namespace comphelper { namespace string { + +rtl::OUString searchAndReplaceAsciiL( + rtl::OUString const & source, char const * from, sal_Int32 fromLength, + rtl::OUString const & to, sal_Int32 beginAt, sal_Int32 * replacedAt) +{ + sal_Int32 n = source.indexOfAsciiL(from, fromLength, beginAt); + if (replacedAt != NULL) { + *replacedAt = n; + } + return n == -1 ? source : source.replaceAt(n, fromLength, to); +} + +::rtl::OUString searchAndReplaceAllAsciiWithAscii( + const ::rtl::OUString& _source, const sal_Char* _from, const sal_Char* _to, + const sal_Int32 _beginAt ) +{ + sal_Int32 fromLength = strlen( _from ); + sal_Int32 n = _source.indexOfAsciiL( _from, fromLength, _beginAt ); + if ( n == -1 ) + return _source; + + ::rtl::OUString dest( _source ); + ::rtl::OUString to( ::rtl::OUString::createFromAscii( _to ) ); + do + { + dest = dest.replaceAt( n, fromLength, to ); + n = dest.indexOfAsciiL( _from, fromLength, n + to.getLength() ); + } + while ( n != -1 ); + + return dest; +} + +::rtl::OUString& searchAndReplaceAsciiI( + ::rtl::OUString & _source, sal_Char const * _asciiPattern, ::rtl::OUString const & _replace, + sal_Int32 _beginAt, sal_Int32 * _replacedAt ) +{ + sal_Int32 fromLength = strlen( _asciiPattern ); + sal_Int32 n = _source.indexOfAsciiL( _asciiPattern, fromLength, _beginAt ); + if ( _replacedAt != NULL ) + *_replacedAt = n; + + if ( n != -1 ) + _source = _source.replaceAt( n, fromLength, _replace ); + + return _source; +} + +// convert between sequence of string and comma separated string + +::rtl::OUString convertCommaSeparated( + ::com::sun::star::uno::Sequence< ::rtl::OUString > const& i_rSeq) +{ + ::rtl::OUStringBuffer buf; + ::comphelper::intersperse( + ::comphelper::stl_begin(i_rSeq), ::comphelper::stl_end(i_rSeq), + ::comphelper::OUStringBufferAppender(buf), + ::rtl::OUString::createFromAscii(", ")); + return buf.makeStringAndClear(); +} + +::com::sun::star::uno::Sequence< ::rtl::OUString > + convertCommaSeparated( ::rtl::OUString const& i_rString ) +{ + std::vector< ::rtl::OUString > vec; + sal_Int32 idx = 0; + do { + ::rtl::OUString kw = + i_rString.getToken(0, static_cast<sal_Unicode> (','), idx); + kw = kw.trim(); + if (kw.getLength() > 0) { + vec.push_back(kw); + } + } while (idx >= 0); + ::com::sun::star::uno::Sequence< ::rtl::OUString > kws(vec.size()); + std::copy(vec.begin(), vec.end(), stl_begin(kws)); + return kws; +} + +} } diff --git a/comphelper/source/misc/synchronousdispatch.cxx b/comphelper/source/misc/synchronousdispatch.cxx new file mode 100644 index 000000000000..3c55556973f3 --- /dev/null +++ b/comphelper/source/misc/synchronousdispatch.cxx @@ -0,0 +1,102 @@ +/************************************************************************* + * + * 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" + +/** === begin UNO includes === **/ +#include "com/sun/star/frame/XDispatchProvider.hpp" +#include "com/sun/star/frame/XSynchronousDispatch.hpp" +#include "com/sun/star/lang/XComponent.hpp" +#include "com/sun/star/lang/XMultiServiceFactory.hpp" +#include "com/sun/star/util/XURLTransformer.hpp" +/** === end UNO includes === **/ + +#include "comphelper/synchronousdispatch.hxx" +#include "comphelper/processfactory.hxx" + +#define UNISTRING(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s)) + +//......................................................................... +namespace comphelper +{ +//......................................................................... + +using namespace ::com::sun::star; + +//==================================================================== +//= SynchronousDispatch +//==================================================================== + +uno::Reference< lang::XComponent > SynchronousDispatch::dispatch( + const uno::Reference< uno::XInterface > &xStartPoint, + const rtl::OUString &sURL, + const rtl::OUString &sTarget, + const sal_Int32 nFlags, + const uno::Sequence< beans::PropertyValue > &lArguments ) +{ + util::URL aURL; + aURL.Complete = sURL; + uno::Reference < util::XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance( + UNISTRING("com.sun.star.util.URLTransformer" )), + uno::UNO_QUERY ); + if ( xTrans.is() ) + xTrans->parseStrict( aURL ); + + uno::Reference < frame::XDispatch > xDispatcher; + uno::Reference < frame::XDispatchProvider > xProvider( xStartPoint, uno::UNO_QUERY ); + + if ( xProvider.is() ) + xDispatcher = xProvider->queryDispatch( aURL, sTarget, nFlags ); + + uno::Reference < lang::XComponent > aComponent; + + if ( xDispatcher.is() ) + { + try + { + uno::Any aRet; + uno::Reference < frame::XSynchronousDispatch > xSyncDisp( xDispatcher, uno::UNO_QUERY_THROW ); + + aRet = xSyncDisp->dispatchWithReturnValue( aURL, lArguments ); + + aRet >>= aComponent; + } + catch ( uno::Exception& ) + { + rtl::OUString aMsg = UNISTRING( "SynchronousDispatch::dispatch() Error while dispatching! "); + OSL_ENSURE( sal_False, OUStringToOString(aMsg, RTL_TEXTENCODING_ASCII_US).getStr()); + } + } + + return aComponent; +} + +//......................................................................... +} // namespace comphelper +//......................................................................... + diff --git a/comphelper/source/misc/types.cxx b/comphelper/source/misc/types.cxx new file mode 100644 index 000000000000..31719eec881a --- /dev/null +++ b/comphelper/source/misc/types.cxx @@ -0,0 +1,477 @@ +/************************************************************************* + * + * 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/types.hxx> +#include <comphelper/extract.hxx> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/awt/FontUnderline.hpp> +#include <com/sun/star/awt/FontStrikeout.hpp> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <osl/diagnose.h> +#include <typelib/typedescription.hxx> + +#include <memory.h> + + +//......................................................................... +namespace comphelper +{ +//......................................................................... + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; + +//------------------------------------------------------------------------- +sal_Bool operator ==(const DateTime& _rLeft, const DateTime& _rRight) +{ + return ( _rLeft.HundredthSeconds == _rRight.HundredthSeconds) && + ( _rLeft.Seconds == _rRight.Seconds) && + ( _rLeft.Minutes == _rRight.Minutes) && + ( _rLeft.Hours == _rRight.Hours) && + ( _rLeft.Day == _rRight.Day) && + ( _rLeft.Month == _rRight.Month) && + ( _rLeft.Year == _rRight.Year) ; +} + +//------------------------------------------------------------------------- +sal_Bool operator ==(const Date& _rLeft, const Date& _rRight) +{ + return ( _rLeft.Day == _rRight.Day) && + ( _rLeft.Month == _rRight.Month) && + ( _rLeft.Year == _rRight.Year) ; +} + +//------------------------------------------------------------------------- +sal_Bool operator ==(const Time& _rLeft, const Time& _rRight) +{ + return ( _rLeft.HundredthSeconds == _rRight.HundredthSeconds) && + ( _rLeft.Seconds == _rRight.Seconds) && + ( _rLeft.Minutes == _rRight.Minutes) && + ( _rLeft.Hours == _rRight.Hours) ; +} + +//------------------------------------------------------------------------------ +sal_Int32 getINT32(const Any& _rAny) +{ + sal_Int32 nReturn = 0; + OSL_VERIFY( _rAny >>= nReturn ); + return nReturn; +} + +//------------------------------------------------------------------------------ +sal_Int16 getINT16(const Any& _rAny) +{ + sal_Int16 nReturn = 0; + OSL_VERIFY( _rAny >>= nReturn ); + return nReturn; +} + +//------------------------------------------------------------------------------ +double getDouble(const Any& _rAny) +{ + double nReturn = 0.0; + OSL_VERIFY( _rAny >>= nReturn ); + return nReturn; +} + +//------------------------------------------------------------------------------ +float getFloat(const Any& _rAny) +{ + float nReturn = 0.0; + OSL_VERIFY( _rAny >>= nReturn ); + return nReturn; +} + +//------------------------------------------------------------------------------ +::rtl::OUString getString(const Any& _rAny) +{ + ::rtl::OUString nReturn; + OSL_VERIFY( _rAny >>= nReturn ); + return nReturn; +} + +//------------------------------------------------------------------------------ +sal_Bool getBOOL(const Any& _rAny) +{ + sal_Bool nReturn = sal_False; + if (_rAny.getValueType() == ::getCppuBooleanType()) + nReturn = *(sal_Bool*)_rAny.getValue(); + else + OSL_ENSURE(sal_False, "comphelper::getBOOL : invalid argument !"); + return nReturn; +} + +//------------------------------------------------------------------------------ +sal_Int32 getEnumAsINT32(const Any& _rAny) throw(IllegalArgumentException) +{ + sal_Int32 nReturn = 0; + if (! ::cppu::enum2int(nReturn,_rAny) ) + throw IllegalArgumentException(); + return nReturn; +} + +//------------------------------------------------------------------------------ +FontDescriptor getDefaultFont() +{ + FontDescriptor aReturn; + aReturn.Slant = FontSlant_DONTKNOW; + aReturn.Underline = FontUnderline::DONTKNOW; + aReturn.Strikeout = FontStrikeout::DONTKNOW; + return aReturn; +} + +//------------------------------------------------------------------------------ +sal_Bool isAssignableFrom(const Type& _rAssignable, const Type& _rFrom) +{ + // getthe type lib descriptions + typelib_TypeDescription* pAssignable = NULL; + _rAssignable.getDescription(&pAssignable); + + typelib_TypeDescription* pFrom = NULL; + _rFrom.getDescription(&pFrom); + + // and ask the type lib + return typelib_typedescription_isAssignableFrom(pAssignable, pFrom); +} + +//------------------------------------------------------------------ +template<class TYPE> +sal_Bool tryCompare(const void* _pData, const Any& _rValue, sal_Bool& _bIdentical, TYPE& _rOut) +{ + sal_Bool bSuccess = _rValue >>= _rOut; + _bIdentical = bSuccess && (_rOut == *reinterpret_cast<const TYPE*>(_pData)); + return bSuccess; +} + +//------------------------------------------------------------------ +sal_Bool tryCompare(const void* _pData, const Any& _rValue, sal_Bool& _bIdentical, sal_Unicode& _rOut) +{ + sal_Bool bSuccess = ( _rValue.getValueTypeClass() == TypeClass_CHAR ); + if ( bSuccess ) + _rOut = *static_cast< const sal_Unicode* >( _rValue.getValue() ); + _bIdentical = bSuccess && ( _rOut == *static_cast< const sal_Unicode* >( _pData ) ); + return bSuccess; +} + +//------------------------------------------------------------------ +sal_Bool compare_impl(const Type& _rType, const void* pData, const Any& _rValue) +{ + sal_Bool bRes = sal_True; + + if (_rType.getTypeClass() == TypeClass_ANY) + { + // beides AnyWerte + if (_rValue.getValueType().getTypeClass() == TypeClass_ANY) + bRes = compare_impl( + reinterpret_cast<const Any*>(pData)->getValueType(), + reinterpret_cast<const Any*>(pData)->getValue(), + *reinterpret_cast<const Any*>(_rValue.getValue())); + else + bRes = compare_impl( + reinterpret_cast<const Any*>(pData)->getValueType(), + reinterpret_cast<const Any*>(pData)->getValue(), + _rValue); + } + else if ( (_rType.getTypeClass() == TypeClass_VOID) + || (_rValue.getValueType().getTypeClass() == TypeClass_VOID) + ) + { + bRes = _rType.getTypeClass() == _rValue.getValueType().getTypeClass(); + } + else + { + sal_Bool bConversionSuccess = sal_False; + switch (_rType.getTypeClass()) + { + case TypeClass_VOID: + bConversionSuccess = sal_True; + bRes = _rValue.getValueType().getTypeClass() == TypeClass_VOID; + break; + case TypeClass_BOOLEAN: + { + sal_Bool aDummy; + bConversionSuccess = tryCompare(pData, _rValue, bRes, aDummy); + break; + } + case TypeClass_CHAR: + { + sal_Unicode aDummy(0); + bConversionSuccess = tryCompare(pData, _rValue, bRes, aDummy); + break; + } + case TypeClass_STRING: + { + ::rtl::OUString aDummy; + bConversionSuccess = tryCompare(pData, _rValue, bRes, aDummy); + break; + } + case TypeClass_FLOAT: + { + float aDummy; + bConversionSuccess = tryCompare(pData, _rValue, bRes, aDummy); + break; + } + case TypeClass_DOUBLE: + { + double aDummy; + bConversionSuccess = tryCompare(pData, _rValue, bRes, aDummy); + break; + } + case TypeClass_BYTE: + { + sal_Int8 aDummy; + bConversionSuccess = tryCompare(pData, _rValue, bRes, aDummy); + break; + } + case TypeClass_SHORT: + { + sal_Int16 aDummy; + bConversionSuccess = tryCompare(pData, _rValue, bRes, aDummy); + break; + } + case TypeClass_ENUM: + { + sal_Int32 nAsInt32 = 0; + bConversionSuccess = ::cppu::enum2int(nAsInt32, _rValue); + bRes = bConversionSuccess && (nAsInt32== *reinterpret_cast<const sal_Int32*>(pData)); + break; + } + case TypeClass_LONG: + { + sal_Int32 aDummy; + bConversionSuccess = tryCompare(pData, _rValue, bRes, aDummy); + break; + } + case TypeClass_UNSIGNED_SHORT: + { + sal_uInt16 aDummy; + bConversionSuccess = tryCompare(pData, _rValue, bRes, aDummy); + break; + } + case TypeClass_UNSIGNED_LONG: + { + sal_uInt32 aDummy; + bConversionSuccess = tryCompare(pData, _rValue, bRes, aDummy); + break; + } + case TypeClass_INTERFACE: + { + InterfaceRef aDummy; + bConversionSuccess = tryCompare(pData, _rValue, bRes, aDummy); + break; + } + case TypeClass_STRUCT: + if (isA(_rType, static_cast<FontDescriptor*>(NULL))) + { + FontDescriptor aTemp; + bConversionSuccess = _rValue >>= aTemp; + if (bConversionSuccess) + { + bRes = *(FontDescriptor*)pData == aTemp; + } + else + bRes = sal_False; + break; + } + if (isA(_rType, static_cast<Date*>(NULL))) + { + Date aDummy; + bConversionSuccess = tryCompare(pData, _rValue, bRes, aDummy); + break; + } + if (isA(_rType, static_cast<Time*>(NULL))) + { + Time aDummy; + bConversionSuccess = tryCompare(pData, _rValue, bRes, aDummy); + break; + } + if (isA(_rType, static_cast<DateTime*>(NULL))) + { + DateTime aDummy; + bConversionSuccess = tryCompare(pData, _rValue, bRes, aDummy); + break; + } + break; + case TypeClass_SEQUENCE: + if (isA(_rType, static_cast< Sequence<sal_Int8>* >(NULL))) + { + Sequence<sal_Int8> aTemp; + bConversionSuccess = _rValue >>= aTemp; + if (bConversionSuccess) + { + const Sequence<sal_Int8>& rLeftSeq = *reinterpret_cast<const Sequence<sal_Int8>*>(pData); + const Sequence<sal_Int8>& rRightSeq = aTemp; + bRes = rLeftSeq.getLength() == rRightSeq.getLength() && + memcmp(rLeftSeq.getConstArray(), rRightSeq.getConstArray(), rLeftSeq.getLength()) == 0; + } + } + else if (isA(_rType, static_cast< Sequence<sal_uInt8>* >(NULL))) + { + Sequence<sal_uInt8> aTemp; + bConversionSuccess = _rValue >>= aTemp; + if (bConversionSuccess) + { + const Sequence<sal_uInt8>& rLeftSeq = *reinterpret_cast<const Sequence<sal_uInt8>*>(pData); + const Sequence<sal_uInt8>& rRightSeq = aTemp; + bRes = rLeftSeq.getLength() == rRightSeq.getLength() && + memcmp(rLeftSeq.getConstArray(), rRightSeq.getConstArray(), rLeftSeq.getLength()) == 0; + } + } + else if (isA(_rType, static_cast< Sequence<sal_Int16>* >(NULL))) + { + Sequence<sal_Int16> aTemp; + bConversionSuccess = _rValue >>= aTemp; + if (bConversionSuccess) + { + const Sequence<sal_Int16>& rLeftSeq = *reinterpret_cast<const Sequence<sal_Int16>*>(pData); + const Sequence<sal_Int16>& rRightSeq = aTemp; + bRes = rLeftSeq.getLength() == rRightSeq.getLength() && + memcmp(rLeftSeq.getConstArray(), rRightSeq.getConstArray(), rLeftSeq.getLength()*sizeof(sal_Int16)) == 0; + } + } + else if (isA(_rType, static_cast< Sequence<sal_uInt16>* >(NULL))) + { + Sequence<sal_uInt16> aTemp; + bConversionSuccess = _rValue >>= aTemp; + if (bConversionSuccess) + { + const Sequence<sal_uInt16>& rLeftSeq = *reinterpret_cast<const Sequence<sal_uInt16>*>(pData); + const Sequence<sal_uInt16>& rRightSeq = aTemp; + bRes = rLeftSeq.getLength() == rRightSeq.getLength() && + memcmp(rLeftSeq.getConstArray(), rRightSeq.getConstArray(), rLeftSeq.getLength()*sizeof(sal_uInt16)) == 0; + } + } + else if (isA(_rType, static_cast< Sequence<sal_Int32>* >(NULL))) + { + Sequence<sal_Int32> aTemp; + bConversionSuccess = _rValue >>= aTemp; + if (bConversionSuccess) + { + const Sequence<sal_Int32>& rLeftSeq = *reinterpret_cast<const Sequence<sal_Int32>*>(pData); + const Sequence<sal_Int32>& rRightSeq = aTemp; + bRes = rLeftSeq.getLength() == rRightSeq.getLength() && + memcmp(rLeftSeq.getConstArray(), rRightSeq.getConstArray(), rLeftSeq.getLength()*sizeof(sal_Int32)) == 0; + } + } + else if (isA(_rType, static_cast< Sequence<sal_uInt32>* >(NULL))) + { + Sequence<sal_uInt32> aTemp; + bConversionSuccess = _rValue >>= aTemp; + if (bConversionSuccess) + { + const Sequence<sal_uInt32>& rLeftSeq = *reinterpret_cast<const Sequence<sal_uInt32>*>(pData); + const Sequence<sal_uInt32>& rRightSeq = aTemp; + bRes = rLeftSeq.getLength() == rRightSeq.getLength() && + memcmp(rLeftSeq.getConstArray(), rRightSeq.getConstArray(), rLeftSeq.getLength()*sizeof(sal_uInt32)) == 0; + } + } + else if (isA(_rType, static_cast< Sequence< ::rtl::OUString >* >(NULL))) + { + Sequence< ::rtl::OUString > aTemp; + bConversionSuccess = _rValue >>= aTemp; + if (bConversionSuccess) + { + const Sequence< ::rtl::OUString >& rLeftSeq = *reinterpret_cast<const Sequence< ::rtl::OUString>*>(pData); + const Sequence< ::rtl::OUString >& rRightSeq = aTemp; + sal_Int32 nSeqLen = rLeftSeq.getLength(); + bRes = ( nSeqLen == rRightSeq.getLength() ); + for ( sal_Int32 n = 0; bRes && ( n < nSeqLen ); n++ ) + { + const ::rtl::OUString& rS1 = rLeftSeq.getConstArray()[n]; + const ::rtl::OUString& rS2 = rRightSeq.getConstArray()[n]; + bRes = ( rS1 == rS2 ); + } + } + } + break; + default: + bRes = sal_False; + } + + bRes = bRes && bConversionSuccess; + } + return bRes; +} + +//------------------------------------------------------------------------------ +sal_Bool compare(const Any& rLeft, const Any& rRight) +{ + return compare_impl(rLeft.getValueType(), rLeft.getValue(), rRight); +} + +//------------------------------------------------------------------------- +sal_Bool operator ==(const FontDescriptor& _rLeft, const FontDescriptor& _rRight) +{ + return ( _rLeft.Name.equals( _rRight.Name ) ) && + ( _rLeft.Height == _rRight.Height ) && + ( _rLeft.Width == _rRight.Width ) && + ( _rLeft.StyleName.equals( _rRight.StyleName ) ) && + ( _rLeft.Family == _rRight.Family ) && + ( _rLeft.CharSet == _rRight.CharSet ) && + ( _rLeft.Pitch == _rRight.Pitch ) && + ( _rLeft.CharacterWidth == _rRight.CharacterWidth ) && + ( _rLeft.Weight == _rRight.Weight ) && + ( _rLeft.Slant == _rRight.Slant ) && + ( _rLeft.Underline == _rRight.Underline ) && + ( _rLeft.Strikeout == _rRight.Strikeout ) && + ( _rLeft.Orientation == _rRight.Orientation ) && + ( _rLeft.Kerning == _rRight.Kerning ) && + ( _rLeft.WordLineMode == _rRight.WordLineMode ) && + ( _rLeft.Type == _rRight.Type ) ; +} + +//------------------------------------------------------------------------- +Type getSequenceElementType(const Type& _rSequenceType) +{ + OSL_ENSURE(_rSequenceType.getTypeClass() == TypeClass_SEQUENCE, + "getSequenceElementType: must be called with a sequence type!"); + + if (!(_rSequenceType.getTypeClass() == TypeClass_SEQUENCE)) + return Type(); + + TypeDescription aTD(_rSequenceType); + typelib_IndirectTypeDescription* pSequenceTD = + reinterpret_cast< typelib_IndirectTypeDescription* >(aTD.get()); + + OSL_ASSERT(pSequenceTD); + OSL_ASSERT(pSequenceTD->pType); + + if (pSequenceTD && pSequenceTD->pType) + return Type(pSequenceTD->pType); + + return Type(); +} +//......................................................................... +} // namespace comphelper +//......................................................................... + diff --git a/comphelper/source/misc/uieventslogger.cxx b/comphelper/source/misc/uieventslogger.cxx new file mode 100644 index 000000000000..710c08fdd706 --- /dev/null +++ b/comphelper/source/misc/uieventslogger.cxx @@ -0,0 +1,686 @@ +/************************************************************************* + * 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/uieventslogger.hxx> +#include <boost/shared_ptr.hpp> +#include <com/sun/star/frame/XDesktop.hpp> +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/logging/LogLevel.hpp> +#include <com/sun/star/logging/XCsvLogFormatter.hpp> +#include <com/sun/star/logging/XLogHandler.hpp> +#include <com/sun/star/logging/XLogger.hpp> +#include <com/sun/star/logging/XLoggerPool.hpp> +#include <com/sun/star/oooimprovement/XCoreController.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/util/XStringSubstitution.hpp> +#include <comphelper/configurationhelper.hxx> +#include <comphelper/processfactory.hxx> +#include <map> +#include <osl/file.hxx> +#include <osl/mutex.hxx> +#include <osl/time.h> +#include <rtl/ustrbuf.hxx> + + +using namespace com::sun::star::beans; +using namespace com::sun::star::frame; +using namespace com::sun::star::lang; +using namespace com::sun::star::logging; +using namespace com::sun::star::oooimprovement; +using namespace com::sun::star::uno; +using namespace com::sun::star::util; +using namespace cppu; +using namespace osl; +using namespace rtl; +using namespace std; + + +namespace +{ + static void lcl_SetupOriginAppAbbr(map<OUString, OUString>& abbrs) + { + abbrs[OUString::createFromAscii("com.sun.star.text.TextDocument")] = OUString::createFromAscii("W"); // Writer + abbrs[OUString::createFromAscii("com.sun.star.sheet.SpreadsheetDocument")] = OUString::createFromAscii("C"); // Calc + abbrs[OUString::createFromAscii("com.sun.star.presentation.PresentationDocument")] = OUString::createFromAscii("I"); // Impress + abbrs[OUString::createFromAscii("com.sun.star.drawing.DrawingDocument")] = OUString::createFromAscii("D"); // Draw + }; + + static void lcl_SetupOriginWidgetAbbr(map<OUString,OUString>& abbrs) + { + abbrs[OUString::createFromAscii("ButtonToolbarController")] = OUString::createFromAscii("0"); + abbrs[OUString::createFromAscii("ComplexToolbarController")] = OUString::createFromAscii("1"); + abbrs[OUString::createFromAscii("ControlMenuController")] = OUString::createFromAscii("2"); + abbrs[OUString::createFromAscii("FontMenuController")] = OUString::createFromAscii("3"); + abbrs[OUString::createFromAscii("FontSizeMenuController")] = OUString::createFromAscii("4"); + abbrs[OUString::createFromAscii("FooterMenuController")] = OUString::createFromAscii("5"); + abbrs[OUString::createFromAscii("GenericToolbarController")] = OUString::createFromAscii("6"); + abbrs[OUString::createFromAscii("HeaderMenuController")] = OUString::createFromAscii("7"); + abbrs[OUString::createFromAscii("LanguageSelectionMenuController")] = OUString::createFromAscii("8"); + abbrs[OUString::createFromAscii("LangSelectionStatusbarController")] = OUString::createFromAscii("9"); + abbrs[OUString::createFromAscii("MacrosMenuController")] = OUString::createFromAscii("10"); + abbrs[OUString::createFromAscii("MenuBarManager")] = OUString::createFromAscii("11"); + abbrs[OUString::createFromAscii("NewMenuController")] = OUString::createFromAscii("12"); + abbrs[OUString::createFromAscii("ObjectMenuController")] = OUString::createFromAscii("13"); + abbrs[OUString::createFromAscii("RecentFilesMenuController")] = OUString::createFromAscii("14"); + abbrs[OUString::createFromAscii("ToolbarsMenuController")] = OUString::createFromAscii("15"); + abbrs[OUString::createFromAscii("SfxToolBoxControl")] = OUString::createFromAscii("16"); + abbrs[OUString::createFromAscii("SfxAsyncExec")] = OUString::createFromAscii("17"); + abbrs[OUString::createFromAscii("AcceleratorExecute")] = OUString::createFromAscii("18"); + }; +} + +namespace comphelper +{ + // declaration of implementation + class UiEventsLogger_Impl; + class UiEventsLogger_Impl : public UiEventsLogger + { + private: + //typedefs and friends + friend class UiEventsLogger; + typedef UiEventsLogger_Impl* ptr; + + // instance methods and data + UiEventsLogger_Impl(); + void initializeLogger(); + void logDispatch(const ::com::sun::star::util::URL& url, + const Sequence<PropertyValue>& args); + void logRotated(); + void logVcl(const ::rtl::OUString& parent_id, + sal_Int32 window_type, + const ::rtl::OUString& id, + const ::rtl::OUString& method, + const ::rtl::OUString& param); + void rotate(); + void hotRotate(); + void prepareLogHandler(); + void checkIdleTimeout(); + OUString getCurrentPath(); + OUString getRotatedPath(); + void disposing(); + + bool m_Active; + TimeValue m_LastLogEventTime; + const OUString m_LogPath; + const TimeValue m_IdleTimeout; + sal_Int32 m_SessionLogEventCount; + Reference<XLogger> m_Logger; + Reference<XLogHandler> m_LogHandler; + Reference<XCsvLogFormatter> m_Formatter; + map<OUString, OUString> m_OriginAppAbbr; + map<OUString, OUString> m_OriginWidgetAbbr; + + + // static methods and data + static ptr getInstance(); + static void prepareMutex(); + static bool shouldActivate(); + static bool getEnabledFromCoreController(); + static bool getEnabledFromCfg(); + static TimeValue getIdleTimeoutFromCfg(); + static OUString getLogPathFromCfg(); + static sal_Int32 findIdx(const Sequence<PropertyValue>& args, const OUString& key); + + static ptr instance; + static Mutex * singleton_mutex; + static const sal_Int32 COLUMNS; + static const OUString CFG_ENABLED; + static const OUString CFG_IDLETIMEOUT; + static const OUString CFG_LOGGING; + static const OUString CFG_LOGPATH; + static const OUString CFG_OOOIMPROVEMENT; + static const OUString ETYPE_DISPATCH; + static const OUString ETYPE_ROTATED; + static const OUString ETYPE_VCL; + static const OUString CSSL_CSVFORMATTER; + static const OUString CSSL_FILEHANDLER; + static const OUString CSSL_LOGGERPOOL; + static const OUString CSSO_CORECONTROLLER; + static const OUString CSST_JOBEXECUTOR; + static const OUString CSSU_PATHSUB; + static const OUString LOGGERNAME; + static const OUString LOGORIGINAPP; + static const OUString LOGORIGINWIDGET; + static const OUString UNKNOWN_ORIGIN; + static const OUString FN_CURRENTLOG; + static const OUString FN_ROTATEDLOG; + static const OUString LOGROTATE_EVENTNAME; + static const OUString URL_UNO; + static const OUString URL_FILE; + }; +} + +namespace comphelper +{ + // consts + const sal_Int32 UiEventsLogger_Impl::COLUMNS = 9; + const OUString UiEventsLogger_Impl::CFG_ENABLED = OUString::createFromAscii("EnablingAllowed"); + const OUString UiEventsLogger_Impl::CFG_IDLETIMEOUT = OUString::createFromAscii("IdleTimeout"); + const OUString UiEventsLogger_Impl::CFG_LOGGING = OUString::createFromAscii("/org.openoffice.Office.Logging"); + const OUString UiEventsLogger_Impl::CFG_LOGPATH = OUString::createFromAscii("LogPath"); + const OUString UiEventsLogger_Impl::CFG_OOOIMPROVEMENT = OUString::createFromAscii("OOoImprovement"); + + const OUString UiEventsLogger_Impl::CSSL_CSVFORMATTER = OUString::createFromAscii("com.sun.star.logging.CsvFormatter"); + const OUString UiEventsLogger_Impl::CSSL_FILEHANDLER = OUString::createFromAscii("com.sun.star.logging.FileHandler"); + const OUString UiEventsLogger_Impl::CSSL_LOGGERPOOL = OUString::createFromAscii("com.sun.star.logging.LoggerPool"); + const OUString UiEventsLogger_Impl::CSSO_CORECONTROLLER = OUString::createFromAscii("com.sun.star.oooimprovement.CoreController"); + const OUString UiEventsLogger_Impl::CSSU_PATHSUB = OUString::createFromAscii("com.sun.star.util.PathSubstitution"); + + const OUString UiEventsLogger_Impl::ETYPE_DISPATCH = OUString::createFromAscii("dispatch"); + const OUString UiEventsLogger_Impl::ETYPE_ROTATED = OUString::createFromAscii("rotated"); + const OUString UiEventsLogger_Impl::ETYPE_VCL = OUString::createFromAscii("vcl"); + + const OUString UiEventsLogger_Impl::LOGGERNAME = OUString::createFromAscii("org.openoffice.oooimprovement.Core.UiEventsLogger"); + const OUString UiEventsLogger_Impl::LOGORIGINWIDGET = OUString::createFromAscii("comphelper.UiEventsLogger.LogOriginWidget"); + const OUString UiEventsLogger_Impl::LOGORIGINAPP = OUString::createFromAscii("comphelper.UiEventsLogger.LogOriginApp"); + + const OUString UiEventsLogger_Impl::UNKNOWN_ORIGIN = OUString::createFromAscii("unknown origin"); + const OUString UiEventsLogger_Impl::FN_CURRENTLOG = OUString::createFromAscii("Current"); + const OUString UiEventsLogger_Impl::FN_ROTATEDLOG = OUString::createFromAscii("OOoImprove"); + const OUString UiEventsLogger_Impl::LOGROTATE_EVENTNAME = OUString::createFromAscii("onOOoImprovementLogRotated"); + + const OUString UiEventsLogger_Impl::URL_UNO = OUString::createFromAscii(".uno:"); + const OUString UiEventsLogger_Impl::URL_FILE = OUString::createFromAscii("file:"); + + + // public UiEventsLogger interface + sal_Bool UiEventsLogger::isEnabled() + { + if ( UiEventsLogger_Impl::getEnabledFromCfg() ) + { + try { + UiEventsLogger_Impl::prepareMutex(); + Guard<Mutex> singleton_guard(UiEventsLogger_Impl::singleton_mutex); + return UiEventsLogger_Impl::getInstance()->m_Active; + } catch(...) { return false; } // never throws + } // if ( ) + return sal_False; + } + + sal_Int32 UiEventsLogger::getSessionLogEventCount() + { + try { + UiEventsLogger_Impl::prepareMutex(); + Guard<Mutex> singleton_guard(UiEventsLogger_Impl::singleton_mutex); + return UiEventsLogger_Impl::getInstance()->m_SessionLogEventCount; + } catch(...) { return 0; } // never throws + } + + void UiEventsLogger::appendDispatchOrigin( + Sequence<PropertyValue>& args, + const OUString& originapp, + const OUString& originwidget) + { + sal_Int32 old_length = args.getLength(); + args.realloc(old_length+2); + args[old_length].Name = UiEventsLogger_Impl::LOGORIGINAPP; + args[old_length].Value = static_cast<Any>(originapp); + args[old_length+1].Name = UiEventsLogger_Impl::LOGORIGINWIDGET; + args[old_length+1].Value = static_cast<Any>(originwidget); + } + + Sequence<PropertyValue> UiEventsLogger::purgeDispatchOrigin( + const Sequence<PropertyValue>& args) + { + Sequence<PropertyValue> result(args.getLength()); + sal_Int32 target_idx=0; + for(sal_Int32 source_idx=0; source_idx<args.getLength(); source_idx++) + if(args[source_idx].Name != UiEventsLogger_Impl::LOGORIGINAPP + && args[source_idx].Name != UiEventsLogger_Impl::LOGORIGINWIDGET) + result[target_idx++] = args[source_idx]; + result.realloc(target_idx); + return result; + } + + void UiEventsLogger::logDispatch( + const URL& url, + const Sequence<PropertyValue>& args) + { + try { + UiEventsLogger_Impl::prepareMutex(); + Guard<Mutex> singleton_guard(UiEventsLogger_Impl::singleton_mutex); + UiEventsLogger_Impl::getInstance()->logDispatch(url, args); + } catch(...) { } // never throws + } + + void UiEventsLogger::logVcl( + const OUString& parent_id, + sal_Int32 window_type, + const OUString& id, + const OUString& method, + const OUString& param) + { + try { + UiEventsLogger_Impl::prepareMutex(); + Guard<Mutex> singleton_guard(UiEventsLogger_Impl::singleton_mutex); + UiEventsLogger_Impl::getInstance()->logVcl(parent_id, window_type, id, method, param); + } catch(...) { } // never throws + } + + void UiEventsLogger::logVcl( + const OUString& parent_id, + sal_Int32 window_type, + const OUString& id, + const OUString& method, + sal_Int32 param) + { + OUStringBuffer buf; + UiEventsLogger::logVcl(parent_id, window_type, id, method, buf.append(param).makeStringAndClear()); + } + + void UiEventsLogger::logVcl( + const OUString& parent_id, + sal_Int32 window_type, + const OUString& id, + const OUString& method) + { + OUString empty; + UiEventsLogger::logVcl(parent_id, window_type, id, method, empty); + } + + void UiEventsLogger::disposing() + { + // we dont want to create an instance just to dispose it + UiEventsLogger_Impl::prepareMutex(); + Guard<Mutex> singleton_guard(UiEventsLogger_Impl::singleton_mutex); + if(UiEventsLogger_Impl::instance!=UiEventsLogger_Impl::ptr()) + UiEventsLogger_Impl::getInstance()->disposing(); + } + + void UiEventsLogger::reinit() + { + UiEventsLogger_Impl::prepareMutex(); + Guard<Mutex> singleton_guard(UiEventsLogger_Impl::singleton_mutex); + if(UiEventsLogger_Impl::instance) + { + UiEventsLogger_Impl::instance->disposing(); + delete UiEventsLogger_Impl::instance; + UiEventsLogger_Impl::instance = NULL; + } + } + + // private UiEventsLogger_Impl methods + UiEventsLogger_Impl::UiEventsLogger_Impl() + : m_Active(UiEventsLogger_Impl::shouldActivate()) + , m_LogPath(UiEventsLogger_Impl::getLogPathFromCfg()) + , m_IdleTimeout(UiEventsLogger_Impl::getIdleTimeoutFromCfg()) + , m_SessionLogEventCount(0) + { + lcl_SetupOriginAppAbbr(m_OriginAppAbbr); + lcl_SetupOriginWidgetAbbr(m_OriginWidgetAbbr); + m_LastLogEventTime.Seconds = m_LastLogEventTime.Nanosec = 0; + if(m_Active) rotate(); + if(m_Active) initializeLogger(); + } + + void UiEventsLogger_Impl::logDispatch( + const URL& url, + const Sequence<PropertyValue>& args) + { + if(!m_Active) return; + if(!url.Complete.match(URL_UNO) && !url.Complete.match(URL_FILE)) return; + checkIdleTimeout(); + + Sequence<OUString> logdata = Sequence<OUString>(COLUMNS); + logdata[0] = ETYPE_DISPATCH; + sal_Int32 originapp_idx = findIdx(args, LOGORIGINAPP); + if(originapp_idx!=-1) + { + OUString app; + args[originapp_idx].Value >>= app; + map<OUString, OUString>::iterator abbr_it = m_OriginAppAbbr.find(app); + if(abbr_it != m_OriginAppAbbr.end()) + app = abbr_it->second; + logdata[1] = app; + } + else + logdata[1] = UNKNOWN_ORIGIN; + sal_Int32 originwidget_idx = findIdx(args, LOGORIGINWIDGET); + if(originwidget_idx!=-1) + { + OUString widget; + args[originwidget_idx].Value >>= widget; + map<OUString, OUString>::iterator widget_it = m_OriginWidgetAbbr.find(widget); + if(widget_it != m_OriginWidgetAbbr.end()) + widget = widget_it->second; + logdata[2] = widget; + } + else + logdata[2] = UNKNOWN_ORIGIN; + if(url.Complete.match(URL_FILE)) + logdata[3] = URL_FILE; + else + logdata[3] = url.Main; + OSL_TRACE("UiEventsLogger Logging: %s,%s,%s,%s,%s,%s,%s,%s", + OUStringToOString(logdata[0],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[1],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[2],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[3],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[4],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[5],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[6],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[7],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[8],RTL_TEXTENCODING_UTF8).getStr()); + m_Logger->log(LogLevel::INFO, m_Formatter->formatMultiColumn(logdata)); + m_SessionLogEventCount++; + } + + void UiEventsLogger_Impl::logRotated() + { + Sequence<OUString> logdata = Sequence<OUString>(COLUMNS); + logdata[0] = ETYPE_ROTATED; + OSL_TRACE("UiEventsLogger Logging: %s,%s,%s,%s,%s,%s,%s,%s", + OUStringToOString(logdata[0],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[1],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[2],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[3],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[4],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[5],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[6],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[7],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[8],RTL_TEXTENCODING_UTF8).getStr()); + m_Logger->log(LogLevel::INFO, m_Formatter->formatMultiColumn(logdata)); + } + + void UiEventsLogger_Impl::logVcl( + const OUString& parent_id, + sal_Int32 window_type, + const OUString& id, + const OUString& method, + const OUString& param) + { + if(!m_Active) return; + checkIdleTimeout(); + + OUStringBuffer buf; + Sequence<OUString> logdata = Sequence<OUString>(COLUMNS); + logdata[0] = ETYPE_VCL; + logdata[4] = parent_id; + logdata[5] = buf.append(window_type).makeStringAndClear(); + logdata[6] = id; + logdata[7] = method; + logdata[8] = param; + OSL_TRACE("UiEventsLogger Logging: %s,%s,%s,%s,%s,%s,%s,%s", + OUStringToOString(logdata[0],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[1],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[2],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[3],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[4],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[5],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[6],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[7],RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(logdata[8],RTL_TEXTENCODING_UTF8).getStr()); + m_Logger->log(LogLevel::INFO, m_Formatter->formatMultiColumn(logdata)); + m_SessionLogEventCount++; + } + + void UiEventsLogger_Impl::rotate() + { + FileBase::RC result = File::move(getCurrentPath(), getRotatedPath()); + if(result!=FileBase::E_None && result!=FileBase::E_NOENT) + m_Active = false; + } + + void UiEventsLogger_Impl::hotRotate() + { + logRotated(); + m_Logger->removeLogHandler(m_LogHandler); + m_LogHandler = NULL; + rotate(); + prepareLogHandler(); + if(m_Formatter.is() && m_LogHandler.is() && m_Logger.is()) + { + m_LogHandler->setFormatter(Reference<XLogFormatter>(m_Formatter, UNO_QUERY)); + m_LogHandler->setLevel(LogLevel::ALL); + m_Logger->addLogHandler(m_LogHandler); + } + else + m_Active = false; + } + + void UiEventsLogger_Impl::prepareLogHandler() + { + Reference<XMultiServiceFactory> sm = getProcessServiceFactory(); + + Sequence<Any> init_args = Sequence<Any>(1); + init_args[0] = static_cast<Any>(getCurrentPath()); + Reference< XInterface > temp = + sm->createInstanceWithArguments(CSSL_FILEHANDLER, init_args); + m_LogHandler = Reference<XLogHandler>(temp, UNO_QUERY); + } + + void UiEventsLogger_Impl::checkIdleTimeout() + { + TimeValue now; + osl_getSystemTime(&now); + if(now.Seconds - m_LastLogEventTime.Seconds > m_IdleTimeout.Seconds && m_SessionLogEventCount>0) + hotRotate(); + m_LastLogEventTime = now; + } + + OUString UiEventsLogger_Impl::getCurrentPath() + { + OUStringBuffer current_path(m_LogPath); + current_path.appendAscii("/"); + current_path.append(FN_CURRENTLOG); + current_path.appendAscii(".csv"); + return current_path.makeStringAndClear(); + } + + OUString UiEventsLogger_Impl::getRotatedPath() + { + OUStringBuffer rotated_path(m_LogPath); + rotated_path.appendAscii("/"); + rotated_path.append(FN_ROTATEDLOG); + rotated_path.appendAscii("-"); + { + // ISO 8601 + char tsrotated_pathfer[20]; + oslDateTime now; + TimeValue now_tv; + osl_getSystemTime(&now_tv); + osl_getDateTimeFromTimeValue(&now_tv, &now); + const size_t rotated_pathfer_size = sizeof(tsrotated_pathfer); + snprintf(tsrotated_pathfer, rotated_pathfer_size, "%04i-%02i-%02iT%02i_%02i_%02i", + now.Year, + now.Month, + now.Day, + now.Hours, + now.Minutes, + now.Seconds); + rotated_path.appendAscii(tsrotated_pathfer); + rotated_path.appendAscii(".csv"); + } + return rotated_path.makeStringAndClear(); + } + + void UiEventsLogger_Impl::initializeLogger() + { + Reference<XMultiServiceFactory> sm = getProcessServiceFactory(); + + // getting the Core Uno proxy object + // It will call disposing and make sure we clear all our references + { + Reference<XTerminateListener> xCore( + sm->createInstance(OUString::createFromAscii("com.sun.star.oooimprovement.Core")), + UNO_QUERY); + Reference<XDesktop> xDesktop( + sm->createInstance(OUString::createFromAscii("com.sun.star.frame.Desktop")), + UNO_QUERY); + if(!(xCore.is() && xDesktop.is())) + { + m_Active = false; + return; + } + xDesktop->addTerminateListener(xCore); + } + // getting the LoggerPool + Reference<XLoggerPool> pool; + { + Reference<XInterface> temp = + sm->createInstance(CSSL_LOGGERPOOL); + pool = Reference<XLoggerPool>(temp, UNO_QUERY); + } + + // getting the Logger + m_Logger = pool->getNamedLogger(LOGGERNAME); + + // getting the FileHandler + prepareLogHandler(); + + // getting the Formatter + { + Reference<XInterface> temp = + sm->createInstance(CSSL_CSVFORMATTER); + m_Formatter = Reference<XCsvLogFormatter>(temp, UNO_QUERY); + } + + if(m_Formatter.is() && m_LogHandler.is() && m_Logger.is()) + { + Sequence<OUString> columns = Sequence<OUString>(COLUMNS); + columns[0] = OUString::createFromAscii("eventtype"); + columns[1] = OUString::createFromAscii("originapp"); + columns[2] = OUString::createFromAscii("originwidget"); + columns[3] = OUString::createFromAscii("uno url"); + columns[4] = OUString::createFromAscii("parent id"); + columns[5] = OUString::createFromAscii("window type"); + columns[6] = OUString::createFromAscii("id"); + columns[7] = OUString::createFromAscii("method"); + columns[8] = OUString::createFromAscii("parameter"); + m_Formatter->setColumnnames(columns); + m_LogHandler->setFormatter(Reference<XLogFormatter>(m_Formatter, UNO_QUERY)); + m_Logger->setLevel(LogLevel::ALL); + m_LogHandler->setLevel(LogLevel::ALL); + m_Logger->addLogHandler(m_LogHandler); + } + else + m_Active = false; + } + + // private static UiEventsLogger_Impl + bool UiEventsLogger_Impl::shouldActivate() + { + return getEnabledFromCfg() && getEnabledFromCoreController(); + } + + OUString UiEventsLogger_Impl::getLogPathFromCfg() + { + OUString result; + Reference<XMultiServiceFactory> sm = getProcessServiceFactory(); + + ConfigurationHelper::readDirectKey( + sm, + CFG_LOGGING, CFG_OOOIMPROVEMENT, CFG_LOGPATH, + ConfigurationHelper::E_READONLY + ) >>= result; + + Reference<XStringSubstitution> path_sub( + sm->createInstance(CSSU_PATHSUB), + UNO_QUERY); + if(path_sub.is()) + result = path_sub->substituteVariables(result, sal_False); + return result; + } + + TimeValue UiEventsLogger_Impl::getIdleTimeoutFromCfg() + { + sal_Int32 timeoutminutes = 360; + Reference<XMultiServiceFactory> sm = getProcessServiceFactory(); + + ConfigurationHelper::readDirectKey( + sm, + CFG_LOGGING, CFG_OOOIMPROVEMENT, CFG_IDLETIMEOUT, + ConfigurationHelper::E_READONLY + ) >>= timeoutminutes; + TimeValue result; + result.Seconds = static_cast<sal_uInt32>(timeoutminutes)*60; + result.Nanosec = 0; + return result; + } + + bool UiEventsLogger_Impl::getEnabledFromCfg() + { + sal_Bool result = false; + Reference<XMultiServiceFactory> sm = getProcessServiceFactory(); + ConfigurationHelper::readDirectKey( + sm, + CFG_LOGGING, CFG_OOOIMPROVEMENT, CFG_ENABLED, + ::comphelper::ConfigurationHelper::E_READONLY + ) >>= result; + return result; + } + + bool UiEventsLogger_Impl::getEnabledFromCoreController() + { + Reference<XMultiServiceFactory> sm = getProcessServiceFactory(); + Reference<XCoreController> core_c( + sm->createInstance(OUString::createFromAscii("com.sun.star.oooimprovement.CoreController")), + UNO_QUERY); + if(!core_c.is()) return false; + return core_c->enablingUiEventsLoggerAllowed(1); + } + + UiEventsLogger_Impl::ptr UiEventsLogger_Impl::instance = UiEventsLogger_Impl::ptr(); + UiEventsLogger_Impl::ptr UiEventsLogger_Impl::getInstance() + { + if(instance == NULL) + instance = UiEventsLogger_Impl::ptr(new UiEventsLogger_Impl()); + return instance; + } + + Mutex * UiEventsLogger_Impl::singleton_mutex = NULL; + void UiEventsLogger_Impl::prepareMutex() + { + if(singleton_mutex == NULL) + { + Guard<Mutex> global_guard(Mutex::getGlobalMutex()); + if(singleton_mutex == NULL) + singleton_mutex = new Mutex(); + } + } + + sal_Int32 UiEventsLogger_Impl::findIdx(const Sequence<PropertyValue>& args, const OUString& key) + { + for(sal_Int32 i=0; i<args.getLength(); i++) + if(args[i].Name == key) + return i; + return -1; + } + + void UiEventsLogger_Impl::disposing() + { + m_Active = false; + m_Logger.clear() ; + m_LogHandler.clear(); + m_Formatter.clear(); + } +} diff --git a/comphelper/source/misc/weak.cxx b/comphelper/source/misc/weak.cxx new file mode 100644 index 000000000000..e84e069f0e38 --- /dev/null +++ b/comphelper/source/misc/weak.cxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * 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/weak.hxx" + +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; + +namespace comphelper +{ + +OWeakTypeObject::OWeakTypeObject() +{ +} + +OWeakTypeObject::~OWeakTypeObject() +{ +} + +Any SAL_CALL OWeakTypeObject::queryInterface(const Type & rType ) throw (RuntimeException) +{ + if( rType == XTypeProvider::static_type() ) + return Any( Reference< XTypeProvider >(this) ); + else + return ::cppu::OWeakObject::queryInterface( rType ); +} + +void SAL_CALL OWeakTypeObject::acquire() throw () +{ + ::cppu::OWeakObject::acquire(); +} + +void SAL_CALL OWeakTypeObject::release() throw () +{ + ::cppu::OWeakObject::release(); +} + +Sequence< Type > SAL_CALL OWeakTypeObject::getTypes( ) throw (RuntimeException) +{ + return Sequence< Type >(); +} + +Sequence< ::sal_Int8 > SAL_CALL OWeakTypeObject::getImplementationId( ) throw (RuntimeException) +{ + return Sequence< ::sal_Int8 >(); +} + +} + diff --git a/comphelper/source/misc/weakeventlistener.cxx b/comphelper/source/misc/weakeventlistener.cxx new file mode 100644 index 000000000000..0a96698e7b92 --- /dev/null +++ b/comphelper/source/misc/weakeventlistener.cxx @@ -0,0 +1,93 @@ +/************************************************************************* + * + * 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/weakeventlistener.hxx> +#include <osl/diagnose.h> + + +//......................................................................... +namespace comphelper +{ +//......................................................................... + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + + //===================================================================== + //= OWeakListenerAdapter + //===================================================================== + //--------------------------------------------------------------------- + OWeakListenerAdapterBase::~OWeakListenerAdapterBase() + { + } + + //===================================================================== + //= OWeakEventListenerAdapter + //===================================================================== + //--------------------------------------------------------------------- + OWeakEventListenerAdapter::OWeakEventListenerAdapter( Reference< XWeak > _rxListener, Reference< XComponent > _rxBroadcaster ) + :OWeakEventListenerAdapter_Base( _rxListener, _rxBroadcaster ) + { + // add ourself as listener to the broadcaster + OSL_ENSURE( _rxBroadcaster.is(), "OWeakEventListenerAdapter::OWeakEventListenerAdapter: invalid broadcaster!" ); + if ( _rxBroadcaster.is() ) + { + osl_incrementInterlockedCount( &m_refCount ); + { + _rxBroadcaster->addEventListener( this ); + } + osl_decrementInterlockedCount( &m_refCount ); + OSL_ENSURE( m_refCount > 0, "OWeakEventListenerAdapter::OWeakEventListenerAdapter: oops - not to be used with implementations which hold their listeners weak!" ); + // the one and only reason for this adapter class (A) is to add as listener to a component (C) which + // holds its listeners hard, and forward all calls then to another listener (L) which is + // held weak by A. + // Now if C holds listeners weak, then we do not need A, we can add L directly to C. + } + + OSL_ENSURE( getListener().is(), "OWeakEventListenerAdapter::OWeakEventListenerAdapter: invalid listener (does not support the XEventListener interface)!" ); + } + + //--------------------------------------------------------------------- + void SAL_CALL OWeakEventListenerAdapter::disposing( ) + { + Reference< XComponent > xBroadcaster( getBroadcaster( ), UNO_QUERY ); + OSL_ENSURE( xBroadcaster.is(), "OWeakEventListenerAdapter::disposing: broadcaster is invalid in the meantime! How this?" ); + if ( xBroadcaster.is() ) + { + xBroadcaster->removeEventListener( this ); + } + + resetListener(); + } + +//......................................................................... +} // namespace comphelper +//......................................................................... + + diff --git a/comphelper/source/officeinstdir/makefile.mk b/comphelper/source/officeinstdir/makefile.mk new file mode 100644 index 000000000000..dfe195da662a --- /dev/null +++ b/comphelper/source/officeinstdir/makefile.mk @@ -0,0 +1,50 @@ +#************************************************************************* +# +# 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=officeinstdir + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings common for the whole project ----- + + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES= $(SLO)$/officeinstallationdirectories.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/comphelper/source/officeinstdir/officeinstallationdirectories.cxx b/comphelper/source/officeinstdir/officeinstallationdirectories.cxx new file mode 100644 index 000000000000..3ce0d4de865a --- /dev/null +++ b/comphelper/source/officeinstdir/officeinstallationdirectories.cxx @@ -0,0 +1,350 @@ +/************************************************************************* + * + * 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_module.hxx" + +/************************************************************************** + TODO + ************************************************************************** + + *************************************************************************/ + +#include "osl/file.hxx" +#include "com/sun/star/beans/XPropertySet.hpp" +#include "com/sun/star/util/XMacroExpander.hpp" + +#include "officeinstallationdirectories.hxx" + +using namespace com::sun::star; + +using namespace comphelper; + +//========================================================================= +// helpers +//========================================================================= + +//========================================================================= +static bool makeCanonicalFileURL( rtl::OUString & rURL ) +{ + OSL_ENSURE( rURL.matchAsciiL( "file:", sizeof( "file:" ) - 1 , 0 ) , + "File URL expected!" ); + + rtl::OUString aNormalizedURL; + if ( osl::FileBase::getAbsoluteFileURL( rtl::OUString(), + rURL, + aNormalizedURL ) + == osl::DirectoryItem::E_None ) + { + osl::DirectoryItem aDirItem; + if ( osl::DirectoryItem::get( aNormalizedURL, aDirItem ) + == osl::DirectoryItem::E_None ) + { + osl::FileStatus aFileStatus( FileStatusMask_FileURL ); + + if ( aDirItem.getFileStatus( aFileStatus ) + == osl::DirectoryItem::E_None ) + { + aNormalizedURL = aFileStatus.getFileURL(); + + if ( aNormalizedURL.getLength() > 0 ) + { + if ( aNormalizedURL + .getStr()[ aNormalizedURL.getLength() - 1 ] + != sal_Unicode( '/' ) ) + rURL = aNormalizedURL; + else + rURL = aNormalizedURL + .copy( 0, aNormalizedURL.getLength() - 1 ); + + return true; + } + } + } + } + return false; +} + +//========================================================================= +//========================================================================= +// +// OfficeInstallationDirectories Implementation. +// +//========================================================================= +//========================================================================= + +OfficeInstallationDirectories::OfficeInstallationDirectories( + const uno::Reference< uno::XComponentContext > & xCtx ) +: m_aOfficeDirMacro( RTL_CONSTASCII_USTRINGPARAM( "$(baseinsturl)" ) ), + m_aUserDirMacro( RTL_CONSTASCII_USTRINGPARAM( "$(userdataurl)" ) ), + m_xCtx( xCtx ), + m_pOfficeDir( 0 ), + m_pUserDir( 0 ) +{ +} + +//========================================================================= +// virtual +OfficeInstallationDirectories::~OfficeInstallationDirectories() +{ +} + +//========================================================================= +// util::XOfficeInstallationDirectories +//========================================================================= + +// virtual +rtl::OUString SAL_CALL +OfficeInstallationDirectories::getOfficeInstallationDirectoryURL() + throw ( uno::RuntimeException ) +{ + // late init m_pOfficeDir and m_pUserDir + initDirs(); + return rtl::OUString( *m_pOfficeDir ); +} + +//========================================================================= +// virtual +rtl::OUString SAL_CALL +OfficeInstallationDirectories::getOfficeUserDataDirectoryURL() + throw ( uno::RuntimeException ) +{ + // late init m_pOfficeDir and m_pUserDir + initDirs(); + return rtl::OUString( *m_pUserDir ); +} + + +//========================================================================= +// virtual +rtl::OUString SAL_CALL +OfficeInstallationDirectories::makeRelocatableURL( const rtl::OUString& URL ) + throw ( uno::RuntimeException ) +{ + if ( URL.getLength() > 0 ) + { + // late init m_pOfficeDir and m_pUserDir + initDirs(); + + rtl::OUString aCanonicalURL( URL ); + makeCanonicalFileURL( aCanonicalURL ); + + sal_Int32 nIndex = aCanonicalURL.indexOf( *m_pOfficeDir ); + if ( nIndex != -1 ) + { + return rtl::OUString( + URL.replaceAt( nIndex, + m_pOfficeDir->getLength(), + m_aOfficeDirMacro ) ); + } + else + { + nIndex = aCanonicalURL.indexOf( *m_pUserDir ); + if ( nIndex != -1 ) + { + return rtl::OUString( + URL.replaceAt( nIndex, + m_pUserDir->getLength(), + m_aUserDirMacro ) ); + } + } + } + return rtl::OUString( URL ); +} + +//========================================================================= +// virtual +rtl::OUString SAL_CALL +OfficeInstallationDirectories::makeAbsoluteURL( const rtl::OUString& URL ) + throw ( uno::RuntimeException ) +{ + if ( URL.getLength() > 0 ) + { + sal_Int32 nIndex = URL.indexOf( m_aOfficeDirMacro ); + if ( nIndex != -1 ) + { + // late init m_pOfficeDir and m_pUserDir + initDirs(); + + return rtl::OUString( + URL.replaceAt( nIndex, + m_aOfficeDirMacro.getLength(), + *m_pOfficeDir ) ); + } + else + { + nIndex = URL.indexOf( m_aUserDirMacro ); + if ( nIndex != -1 ) + { + // late init m_pOfficeDir and m_pUserDir + initDirs(); + + return rtl::OUString( + URL.replaceAt( nIndex, + m_aUserDirMacro.getLength(), + *m_pUserDir ) ); + } + } + } + return rtl::OUString( URL ); +} + +//========================================================================= +// lang::XServiceInfo +//========================================================================= + +// virtual +rtl::OUString SAL_CALL +OfficeInstallationDirectories::getImplementationName() + throw ( uno::RuntimeException ) +{ + return getImplementationName_static(); +} + +//========================================================================= +// virtual +sal_Bool SAL_CALL +OfficeInstallationDirectories::supportsService( const rtl::OUString& ServiceName ) + throw ( uno::RuntimeException ) +{ + const uno::Sequence< rtl::OUString > & aNames + = getSupportedServiceNames(); + const rtl::OUString * p = aNames.getConstArray(); + for ( sal_Int32 nPos = 0; nPos < aNames.getLength(); nPos++ ) + { + if ( p[ nPos ].equals( ServiceName ) ) + return sal_True; + } + return sal_False; + +} + +//========================================================================= +// virtual +uno::Sequence< ::rtl::OUString > SAL_CALL +OfficeInstallationDirectories::getSupportedServiceNames() + throw ( uno::RuntimeException ) +{ + return getSupportedServiceNames_static(); +} + +//========================================================================= +// static +rtl::OUString SAL_CALL +OfficeInstallationDirectories::getImplementationName_static() +{ + return rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.comp.util.OfficeInstallationDirectories" ) ); +} + +//========================================================================= +// static +uno::Sequence< ::rtl::OUString > SAL_CALL +OfficeInstallationDirectories::getSupportedServiceNames_static() +{ + const rtl::OUString aServiceName( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.util.OfficeInstallationDirectories" ) ); + return uno::Sequence< rtl::OUString >( &aServiceName, 1 ); +} + +//========================================================================= +// static +rtl::OUString SAL_CALL OfficeInstallationDirectories::getSingletonName_static() +{ + return rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.util.theOfficeInstallationDirectories" ) ); +} + +//========================================================================= +// static +uno::Reference< uno::XInterface > SAL_CALL +OfficeInstallationDirectories::Create( + const uno::Reference< uno::XComponentContext > & rxContext ) +{ + return static_cast< cppu::OWeakObject * >( + new OfficeInstallationDirectories( rxContext ) ); +} + +//========================================================================= +// non-UNO +//========================================================================= + +void OfficeInstallationDirectories::initDirs() +{ + if ( m_pOfficeDir == 0 ) + { + osl::MutexGuard aGuard( m_aMutex ); + if ( m_pOfficeDir == 0 ) + { + m_pOfficeDir = new rtl::OUString; + m_pUserDir = new rtl::OUString; + + uno::Reference< util::XMacroExpander > xExpander; + + m_xCtx->getValueByName( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "/singletons/com.sun.star.util.theMacroExpander" ) ) ) + >>= xExpander; + + OSL_ENSURE( xExpander.is(), + "Unable to obtain macro expander singleton!" ); + + if ( xExpander.is() ) + { + *m_pOfficeDir = + xExpander->expandMacros( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE( "bootstrap" ) ":BaseInstallation}" ) ) ); + + OSL_ENSURE( m_pOfficeDir->getLength() > 0, + "Unable to obtain office installation directory!" ); + + makeCanonicalFileURL( *m_pOfficeDir ); + + *m_pUserDir = + xExpander->expandMacros( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE( "bootstrap" ) ":UserInstallation}" ) ) ); + + OSL_ENSURE( m_pUserDir->getLength() > 0, + "Unable to obtain office user data directory!" ); + + makeCanonicalFileURL( *m_pUserDir ); + } + } + } +} + +void createRegistryInfo_OfficeInstallationDirectories() +{ + static ::comphelper::module::OSingletonRegistration< OfficeInstallationDirectories > aAutoRegistration; +} diff --git a/comphelper/source/officeinstdir/officeinstallationdirectories.hxx b/comphelper/source/officeinstdir/officeinstallationdirectories.hxx new file mode 100644 index 000000000000..2ffb3582718a --- /dev/null +++ b/comphelper/source/officeinstdir/officeinstallationdirectories.hxx @@ -0,0 +1,107 @@ +/************************************************************************* + * + * 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 INCLUDED_OFFICEINSTALLATIONDIRECTORIES_HXX +#define INCLUDED_OFFICEINSTALLATIONDIRECTORIES_HXX + +#include "osl/mutex.hxx" +#include "cppuhelper/implbase2.hxx" + +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/util/XOfficeInstallationDirectories.hpp" + +namespace comphelper { + +//========================================================================= + +typedef cppu::WeakImplHelper2< + com::sun::star::util::XOfficeInstallationDirectories, + com::sun::star::lang::XServiceInfo > UnoImplBase; + +struct mutex_holder +{ + osl::Mutex m_aMutex; +}; + +class OfficeInstallationDirectories : public mutex_holder, public UnoImplBase +{ +public: + OfficeInstallationDirectories( + const com::sun::star::uno::Reference< + com::sun::star::uno::XComponentContext > & xCtx ); + virtual ~OfficeInstallationDirectories(); + + // XOfficeInstallationDirectories + virtual ::rtl::OUString SAL_CALL + getOfficeInstallationDirectoryURL() + throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL + getOfficeUserDataDirectoryURL() + throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL + makeRelocatableURL( const ::rtl::OUString& URL ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL + makeAbsoluteURL( const ::rtl::OUString& URL ) + throw (::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); + + // XServiceInfo - static versions (used for component registration) + static ::rtl::OUString SAL_CALL + getImplementationName_static(); + static ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL + getSupportedServiceNames_static(); + static ::rtl::OUString SAL_CALL + getSingletonName_static(); + 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 >& ); + +private: + void initDirs(); + + rtl::OUString m_aOfficeDirMacro; + rtl::OUString m_aUserDirMacro; + com::sun::star::uno::Reference< + com::sun::star::uno::XComponentContext > m_xCtx; + rtl::OUString * m_pOfficeDir; + rtl::OUString * m_pUserDir; +}; + +} // namespace comphelper + +#endif /* !INCLUDED_OFFICEINSTALLATIONDIRECTORIES_HXX */ diff --git a/comphelper/source/processfactory/componentfactory.cxx b/comphelper/source/processfactory/componentfactory.cxx new file mode 100644 index 000000000000..7a3b17111072 --- /dev/null +++ b/comphelper/source/processfactory/componentfactory.cxx @@ -0,0 +1,86 @@ +/************************************************************************* + * + * 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/componentfactory.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#ifndef _COM_SUN_STAR_REGISTRY_XREGISTRYKEY_HDL_ +#include <com/sun/star/registry/XRegistryKey.hpp> +#endif +#include <cppuhelper/shlib.hxx> + + +#ifndef GCC +#endif + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; +using namespace ::rtl; + + +namespace comphelper +{ + +Reference< XInterface > getComponentInstance( + const OUString & rLibraryName, + const OUString & rImplementationName + ) +{ + Reference< XInterface > xI; + Reference< XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + if ( xMSF.is() ) + xI = xMSF->createInstance( rImplementationName ); + if( !xI.is() ) + { + Reference< XSingleServiceFactory > xSSF = + loadLibComponentFactory( rLibraryName, rImplementationName, + Reference< XMultiServiceFactory >(), Reference< XRegistryKey >() ); + if (xSSF.is()) + xI = xSSF->createInstance(); + } + return xI; +} + + +Reference< XSingleServiceFactory > loadLibComponentFactory( + const OUString & rLibName, + const OUString & rImplName, + const Reference< XMultiServiceFactory > & xSF, + const Reference< XRegistryKey > & xKey + ) +{ + return Reference< XSingleServiceFactory >( ::cppu::loadSharedLibComponentFactory( + rLibName, OUString(), rImplName, xSF, xKey ), UNO_QUERY ); +} + +} // namespace comphelper diff --git a/comphelper/source/processfactory/makefile.mk b/comphelper/source/processfactory/makefile.mk new file mode 100644 index 000000000000..531291bb3a15 --- /dev/null +++ b/comphelper/source/processfactory/makefile.mk @@ -0,0 +1,52 @@ +#************************************************************************* +# +# 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=..$/.. +PRJNAME=comphelper +TARGET=processfactory + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings common for the whole project ----- + + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Types ------------------------------------- + +# --- Files ------------------------------------- + +SLOFILES= $(SLO)$/processfactory.obj \ + $(SLO)$/componentfactory.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/comphelper/source/processfactory/processfactory.cxx b/comphelper/source/processfactory/processfactory.cxx new file mode 100644 index 000000000000..514d3377edab --- /dev/null +++ b/comphelper/source/processfactory/processfactory.cxx @@ -0,0 +1,127 @@ +/************************************************************************* + * + * 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 <osl/mutex.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#include "com/sun/star/beans/XPropertySet.hpp" + + +using namespace ::com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace osl; + +namespace comphelper +{ + +/* + This function preserves only that the xProcessFactory variable will not be create when + the library is loaded. +*/ +Reference< XMultiServiceFactory > localProcessFactory( const Reference< XMultiServiceFactory >& xSMgr, sal_Bool bSet ) +{ + Guard< Mutex > aGuard( Mutex::getGlobalMutex() ); + + static Reference< XMultiServiceFactory > xProcessFactory; + if ( bSet ) + { + xProcessFactory = xSMgr; + } + + return xProcessFactory; +} + + +void setProcessServiceFactory(const Reference< XMultiServiceFactory >& xSMgr) +{ + localProcessFactory( xSMgr, sal_True ); +} + +Reference< XMultiServiceFactory > getProcessServiceFactory() +{ + Reference< XMultiServiceFactory> xReturn; + xReturn = localProcessFactory( xReturn, sal_False ); + return xReturn; +} + +Reference< XInterface > createProcessComponent( const ::rtl::OUString& _rServiceSpecifier ) SAL_THROW( ( RuntimeException ) ) +{ + Reference< XInterface > xComponent; + + Reference< XMultiServiceFactory > xFactory( getProcessServiceFactory() ); + if ( xFactory.is() ) + xComponent = xFactory->createInstance( _rServiceSpecifier ); + + return xComponent; +} + +Reference< XInterface > createProcessComponentWithArguments( const ::rtl::OUString& _rServiceSpecifier, + const Sequence< Any >& _rArgs ) SAL_THROW( ( RuntimeException ) ) +{ + Reference< XInterface > xComponent; + + Reference< XMultiServiceFactory > xFactory( getProcessServiceFactory() ); + if ( xFactory.is() ) + xComponent = xFactory->createInstanceWithArguments( _rServiceSpecifier, _rArgs ); + + return xComponent; +} + +Reference< XComponentContext > getProcessComponentContext() +{ + Reference< XComponentContext > xRet; + uno::Reference<beans::XPropertySet> const xProps( + comphelper::getProcessServiceFactory(), uno::UNO_QUERY ); + if (xProps.is()) { + try { + xRet.set( xProps->getPropertyValue( rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ), + uno::UNO_QUERY ); + } + catch (beans::UnknownPropertyException const&) { + } + } + return xRet; +} + +} // namespace comphelper + +extern "C" { +uno::XComponentContext * comphelper_getProcessComponentContext() +{ + uno::Reference<uno::XComponentContext> xRet; + xRet = ::comphelper::getProcessComponentContext(); + if (xRet.is()) + xRet->acquire(); + return xRet.get(); +} +} // extern "C" + 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..e796c29eba90 --- /dev/null +++ b/comphelper/source/property/propagg.cxx @@ -0,0 +1,1027 @@ +/************************************************************************* + * + * 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(); + + // 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 ); + + // create the map for the aggregate properties + sal_Int32 nAggregateHandle = _nFirstAggregateId; + pMergedProps += nDelegatorProps; + for ( ; nMPLoop < nMergedProps; ++nMPLoop, ++pMergedProps, ++pAggregateProps ) + { + // next aggregate property - remember it + *pMergedProps = *pAggregateProps; + + // determine the handle for the property which we will expose to the ourside 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; + } + 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(); + } + +//......................................................................... +} +//......................................................................... + diff --git a/comphelper/source/streaming/basicio.cxx b/comphelper/source/streaming/basicio.cxx new file mode 100644 index 000000000000..eef5c6b844fa --- /dev/null +++ b/comphelper/source/streaming/basicio.cxx @@ -0,0 +1,174 @@ +/************************************************************************* + * + * 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/basicio.hxx> + +//......................................................................... +namespace comphelper +{ +//......................................................................... + +//------------------------------------------------------------------------------ +const staruno::Reference<stario::XObjectOutputStream>& operator << ( + const staruno::Reference<stario::XObjectOutputStream>& _rxOutStream, + const starawt::FontDescriptor& _rFont) +{ + _rxOutStream->writeUTF( _rFont.Name ); + _rxOutStream->writeShort( _rFont.Height ); + _rxOutStream->writeShort( _rFont.Width ); + _rxOutStream->writeUTF( _rFont.StyleName ); + _rxOutStream->writeShort( _rFont.Family ); + _rxOutStream->writeShort( _rFont.CharSet ); + _rxOutStream->writeShort( _rFont.Pitch ); + _rxOutStream->writeDouble( _rFont.CharacterWidth ); + _rxOutStream->writeDouble( _rFont.Weight ); + _rxOutStream->writeShort( static_cast< sal_Int16 >(_rFont.Slant) ); + _rxOutStream->writeShort( _rFont.Underline ); + _rxOutStream->writeShort( _rFont.Strikeout ); + _rxOutStream->writeDouble( _rFont.Orientation ); + _rxOutStream->writeBoolean( _rFont.Kerning ); + _rxOutStream->writeBoolean( _rFont.WordLineMode ); + _rxOutStream->writeShort( _rFont.Type ); + return _rxOutStream; +} + +// FontDescriptor +//------------------------------------------------------------------------------ +const staruno::Reference<stario::XObjectInputStream>& operator >> ( + const staruno::Reference<stario::XObjectInputStream>& _rxInStream, + starawt::FontDescriptor& _rFont) +{ + // schreiben des Fontdescriptors + _rFont.Name = _rxInStream->readUTF(); + _rFont.Height = _rxInStream->readShort(); + _rFont.Width = _rxInStream->readShort(); + _rFont.StyleName = _rxInStream->readUTF(); + _rFont.Family = _rxInStream->readShort(); + _rFont.CharSet = _rxInStream->readShort(); + _rFont.Pitch = _rxInStream->readShort(); + _rFont.CharacterWidth = static_cast< float >(_rxInStream->readDouble()); + _rFont.Weight = static_cast< float >(_rxInStream->readDouble()); + _rFont.Slant = (starawt::FontSlant)_rxInStream->readShort(); + _rFont.Underline = _rxInStream->readShort(); + _rFont.Strikeout = _rxInStream->readShort(); + _rFont.Orientation = static_cast< float >(_rxInStream->readDouble()); + _rFont.Kerning = _rxInStream->readBoolean(); + _rFont.WordLineMode = _rxInStream->readBoolean(); + _rFont.Type = _rxInStream->readShort(); + return _rxInStream; +} + +//------------------------------------------------------------------------------ +const staruno::Reference<stario::XObjectInputStream>& operator >> (const staruno::Reference<stario::XObjectInputStream>& _rxInStream, sal_Bool& _rVal) +{ + _rVal = _rxInStream->readBoolean(); + return _rxInStream; +} + +//------------------------------------------------------------------------------ +const staruno::Reference<stario::XObjectOutputStream>& operator << (const staruno::Reference<stario::XObjectOutputStream>& _rxOutStream, sal_Bool _bVal) +{ + _rxOutStream->writeBoolean(_bVal); + return _rxOutStream; +} + +//------------------------------------------------------------------------------ +const staruno::Reference<stario::XObjectInputStream>& operator >> (const staruno::Reference<stario::XObjectInputStream>& _rxInStream, ::rtl::OUString& rStr) +{ + rStr = _rxInStream->readUTF(); + return _rxInStream; +} + +//------------------------------------------------------------------------------ +const staruno::Reference<stario::XObjectOutputStream>& operator << (const staruno::Reference<stario::XObjectOutputStream>& _rxOutStream, const ::rtl::OUString& rStr) +{ + _rxOutStream->writeUTF(rStr); + return _rxOutStream; +} + +//------------------------------------------------------------------------------ +const staruno::Reference<stario::XObjectInputStream>& operator >> (const staruno::Reference<stario::XObjectInputStream>& _rxInStream, sal_Int16& _rValue) +{ + _rValue = _rxInStream->readShort(); + return _rxInStream; +} + +//------------------------------------------------------------------------------ +const staruno::Reference<stario::XObjectOutputStream>& operator << (const staruno::Reference<stario::XObjectOutputStream>& _rxOutStream, sal_Int16 _nValue) +{ + _rxOutStream->writeShort(_nValue); + return _rxOutStream; +} + +//------------------------------------------------------------------------------ +const staruno::Reference<stario::XObjectInputStream>& operator >> (const staruno::Reference<stario::XObjectInputStream>& _rxInStream, sal_uInt16& _rValue) +{ + _rValue = _rxInStream->readShort(); + return _rxInStream; +} + +//------------------------------------------------------------------------------ +const staruno::Reference<stario::XObjectOutputStream>& operator << (const staruno::Reference<stario::XObjectOutputStream>& _rxOutStream, sal_uInt16 _nValue) +{ + _rxOutStream->writeShort(_nValue); + return _rxOutStream; +} + +//------------------------------------------------------------------------------ +const staruno::Reference<stario::XObjectInputStream>& operator >> (const staruno::Reference<stario::XObjectInputStream>& _rxInStream, sal_uInt32& _rValue) +{ + _rValue = _rxInStream->readLong(); + return _rxInStream; +} + +//------------------------------------------------------------------------------ +const staruno::Reference<stario::XObjectOutputStream>& operator << (const staruno::Reference<stario::XObjectOutputStream>& _rxOutStream, sal_uInt32 _nValue) +{ + _rxOutStream->writeLong(_nValue); + return _rxOutStream; +} + +//------------------------------------------------------------------------------ +const staruno::Reference<stario::XObjectInputStream>& operator >> (const staruno::Reference<stario::XObjectInputStream>& _rxInStream, sal_Int32& _rValue) +{ + _rValue = _rxInStream->readLong(); + return _rxInStream; +} + +//------------------------------------------------------------------------------ +const staruno::Reference<stario::XObjectOutputStream>& operator << (const staruno::Reference<stario::XObjectOutputStream>& _rxOutStream, sal_Int32 _nValue) +{ + _rxOutStream->writeLong(_nValue); + return _rxOutStream; +} + +//......................................................................... +} // namespace comphelper +//......................................................................... + diff --git a/comphelper/source/streaming/makefile.mk b/comphelper/source/streaming/makefile.mk new file mode 100644 index 000000000000..2a6ea38ca65e --- /dev/null +++ b/comphelper/source/streaming/makefile.mk @@ -0,0 +1,54 @@ +#************************************************************************* +# +# 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=..$/.. +PRJNAME=comphelper +TARGET=streaming + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES= $(SLO)$/basicio.obj \ + $(SLO)$/oslfile2streamwrap.obj \ + $(SLO)$/seqstream.obj \ + $(SLO)$/seqinputstreamserv.obj \ + $(SLO)$/seqoutputstreamserv.obj \ + $(SLO)$/streamsection.obj \ + $(SLO)$/seekableinput.obj \ + $(SLO)$/otransactedfilestream.obj \ + $(SLO)$/memorystream.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/comphelper/source/streaming/memorystream.cxx b/comphelper/source/streaming/memorystream.cxx new file mode 100644 index 000000000000..5298b7511f09 --- /dev/null +++ b/comphelper/source/streaming/memorystream.cxx @@ -0,0 +1,247 @@ +/************************************************************************* + * + * 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_module.hxx" + +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XSeekableInputStream.hpp> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <cppuhelper/implbase4.hxx> + +#include <string.h> +#include <vector> + +using ::rtl::OUString; +using ::cppu::OWeakObject; +using ::cppu::WeakImplHelper4; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::osl; + +namespace comphelper +{ + +class UNOMemoryStream : public WeakImplHelper4 < XStream, XSeekableInputStream, XOutputStream, XTruncate > +{ +public: + UNOMemoryStream(); + virtual ~UNOMemoryStream(); + + // XStream + virtual Reference< XInputStream > SAL_CALL getInputStream( ) throw (RuntimeException); + virtual Reference< XOutputStream > SAL_CALL getOutputStream( ) throw (RuntimeException); + + // XInputStream + virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException); + virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException); + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException); + virtual sal_Int32 SAL_CALL available() throw (NotConnectedException, IOException, RuntimeException); + virtual void SAL_CALL closeInput() throw (NotConnectedException, IOException, RuntimeException); + + // XSeekable + virtual void SAL_CALL seek( sal_Int64 location ) throw (IllegalArgumentException, IOException, RuntimeException); + virtual sal_Int64 SAL_CALL getPosition() throw (IOException, RuntimeException); + virtual sal_Int64 SAL_CALL getLength() throw (IOException, RuntimeException); + + // XOutputStream + virtual void SAL_CALL writeBytes( const Sequence< sal_Int8 >& aData ) throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException); + virtual void SAL_CALL flush() throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException); + virtual void SAL_CALL closeOutput() throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException); + + // XTruncate + virtual void SAL_CALL truncate() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + // XServiceInfo - static versions (used for component registration) + static ::rtl::OUString SAL_CALL getImplementationName_static(); + static Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static(); + static Reference< XInterface > SAL_CALL Create( const Reference< ::com::sun::star::uno::XComponentContext >& ); + +private: + std::vector< sal_Int8 > maData; + sal_Int32 mnCursor; +}; + +UNOMemoryStream::UNOMemoryStream() +: mnCursor(0) +{ +} + +UNOMemoryStream::~UNOMemoryStream() +{ +} + +// XStream +Reference< XInputStream > SAL_CALL UNOMemoryStream::getInputStream( ) throw (RuntimeException) +{ + return this; +} + +Reference< XOutputStream > SAL_CALL UNOMemoryStream::getOutputStream( ) throw (RuntimeException) +{ + return this; +} + +// XInputStream +sal_Int32 SAL_CALL UNOMemoryStream::readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + if( nBytesToRead < 0 ) + throw IOException(); + + nBytesToRead = std::min( nBytesToRead, available() ); + aData.realloc( nBytesToRead ); + + if( nBytesToRead ) + { + sal_Int8* pData = static_cast<sal_Int8*>(&(*maData.begin())); + sal_Int8* pCursor = &((pData)[mnCursor]); + memcpy( (void*)aData.getArray(), (void*)pCursor, nBytesToRead ); + + mnCursor += nBytesToRead; + } + + return nBytesToRead; +} + +sal_Int32 SAL_CALL UNOMemoryStream::readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + return readBytes( aData, nMaxBytesToRead ); +} + +void SAL_CALL UNOMemoryStream::skipBytes( sal_Int32 nBytesToSkip ) throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + if( nBytesToSkip < 0 ) + throw IOException(); + + mnCursor += std::min( nBytesToSkip, available() ); +} + +sal_Int32 SAL_CALL UNOMemoryStream::available() throw (NotConnectedException, IOException, RuntimeException) +{ + return static_cast< sal_Int32 >( maData.size() ) - mnCursor; +} + +void SAL_CALL UNOMemoryStream::closeInput() throw (NotConnectedException, IOException, RuntimeException) +{ + mnCursor = 0; +} + +// XSeekable +void SAL_CALL UNOMemoryStream::seek( sal_Int64 location ) throw (IllegalArgumentException, IOException, RuntimeException) +{ + if( (location < 0) || (location > SAL_MAX_INT32) ) + throw IllegalArgumentException( OUString(RTL_CONSTASCII_USTRINGPARAM("this implementation does not support more than 2GB!")), Reference< XInterface >(static_cast<OWeakObject*>(this)), 0 ); + + // seek operation should be able to resize the stream + if ( location > static_cast< sal_Int64 >( maData.size() ) ) + maData.resize( static_cast< sal_Int32 >( location ) ); + + if ( location > static_cast< sal_Int64 >( maData.size() ) ) + maData.resize( static_cast< sal_Int32 >( location ) ); + + mnCursor = static_cast< sal_Int32 >( location ); +} + +sal_Int64 SAL_CALL UNOMemoryStream::getPosition() throw (IOException, RuntimeException) +{ + return static_cast< sal_Int64 >( mnCursor ); +} + +sal_Int64 SAL_CALL UNOMemoryStream::getLength() throw (IOException, RuntimeException) +{ + return static_cast< sal_Int64 >( maData.size() ); +} + +// XOutputStream +void SAL_CALL UNOMemoryStream::writeBytes( const Sequence< sal_Int8 >& aData ) throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + const sal_Int32 nBytesToWrite( aData.getLength() ); + if( nBytesToWrite ) + { + sal_Int64 nNewSize = static_cast< sal_Int64 >( mnCursor + nBytesToWrite ); + if( nNewSize > SAL_MAX_INT32 ) + { + OSL_ASSERT(false); + throw IOException( OUString(RTL_CONSTASCII_USTRINGPARAM("this implementation does not support more than 2GB!")), Reference< XInterface >(static_cast<OWeakObject*>(this)) ); + } + + if( static_cast< sal_Int32 >( nNewSize ) > static_cast< sal_Int32 >( maData.size() ) ) + maData.resize( static_cast< sal_Int32 >( nNewSize ) ); + + sal_Int8* pData = static_cast<sal_Int8*>(&(*maData.begin())); + sal_Int8* pCursor = &(pData[mnCursor]); + memcpy( (void*)pCursor, (void*)aData.getConstArray(), nBytesToWrite ); + + mnCursor += nBytesToWrite; + } +} + +void SAL_CALL UNOMemoryStream::flush() throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ +} + +void SAL_CALL UNOMemoryStream::closeOutput() throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + mnCursor = 0; +} + +//XTruncate +void SAL_CALL UNOMemoryStream::truncate() throw (IOException, RuntimeException) +{ + maData.resize( 0 ); + mnCursor = 0; +} + +::rtl::OUString SAL_CALL UNOMemoryStream::getImplementationName_static() +{ + static const OUString sImplName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.MemoryStream" ) ); + return sImplName; +} + +Sequence< ::rtl::OUString > SAL_CALL UNOMemoryStream::getSupportedServiceNames_static() +{ + Sequence< OUString > aSeq(1); + aSeq[0] = getImplementationName_static(); + return aSeq; +} + +Reference< XInterface > SAL_CALL UNOMemoryStream::Create( + const Reference< XComponentContext >& ) +{ + return static_cast<OWeakObject*>(new UNOMemoryStream()); +} + +} // namespace comphelper + +void createRegistryInfo_UNOMemoryStream() +{ + static ::comphelper::module::OAutoRegistration< ::comphelper::UNOMemoryStream > aAutoRegistration; +} diff --git a/comphelper/source/streaming/oslfile2streamwrap.cxx b/comphelper/source/streaming/oslfile2streamwrap.cxx new file mode 100644 index 000000000000..9cf8eeaaf08a --- /dev/null +++ b/comphelper/source/streaming/oslfile2streamwrap.cxx @@ -0,0 +1,198 @@ +/************************************************************************* + * + * 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/oslfile2streamwrap.hxx> + +#include <algorithm> + +namespace comphelper +{ + using namespace osl; + +//------------------------------------------------------------------ +OSLInputStreamWrapper::OSLInputStreamWrapper( File& _rFile ) + :m_pFile(&_rFile) + ,m_bFileOwner(sal_False) +{ +} + +//------------------------------------------------------------------ +OSLInputStreamWrapper::OSLInputStreamWrapper( File* pStream, sal_Bool bOwner ) + :m_pFile( pStream ) + ,m_bFileOwner( bOwner ) +{ +} + +//------------------------------------------------------------------ +OSLInputStreamWrapper::~OSLInputStreamWrapper() +{ + if( m_bFileOwner ) + delete m_pFile; +} + +//------------------------------------------------------------------------------ +sal_Int32 SAL_CALL OSLInputStreamWrapper::readBytes(staruno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) + throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException ) +{ + if (!m_pFile) + throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + if (nBytesToRead < 0) + throw stario::BufferSizeExceededException(::rtl::OUString(),static_cast<staruno::XWeak*>(this)); + + ::osl::MutexGuard aGuard( m_aMutex ); + + aData.realloc(nBytesToRead); + + sal_uInt64 nRead = 0; + FileBase::RC eError = m_pFile->read((void*)aData.getArray(), nBytesToRead, nRead); + if (eError != FileBase::E_None) + throw stario::BufferSizeExceededException(::rtl::OUString(),static_cast<staruno::XWeak*>(this)); + + // Wenn gelesene Zeichen < MaxLength, staruno::Sequence anpassen + if (nRead < (sal_uInt32)nBytesToRead) + aData.realloc( sal::static_int_cast< sal_Int32 >(nRead) ); + + return sal::static_int_cast< sal_Int32 >(nRead); +} + +//------------------------------------------------------------------------------ +sal_Int32 SAL_CALL OSLInputStreamWrapper::readSomeBytes(staruno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException ) +{ + if (!m_pFile) + throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + if (nMaxBytesToRead < 0) + throw stario::BufferSizeExceededException(::rtl::OUString(),static_cast<staruno::XWeak*>(this)); + + /* + if (m_pFile->IsEof()) + { + aData.realloc(0); + return 0; + } + else + */ + return readBytes(aData, nMaxBytesToRead); +} + +//------------------------------------------------------------------------------ +void SAL_CALL OSLInputStreamWrapper::skipBytes(sal_Int32 nBytesToSkip) throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (!m_pFile) + throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + sal_uInt64 nCurrentPos; + m_pFile->getPos(nCurrentPos); + + sal_uInt64 nNewPos = nCurrentPos + nBytesToSkip; + FileBase::RC eError = m_pFile->setPos(osl_Pos_Absolut, nNewPos); + if (eError != FileBase::E_None) + { + throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + } + +#ifdef DBG_UTIL + m_pFile->getPos(nCurrentPos); +// volatile int dummy = 0; // to take a look at last changes ;-) +#endif +} + +//------------------------------------------------------------------------------ +sal_Int32 SAL_CALL OSLInputStreamWrapper::available() throw( stario::NotConnectedException, staruno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (!m_pFile) + throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + sal_uInt64 nPos; + FileBase::RC eError = m_pFile->getPos(nPos); + if (eError != FileBase::E_None) + throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + sal_uInt64 nDummy = 0; + eError = m_pFile->setPos(Pos_End, nDummy); + if (eError != FileBase::E_None) + throw stario::NotConnectedException(::rtl::OUString(),static_cast<staruno::XWeak*>(this)); + + sal_uInt64 nAvailable; + eError = m_pFile->getPos(nAvailable); + if (eError != FileBase::E_None) + throw stario::NotConnectedException(::rtl::OUString(),static_cast<staruno::XWeak*>(this)); + + nAvailable = nAvailable - nPos; + eError = m_pFile->setPos(Pos_Absolut, nPos); + if (eError != FileBase::E_None) + throw stario::NotConnectedException(::rtl::OUString(),static_cast<staruno::XWeak*>(this)); + return sal::static_int_cast< sal_Int32 >( + std::max(nAvailable, sal::static_int_cast< sal_uInt64 >(SAL_MAX_INT32))); +} + +//------------------------------------------------------------------------------ +void SAL_CALL OSLInputStreamWrapper::closeInput() throw( stario::NotConnectedException, staruno::RuntimeException ) +{ + if (!m_pFile) + throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + m_pFile->close(); + if (m_bFileOwner) + delete m_pFile; + + m_pFile = NULL; +} + +/*************************************************************************/ +// stario::XOutputStream +//------------------------------------------------------------------------------ +void SAL_CALL OSLOutputStreamWrapper::writeBytes(const staruno::Sequence< sal_Int8 >& aData) throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException ) +{ + sal_uInt64 nWritten; + FileBase::RC eError = rFile.write(aData.getConstArray(),aData.getLength(), nWritten); + if (eError != FileBase::E_None + || nWritten != sal::static_int_cast< sal_uInt32 >(aData.getLength())) + { + throw stario::BufferSizeExceededException(::rtl::OUString(),static_cast<staruno::XWeak*>(this)); + } +} + +//------------------------------------------------------------------ +void SAL_CALL OSLOutputStreamWrapper::flush() throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException ) +{ +} + +//------------------------------------------------------------------ +void SAL_CALL OSLOutputStreamWrapper::closeOutput() throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException ) +{ + rFile.close(); +} + +} // namespace comphelper + + diff --git a/comphelper/source/streaming/otransactedfilestream.cxx b/comphelper/source/streaming/otransactedfilestream.cxx new file mode 100644 index 000000000000..03539a12305b --- /dev/null +++ b/comphelper/source/streaming/otransactedfilestream.cxx @@ -0,0 +1,824 @@ +/************************************************************************* + * + * 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 <osl/diagnose.h> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/io/XAsyncOutputMonitor.hpp> +#include <com/sun/star/embed/UseBackupException.hpp> + +#include <comphelper/otransactedfilestream.hxx> +#include <comphelper/storagehelper.hxx> +#include <cppuhelper/implbase1.hxx> + +using namespace ::com::sun::star; + +namespace comphelper +{ + +// ======================================================================== +class OTransactionHelper : public ::cppu::WeakImplHelper1 < embed::XTransactedObject > +{ + OTruncatedTransactedFileStream* m_pFileStream; + uno::Reference< io::XStream > m_xStreamHolder; + +public: + OTransactionHelper( OTruncatedTransactedFileStream* pStream ) + : m_pFileStream( pStream ) + { + m_xStreamHolder = static_cast< io::XStream* >( pStream ); + if ( !m_xStreamHolder.is() ) + throw uno::RuntimeException(); + } + + virtual void SAL_CALL commit( ) throw (io::IOException, lang::WrappedTargetException, uno::RuntimeException); + virtual void SAL_CALL revert( ) throw (io::IOException, lang::WrappedTargetException, uno::RuntimeException); +}; + +// ------------------------------------------------------------------------ +void SAL_CALL OTransactionHelper::commit( ) throw (io::IOException, lang::WrappedTargetException, uno::RuntimeException) +{ + m_pFileStream->Commit_Impl(); +} + +// ------------------------------------------------------------------------ +void SAL_CALL OTransactionHelper::revert( ) throw (io::IOException, lang::WrappedTargetException, uno::RuntimeException) +{ + m_pFileStream->Revert_Impl(); +} + +// ======================================================================== +struct TTFileStreamData_Impl +{ + uno::Reference< ucb::XSimpleFileAccess > m_xFileAccess; + sal_Bool m_bDelete; + ::rtl::OUString m_aURL; + + // the streams below are not visible from outside so there is no need to remember position + + // original stream related members + uno::Reference< io::XStream > m_xOrigStream; + uno::Reference< io::XTruncate > m_xOrigTruncate; + uno::Reference< io::XSeekable > m_xOrigSeekable; + uno::Reference< io::XInputStream > m_xOrigInStream; + uno::Reference< io::XOutputStream > m_xOrigOutStream; + + // temporary stream related members + uno::Reference< io::XStream > m_xTempStream; + uno::Reference< io::XTruncate > m_xTempTruncate; + uno::Reference< io::XSeekable > m_xTempSeekable; + uno::Reference< io::XInputStream > m_xTempInStream; + uno::Reference< io::XOutputStream > m_xTempOutStream; + + sal_Bool m_bInOpen; + sal_Bool m_bOutOpen; + + sal_Bool m_bTransacted; + + + TTFileStreamData_Impl( + const uno::Reference< ucb::XSimpleFileAccess >& xFileAccess, + sal_Bool bDelete, + const ::rtl::OUString& aURL, + const uno::Reference< io::XStream >& xOrigStream, + const uno::Reference< io::XTruncate >& xOrigTruncate, + const uno::Reference< io::XSeekable >& xOrigSeekable, + const uno::Reference< io::XInputStream >& xOrigInStream, + const uno::Reference< io::XOutputStream >& xOrigOutStream, + const uno::Reference< io::XStream >& xTempStream, + const uno::Reference< io::XTruncate >& xTempTruncate, + const uno::Reference< io::XSeekable >& xTempSeekable, + const uno::Reference< io::XInputStream >& xTempInStream, + const uno::Reference< io::XOutputStream >& xTempOutStream ) + : m_xFileAccess( xFileAccess ) + , m_bDelete( bDelete ) + , m_aURL( aURL ) + , m_xOrigStream( xOrigStream ) + , m_xOrigTruncate( xOrigTruncate ) + , m_xOrigSeekable( xOrigSeekable ) + , m_xOrigInStream( xOrigInStream ) + , m_xOrigOutStream( xOrigOutStream ) + , m_xTempStream( xTempStream ) + , m_xTempTruncate( xTempTruncate ) + , m_xTempSeekable( xTempSeekable ) + , m_xTempInStream( xTempInStream ) + , m_xTempOutStream( xTempOutStream ) + , m_bInOpen( sal_False ) + , m_bOutOpen( sal_False ) + , m_bTransacted( sal_True ) + {} + + void NoTransaction() + { + m_bDelete = sal_False; + m_bTransacted = sal_False; + m_xTempStream = uno::Reference< io::XStream >(); + m_xTempTruncate = uno::Reference< io::XTruncate >(); + m_xTempSeekable = uno::Reference< io::XSeekable >(); + m_xTempInStream = uno::Reference< io::XInputStream >(); + m_xTempOutStream = uno::Reference< io::XOutputStream >(); + } + + void FreeOriginal() + { + m_bDelete = sal_False; + m_bTransacted = sal_False; + + m_xOrigStream = m_xTempStream; + m_xTempStream = uno::Reference< io::XStream >(); + + m_xOrigTruncate = m_xTempTruncate; + m_xTempTruncate = uno::Reference< io::XTruncate >(); + + m_xOrigSeekable = m_xTempSeekable; + m_xTempSeekable = uno::Reference< io::XSeekable >(); + + m_xOrigInStream = m_xTempInStream; + m_xTempInStream = uno::Reference< io::XInputStream >(); + + m_xOrigOutStream = m_xTempOutStream; + m_xTempOutStream = uno::Reference< io::XOutputStream >(); + } +}; + +// ======================================================================== +// ------------------------------------------------------------------------ +OTruncatedTransactedFileStream::OTruncatedTransactedFileStream( + const ::rtl::OUString& aURL, + const uno::Reference< lang::XMultiServiceFactory >& xFactory ) +: m_pStreamData( NULL ) +{ + uno::Reference< ucb::XSimpleFileAccess > xSimpleFileAccess( + xFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ucb.SimpleFileAccess" ) ) ), + uno::UNO_QUERY_THROW ); + + CommonInit_Impl( aURL, xSimpleFileAccess, xFactory, sal_False ); +} + +// ------------------------------------------------------------------------ +OTruncatedTransactedFileStream::OTruncatedTransactedFileStream( + const ::rtl::OUString& aURL, + const uno::Reference< ucb::XSimpleFileAccess >& xFileAccess, + const uno::Reference< lang::XMultiServiceFactory >& xFactory ) +: m_pStreamData( NULL ) +{ + CommonInit_Impl( aURL, xFileAccess, xFactory, sal_False ); +} + +// ------------------------------------------------------------------------ +OTruncatedTransactedFileStream::OTruncatedTransactedFileStream( + const ::rtl::OUString& aURL, + const uno::Reference< ucb::XSimpleFileAccess >& xFileAccess, + const uno::Reference< lang::XMultiServiceFactory >& xFactory, + sal_Bool bDeleteIfNotCommited ) +: m_pStreamData( NULL ) +{ + CommonInit_Impl( aURL, xFileAccess, xFactory, sal_True ); + if ( m_pStreamData ) + m_pStreamData->m_bDelete = bDeleteIfNotCommited; +} + +// ------------------------------------------------------------------------ +OTruncatedTransactedFileStream::~OTruncatedTransactedFileStream() +{ + CloseAll_Impl(); +} + +// ------------------------------------------------------------------------ +void OTruncatedTransactedFileStream::CloseAll_Impl() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pStreamData ) + { + sal_Bool bDelete = m_pStreamData->m_bDelete; + ::rtl::OUString aURL = m_pStreamData->m_aURL; + uno::Reference< ucb::XSimpleFileAccess > xFileAccess = m_pStreamData->m_xFileAccess; + + delete m_pStreamData; + m_pStreamData = NULL; + + if ( bDelete && xFileAccess.is() && aURL.getLength() ) + { + // delete the file + try + { + xFileAccess->kill( aURL ); + } catch( uno::Exception& ) + { + OSL_ENSURE( sal_False, "Could not remove the file!" ); + } + } + } +} + +// ------------------------------------------------------------------------ +void OTruncatedTransactedFileStream::CommonInit_Impl( + const ::rtl::OUString& aURL, + const uno::Reference< ucb::XSimpleFileAccess >& xFileAccess, + const uno::Reference< lang::XMultiServiceFactory >& xFactory, + sal_Bool bDeleteOptionIsProvided ) +{ + sal_Bool bDelete = sal_False; + if ( !bDeleteOptionIsProvided ) + bDelete = !xFileAccess->exists( aURL ); + + uno::Reference< io::XStream > xOrigStream = xFileAccess->openFileReadWrite( aURL ); + uno::Reference< io::XTruncate > xOrigTruncate( xOrigStream, uno::UNO_QUERY_THROW ); + uno::Reference< io::XSeekable > xOrigSeekable( xOrigStream, uno::UNO_QUERY_THROW ); + uno::Reference< io::XInputStream > xOrigInStream = xOrigStream->getInputStream(); + uno::Reference< io::XOutputStream > xOrigOutStream = xOrigStream->getOutputStream(); + if ( !xOrigInStream.is() || !xOrigOutStream.is() ) + throw uno::RuntimeException(); + + // temporary stream related members + uno::Reference< io::XStream > xTempStream( xFactory->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ) ), + uno::UNO_QUERY_THROW ); + uno::Reference< io::XTruncate > xTempTruncate( xTempStream, uno::UNO_QUERY_THROW ); + uno::Reference< io::XSeekable > xTempSeekable( xTempStream, uno::UNO_QUERY_THROW ); + uno::Reference< io::XInputStream > xTempInStream = xTempStream->getInputStream(); + uno::Reference< io::XOutputStream > xTempOutStream = xTempStream->getOutputStream(); + if ( !xTempInStream.is() || !xTempOutStream.is() ) + throw uno::RuntimeException(); + + m_pStreamData = new TTFileStreamData_Impl( xFileAccess, bDelete, aURL, + xOrigStream, xOrigTruncate, xOrigSeekable, xOrigInStream, xOrigOutStream, + xTempStream, xTempTruncate, xTempSeekable, xTempInStream, xTempOutStream ); +} + +// ------------------------------------------------------------------------ +void OTruncatedTransactedFileStream::Commit_Impl() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + if ( m_pStreamData->m_bTransacted ) + { + sal_Int64 nPos = m_pStreamData->m_xTempSeekable->getPosition(); + m_pStreamData->m_xTempSeekable->seek( 0 ); + + // after the following step fails the information might be lost, throw an exception with URL of temporary file + try + { + m_pStreamData->m_xOrigTruncate->truncate(); + OStorageHelper::CopyInputToOutput( m_pStreamData->m_xTempInStream, m_pStreamData->m_xOrigOutStream ); + m_pStreamData->m_xOrigOutStream->flush(); + + // in case the stream is based on a file it will implement the following interface + // the call should be used to be sure that the contents are written to the file system + uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( m_pStreamData->m_xOrigOutStream, uno::UNO_QUERY ); + if ( asyncOutputMonitor.is() ) + asyncOutputMonitor->waitForCompletion(); + } + catch( uno::Exception& ) + { + ::rtl::OUString aTempURL; + try { + uno::Reference< beans::XPropertySet > xTempFile( m_pStreamData->m_xTempStream, uno::UNO_QUERY_THROW ); + uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) ); + aUrl >>= aTempURL; + xTempFile->setPropertyValue( ::rtl::OUString::createFromAscii( "RemoveFile" ), + uno::makeAny( sal_False ) ); + + m_pStreamData->m_xTempSeekable->seek( nPos ); + } + catch( uno::Exception& ) + { + OSL_ENSURE( sal_False, "These calls are pretty simple, they should not fail!\n" ); + } + + m_pStreamData->FreeOriginal(); + + ::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( "Writing file failed!" ) ); + embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), aTempURL ); + throw lang::WrappedTargetException( aErrTxt, + static_cast < OWeakObject * > ( this ), + uno::makeAny ( aException ) ); + } + + m_pStreamData->m_xOrigSeekable->seek( nPos ); + m_pStreamData->NoTransaction(); + } + else + throw io::NotConnectedException(); +} + +// ------------------------------------------------------------------------ +void OTruncatedTransactedFileStream::Revert_Impl() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + if ( m_pStreamData->m_bTransacted ) + m_pStreamData->m_xTempTruncate->truncate(); + else + throw io::NotConnectedException(); +} + +// com::sun::star::io::XStream +// ------------------------------------------------------------------------ +uno::Reference< io::XInputStream > SAL_CALL OTruncatedTransactedFileStream::getInputStream( ) + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pStreamData ) + m_pStreamData->m_bInOpen = sal_True; + return static_cast< io::XInputStream* >( this ); +} + + +// ------------------------------------------------------------------------ +uno::Reference< io::XOutputStream > SAL_CALL OTruncatedTransactedFileStream::getOutputStream( ) + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pStreamData ) + m_pStreamData->m_bOutOpen = sal_True; + return static_cast< io::XOutputStream* >( this ); +} + + + +// com::sun::star::io::XInputStream +// ------------------------------------------------------------------------ +::sal_Int32 SAL_CALL OTruncatedTransactedFileStream::readBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nBytesToRead ) + throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + if ( m_pStreamData->m_bTransacted ) + { + // temporary stream data should be provided + if ( !m_pStreamData->m_xTempInStream.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xTempInStream->readBytes( aData, nBytesToRead ); + } + else + { + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigInStream.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xOrigInStream->readBytes( aData, nBytesToRead ); + } +} + + +// ------------------------------------------------------------------------ +::sal_Int32 SAL_CALL OTruncatedTransactedFileStream::readSomeBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nMaxBytesToRead ) + throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + if ( m_pStreamData->m_bTransacted ) + { + // temporary stream data should be provided + if ( !m_pStreamData->m_xTempInStream.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xTempInStream->readSomeBytes( aData, nMaxBytesToRead ); + } + else + { + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigInStream.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xOrigInStream->readSomeBytes( aData, nMaxBytesToRead ); + } +} + +// ------------------------------------------------------------------------ +void SAL_CALL OTruncatedTransactedFileStream::skipBytes( ::sal_Int32 nBytesToSkip ) + throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + if ( m_pStreamData->m_bTransacted ) + { + // temporary stream data should be provided + if ( !m_pStreamData->m_xTempInStream.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xTempInStream->skipBytes( nBytesToSkip ); + } + else + { + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigInStream.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xOrigInStream->skipBytes( nBytesToSkip ); + } +} + + +// ------------------------------------------------------------------------ +::sal_Int32 SAL_CALL OTruncatedTransactedFileStream::available( ) + throw (io::NotConnectedException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + if ( m_pStreamData->m_bTransacted ) + { + // temporary stream data should be provided + if ( !m_pStreamData->m_xTempInStream.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xTempInStream->available(); + } + else + { + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigInStream.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xOrigInStream->available(); + } +} + + +// ------------------------------------------------------------------------ +void SAL_CALL OTruncatedTransactedFileStream::closeInput() + throw (io::NotConnectedException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + m_pStreamData->m_bInOpen = sal_False; + if ( !m_pStreamData->m_bOutOpen ) + CloseAll_Impl(); +} + + + +// com::sun::star::io::XOutputStream +// ------------------------------------------------------------------------ +void SAL_CALL OTruncatedTransactedFileStream::writeBytes( const uno::Sequence< ::sal_Int8 >& aData ) + throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + if ( m_pStreamData->m_bTransacted ) + { + // temporary stream data should be provided + if ( !m_pStreamData->m_xTempOutStream.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xTempOutStream->writeBytes( aData ); + } + else + { + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigOutStream.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xOrigOutStream->writeBytes( aData ); + } +} + + +// ------------------------------------------------------------------------ +void SAL_CALL OTruncatedTransactedFileStream::flush( ) + throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + { + OSL_ENSURE( sal_False, "flush() call on closed stream!\n" ); + return; + // in future throw exception, for now some code might call flush() on closed stream + // since file ucp implementation allows it + // throw io::NotConnectedException(); + } + + if ( m_pStreamData->m_bTransacted ) + { + // temporary stream data should be provided + if ( !m_pStreamData->m_xTempOutStream.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xTempOutStream->flush(); + } + else + { + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigOutStream.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xOrigOutStream->flush(); + } +} + + +// ------------------------------------------------------------------------ +void SAL_CALL OTruncatedTransactedFileStream::closeOutput( ) + throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + m_pStreamData->m_bOutOpen = sal_False; + if ( !m_pStreamData->m_bInOpen ) + CloseAll_Impl(); +} + + + +// com::sun::star::io::XTruncate +// ------------------------------------------------------------------------ +void SAL_CALL OTruncatedTransactedFileStream::truncate( ) + throw (io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + if ( m_pStreamData->m_bTransacted ) + { + // temporary stream data should be provided + if ( !m_pStreamData->m_xTempTruncate.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xTempTruncate->truncate(); + } + else + { + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigTruncate.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xOrigTruncate->truncate(); + } +} + + + +// com::sun::star::io::XSeekable +// ------------------------------------------------------------------------ +void SAL_CALL OTruncatedTransactedFileStream::seek( ::sal_Int64 location ) + throw (lang::IllegalArgumentException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + if ( m_pStreamData->m_bTransacted ) + { + // temporary stream data should be provided + if ( !m_pStreamData->m_xTempSeekable.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xTempSeekable->seek( location ); + } + else + { + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigSeekable.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xOrigSeekable->seek( location ); + } +} + + +// ------------------------------------------------------------------------ +::sal_Int64 SAL_CALL OTruncatedTransactedFileStream::getPosition( ) + throw (io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + if ( m_pStreamData->m_bTransacted ) + { + // temporary stream data should be provided + if ( !m_pStreamData->m_xTempSeekable.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xTempSeekable->getPosition(); + } + else + { + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigSeekable.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xOrigSeekable->getPosition(); + } +} + + +// ------------------------------------------------------------------------ +::sal_Int64 SAL_CALL OTruncatedTransactedFileStream::getLength( ) + throw (io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + if ( m_pStreamData->m_bTransacted ) + { + // temporary stream data should be provided + if ( !m_pStreamData->m_xTempSeekable.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xTempSeekable->getLength(); + } + else + { + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigSeekable.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xOrigSeekable->getLength(); + } +} + +// com::sun::star::beans::XPropertySetInfo +// ------------------------------------------------------------------------ +uno::Sequence< beans::Property > SAL_CALL OTruncatedTransactedFileStream::getProperties() + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + uno::Sequence< beans::Property > aProps( 1 ); + aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TransactionSupport" ) ); + aProps[0].Type = getCppuType( static_cast< uno::Reference< beans::XPropertySet >* >( NULL ) ); + aProps[0].Attributes = beans::PropertyAttribute::TRANSIENT | beans::PropertyAttribute::READONLY; + + return aProps; +} + + +// ------------------------------------------------------------------------ +beans::Property SAL_CALL OTruncatedTransactedFileStream::getPropertyByName( const ::rtl::OUString& aName ) + throw (beans::UnknownPropertyException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ::rtl::OUString aTransactionPropName( RTL_CONSTASCII_USTRINGPARAM( "TransactionSupport" ) ); + + if ( !aName.equals( aTransactionPropName ) ) + throw beans::UnknownPropertyException(); + + beans::Property aProp; + aProp.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TransactionSupport" ) ); + aProp.Type = getCppuType( static_cast< uno::Reference< beans::XPropertySet >* >( NULL ) ); + aProp.Attributes = beans::PropertyAttribute::TRANSIENT | beans::PropertyAttribute::READONLY; + + return aProp; +} + + +// ------------------------------------------------------------------------ +::sal_Bool SAL_CALL OTruncatedTransactedFileStream::hasPropertyByName( const ::rtl::OUString& Name ) + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ::rtl::OUString aTransactionPropName( RTL_CONSTASCII_USTRINGPARAM( "TransactionSupport" ) ); + return ( Name.equals( aTransactionPropName ) ); +} + + + +// com::sun::star::beans::XPropertySet +// ------------------------------------------------------------------------ +uno::Reference< beans::XPropertySetInfo > SAL_CALL OTruncatedTransactedFileStream::getPropertySetInfo() + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + return static_cast< beans::XPropertySetInfo* >( this ); +} + + +// ------------------------------------------------------------------------ +void SAL_CALL OTruncatedTransactedFileStream::setPropertyValue( const ::rtl::OUString& aPropertyName, const uno::Any& ) + throw (beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ::rtl::OUString aTransactionPropName( RTL_CONSTASCII_USTRINGPARAM( "TransactionSupport" ) ); + if ( aPropertyName.equals( aTransactionPropName ) ) + throw beans::PropertyVetoException(); + + throw beans::UnknownPropertyException(); +} + + +// ------------------------------------------------------------------------ +uno::Any SAL_CALL OTruncatedTransactedFileStream::getPropertyValue( const ::rtl::OUString& PropertyName ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + ::rtl::OUString aTransactionPropName( RTL_CONSTASCII_USTRINGPARAM( "TransactionSupport" ) ); + if ( PropertyName.equals( aTransactionPropName ) ) + { + uno::Reference< embed::XTransactedObject > xObj; + if ( m_pStreamData->m_bTransacted ) + xObj = static_cast< embed::XTransactedObject* >( new OTransactionHelper( this ) ); + + return uno::makeAny( xObj ); + } + + throw beans::UnknownPropertyException(); +} + + +// ------------------------------------------------------------------------ +void SAL_CALL OTruncatedTransactedFileStream::addPropertyChangeListener( const ::rtl::OUString&, const uno::Reference< beans::XPropertyChangeListener >& ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + // not implemented +} + + +// ------------------------------------------------------------------------ +void SAL_CALL OTruncatedTransactedFileStream::removePropertyChangeListener( const ::rtl::OUString&, const uno::Reference< beans::XPropertyChangeListener >& ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + // not implemented +} + + +// ------------------------------------------------------------------------ +void SAL_CALL OTruncatedTransactedFileStream::addVetoableChangeListener( const ::rtl::OUString&, const uno::Reference< beans::XVetoableChangeListener >& ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + // not implemented +} + + +// ------------------------------------------------------------------------ +void SAL_CALL OTruncatedTransactedFileStream::removeVetoableChangeListener( const ::rtl::OUString&, const uno::Reference< beans::XVetoableChangeListener >& ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + // not implemented +} + + +} // namespace comphelper + diff --git a/comphelper/source/streaming/seekableinput.cxx b/comphelper/source/streaming/seekableinput.cxx new file mode 100644 index 000000000000..abaf46faf014 --- /dev/null +++ b/comphelper/source/streaming/seekableinput.cxx @@ -0,0 +1,267 @@ +/************************************************************************* + * + * 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/io/XOutputStream.hpp> + + +#include <comphelper/seekableinput.hxx> + +using namespace ::com::sun::star; + +namespace comphelper +{ + +const sal_Int32 nConstBufferSize = 32000; + +//--------------------------------------------------------------------------- +void copyInputToOutput_Impl( const uno::Reference< io::XInputStream >& xIn, + const uno::Reference< io::XOutputStream >& xOut ) +{ + sal_Int32 nRead; + uno::Sequence< sal_Int8 > aSequence( nConstBufferSize ); + + do + { + nRead = xIn->readBytes( aSequence, nConstBufferSize ); + if ( nRead < nConstBufferSize ) + { + uno::Sequence< sal_Int8 > aTempBuf( aSequence.getConstArray(), nRead ); + xOut->writeBytes( aTempBuf ); + } + else + xOut->writeBytes( aSequence ); + } + while ( nRead == nConstBufferSize ); +} + +//--------------------------------------------------------------------------- +OSeekableInputWrapper::OSeekableInputWrapper( + const uno::Reference< io::XInputStream >& xInStream, + const uno::Reference< lang::XMultiServiceFactory >& xFactory ) +: m_xFactory( xFactory ) +, m_xOriginalStream( xInStream ) +{ + if ( !m_xFactory.is() ) + throw uno::RuntimeException(); +} + +//--------------------------------------------------------------------------- +OSeekableInputWrapper::~OSeekableInputWrapper() +{ +} + +//--------------------------------------------------------------------------- +uno::Reference< io::XInputStream > OSeekableInputWrapper::CheckSeekableCanWrap( + const uno::Reference< io::XInputStream >& xInStream, + const uno::Reference< lang::XMultiServiceFactory >& xFactory ) +{ + // check that the stream is seekable and just wrap it if it is not + uno::Reference< io::XSeekable > xSeek( xInStream, uno::UNO_QUERY ); + if ( xSeek.is() ) + return xInStream; + + uno::Reference< io::XInputStream > xNewStream( + static_cast< io::XInputStream* >( + new OSeekableInputWrapper( xInStream, xFactory ) ) ); + return xNewStream; +} + +//--------------------------------------------------------------------------- +void OSeekableInputWrapper::PrepareCopy_Impl() +{ + if ( !m_xCopyInput.is() ) + { + if ( !m_xFactory.is() ) + throw uno::RuntimeException(); + + uno::Reference< io::XOutputStream > xTempOut( + m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ), + uno::UNO_QUERY ); + + if ( xTempOut.is() ) + { + copyInputToOutput_Impl( m_xOriginalStream, xTempOut ); + xTempOut->closeOutput(); + + uno::Reference< io::XSeekable > xTempSeek( xTempOut, uno::UNO_QUERY ); + if ( xTempSeek.is() ) + { + xTempSeek->seek( 0 ); + m_xCopyInput = uno::Reference< io::XInputStream >( xTempOut, uno::UNO_QUERY ); + if ( m_xCopyInput.is() ) + m_xCopySeek = xTempSeek; + } + } + } + + if ( !m_xCopyInput.is() ) + throw io::IOException(); +} + +// XInputStream +//--------------------------------------------------------------------------- +sal_Int32 SAL_CALL OSeekableInputWrapper::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_xOriginalStream.is() ) + throw io::NotConnectedException(); + + PrepareCopy_Impl(); + + return m_xCopyInput->readBytes( aData, nBytesToRead ); +} + +//--------------------------------------------------------------------------- +sal_Int32 SAL_CALL OSeekableInputWrapper::readSomeBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_xOriginalStream.is() ) + throw io::NotConnectedException(); + + PrepareCopy_Impl(); + + return m_xCopyInput->readSomeBytes( aData, nMaxBytesToRead ); +} + +//--------------------------------------------------------------------------- +void SAL_CALL OSeekableInputWrapper::skipBytes( sal_Int32 nBytesToSkip ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_xOriginalStream.is() ) + throw io::NotConnectedException(); + + PrepareCopy_Impl(); + + m_xCopyInput->skipBytes( nBytesToSkip ); +} + +//--------------------------------------------------------------------------- +sal_Int32 SAL_CALL OSeekableInputWrapper::available() + throw ( io::NotConnectedException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_xOriginalStream.is() ) + throw io::NotConnectedException(); + + PrepareCopy_Impl(); + + return m_xCopyInput->available(); +} + +//--------------------------------------------------------------------------- +void SAL_CALL OSeekableInputWrapper::closeInput() + throw ( io::NotConnectedException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_xOriginalStream.is() ) + throw io::NotConnectedException(); + + m_xOriginalStream->closeInput(); + m_xOriginalStream = uno::Reference< io::XInputStream >(); + + if ( m_xCopyInput.is() ) + { + m_xCopyInput->closeInput(); + m_xCopyInput = uno::Reference< io::XInputStream >(); + } + + m_xCopySeek = uno::Reference< io::XSeekable >(); +} + + +// XSeekable +//--------------------------------------------------------------------------- +void SAL_CALL OSeekableInputWrapper::seek( sal_Int64 location ) + throw ( lang::IllegalArgumentException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_xOriginalStream.is() ) + throw io::NotConnectedException(); + + PrepareCopy_Impl(); + + m_xCopySeek->seek( location ); +} + +//--------------------------------------------------------------------------- +sal_Int64 SAL_CALL OSeekableInputWrapper::getPosition() + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_xOriginalStream.is() ) + throw io::NotConnectedException(); + + PrepareCopy_Impl(); + + return m_xCopySeek->getPosition(); +} + +//--------------------------------------------------------------------------- +sal_Int64 SAL_CALL OSeekableInputWrapper::getLength() + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_xOriginalStream.is() ) + throw io::NotConnectedException(); + + PrepareCopy_Impl(); + + return m_xCopySeek->getLength(); +} + +} // namespace comphelper + diff --git a/comphelper/source/streaming/seqinputstreamserv.cxx b/comphelper/source/streaming/seqinputstreamserv.cxx new file mode 100644 index 000000000000..015387b9894d --- /dev/null +++ b/comphelper/source/streaming/seqinputstreamserv.cxx @@ -0,0 +1,251 @@ +/************************************************************************* + * + * 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_module.hxx" + +#include <sal/config.h> +#include <osl/mutex.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <cppuhelper/implbase3.hxx> +#include <comphelper/seqstream.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/io/XSeekableInputStream.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/frame/DoubleInitializationException.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + + +using namespace ::com::sun::star; + +namespace { + +class SequenceInputStreamService: + public ::cppu::WeakImplHelper3< + lang::XServiceInfo, + io::XSeekableInputStream, + lang::XInitialization> +{ +public: + explicit SequenceInputStreamService(); + + // ::com::sun::star::lang::XServiceInfo: + virtual ::rtl::OUString SAL_CALL getImplementationName() throw ( uno::RuntimeException ); + virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString & ServiceName ) throw ( uno::RuntimeException ); + virtual uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw ( uno::RuntimeException ); + + // XServiceInfo - static versions (used for component registration) + static ::rtl::OUString SAL_CALL getImplementationName_static(); + static uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static(); + static uno::Reference< uno::XInterface > SAL_CALL Create( const uno::Reference< uno::XComponentContext >& ); + + // ::com::sun::star::io::XInputStream: + virtual ::sal_Int32 SAL_CALL readBytes( uno::Sequence< ::sal_Int8 > & aData, ::sal_Int32 nBytesToRead ) throw ( uno::RuntimeException, io::NotConnectedException, io::BufferSizeExceededException, io::IOException ); + virtual ::sal_Int32 SAL_CALL readSomeBytes( uno::Sequence< ::sal_Int8 > & aData, ::sal_Int32 nMaxBytesToRead ) throw ( uno::RuntimeException, io::NotConnectedException, io::BufferSizeExceededException, io::IOException ); + virtual void SAL_CALL skipBytes( ::sal_Int32 nBytesToSkip ) throw ( uno::RuntimeException, io::NotConnectedException, io::BufferSizeExceededException, io::IOException ); + virtual ::sal_Int32 SAL_CALL available() throw ( uno::RuntimeException, io::NotConnectedException, io::IOException ); + virtual void SAL_CALL closeInput() throw ( uno::RuntimeException, io::NotConnectedException, io::IOException ); + + // ::com::sun::star::io::XSeekable: + virtual void SAL_CALL seek( ::sal_Int64 location ) throw ( uno::RuntimeException, lang::IllegalArgumentException, io::IOException ); + virtual ::sal_Int64 SAL_CALL getPosition() throw ( uno::RuntimeException, io::IOException ); + virtual ::sal_Int64 SAL_CALL getLength() throw ( uno::RuntimeException, io::IOException ); + + // ::com::sun::star::lang::XInitialization: + virtual void SAL_CALL initialize( const uno::Sequence< ::com::sun::star::uno::Any > & aArguments ) throw ( uno::RuntimeException, uno::Exception ); + +private: + SequenceInputStreamService( SequenceInputStreamService & ); // not defined + void operator =( SequenceInputStreamService & ); // not defined + + virtual ~SequenceInputStreamService() {} + + + ::osl::Mutex m_aMutex; + sal_Bool m_bInitialized; + uno::Reference< io::XInputStream > m_xInputStream; + uno::Reference< io::XSeekable > m_xSeekable; +}; + +SequenceInputStreamService::SequenceInputStreamService() +: m_bInitialized( sal_False ) +{} + +// com.sun.star.uno.XServiceInfo: +::rtl::OUString SAL_CALL SequenceInputStreamService::getImplementationName() throw ( uno::RuntimeException ) +{ + return getImplementationName_static(); +} + +::rtl::OUString SAL_CALL SequenceInputStreamService::getImplementationName_static() +{ + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.SequenceInputStreamService" ) ); +} + +::sal_Bool SAL_CALL SequenceInputStreamService::supportsService( ::rtl::OUString const & serviceName ) throw ( uno::RuntimeException ) +{ + uno::Sequence< ::rtl::OUString > serviceNames = getSupportedServiceNames(); + for ( ::sal_Int32 i = 0; i < serviceNames.getLength(); ++i ) { + if ( serviceNames[i] == serviceName ) + return sal_True; + } + return sal_False; +} + +uno::Sequence< ::rtl::OUString > SAL_CALL SequenceInputStreamService::getSupportedServiceNames() throw ( uno::RuntimeException ) +{ + return getSupportedServiceNames_static(); +} + +uno::Sequence< ::rtl::OUString > SAL_CALL SequenceInputStreamService::getSupportedServiceNames_static() +{ + uno::Sequence< ::rtl::OUString > s( 1 ); + s[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.io.SequenceInputStream" ) ); + return s; +} + +uno::Reference< uno::XInterface > SAL_CALL SequenceInputStreamService::Create( + const uno::Reference< uno::XComponentContext >& ) +{ + return static_cast< ::cppu::OWeakObject * >( new SequenceInputStreamService() ); +} + +// ::com::sun::star::io::XInputStream: +::sal_Int32 SAL_CALL SequenceInputStreamService::readBytes( uno::Sequence< ::sal_Int8 > & aData, ::sal_Int32 nBytesToRead ) throw ( uno::RuntimeException, io::NotConnectedException, io::BufferSizeExceededException, io::IOException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xInputStream.is() ) + throw io::NotConnectedException(); + + return m_xInputStream->readBytes( aData, nBytesToRead ); +} + +::sal_Int32 SAL_CALL SequenceInputStreamService::readSomeBytes( uno::Sequence< ::sal_Int8 > & aData, ::sal_Int32 nMaxBytesToRead ) throw ( uno::RuntimeException, io::NotConnectedException, io::BufferSizeExceededException, io::IOException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xInputStream.is() ) + throw io::NotConnectedException(); + + return m_xInputStream->readSomeBytes( aData, nMaxBytesToRead ); +} + +void SAL_CALL SequenceInputStreamService::skipBytes( ::sal_Int32 nBytesToSkip ) throw ( uno::RuntimeException, io::NotConnectedException, io::BufferSizeExceededException, io::IOException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xInputStream.is() ) + throw io::NotConnectedException(); + + return m_xInputStream->skipBytes( nBytesToSkip ); +} + +::sal_Int32 SAL_CALL SequenceInputStreamService::available() throw ( uno::RuntimeException, io::NotConnectedException, io::IOException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xInputStream.is() ) + throw io::NotConnectedException(); + + return m_xInputStream->available(); +} + +void SAL_CALL SequenceInputStreamService::closeInput() throw ( uno::RuntimeException, io::NotConnectedException, io::IOException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xInputStream.is() ) + throw io::NotConnectedException(); + + m_xInputStream->closeInput(); + m_xInputStream = uno::Reference< io::XInputStream >(); + m_xSeekable = uno::Reference< io::XSeekable >(); +} + +// ::com::sun::star::io::XSeekable: +void SAL_CALL SequenceInputStreamService::seek( ::sal_Int64 location ) throw ( uno::RuntimeException, lang::IllegalArgumentException, io::IOException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xSeekable.is() ) + throw io::NotConnectedException(); + + m_xSeekable->seek( location ); +} + +::sal_Int64 SAL_CALL SequenceInputStreamService::getPosition() throw ( uno::RuntimeException, io::IOException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xSeekable.is() ) + throw io::NotConnectedException(); + + return m_xSeekable->getPosition(); +} + +::sal_Int64 SAL_CALL SequenceInputStreamService::getLength() throw ( uno::RuntimeException, io::IOException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xSeekable.is() ) + throw io::NotConnectedException(); + + return m_xSeekable->getLength(); +} + +// ::com::sun::star::lang::XInitialization: +void SAL_CALL SequenceInputStreamService::initialize( const uno::Sequence< ::com::sun::star::uno::Any > & aArguments ) throw ( uno::RuntimeException, uno::Exception ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_bInitialized ) + throw frame::DoubleInitializationException(); + + if ( aArguments.getLength() != 1 ) + throw lang::IllegalArgumentException( ::rtl::OUString::createFromAscii( "Wrong number of arguments!\n" ), + uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ), + 1 ); + + uno::Sequence< sal_Int8 > aSeq; + if ( aArguments[0] >>= aSeq ) + { + uno::Reference< io::XInputStream > xInputStream( + static_cast< ::cppu::OWeakObject* >( new ::comphelper::SequenceInputStream( aSeq ) ), + uno::UNO_QUERY_THROW ); + uno::Reference< io::XSeekable > xSeekable( xInputStream, uno::UNO_QUERY_THROW ); + m_xInputStream = xInputStream; + m_xSeekable = xSeekable; + m_bInitialized = sal_True; + } + else + throw lang::IllegalArgumentException( ::rtl::OUString::createFromAscii( "Unexpected type of argument!\n" ), + uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ), + 1 ); +} + +} // anonymous namespace + +void createRegistryInfo_SequenceInputStream() +{ + static ::comphelper::module::OAutoRegistration< SequenceInputStreamService > aAutoRegistration; +} diff --git a/comphelper/source/streaming/seqoutputstreamserv.cxx b/comphelper/source/streaming/seqoutputstreamserv.cxx new file mode 100644 index 000000000000..a51653e6e419 --- /dev/null +++ b/comphelper/source/streaming/seqoutputstreamserv.cxx @@ -0,0 +1,172 @@ +/************************************************************************* +* + * 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. + * +************************************************************************/ + +#include "precompiled_comphelper.hxx" + +#include "comphelper_module.hxx" + +#include <sal/config.h> +#include <osl/mutex.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <cppuhelper/implbase2.hxx> +#include <comphelper/seqstream.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/io/XSequenceOutputStream.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +using namespace ::com::sun::star; + + +namespace { + +class SequenceOutputStreamService: +public ::cppu::WeakImplHelper2 < lang::XServiceInfo, io::XSequenceOutputStream > +{ +public: + explicit SequenceOutputStreamService(); + + // ::com::sun::star::lang::XServiceInfo: + virtual ::rtl::OUString SAL_CALL getImplementationName() throw ( uno::RuntimeException ); + virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString & ServiceName ) throw ( uno::RuntimeException ); + virtual uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw ( uno::RuntimeException ); + + // XServiceInfo - static versions (used for component registration) + static ::rtl::OUString SAL_CALL getImplementationName_static(); + static uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static(); + static uno::Reference< uno::XInterface > SAL_CALL Create( const uno::Reference< uno::XComponentContext >& ); + + // ::com::sun::star::io::XOutputStream: + virtual void SAL_CALL writeBytes( const uno::Sequence< ::sal_Int8 > & aData ) throw ( io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException ); + virtual void SAL_CALL flush() throw ( uno::RuntimeException, io::NotConnectedException, io::BufferSizeExceededException, io::IOException ); + virtual void SAL_CALL closeOutput() throw ( uno::RuntimeException, io::NotConnectedException, io::BufferSizeExceededException, io::IOException ); + + // ::com::sun::star::io::XSequenceOutputStream: + virtual uno::Sequence< ::sal_Int8 > SAL_CALL getWrittenBytes( ) throw ( io::NotConnectedException, io::IOException, uno::RuntimeException); + +private: + SequenceOutputStreamService( SequenceOutputStreamService & ); //not defined + void operator =( SequenceOutputStreamService & ); //not defined + + virtual ~SequenceOutputStreamService() {}; + + + ::osl::Mutex m_aMutex; + uno::Reference< io::XOutputStream > m_xOutputStream; + uno::Sequence< ::sal_Int8 > m_aSequence; +}; +SequenceOutputStreamService::SequenceOutputStreamService() +{ + m_xOutputStream.set( static_cast < ::cppu::OWeakObject* >( new ::comphelper::OSequenceOutputStream( m_aSequence ) ), uno::UNO_QUERY_THROW ); +} + +// com.sun.star.uno.XServiceInfo: +::rtl::OUString SAL_CALL SequenceOutputStreamService::getImplementationName() throw ( uno::RuntimeException ) +{ + return getImplementationName_static(); +} + +::rtl::OUString SAL_CALL SequenceOutputStreamService::getImplementationName_static() +{ + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.SequenceOutputStreamService" ) ); +} + +::sal_Bool SAL_CALL SequenceOutputStreamService::supportsService( ::rtl::OUString const & serviceName ) throw ( uno::RuntimeException ) +{ + uno::Sequence< ::rtl::OUString > serviceNames = getSupportedServiceNames(); + for ( ::sal_Int32 i = 0; i < serviceNames.getLength(); ++i ) { + if ( serviceNames[i] == serviceName ) + return sal_True; + } + return sal_False; +} + +uno::Sequence< ::rtl::OUString > SAL_CALL SequenceOutputStreamService::getSupportedServiceNames() throw ( uno::RuntimeException ) +{ + return getSupportedServiceNames_static(); +} + +uno::Sequence< ::rtl::OUString > SAL_CALL SequenceOutputStreamService::getSupportedServiceNames_static() +{ + uno::Sequence< ::rtl::OUString > s( 1 ); + s[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.SequenceOutputStream" ) ); + return s; +} + +uno::Reference< uno::XInterface > SAL_CALL SequenceOutputStreamService::Create( + const uno::Reference< uno::XComponentContext >& ) +{ + return static_cast< ::cppu::OWeakObject * >( new SequenceOutputStreamService()); +} + +// ::com::sun::star::io::XOutputStream: +void SAL_CALL SequenceOutputStreamService::writeBytes( const uno::Sequence< ::sal_Int8 > & aData ) throw ( uno::RuntimeException, io::NotConnectedException, io::BufferSizeExceededException, io::IOException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xOutputStream.is() ) + throw io::NotConnectedException(); + + m_xOutputStream->writeBytes( aData ); + m_aSequence = aData; +} + +void SAL_CALL SequenceOutputStreamService::flush() throw ( uno::RuntimeException, io::NotConnectedException, io::BufferSizeExceededException, io::IOException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xOutputStream.is() ) + throw io::NotConnectedException(); + + m_xOutputStream->flush(); +}; + +void SAL_CALL SequenceOutputStreamService::closeOutput() throw ( uno::RuntimeException, io::NotConnectedException, io::BufferSizeExceededException, io::IOException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xOutputStream.is() ) + throw io::NotConnectedException(); + + m_xOutputStream->closeOutput(); + m_xOutputStream = uno::Reference< io::XOutputStream >(); +} + +// ::com::sun::star::io::XSequenceOutputStream: +uno::Sequence< ::sal_Int8 > SAL_CALL SequenceOutputStreamService::getWrittenBytes() throw ( io::NotConnectedException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xOutputStream.is() ) + throw io::NotConnectedException(); + + m_xOutputStream->flush(); + return m_aSequence; +} + +} // anonymous namespace + +void createRegistryInfo_SequenceOutputStream() +{ + static ::comphelper::module::OAutoRegistration< SequenceOutputStreamService > aAutoRegistration; +} diff --git a/comphelper/source/streaming/seqstream.cxx b/comphelper/source/streaming/seqstream.cxx new file mode 100644 index 000000000000..5c8a32b1f6e5 --- /dev/null +++ b/comphelper/source/streaming/seqstream.cxx @@ -0,0 +1,243 @@ +/************************************************************************* + * + * 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/seqstream.hxx> + +#include <memory.h> // for memcpy + +namespace comphelper +{ +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::uno; +using namespace ::osl; + +//--------------------------------------------------------------------------------------------- +// class SequenceInputStream +//--------------------------------------------------------------------------------------------- + +//------------------------------------------------------------------ +SequenceInputStream::SequenceInputStream(const ByteSequence& rData) +: m_aData(rData) +, m_nPos(0) +{ +} + +// checks if closed, returns available size, not mutex-protected +//------------------------------------------------------------------ +inline sal_Int32 SequenceInputStream::avail() +{ + if (m_nPos == -1) + throw NotConnectedException(::rtl::OUString(), *this); + + return m_aData.getLength() - m_nPos; +} + +// com::sun::star::io::XInputStream +//------------------------------------------------------------------ +sal_Int32 SAL_CALL SequenceInputStream::readBytes( Sequence<sal_Int8>& aData, sal_Int32 nBytesToRead ) + throw(NotConnectedException, BufferSizeExceededException, + IOException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + sal_Int32 nAvail = avail(); + + if (nBytesToRead < 0) + throw BufferSizeExceededException(::rtl::OUString(),*this); + + if (nAvail < nBytesToRead) + nBytesToRead = nAvail; + + aData.realloc(nBytesToRead); + memcpy(aData.getArray(), m_aData.getConstArray() + m_nPos, nBytesToRead); + m_nPos += nBytesToRead; + + return nBytesToRead; +} + +//------------------------------------------------------------------ +sal_Int32 SAL_CALL SequenceInputStream::readSomeBytes( Sequence<sal_Int8>& aData, sal_Int32 nMaxBytesToRead ) + throw(NotConnectedException, BufferSizeExceededException, + IOException, RuntimeException) +{ + // all data is available at once + return readBytes(aData, nMaxBytesToRead); +} + +//------------------------------------------------------------------ +void SAL_CALL SequenceInputStream::skipBytes( sal_Int32 nBytesToSkip ) + throw(NotConnectedException, BufferSizeExceededException, + IOException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + sal_Int32 nAvail = avail(); + + if (nBytesToSkip < 0) + throw BufferSizeExceededException(::rtl::OUString(),*this); + + if (nAvail < nBytesToSkip) + nBytesToSkip = nAvail; + + m_nPos += nBytesToSkip; +} + +//------------------------------------------------------------------ +sal_Int32 SAL_CALL SequenceInputStream::available( ) + throw(NotConnectedException, IOException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + return avail(); +} + +//------------------------------------------------------------------ +void SAL_CALL SequenceInputStream::closeInput( ) + throw(NotConnectedException, IOException, RuntimeException) +{ + if (m_nPos == -1) + throw NotConnectedException(::rtl::OUString(), *this); + + m_nPos = -1; +} + +void SAL_CALL SequenceInputStream::seek( sal_Int64 location ) throw (IllegalArgumentException, IOException, RuntimeException) +{ + if ( location > m_aData.getLength() || location < 0 || location > SAL_MAX_INT32 ) + throw IllegalArgumentException(); + m_nPos = (sal_Int32) location; +} + +sal_Int64 SAL_CALL SequenceInputStream::getPosition() throw (IOException, RuntimeException) +{ + return m_nPos; +} + +sal_Int64 SAL_CALL SequenceInputStream::getLength( ) throw (IOException, RuntimeException) +{ + return m_aData.getLength(); +} + +//-------------------------------------------------------------------------- +OSequenceOutputStream::OSequenceOutputStream(Sequence< sal_Int8 >& _rSeq, double _nResizeFactor, sal_Int32 _nMinimumResize, sal_Int32 _nMaximumResize) + :m_rSequence(_rSeq) + ,m_nResizeFactor(_nResizeFactor) + ,m_nMinimumResize(_nMinimumResize) + ,m_nMaximumResize(_nMaximumResize) + ,m_nSize(0) // starting at position 0 + ,m_bConnected(sal_True) +{ + OSL_ENSURE(m_nResizeFactor > 1, "OSequenceOutputStream::OSequenceOutputStream : invalid resize factor !"); + OSL_ENSURE((m_nMaximumResize < 0) || (m_nMaximumResize > m_nMinimumResize), + "OSequenceOutputStream::OSequenceOutputStream : these limits don't make any sense !"); + + if (m_nResizeFactor <= 1) + m_nResizeFactor = 1.3; + if ((m_nMaximumResize >= 0) && (m_nMaximumResize <= m_nMinimumResize)) + m_nMaximumResize = m_nMinimumResize * 2; + // this heuristic is as good as any other ... supply better parameters if you don't like it :) +} + +//-------------------------------------------------------------------------- +void SAL_CALL OSequenceOutputStream::writeBytes( const Sequence< sal_Int8 >& _rData ) throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + if (!m_bConnected) + throw NotConnectedException(); + + // ensure the sequence has enoungh space left + if (m_nSize + _rData.getLength() > m_rSequence.getLength()) + { + sal_Int32 nCurrentLength = m_rSequence.getLength(); + sal_Int32 nNewLength = static_cast< sal_Int32 >( + nCurrentLength * m_nResizeFactor); + + if (m_nMinimumResize > nNewLength - nCurrentLength) + // we have a minimum so it's not too inefficient for small sequences and small write requests + nNewLength = nCurrentLength + m_nMinimumResize; + + if ((m_nMaximumResize > 0) && (nNewLength - nCurrentLength > m_nMaximumResize)) + // such a large step is not allowed + nNewLength = nCurrentLength + m_nMaximumResize; + + if (nNewLength < m_nSize + _rData.getLength()) + { // it's not enough .... the data would not fit + + // let's take the double amount of the length of the data to be written, as the next write + // request could be as large as this one + sal_Int32 nNewGrowth = _rData.getLength() * 2; + if ((m_nMaximumResize > 0) && (nNewGrowth > m_nMaximumResize)) + { // we came to the limit, again ... + nNewGrowth = m_nMaximumResize; + if (nNewGrowth + nCurrentLength < m_nSize + _rData.getLength()) + // but it would not fit if we respect the limit + nNewGrowth = m_nSize + _rData.getLength() - nCurrentLength; + } + nNewLength = nCurrentLength + nNewGrowth; + } + + // round it off to the next multiple of 4 ... + nNewLength = (nNewLength + 3) / 4 * 4; + + m_rSequence.realloc(nNewLength); + } + + OSL_ENSURE(m_rSequence.getLength() >= m_nSize + _rData.getLength(), + "ooops ... the realloc algorithm seems to be wrong :( !"); + + memcpy(m_rSequence.getArray() + m_nSize, _rData.getConstArray(), _rData.getLength()); + m_nSize += _rData.getLength(); +} + +//-------------------------------------------------------------------------- +void SAL_CALL OSequenceOutputStream::flush( ) throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + if (!m_bConnected) + throw NotConnectedException(); + + // cut the sequence to the real size + m_rSequence.realloc(m_nSize); +} + +//-------------------------------------------------------------------------- +void SAL_CALL OSequenceOutputStream::closeOutput( ) throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + if (!m_bConnected) + throw NotConnectedException(); + + // cut the sequence to the real size + m_rSequence.realloc(m_nSize); + // and don't allow any further accesses + m_bConnected = sal_False; +} + +} // namespace comphelper diff --git a/comphelper/source/streaming/streamsection.cxx b/comphelper/source/streaming/streamsection.cxx new file mode 100644 index 000000000000..324299813986 --- /dev/null +++ b/comphelper/source/streaming/streamsection.cxx @@ -0,0 +1,122 @@ +/************************************************************************* + * + * 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/streamsection.hxx> +#include <osl/diagnose.h> + +namespace comphelper +{ + +//------------------------------------------------------------------------- +OStreamSection::OStreamSection(const staruno::Reference< stario::XDataInputStream >& _rxInput) + :m_xMarkStream(_rxInput, ::com::sun::star::uno::UNO_QUERY) + ,m_xInStream(_rxInput) + ,m_nBlockStart(-1) + ,m_nBlockLen(-1) +{ + OSL_ENSURE(m_xInStream.is() && m_xMarkStream.is(), "OStreamSection::OStreamSection : invalid argument !"); + if (m_xInStream.is() && m_xMarkStream.is()) + { + m_nBlockLen = _rxInput->readLong(); + m_nBlockStart = m_xMarkStream->createMark(); + } +} + +//------------------------------------------------------------------------- +OStreamSection::OStreamSection(const staruno::Reference< stario::XDataOutputStream >& _rxOutput, sal_Int32 _nPresumedLength) + :m_xMarkStream(_rxOutput, ::com::sun::star::uno::UNO_QUERY) + ,m_xOutStream(_rxOutput) + ,m_nBlockStart(-1) + ,m_nBlockLen(-1) +{ + OSL_ENSURE(m_xOutStream.is() && m_xMarkStream.is(), "OStreamSection::OStreamSection : invalid argument !"); + if (m_xOutStream.is() && m_xMarkStream.is()) + { + m_nBlockStart = m_xMarkStream->createMark(); + // a placeholder where we will write the overall length (within the destructor) + if (_nPresumedLength > 0) + m_nBlockLen = _nPresumedLength + sizeof(m_nBlockLen); + // as the caller did not consider - of course - the placeholder we are going to write + else + m_nBlockLen = 0; + m_xOutStream->writeLong(m_nBlockLen); + } +} + +//------------------------------------------------------------------------- +OStreamSection::~OStreamSection() +{ + try + { // don't allow any exceptions to leave this block, this may be called during the stack unwinding of an exception + // handling routing + if (m_xInStream.is() && m_xMarkStream.is()) + { // we're working on an input stream + m_xMarkStream->jumpToMark(m_nBlockStart); + m_xInStream->skipBytes(m_nBlockLen); + m_xMarkStream->deleteMark(m_nBlockStart); + } + else if (m_xOutStream.is() && m_xMarkStream.is()) + { + sal_Int32 nRealBlockLength = m_xMarkStream->offsetToMark(m_nBlockStart) - sizeof(m_nBlockLen); + if (m_nBlockLen && (m_nBlockLen == nRealBlockLength)) + // nothing to do : the estimation the caller gave us (in the ctor) was correct + m_xMarkStream->deleteMark(m_nBlockStart); + else + { // the estimation was wrong (or we didn't get one) + m_nBlockLen = nRealBlockLength; + m_xMarkStream->jumpToMark(m_nBlockStart); + m_xOutStream->writeLong(m_nBlockLen); + m_xMarkStream->jumpToFurthest(); + m_xMarkStream->deleteMark(m_nBlockStart); + } + } + } + catch(const staruno::Exception&) + { + } +} +// ----------------------------------------------------------------------------- +sal_Int32 OStreamSection::available() +{ + sal_Int32 nBytes = 0; + try + { // don't allow any exceptions to leave this block, this may be called during the stack unwinding of an exception + if (m_xInStream.is() && m_xMarkStream.is()) + nBytes = m_xMarkStream->offsetToMark(m_nBlockStart) - sizeof(m_nBlockLen); + } + catch(const staruno::Exception&) + { + } + return nBytes; +} +// ----------------------------------------------------------------------------- + +} // namespace comphelper + + diff --git a/comphelper/source/xml/attributelist.cxx b/comphelper/source/xml/attributelist.cxx new file mode 100644 index 000000000000..bcf32b85011f --- /dev/null +++ b/comphelper/source/xml/attributelist.cxx @@ -0,0 +1,179 @@ +/************************************************************************* + * + * 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/attributelist.hxx> +#include <vos/diagnose.hxx> + +#include <vector> + +using namespace rtl; +using namespace osl; +using namespace com::sun::star; + +namespace comphelper { + +struct TagAttribute_Impl +{ + TagAttribute_Impl(){} + TagAttribute_Impl( const OUString &aName, const OUString &aType, + const OUString &aValue ) + { + this->sName = aName; + this->sType = aType; + this->sValue = aValue; + } + + OUString sName; + OUString sType; + OUString sValue; +}; + +struct AttributeList_Impl +{ + AttributeList_Impl() + { + // performance improvement during adding + vecAttribute.reserve(20); + } + ::std::vector<struct TagAttribute_Impl> vecAttribute; +}; + +sal_Int16 SAL_CALL AttributeList::getLength(void) throw( ::com::sun::star::uno::RuntimeException ) +{ + return (sal_Int16)(m_pImpl->vecAttribute.size()); +} + +OUString SAL_CALL AttributeList::getNameByIndex(sal_Int16 i) throw( ::com::sun::star::uno::RuntimeException ) +{ + return ( i < static_cast < sal_Int16 > (m_pImpl->vecAttribute.size()) ) ? m_pImpl->vecAttribute[i].sName : OUString(); +} + +OUString SAL_CALL AttributeList::getTypeByIndex(sal_Int16 i) throw( ::com::sun::star::uno::RuntimeException ) +{ + if( i < static_cast < sal_Int16 > (m_pImpl->vecAttribute.size() ) ) { + return m_pImpl->vecAttribute[i].sType; + } + return OUString(); +} + +OUString SAL_CALL AttributeList::getValueByIndex(sal_Int16 i) throw( ::com::sun::star::uno::RuntimeException ) +{ + return ( i < static_cast < sal_Int16 > (m_pImpl->vecAttribute.size() ) ) ? m_pImpl->vecAttribute[i].sValue : OUString(); +} + +OUString SAL_CALL AttributeList::getTypeByName( const OUString& sName ) throw( ::com::sun::star::uno::RuntimeException ) +{ + ::std::vector<struct TagAttribute_Impl>::iterator ii = m_pImpl->vecAttribute.begin(); + + for( ; ii != m_pImpl->vecAttribute.end() ; ii ++ ) { + if( (*ii).sName == sName ) { + return (*ii).sType; + } + } + return OUString(); +} + +OUString SAL_CALL AttributeList::getValueByName(const OUString& sName) throw( ::com::sun::star::uno::RuntimeException ) +{ + ::std::vector<struct TagAttribute_Impl>::iterator ii = m_pImpl->vecAttribute.begin(); + + for( ; ii != m_pImpl->vecAttribute.end() ; ii ++ ) { + if( (*ii).sName == sName ) { + return (*ii).sValue; + } + } + return OUString(); +} + + +AttributeList::AttributeList() +{ + m_pImpl = new AttributeList_Impl; +} + + + +AttributeList::~AttributeList() +{ + delete m_pImpl; +} + +void AttributeList::AddAttribute( const OUString &sName , + const OUString &sType , + const OUString &sValue ) +{ + m_pImpl->vecAttribute.push_back( TagAttribute_Impl( sName , sType , sValue ) ); +} + +void AttributeList::Clear() +{ + m_pImpl->vecAttribute.clear(); + + VOS_ENSURE( ! getLength(), "Length > 0 after AttributeList::Clear!"); +} + +void AttributeList::RemoveAttribute( const OUString sName ) +{ + ::std::vector<struct TagAttribute_Impl>::iterator ii = m_pImpl->vecAttribute.begin(); + + for( ; ii != m_pImpl->vecAttribute.end() ; ii ++ ) { + if( (*ii).sName == sName ) { + m_pImpl->vecAttribute.erase( ii ); + break; + } + } +} + + +void AttributeList::SetAttributeList( const uno::Reference< ::com::sun::star::xml::sax::XAttributeList > &r ) +{ + Clear(); + AppendAttributeList( r ); +} + +void AttributeList::AppendAttributeList( const uno::Reference< ::com::sun::star::xml::sax::XAttributeList > &r ) +{ + VOS_ENSURE( r.is(), "r isn't!" ); + + sal_Int32 nMax = r->getLength(); + sal_Int32 nTotalSize = m_pImpl->vecAttribute.size() + nMax; + m_pImpl->vecAttribute.reserve( nTotalSize ); + + for( sal_Int16 i = 0 ; i < nMax ; i ++ ) { + m_pImpl->vecAttribute.push_back( TagAttribute_Impl( + r->getNameByIndex( i ) , + r->getTypeByIndex( i ) , + r->getValueByIndex( i ))); + } + + VOS_ENSURE( nTotalSize == getLength(), "nTotalSize != getLength()"); +} + +} // namespace comphelper + diff --git a/comphelper/source/xml/makefile.mk b/comphelper/source/xml/makefile.mk new file mode 100644 index 000000000000..8fa34b2477a2 --- /dev/null +++ b/comphelper/source/xml/makefile.mk @@ -0,0 +1,48 @@ +#************************************************************************* +# +# 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=..$/.. +PRJNAME=comphelper +TARGET=xml + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES= \ + $(SLO)$/ofopxmlhelper.obj \ + $(SLO)$/attributelist.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/comphelper/source/xml/ofopxmlhelper.cxx b/comphelper/source/xml/ofopxmlhelper.cxx new file mode 100644 index 000000000000..9ad617b0e6d1 --- /dev/null +++ b/comphelper/source/xml/ofopxmlhelper.cxx @@ -0,0 +1,467 @@ +/************************************************************************* + * + * 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 _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_ +#include <com/sun/star/beans/StringPair.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#endif +#ifndef _COM_SUN_STAR_IO_XACTIVEDATASOURCE_HPP +#include <com/sun/star/io/XActiveDataSource.hpp> +#endif +#ifndef _COM_SUN_STAR_XML_SAX_XPARSER_HPP +#include <com/sun/star/xml/sax/XParser.hpp> +#endif +#ifndef _COM_SUN_STAR_XML_SAX_XDOCUMENTHANDLER_HPP +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_ILLEGALARGUMENTEXCEPTION_HPP +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#endif + +#include <comphelper/ofopxmlhelper.hxx> +#include <comphelper/attributelist.hxx> + +#define RELATIONINFO_FORMAT 0 +#define CONTENTTYPE_FORMAT 1 +#define FORMAT_MAX_ID CONTENTTYPE_FORMAT + +using namespace ::com::sun::star; + +namespace comphelper { + +// ----------------------------------- +uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OFOPXMLHelper::ReadRelationsInfoSequence( const uno::Reference< io::XInputStream >& xInStream, const ::rtl::OUString aStreamName, const uno::Reference< lang::XMultiServiceFactory > xFactory ) + throw( uno::Exception ) +{ + ::rtl::OUString aStringID = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels/" ) ); + aStringID += aStreamName; + return ReadSequence_Impl( xInStream, aStringID, RELATIONINFO_FORMAT, xFactory ); +} + +// ----------------------------------- +uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OFOPXMLHelper::ReadContentTypeSequence( const uno::Reference< io::XInputStream >& xInStream, const uno::Reference< lang::XMultiServiceFactory > xFactory ) + throw( uno::Exception ) +{ + ::rtl::OUString aStringID = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "[Content_Types].xml" ) ); + return ReadSequence_Impl( xInStream, aStringID, CONTENTTYPE_FORMAT, xFactory ); +} + +// ----------------------------------- +void SAL_CALL OFOPXMLHelper::WriteRelationsInfoSequence( const uno::Reference< io::XOutputStream >& xOutStream, const uno::Sequence< uno::Sequence< beans::StringPair > >& aSequence, const uno::Reference< lang::XMultiServiceFactory > xFactory ) + throw( uno::Exception ) +{ + if ( !xOutStream.is() ) + throw uno::RuntimeException(); + + uno::Reference< io::XActiveDataSource > xWriterSource( + xFactory->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.sax.Writer" ) ) ), + uno::UNO_QUERY_THROW ); + uno::Reference< xml::sax::XDocumentHandler > xWriterHandler( xWriterSource, uno::UNO_QUERY_THROW ); + + xWriterSource->setOutputStream( xOutStream ); + + ::rtl::OUString aRelListElement( RTL_CONSTASCII_USTRINGPARAM( "Relationships" ) ); + ::rtl::OUString aRelElement( RTL_CONSTASCII_USTRINGPARAM( "Relationship" ) ); + ::rtl::OUString aIDAttr( RTL_CONSTASCII_USTRINGPARAM( "Id" ) ); + ::rtl::OUString aTypeAttr( RTL_CONSTASCII_USTRINGPARAM( "Type" ) ); + ::rtl::OUString aTargetModeAttr( RTL_CONSTASCII_USTRINGPARAM( "TargetMode" ) ); + ::rtl::OUString aTargetAttr( RTL_CONSTASCII_USTRINGPARAM( "Target" ) ); + ::rtl::OUString aCDATAString( RTL_CONSTASCII_USTRINGPARAM ( "CDATA" ) ); + ::rtl::OUString aWhiteSpace( RTL_CONSTASCII_USTRINGPARAM ( " " ) ); + + // write the namespace + AttributeList* pRootAttrList = new AttributeList; + uno::Reference< xml::sax::XAttributeList > xRootAttrList( pRootAttrList ); + pRootAttrList->AddAttribute( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "xmlns" ) ), + aCDATAString, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "http://schemas.openxmlformats.org/package/2006/relationships" ) ) ); + + xWriterHandler->startDocument(); + xWriterHandler->startElement( aRelListElement, xRootAttrList ); + + for ( sal_Int32 nInd = 0; nInd < aSequence.getLength(); nInd++ ) + { + AttributeList *pAttrList = new AttributeList; + uno::Reference< xml::sax::XAttributeList > xAttrList( pAttrList ); + for( sal_Int32 nSecInd = 0; nSecInd < aSequence[nInd].getLength(); nSecInd++ ) + { + if ( aSequence[nInd][nSecInd].First.equals( aIDAttr ) + || aSequence[nInd][nSecInd].First.equals( aTypeAttr ) + || aSequence[nInd][nSecInd].First.equals( aTargetModeAttr ) + || aSequence[nInd][nSecInd].First.equals( aTargetAttr ) ) + { + pAttrList->AddAttribute( aSequence[nInd][nSecInd].First, aCDATAString, aSequence[nInd][nSecInd].Second ); + } + else + { + // TODO/LATER: should the extensions be allowed? + throw lang::IllegalArgumentException(); + } + } + + xWriterHandler->startElement( aRelElement, xAttrList ); + xWriterHandler->ignorableWhitespace( aWhiteSpace ); + xWriterHandler->endElement( aRelElement ); + } + + xWriterHandler->ignorableWhitespace( aWhiteSpace ); + xWriterHandler->endElement( aRelListElement ); + xWriterHandler->endDocument(); +} + +// ----------------------------------- +void SAL_CALL OFOPXMLHelper::WriteContentSequence( const uno::Reference< io::XOutputStream >& xOutStream, const uno::Sequence< beans::StringPair >& aDefaultsSequence, const uno::Sequence< beans::StringPair >& aOverridesSequence, const uno::Reference< lang::XMultiServiceFactory > xFactory ) + throw( uno::Exception ) +{ + if ( !xOutStream.is() ) + throw uno::RuntimeException(); + + uno::Reference< io::XActiveDataSource > xWriterSource( + xFactory->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.sax.Writer" ) ) ), + uno::UNO_QUERY_THROW ); + uno::Reference< xml::sax::XDocumentHandler > xWriterHandler( xWriterSource, uno::UNO_QUERY_THROW ); + + xWriterSource->setOutputStream( xOutStream ); + + ::rtl::OUString aTypesElement( RTL_CONSTASCII_USTRINGPARAM( "Types" ) ); + ::rtl::OUString aDefaultElement( RTL_CONSTASCII_USTRINGPARAM( "Default" ) ); + ::rtl::OUString aOverrideElement( RTL_CONSTASCII_USTRINGPARAM( "Override" ) ); + ::rtl::OUString aExtensionAttr( RTL_CONSTASCII_USTRINGPARAM( "Extension" ) ); + ::rtl::OUString aPartNameAttr( RTL_CONSTASCII_USTRINGPARAM( "PartName" ) ); + ::rtl::OUString aContentTypeAttr( RTL_CONSTASCII_USTRINGPARAM( "ContentType" ) ); + ::rtl::OUString aCDATAString( RTL_CONSTASCII_USTRINGPARAM ( "CDATA" ) ); + ::rtl::OUString aWhiteSpace( RTL_CONSTASCII_USTRINGPARAM ( " " ) ); + + // write the namespace + AttributeList* pRootAttrList = new AttributeList; + uno::Reference< xml::sax::XAttributeList > xRootAttrList( pRootAttrList ); + pRootAttrList->AddAttribute( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "xmlns" ) ), + aCDATAString, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "http://schemas.openxmlformats.org/package/2006/content-types" ) ) ); + + xWriterHandler->startDocument(); + xWriterHandler->startElement( aTypesElement, xRootAttrList ); + + for ( sal_Int32 nInd = 0; nInd < aDefaultsSequence.getLength(); nInd++ ) + { + AttributeList *pAttrList = new AttributeList; + uno::Reference< xml::sax::XAttributeList > xAttrList( pAttrList ); + pAttrList->AddAttribute( aExtensionAttr, aCDATAString, aDefaultsSequence[nInd].First ); + pAttrList->AddAttribute( aContentTypeAttr, aCDATAString, aDefaultsSequence[nInd].Second ); + + xWriterHandler->startElement( aDefaultElement, xAttrList ); + xWriterHandler->ignorableWhitespace( aWhiteSpace ); + xWriterHandler->endElement( aDefaultElement ); + } + + for ( sal_Int32 nInd = 0; nInd < aOverridesSequence.getLength(); nInd++ ) + { + AttributeList *pAttrList = new AttributeList; + uno::Reference< xml::sax::XAttributeList > xAttrList( pAttrList ); + pAttrList->AddAttribute( aPartNameAttr, aCDATAString, aOverridesSequence[nInd].First ); + pAttrList->AddAttribute( aContentTypeAttr, aCDATAString, aOverridesSequence[nInd].Second ); + + xWriterHandler->startElement( aOverrideElement, xAttrList ); + xWriterHandler->ignorableWhitespace( aWhiteSpace ); + xWriterHandler->endElement( aOverrideElement ); + } + + xWriterHandler->ignorableWhitespace( aWhiteSpace ); + xWriterHandler->endElement( aTypesElement ); + xWriterHandler->endDocument(); + +} + +// ================================================================================== + +// ----------------------------------- +uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OFOPXMLHelper::ReadSequence_Impl( const uno::Reference< io::XInputStream >& xInStream, const ::rtl::OUString& aStringID, sal_uInt16 nFormat, const uno::Reference< lang::XMultiServiceFactory > xFactory ) + throw( uno::Exception ) +{ + if ( !xFactory.is() || !xInStream.is() || nFormat > FORMAT_MAX_ID ) + throw uno::RuntimeException(); + + uno::Sequence< uno::Sequence< beans::StringPair > > aResult; + + uno::Reference< xml::sax::XParser > xParser( xFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.sax.Parser" ) ) ), uno::UNO_QUERY_THROW ); + + OFOPXMLHelper* pHelper = new OFOPXMLHelper( nFormat ); + uno::Reference< xml::sax::XDocumentHandler > xHelper( static_cast< xml::sax::XDocumentHandler* >( pHelper ) ); + xml::sax::InputSource aParserInput; + aParserInput.aInputStream = xInStream; + aParserInput.sSystemId = aStringID; + xParser->setDocumentHandler( xHelper ); + xParser->parseStream( aParserInput ); + xParser->setDocumentHandler( uno::Reference < xml::sax::XDocumentHandler > () ); + + return pHelper->GetParsingResult(); +} + +// ----------------------------------- +OFOPXMLHelper::OFOPXMLHelper( sal_uInt16 nFormat ) +: m_nFormat( nFormat ) +, m_aRelListElement( RTL_CONSTASCII_USTRINGPARAM( "Relationships" ) ) +, m_aRelElement( RTL_CONSTASCII_USTRINGPARAM( "Relationship" ) ) +, m_aIDAttr( RTL_CONSTASCII_USTRINGPARAM( "Id" ) ) +, m_aTypeAttr( RTL_CONSTASCII_USTRINGPARAM( "Type" ) ) +, m_aTargetModeAttr( RTL_CONSTASCII_USTRINGPARAM( "TargetMode" ) ) +, m_aTargetAttr( RTL_CONSTASCII_USTRINGPARAM( "Target" ) ) +, m_aTypesElement( RTL_CONSTASCII_USTRINGPARAM( "Types" ) ) +, m_aDefaultElement( RTL_CONSTASCII_USTRINGPARAM( "Default" ) ) +, m_aOverrideElement( RTL_CONSTASCII_USTRINGPARAM( "Override" ) ) +, m_aExtensionAttr( RTL_CONSTASCII_USTRINGPARAM( "Extension" ) ) +, m_aPartNameAttr( RTL_CONSTASCII_USTRINGPARAM( "PartName" ) ) +, m_aContentTypeAttr( RTL_CONSTASCII_USTRINGPARAM( "ContentType" ) ) +{ +} + +// ----------------------------------- +OFOPXMLHelper::~OFOPXMLHelper() +{ +} + +// ----------------------------------- +uno::Sequence< uno::Sequence< beans::StringPair > > OFOPXMLHelper::GetParsingResult() +{ + if ( m_aElementsSeq.getLength() ) + throw uno::RuntimeException(); // the parsing has still not finished! + + return m_aResultSeq; +} + +// ----------------------------------- +void SAL_CALL OFOPXMLHelper::startDocument() + throw(xml::sax::SAXException, uno::RuntimeException) +{ +} + +// ----------------------------------- +void SAL_CALL OFOPXMLHelper::endDocument() + throw(xml::sax::SAXException, uno::RuntimeException) +{ +} + +// ----------------------------------- +void SAL_CALL OFOPXMLHelper::startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) + throw( xml::sax::SAXException, uno::RuntimeException ) +{ + if ( m_nFormat == RELATIONINFO_FORMAT ) + { + if ( aName == m_aRelListElement ) + { + sal_Int32 nNewLength = m_aElementsSeq.getLength() + 1; + + if ( nNewLength != 1 ) + throw xml::sax::SAXException(); // TODO: this element must be the first level element + + m_aElementsSeq.realloc( nNewLength ); + m_aElementsSeq[nNewLength-1] = aName; + + return; // nothing to do + } + else if ( aName == m_aRelElement ) + { + sal_Int32 nNewLength = m_aElementsSeq.getLength() + 1; + if ( nNewLength != 2 ) + throw xml::sax::SAXException(); // TODO: this element must be the second level element + + m_aElementsSeq.realloc( nNewLength ); + m_aElementsSeq[nNewLength-1] = aName; + + sal_Int32 nNewEntryNum = m_aResultSeq.getLength() + 1; + m_aResultSeq.realloc( nNewEntryNum ); + sal_Int32 nAttrNum = 0; + m_aResultSeq[nNewEntryNum-1].realloc( 4 ); // the maximal expected number of arguments is 4 + + ::rtl::OUString aIDValue = xAttribs->getValueByName( m_aIDAttr ); + if ( !aIDValue.getLength() ) + throw xml::sax::SAXException(); // TODO: the ID value must present + + ::rtl::OUString aTypeValue = xAttribs->getValueByName( m_aTypeAttr ); + ::rtl::OUString aTargetValue = xAttribs->getValueByName( m_aTargetAttr ); + ::rtl::OUString aTargetModeValue = xAttribs->getValueByName( m_aTargetModeAttr ); + + m_aResultSeq[nNewEntryNum-1][++nAttrNum - 1].First = m_aIDAttr; + m_aResultSeq[nNewEntryNum-1][nAttrNum - 1].Second = aIDValue; + + if ( aTypeValue.getLength() ) + { + m_aResultSeq[nNewEntryNum-1][++nAttrNum - 1].First = m_aTypeAttr; + m_aResultSeq[nNewEntryNum-1][nAttrNum - 1].Second = aTypeValue; + } + + if ( aTargetValue.getLength() ) + { + m_aResultSeq[nNewEntryNum-1][++nAttrNum - 1].First = m_aTargetAttr; + m_aResultSeq[nNewEntryNum-1][nAttrNum - 1].Second = aTargetValue; + } + + if ( aTargetModeValue.getLength() ) + { + m_aResultSeq[nNewEntryNum-1][++nAttrNum - 1].First = m_aTargetModeAttr; + m_aResultSeq[nNewEntryNum-1][nAttrNum - 1].Second = aTargetModeValue; + } + + m_aResultSeq[nNewEntryNum-1].realloc( nAttrNum ); + } + else + throw xml::sax::SAXException(); // TODO: no other elements expected! + } + else if ( m_nFormat == CONTENTTYPE_FORMAT ) + { + if ( aName == m_aTypesElement ) + { + sal_Int32 nNewLength = m_aElementsSeq.getLength() + 1; + + if ( nNewLength != 1 ) + throw xml::sax::SAXException(); // TODO: this element must be the first level element + + m_aElementsSeq.realloc( nNewLength ); + m_aElementsSeq[nNewLength-1] = aName; + + if ( !m_aResultSeq.getLength() ) + m_aResultSeq.realloc( 2 ); + + return; // nothing to do + } + else if ( aName == m_aDefaultElement ) + { + sal_Int32 nNewLength = m_aElementsSeq.getLength() + 1; + if ( nNewLength != 2 ) + throw xml::sax::SAXException(); // TODO: this element must be the second level element + + m_aElementsSeq.realloc( nNewLength ); + m_aElementsSeq[nNewLength-1] = aName; + + if ( !m_aResultSeq.getLength() ) + m_aResultSeq.realloc( 2 ); + + if ( m_aResultSeq.getLength() != 2 ) + throw uno::RuntimeException(); + + ::rtl::OUString aExtensionValue = xAttribs->getValueByName( m_aExtensionAttr ); + if ( !aExtensionValue.getLength() ) + throw xml::sax::SAXException(); // TODO: the Extension value must present + + ::rtl::OUString aContentTypeValue = xAttribs->getValueByName( m_aContentTypeAttr ); + if ( !aContentTypeValue.getLength() ) + throw xml::sax::SAXException(); // TODO: the ContentType value must present + + sal_Int32 nNewResultLen = m_aResultSeq[0].getLength() + 1; + m_aResultSeq[0].realloc( nNewResultLen ); + + m_aResultSeq[0][nNewResultLen-1].First = aExtensionValue; + m_aResultSeq[0][nNewResultLen-1].Second = aContentTypeValue; + } + else if ( aName == m_aOverrideElement ) + { + sal_Int32 nNewLength = m_aElementsSeq.getLength() + 1; + if ( nNewLength != 2 ) + throw xml::sax::SAXException(); // TODO: this element must be the second level element + + m_aElementsSeq.realloc( nNewLength ); + m_aElementsSeq[nNewLength-1] = aName; + + if ( !m_aResultSeq.getLength() ) + m_aResultSeq.realloc( 2 ); + + if ( m_aResultSeq.getLength() != 2 ) + throw uno::RuntimeException(); + + ::rtl::OUString aPartNameValue = xAttribs->getValueByName( m_aPartNameAttr ); + if ( !aPartNameValue.getLength() ) + throw xml::sax::SAXException(); // TODO: the PartName value must present + + ::rtl::OUString aContentTypeValue = xAttribs->getValueByName( m_aContentTypeAttr ); + if ( !aContentTypeValue.getLength() ) + throw xml::sax::SAXException(); // TODO: the ContentType value must present + + sal_Int32 nNewResultLen = m_aResultSeq[1].getLength() + 1; + m_aResultSeq[1].realloc( nNewResultLen ); + + m_aResultSeq[1][nNewResultLen-1].First = aPartNameValue; + m_aResultSeq[1][nNewResultLen-1].Second = aContentTypeValue; + } + else + throw xml::sax::SAXException(); // TODO: no other elements expected! + } + else + throw xml::sax::SAXException(); // TODO: no other elements expected! +} + +// ----------------------------------- +void SAL_CALL OFOPXMLHelper::endElement( const ::rtl::OUString& aName ) + throw( xml::sax::SAXException, uno::RuntimeException ) +{ + if ( m_nFormat == RELATIONINFO_FORMAT || m_nFormat == CONTENTTYPE_FORMAT ) + { + sal_Int32 nLength = m_aElementsSeq.getLength(); + if ( nLength <= 0 ) + throw xml::sax::SAXException(); // TODO: no other end elements expected! + + if ( !m_aElementsSeq[nLength-1].equals( aName ) ) + throw xml::sax::SAXException(); // TODO: unexpected element ended + + m_aElementsSeq.realloc( nLength - 1 ); + } +} + +// ----------------------------------- +void SAL_CALL OFOPXMLHelper::characters( const ::rtl::OUString& /*aChars*/ ) + throw(xml::sax::SAXException, uno::RuntimeException) +{ +} + +// ----------------------------------- +void SAL_CALL OFOPXMLHelper::ignorableWhitespace( const ::rtl::OUString& /*aWhitespaces*/ ) + throw(xml::sax::SAXException, uno::RuntimeException) +{ +} + +// ----------------------------------- +void SAL_CALL OFOPXMLHelper::processingInstruction( const ::rtl::OUString& /*aTarget*/, const ::rtl::OUString& /*aData*/ ) + throw(xml::sax::SAXException, uno::RuntimeException) +{ +} + +// ----------------------------------- +void SAL_CALL OFOPXMLHelper::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& /*xLocator*/ ) + throw(xml::sax::SAXException, uno::RuntimeException) +{ +} + +} // namespace comphelper + |