diff options
Diffstat (limited to 'dbaccess/source/core/dataaccess')
42 files changed, 18529 insertions, 0 deletions
diff --git a/dbaccess/source/core/dataaccess/ComponentDefinition.cxx b/dbaccess/source/core/dataaccess/ComponentDefinition.cxx new file mode 100644 index 000000000000..df7a85434a91 --- /dev/null +++ b/dbaccess/source/core/dataaccess/ComponentDefinition.cxx @@ -0,0 +1,301 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +#include "ComponentDefinition.hxx" +#include "apitools.hxx" +#include "dbastrings.hrc" +#include "module_dba.hxx" + +#include <tools/debug.hxx> +#include <comphelper/sequence.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <comphelper/property.hxx> +#include "definitioncolumn.hxx" +#include <cppuhelper/implbase1.hxx> +#include <comphelper/componentcontext.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::lang; + +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::osl; +using namespace ::comphelper; +using namespace ::cppu; + +extern "C" void SAL_CALL createRegistryInfo_OComponentDefinition() +{ + static ::dba::OAutoRegistration< ::dbaccess::OComponentDefinition > aAutoRegistration; +} + +namespace dbaccess +{ + +/// helper class for column property change events which holds the OComponentDefinition weak +typedef ::cppu::WeakImplHelper1 < XPropertyChangeListener > TColumnPropertyListener_BASE; +class OColumnPropertyListener : public TColumnPropertyListener_BASE +{ + OComponentDefinition* m_pComponent; + + OColumnPropertyListener(const OColumnPropertyListener&); + void operator =(const OColumnPropertyListener&); +protected: + virtual ~OColumnPropertyListener(){} +public: + OColumnPropertyListener(OComponentDefinition* _pComponent) : m_pComponent(_pComponent){} + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const PropertyChangeEvent& /*_rEvent*/ ) throw (RuntimeException) + { + if ( m_pComponent ) + m_pComponent->notifyDataSourceModified(); + } + // XEventListener + virtual void SAL_CALL disposing( const EventObject& /*_rSource*/ ) throw (RuntimeException) + { + } + void clear() { m_pComponent = NULL; } +}; +DBG_NAME(OComponentDefinition_Impl) +OComponentDefinition_Impl::OComponentDefinition_Impl() +{ + DBG_CTOR(OComponentDefinition_Impl,NULL); +} + +OComponentDefinition_Impl::~OComponentDefinition_Impl() +{ + DBG_DTOR(OComponentDefinition_Impl,NULL); +} +//========================================================================== +//= OComponentDefinition +//========================================================================== + +DBG_NAME(OComponentDefinition) + +void OComponentDefinition::registerProperties() +{ + m_xColumnPropertyListener = ::comphelper::ImplementationReference<OColumnPropertyListener,XPropertyChangeListener>(new OColumnPropertyListener(this)); + OComponentDefinition_Impl& rDefinition( getDefinition() ); + ODataSettings::registerPropertiesFor( &rDefinition ); + + registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::BOUND | PropertyAttribute::READONLY|PropertyAttribute::CONSTRAINED, + &rDefinition.m_aProps.aTitle, ::getCppuType(&rDefinition.m_aProps.aTitle)); + + if ( m_bTable ) + { + registerProperty(PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, PropertyAttribute::BOUND, + &rDefinition.m_sSchemaName, ::getCppuType(&rDefinition.m_sSchemaName)); + + registerProperty(PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, PropertyAttribute::BOUND, + &rDefinition.m_sCatalogName, ::getCppuType(&rDefinition.m_sCatalogName)); + } +} + +OComponentDefinition::OComponentDefinition(const Reference< XMultiServiceFactory >& _xORB + ,const Reference< XInterface >& _xParentContainer + ,const TContentPtr& _pImpl + ,sal_Bool _bTable) + :OContentHelper(_xORB,_xParentContainer,_pImpl) + ,ODataSettings(OContentHelper::rBHelper,!_bTable) + ,m_bTable(_bTable) +{ + DBG_CTOR(OComponentDefinition, NULL); + registerProperties(); +} + +OComponentDefinition::~OComponentDefinition() +{ + DBG_DTOR(OComponentDefinition, NULL); +} + + +OComponentDefinition::OComponentDefinition( const Reference< XInterface >& _rxContainer + ,const ::rtl::OUString& _rElementName + ,const Reference< XMultiServiceFactory >& _xORB + ,const TContentPtr& _pImpl + ,sal_Bool _bTable) + :OContentHelper(_xORB,_rxContainer,_pImpl) + ,ODataSettings(OContentHelper::rBHelper,!_bTable) + ,m_bTable(_bTable) +{ + DBG_CTOR(OComponentDefinition, NULL); + registerProperties(); + + m_pImpl->m_aProps.aTitle = _rElementName; + DBG_ASSERT(m_pImpl->m_aProps.aTitle.getLength() != 0, "OComponentDefinition::OComponentDefinition : invalid name !"); +} + +IMPLEMENT_IMPLEMENTATION_ID(OComponentDefinition); +IMPLEMENT_GETTYPES3(OComponentDefinition,ODataSettings,OContentHelper,OComponentDefinition_BASE); +IMPLEMENT_FORWARD_XINTERFACE3( OComponentDefinition,OContentHelper,ODataSettings,OComponentDefinition_BASE) + +::rtl::OUString OComponentDefinition::getImplementationName_static( ) throw(RuntimeException) +{ + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.dba.OComponentDefinition")); +} + +::rtl::OUString SAL_CALL OComponentDefinition::getImplementationName( ) throw(RuntimeException) +{ + return getImplementationName_static(); +} + +Sequence< ::rtl::OUString > OComponentDefinition::getSupportedServiceNames_static( ) throw(RuntimeException) +{ + Sequence< ::rtl::OUString > aServices(2); + aServices.getArray()[0] = SERVICE_SDB_TABLEDEFINITION; + aServices.getArray()[1] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.Content")); + + return aServices; +} + +Sequence< ::rtl::OUString > SAL_CALL OComponentDefinition::getSupportedServiceNames( ) throw(RuntimeException) +{ + return getSupportedServiceNames_static(); +} + +Reference< XInterface > OComponentDefinition::Create( const Reference< XComponentContext >& _rxContext ) +{ + ::comphelper::ComponentContext aContext( _rxContext ); + return *(new OComponentDefinition( aContext.getLegacyServiceFactory(), NULL, TContentPtr( new OComponentDefinition_Impl ) ) ); +} + +void SAL_CALL OComponentDefinition::disposing() +{ + OContentHelper::disposing(); + if ( m_pColumns.get() ) + m_pColumns->disposing(); + m_xColumnPropertyListener->clear(); + m_xColumnPropertyListener.dispose(); +} + +IPropertyArrayHelper& OComponentDefinition::getInfoHelper() +{ + return *getArrayHelper(); +} + +IPropertyArrayHelper* OComponentDefinition::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new OPropertyArrayHelper(aProps); +} + +Reference< XPropertySetInfo > SAL_CALL OComponentDefinition::getPropertySetInfo( ) throw(RuntimeException) +{ + Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +::rtl::OUString OComponentDefinition::determineContentType() const +{ + return m_bTable + ? ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.org.openoffice.DatabaseTable" ) ) + : ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.org.openoffice.DatabaseCommandDefinition" ) ); +} + +Reference< XNameAccess> OComponentDefinition::getColumns() throw (RuntimeException) +{ + ::osl::MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OContentHelper::rBHelper.bDisposed); + + if ( !m_pColumns.get() ) + { + ::std::vector< ::rtl::OUString> aNames; + + const OComponentDefinition_Impl& rDefinition( getDefinition() ); + aNames.reserve( rDefinition.size() ); + + OComponentDefinition_Impl::const_iterator aIter = rDefinition.begin(); + OComponentDefinition_Impl::const_iterator aEnd = rDefinition.end(); + for ( ; aIter != aEnd; ++aIter ) + aNames.push_back( aIter->first ); + + m_pColumns.reset( new OColumns( *this, m_aMutex, sal_True, aNames, this, NULL, sal_True, sal_False, sal_False ) ); + m_pColumns->setParent( *this ); + } + return m_pColumns.get(); +} + +OColumn* OComponentDefinition::createColumn(const ::rtl::OUString& _rName) const +{ + const OComponentDefinition_Impl& rDefinition( getDefinition() ); + OComponentDefinition_Impl::const_iterator aFind = rDefinition.find( _rName ); + if ( aFind != rDefinition.end() ) + { + aFind->second->addPropertyChangeListener(::rtl::OUString(),m_xColumnPropertyListener.getRef()); + return new OTableColumnWrapper( aFind->second, aFind->second, true ); + } + OSL_ENSURE( false, "OComponentDefinition::createColumn: is this a valid case?" ); + // This here is the last place creating a OTableColumn, and somehow /me thinks it is not needed ... + return new OTableColumn( _rName ); +} + +Reference< XPropertySet > OComponentDefinition::createColumnDescriptor() +{ + return new OTableColumnDescriptor( true ); +} + +void OComponentDefinition::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) throw (Exception) +{ + ODataSettings::setFastPropertyValue_NoBroadcast(nHandle,rValue); + notifyDataSourceModified(); +} + +void OComponentDefinition::columnDropped(const ::rtl::OUString& _sName) +{ + getDefinition().erase( _sName ); + notifyDataSourceModified(); +} + +void OComponentDefinition::columnAppended( const Reference< XPropertySet >& _rxSourceDescriptor ) +{ + ::rtl::OUString sName; + _rxSourceDescriptor->getPropertyValue( PROPERTY_NAME ) >>= sName; + + Reference<XPropertySet> xColDesc = new OTableColumnDescriptor( true ); + ::comphelper::copyProperties( _rxSourceDescriptor, xColDesc ); + getDefinition().insert( sName, xColDesc ); + + // formerly, here was a setParent at the xColDesc. The parent used was an adapter (ChildHelper_Impl) + // which held another XChild weak, and forwarded all getParent requests to this other XChild. + // m_pColumns was used for this. This was nonsense, since m_pColumns dies when our instance dies, + // but xColDesc will live longer than this. So effectively, the setParent call was pretty useless. + // + // The intention for this parenting was that the column descriptor is able to find the data source, + // by traveling up the parent hierachy until there's an XDataSource. This didn't work (which + // for instance causes #i65023#). We need another way to properly ensure this. + + notifyDataSourceModified(); +} + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/ComponentDefinition.hxx b/dbaccess/source/core/dataaccess/ComponentDefinition.hxx new file mode 100644 index 000000000000..6da15cd19fbb --- /dev/null +++ b/dbaccess/source/core/dataaccess/ComponentDefinition.hxx @@ -0,0 +1,184 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 DBA_COREDATAACESS_COMPONENTDEFINITION_HXX +#define DBA_COREDATAACESS_COMPONENTDEFINITION_HXX + +#include "commandbase.hxx" +#include <comphelper/propertycontainer.hxx> +#include <com/sun/star/sdbcx/XRename.hpp> +#include <cppuhelper/implbase1.hxx> +#include <comphelper/proparrhlp.hxx> +#include "datasettings.hxx" +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include "ContentHelper.hxx" +#include "apitools.hxx" +#include <column.hxx> +#include <comphelper/implementationreference.hxx> + +#include <memory> +//........................................................................ +namespace dbaccess +{ +//........................................................................ + + typedef ::cppu::ImplHelper1< ::com::sun::star::sdbcx::XColumnsSupplier > OComponentDefinition_BASE; + + class OComponentDefinition_Impl : public OContentHelper_Impl + ,public ODataSettings_Base + { + public: + typedef ::std::map < ::rtl::OUString + , ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > + > Columns; + typedef Columns::iterator iterator; + typedef Columns::const_iterator const_iterator; + + private: + Columns m_aColumns; + + public: + ::rtl::OUString m_sSchemaName; + ::rtl::OUString m_sCatalogName; + + public: + OComponentDefinition_Impl(); + virtual ~OComponentDefinition_Impl(); + + inline size_t size() const { return m_aColumns.size(); } + + inline const_iterator begin() const { return m_aColumns.begin(); } + inline const_iterator end() const { return m_aColumns.end(); } + + inline const_iterator find( const ::rtl::OUString& _rName ) const { return m_aColumns.find( _rName ); } + + inline void erase( const ::rtl::OUString& _rName ) { m_aColumns.erase( _rName ); } + + inline void insert( const ::rtl::OUString& _rName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxColumn ) + { + OSL_PRECOND( m_aColumns.find( _rName ) == m_aColumns.end(), "OComponentDefinition_Impl::insert: there's already an element with this name!" ); + m_aColumns.insert( Columns::value_type( _rName, _rxColumn ) ); + } + }; + +class OColumnPropertyListener; +//========================================================================= +//= OComponentDefinition - a database "document" which describes a query +//========================================================================= +class OComponentDefinition :public OContentHelper + ,public ODataSettings + ,public IColumnFactory + ,public OComponentDefinition_BASE + ,public ::comphelper::OPropertyArrayUsageHelper< OComponentDefinition > +{ + OComponentDefinition(); + +protected: + ::std::auto_ptr< OColumns > m_pColumns; + ::comphelper::ImplementationReference< OColumnPropertyListener,::com::sun::star::beans::XPropertyChangeListener> + m_xColumnPropertyListener; + sal_Bool m_bTable; + + virtual ~OComponentDefinition(); + virtual void SAL_CALL disposing(); + + +protected: + OComponentDefinition(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& + ,const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _xParentContainer + ,const TContentPtr& _pImpl + ,sal_Bool _bTable = sal_True); + + const OComponentDefinition_Impl& getDefinition() const { return dynamic_cast< const OComponentDefinition_Impl& >( *m_pImpl.get() ); } + OComponentDefinition_Impl& getDefinition() { return dynamic_cast< OComponentDefinition_Impl& >( *m_pImpl.get() ); } +public: + + OComponentDefinition( + const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxContainer + ,const ::rtl::OUString& _rElementName + ,const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& + ,const TContentPtr& _pImpl + ,sal_Bool _bTable = sal_True + ); + +// com::sun::star::lang::XTypeProvider + DECLARE_TYPEPROVIDER( ); + +// ::com::sun::star::uno::XInterface + DECLARE_XINTERFACE( ) + +// ::com::sun::star::lang::XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw(::com::sun::star::uno::RuntimeException); + + 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 >&); + +// ::com::sun::star::beans::XPropertySet + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw(::com::sun::star::uno::RuntimeException); + + // XColumnsSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getColumns( ) throw (::com::sun::star::uno::RuntimeException); + + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper(); + + // IColumnFactory + virtual OColumn* createColumn(const ::rtl::OUString& _rName) const; + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > createColumnDescriptor(); + virtual void columnAppended( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxSourceDescriptor ); + virtual void columnDropped(const ::rtl::OUString& _sName); + virtual void notifyDataSourceModified() { OContentHelper::notifyDataSourceModified(); } + +protected: +// OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const; + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const ::com::sun::star::uno::Any& rValue) throw (::com::sun::star::uno::Exception); + + // OContentHelper overridables + virtual ::rtl::OUString determineContentType() const; + +private: + void registerProperties(); +}; + +//........................................................................ +} // namespace dbaccess +//........................................................................ + +#endif // DBA_COREDATAACESS_COMPONENTDEFINITION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/ContentHelper.cxx b/dbaccess/source/core/dataaccess/ContentHelper.cxx new file mode 100644 index 000000000000..da4e3c271a69 --- /dev/null +++ b/dbaccess/source/core/dataaccess/ContentHelper.cxx @@ -0,0 +1,673 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" +#include "ContentHelper.hxx" +#include <ucbhelper/cancelcommandexecution.hxx> +#include <comphelper/property.hxx> +#include <com/sun/star/ucb/UnsupportedCommandException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/IllegalAccessException.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <ucbhelper/propertyvalueset.hxx> +#include <ucbhelper/contentidentifier.hxx> +#include "myucp_resultset.hxx" +#include <com/sun/star/container/XNameContainer.hpp> +#include "sdbcoretools.hxx" +#include "dbastrings.hrc" +#include <tools/debug.hxx> + + +namespace dbaccess +{ +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::container; +using namespace ::comphelper; +using namespace ::cppu; + +DBG_NAME(OContentHelper_Impl) +OContentHelper_Impl::OContentHelper_Impl() +{ + DBG_CTOR(OContentHelper_Impl,NULL); +} + +OContentHelper_Impl::~OContentHelper_Impl() +{ + DBG_DTOR(OContentHelper_Impl,NULL); +} + +OContentHelper::OContentHelper(const Reference< XMultiServiceFactory >& _xORB + ,const Reference< XInterface >& _xParentContainer + ,const TContentPtr& _pImpl) + : OContentHelper_COMPBASE(m_aMutex) + ,m_aContentListeners(m_aMutex) + ,m_aPropertyChangeListeners(m_aMutex) + ,m_xParentContainer(_xParentContainer) + ,m_aContext( _xORB ) + ,m_aErrorHelper( m_aContext ) + ,m_pImpl(_pImpl) + ,m_nCommandId(0) +{ +} + +void SAL_CALL OContentHelper::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + // say our listeners goobye + EventObject aEvt(*this); + m_aContentListeners.disposeAndClear(aEvt); + + m_xParentContainer = NULL; +} + +IMPLEMENT_SERVICE_INFO1(OContentHelper,"com.sun.star.comp.sdb.Content","com.sun.star.ucb.Content"); +IMPLEMENT_IMPLEMENTATION_ID(OContentHelper) + +// XContent +Reference< XContentIdentifier > SAL_CALL OContentHelper::getIdentifier( ) throw (RuntimeException) +{ + ::osl::MutexGuard aGuard(m_aMutex); + ::rtl::OUStringBuffer aIdentifier; + aIdentifier.appendAscii( "private:" ); + aIdentifier.append( impl_getHierarchicalName( true ) ); + return new ::ucbhelper::ContentIdentifier( m_aContext.getLegacyServiceFactory(), aIdentifier.makeStringAndClear() ); +} + +::rtl::OUString OContentHelper::impl_getHierarchicalName( bool _includingRootContainer ) const +{ + ::rtl::OUStringBuffer aHierarchicalName( m_pImpl->m_aProps.aTitle ); + Reference< XInterface > xParent = m_xParentContainer; + while( xParent.is() ) + { + Reference<XPropertySet> xProp( xParent, UNO_QUERY ); + Reference< XChild > xChild( xParent, UNO_QUERY ); + xParent.set( xChild.is() ? xChild->getParent() : Reference< XInterface >(), UNO_QUERY ); + if ( xProp.is() && xParent.is() ) + { + ::rtl::OUString sName; + xProp->getPropertyValue( PROPERTY_NAME ) >>= sName; + + ::rtl::OUString sPrevious = aHierarchicalName.makeStringAndClear(); + aHierarchicalName.append( sName ); + aHierarchicalName.append( sal_Unicode( '/' ) ); + aHierarchicalName.append( sPrevious ); + } + } + ::rtl::OUString sHierarchicalName( aHierarchicalName.makeStringAndClear() ); + if ( !_includingRootContainer ) + sHierarchicalName = sHierarchicalName.copy( sHierarchicalName.indexOf( '/' ) + 1 ); + return sHierarchicalName; +} + +::rtl::OUString SAL_CALL OContentHelper::getContentType() throw (RuntimeException) +{ + ::osl::MutexGuard aGuard(m_aMutex); + + if ( !m_pImpl->m_aProps.aContentType ) + { // content type not yet retrieved + m_pImpl->m_aProps.aContentType.reset( determineContentType() ); + } + + return *m_pImpl->m_aProps.aContentType; +} + +void SAL_CALL OContentHelper::addContentEventListener( const Reference< XContentEventListener >& _rxListener ) throw (RuntimeException) +{ + ::osl::MutexGuard aGuard(m_aMutex); + if ( _rxListener.is() ) + m_aContentListeners.addInterface(_rxListener); +} + +void SAL_CALL OContentHelper::removeContentEventListener( const Reference< XContentEventListener >& _rxListener ) throw (RuntimeException) +{ + ::osl::MutexGuard aGuard(m_aMutex); + if (_rxListener.is()) + m_aContentListeners.removeInterface(_rxListener); +} + +// XCommandProcessor +sal_Int32 SAL_CALL OContentHelper::createCommandIdentifier( ) throw (RuntimeException) +{ + ::osl::MutexGuard aGuard(m_aMutex); + // Just increase counter on every call to generate an identifier. + return ++m_nCommandId; +} + +Any SAL_CALL OContentHelper::execute( const Command& aCommand, sal_Int32 /*CommandId*/, const Reference< XCommandEnvironment >& Environment ) throw (Exception, CommandAbortedException, RuntimeException) +{ + Any aRet; + if ( aCommand.Name.compareToAscii( "getPropertyValues" ) == 0 ) + { + ////////////////////////////////////////////////////////////////// + // getPropertyValues + ////////////////////////////////////////////////////////////////// + + Sequence< Property > Properties; + if ( !( aCommand.Argument >>= Properties ) ) + { + OSL_ENSURE( sal_False, "Wrong argument type!" ); + ucbhelper::cancelCommandExecution( + makeAny( IllegalArgumentException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + aRet <<= getPropertyValues( Properties); + } + else if ( aCommand.Name.compareToAscii( "setPropertyValues" ) == 0 ) + { + ////////////////////////////////////////////////////////////////// + // setPropertyValues + ////////////////////////////////////////////////////////////////// + + Sequence< PropertyValue > aProperties; + if ( !( aCommand.Argument >>= aProperties ) ) + { + OSL_ENSURE( sal_False, "Wrong argument type!" ); + ucbhelper::cancelCommandExecution( + makeAny( IllegalArgumentException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + if ( !aProperties.getLength() ) + { + OSL_ENSURE( sal_False, "No properties!" ); + ucbhelper::cancelCommandExecution( + makeAny( IllegalArgumentException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + aRet <<= setPropertyValues( aProperties, Environment ); + } + else if ( aCommand.Name.compareToAscii( "getPropertySetInfo" ) == 0 ) + { + ////////////////////////////////////////////////////////////////// + // getPropertySetInfo + ////////////////////////////////////////////////////////////////// + + Reference<XPropertySet> xProp(*this,UNO_QUERY); + if ( xProp.is() ) + aRet <<= xProp->getPropertySetInfo(); + // aRet <<= getPropertySetInfo(); // TODO + } + else + { + ////////////////////////////////////////////////////////////////// + // Unsupported command + ////////////////////////////////////////////////////////////////// + + OSL_ENSURE( sal_False, "Content::execute - unsupported command!" ); + + ucbhelper::cancelCommandExecution( + makeAny( UnsupportedCommandException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ) ) ), + Environment ); + // Unreachable + } + + return aRet; +} + +void SAL_CALL OContentHelper::abort( sal_Int32 /*CommandId*/ ) throw (RuntimeException) +{ +} + +// XPropertiesChangeNotifier +void SAL_CALL OContentHelper::addPropertiesChangeListener( const Sequence< ::rtl::OUString >& PropertyNames, const Reference< XPropertiesChangeListener >& Listener ) throw (RuntimeException) +{ + ::osl::MutexGuard aGuard(m_aMutex); + sal_Int32 nCount = PropertyNames.getLength(); + if ( !nCount ) + { + // Note: An empty sequence means a listener for "all" properties. + m_aPropertyChangeListeners.addInterface(::rtl::OUString(), Listener ); + } + else + { + const ::rtl::OUString* pSeq = PropertyNames.getConstArray(); + + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const ::rtl::OUString& rName = pSeq[ n ]; + if ( rName.getLength() ) + m_aPropertyChangeListeners.addInterface(rName, Listener ); + } + } +} + +void SAL_CALL OContentHelper::removePropertiesChangeListener( const Sequence< ::rtl::OUString >& PropertyNames, const Reference< XPropertiesChangeListener >& Listener ) throw (RuntimeException) +{ + ::osl::MutexGuard aGuard(m_aMutex); + sal_Int32 nCount = PropertyNames.getLength(); + if ( !nCount ) + { + // Note: An empty sequence means a listener for "all" properties. + m_aPropertyChangeListeners.removeInterface( ::rtl::OUString(), Listener ); + } + else + { + const ::rtl::OUString* pSeq = PropertyNames.getConstArray(); + + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const ::rtl::OUString& rName = pSeq[ n ]; + if ( rName.getLength() ) + m_aPropertyChangeListeners.removeInterface( rName, Listener ); + } + } +} + +// XPropertyContainer +void SAL_CALL OContentHelper::addProperty( const ::rtl::OUString& /*Name*/, sal_Int16 /*Attributes*/, const Any& /*DefaultValue*/ ) throw (PropertyExistException, IllegalTypeException, IllegalArgumentException, RuntimeException) +{ + DBG_ERROR( "OContentHelper::addProperty: not implemented!" ); +} + +void SAL_CALL OContentHelper::removeProperty( const ::rtl::OUString& /*Name*/ ) throw (UnknownPropertyException, NotRemoveableException, RuntimeException) +{ + DBG_ERROR( "OContentHelper::removeProperty: not implemented!" ); +} + +// XInitialization +void SAL_CALL OContentHelper::initialize( const Sequence< Any >& _aArguments ) throw(Exception, RuntimeException) +{ + const Any* pBegin = _aArguments.getConstArray(); + const Any* pEnd = pBegin + _aArguments.getLength(); + PropertyValue aValue;; + for(;pBegin != pEnd;++pBegin) + { + *pBegin >>= aValue; + if ( aValue.Name.equalsAscii("Parent") ) + { + m_xParentContainer.set(aValue.Value,UNO_QUERY); + } + else if ( aValue.Name.equalsAscii(PROPERTY_NAME) ) + { + aValue.Value >>= m_pImpl->m_aProps.aTitle; + } + else if ( aValue.Name.equalsAscii(PROPERTY_PERSISTENT_NAME) ) + { + aValue.Value >>= m_pImpl->m_aProps.sPersistentName; + } + } +} + +Sequence< Any > OContentHelper::setPropertyValues(const Sequence< PropertyValue >& rValues,const Reference< XCommandEnvironment >& /*xEnv*/ ) +{ + osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); + + Sequence< Any > aRet( rValues.getLength() ); + Sequence< PropertyChangeEvent > aChanges( rValues.getLength() ); + sal_Int32 nChanged = 0; + + PropertyChangeEvent aEvent; + aEvent.Source = static_cast< cppu::OWeakObject * >( this ); + aEvent.Further = sal_False; + aEvent.PropertyHandle = -1; + + const PropertyValue* pValues = rValues.getConstArray(); + sal_Int32 nCount = rValues.getLength(); + + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const PropertyValue& rValue = pValues[ n ]; + + if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ) + { + // Read-only property! + aRet[ n ] <<= IllegalAccessException( + rtl::OUString::createFromAscii( + "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ) + { + // Read-only property! + aRet[ n ] <<= IllegalAccessException( + rtl::OUString::createFromAscii( + "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ) + { + // Read-only property! + aRet[ n ] <<= IllegalAccessException( + rtl::OUString::createFromAscii( + "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) + { + rtl::OUString aNewValue; + if ( rValue.Value >>= aNewValue ) + { + if ( aNewValue != m_pImpl->m_aProps.aTitle ) + { + aEvent.PropertyName = rValue.Name; + aEvent.OldValue = makeAny( m_pImpl->m_aProps.aTitle ); + + try + { + impl_rename_throw( aNewValue ,false); + OSL_ENSURE( m_pImpl->m_aProps.aTitle == aNewValue, "OContentHelper::setPropertyValues('Title'): rename did not work!" ); + + aEvent.NewValue = makeAny( aNewValue ); + aChanges.getArray()[ nChanged ] = aEvent; + nChanged++; + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "OContentHelper::setPropertyValues('Title'): caught an exception while renaming!" ); + } + } + else + { + // Old value equals new value. No error! + } + } + else + { + aRet[ n ] <<= IllegalTypeException( + rtl::OUString::createFromAscii( + "Property value has wrong type!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + } + + else + { + aRet[ n ] <<= Exception( + rtl::OUString::createFromAscii( + "No property set for storing the value!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + } + + if ( nChanged > 0 ) + { + // @@@ Save changes. +// storeData(); + + notifyDataSourceModified(); + aGuard.clear(); + aChanges.realloc( nChanged ); + notifyPropertiesChange( aChanges ); + } + + return aRet; +} + +//========================================================================= +// static +Reference< XRow > OContentHelper::getPropertyValues( const Sequence< Property >& rProperties) +{ + // Note: Empty sequence means "get values of all supported properties". + + rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( m_aContext.getLegacyServiceFactory() ); + + sal_Int32 nCount = rProperties.getLength(); + if ( nCount ) + { + const Property* pProps = rProperties.getConstArray(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const Property& rProp = pProps[ n ]; + + // Process Core properties. + + if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ) + { + xRow->appendString ( rProp, getContentType() ); + } + else if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) + { + xRow->appendString ( rProp, m_pImpl->m_aProps.aTitle ); + } + else if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ) + { + xRow->appendBoolean( rProp, m_pImpl->m_aProps.bIsDocument ); + } + else if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ) + { + xRow->appendBoolean( rProp, m_pImpl->m_aProps.bIsFolder ); + } + else + xRow->appendVoid(rProp); + } + } + else + { + // Append all Core Properties. + xRow->appendString ( + Property( rtl::OUString::createFromAscii( "ContentType" ), + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + PropertyAttribute::BOUND + | PropertyAttribute::READONLY ), + getContentType() ); + xRow->appendString ( + Property( rtl::OUString::createFromAscii( "Title" ), + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + PropertyAttribute::BOUND ), + m_pImpl->m_aProps.aTitle ); + xRow->appendBoolean( + Property( rtl::OUString::createFromAscii( "IsDocument" ), + -1, + getCppuBooleanType(), + PropertyAttribute::BOUND + | PropertyAttribute::READONLY ), + m_pImpl->m_aProps.bIsDocument ); + xRow->appendBoolean( + Property( rtl::OUString::createFromAscii( "IsFolder" ), + -1, + getCppuBooleanType(), + PropertyAttribute::BOUND + | PropertyAttribute::READONLY ), + m_pImpl->m_aProps.bIsFolder ); + + // @@@ Append other properties supported directly. + } + + return Reference< XRow >( xRow.get() ); +} + +void OContentHelper::notifyPropertiesChange( const Sequence< PropertyChangeEvent >& evt ) const +{ + + sal_Int32 nCount = evt.getLength(); + if ( nCount ) + { + // First, notify listeners interested in changes of every property. + OInterfaceContainerHelper* pAllPropsContainer = m_aPropertyChangeListeners.getContainer( ::rtl::OUString() ); + if ( pAllPropsContainer ) + { + OInterfaceIteratorHelper aIter( *pAllPropsContainer ); + while ( aIter.hasMoreElements() ) + { + // Propagate event. + Reference< XPropertiesChangeListener > xListener( aIter.next(), UNO_QUERY ); + if ( xListener.is() ) + xListener->propertiesChange( evt ); + } + } + + typedef Sequence< PropertyChangeEvent > PropertyEventSequence; + typedef ::std::map< XPropertiesChangeListener*, PropertyEventSequence* > PropertiesEventListenerMap; + PropertiesEventListenerMap aListeners; + + const PropertyChangeEvent* propertyChangeEvent = evt.getConstArray(); + + for ( sal_Int32 n = 0; n < nCount; ++n, ++propertyChangeEvent ) + { + const PropertyChangeEvent& rEvent = *propertyChangeEvent; + const ::rtl::OUString& rName = rEvent.PropertyName; + + OInterfaceContainerHelper* pPropsContainer = m_aPropertyChangeListeners.getContainer( rName ); + if ( pPropsContainer ) + { + OInterfaceIteratorHelper aIter( *pPropsContainer ); + while ( aIter.hasMoreElements() ) + { + PropertyEventSequence* propertyEvents = NULL; + + XPropertiesChangeListener* pListener = static_cast< XPropertiesChangeListener * >( aIter.next() ); + PropertiesEventListenerMap::iterator it = aListeners.find( pListener ); + if ( it == aListeners.end() ) + { + // Not in map - create and insert new entry. + propertyEvents = new PropertyEventSequence( nCount ); + aListeners[ pListener ] = propertyEvents; + } + else + propertyEvents = (*it).second; + + if ( propertyEvents ) + (*propertyEvents)[n] = rEvent; + } + } + } + + // Notify listeners. + PropertiesEventListenerMap::iterator it = aListeners.begin(); + while ( !aListeners.empty() ) + { + XPropertiesChangeListener* pListener = + static_cast< XPropertiesChangeListener * >( (*it).first ); + PropertyEventSequence* pSeq = (*it).second; + + // Remove current element. + aListeners.erase( it ); + + // Propagate event. + pListener->propertiesChange( *pSeq ); + + delete pSeq; + + it = aListeners.begin(); + } + } +} + +// com::sun::star::lang::XUnoTunnel +sal_Int64 OContentHelper::getSomething( const Sequence< sal_Int8 > & rId ) throw (RuntimeException) +{ + if (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(), rId.getConstArray(), 16 ) ) + return reinterpret_cast<sal_Int64>(this); + + return 0; +} + +OContentHelper* OContentHelper::getImplementation( const Reference< XInterface >& _rxComponent ) +{ + OContentHelper* pContent( NULL ); + + Reference< XUnoTunnel > xUnoTunnel( _rxComponent, UNO_QUERY ); + if ( xUnoTunnel.is() ) + pContent = reinterpret_cast< OContentHelper* >( xUnoTunnel->getSomething( getUnoTunnelImplementationId() ) ); + + return pContent; +} + +Reference< XInterface > SAL_CALL OContentHelper::getParent( ) throw (RuntimeException) +{ + ::osl::MutexGuard aGuard(m_aMutex); + return m_xParentContainer; +} + +void SAL_CALL OContentHelper::setParent( const Reference< XInterface >& _xParent ) throw (NoSupportException, RuntimeException) +{ + ::osl::MutexGuard aGuard(m_aMutex); + m_xParentContainer = _xParent; +} + +void OContentHelper::impl_rename_throw(const ::rtl::OUString& _sNewName,bool _bNotify ) +{ + osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex); + if ( _sNewName.equals( m_pImpl->m_aProps.aTitle ) ) + return; + try + { + Sequence< PropertyChangeEvent > aChanges( 1 ); + + aChanges[0].Source = static_cast< cppu::OWeakObject * >( this ); + aChanges[0].Further = sal_False; + aChanges[0].PropertyName = PROPERTY_NAME; + aChanges[0].PropertyHandle = PROPERTY_ID_NAME; + aChanges[0].OldValue <<= m_pImpl->m_aProps.aTitle; + aChanges[0].NewValue <<= _sNewName; + + aGuard.clear(); + + m_pImpl->m_aProps.aTitle = _sNewName; + if ( _bNotify ) + notifyPropertiesChange( aChanges ); + notifyDataSourceModified(); + } + catch(const PropertyVetoException&) + { + throw ElementExistException(_sNewName,*this); + } +} + +void SAL_CALL OContentHelper::rename( const ::rtl::OUString& newName ) throw (SQLException, ElementExistException, RuntimeException) +{ + + impl_rename_throw(newName); + +} + +void OContentHelper::notifyDataSourceModified() +{ + ::dbaccess::notifyDataSourceModified(m_xParentContainer,sal_True); +} + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/ModelImpl.cxx b/dbaccess/source/core/dataaccess/ModelImpl.cxx new file mode 100644 index 000000000000..d3de75af3d53 --- /dev/null +++ b/dbaccess/source/core/dataaccess/ModelImpl.cxx @@ -0,0 +1,1435 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +#include "commandcontainer.hxx" +#include "connection.hxx" +#include "core_resource.hrc" +#include "core_resource.hxx" +#include "databasecontext.hxx" +#include "databasedocument.hxx" +#include "datasource.hxx" +#include "dbastrings.hrc" +#include "ModelImpl.hxx" +#include "userinformation.hxx" +#include "sdbcoretools.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/container/XSet.hpp> +#include <com/sun/star/document/MacroExecMode.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/embed/XTransactionBroadcaster.hpp> +#include <com/sun/star/sdb/BooleanComparisonMode.hpp> +#include <com/sun/star/script/DocumentScriptLibraryContainer.hpp> +#include <com/sun/star/script/DocumentDialogLibraryContainer.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/form/XLoadable.hpp> +/** === end UNO includes === **/ + +#include <comphelper/interaction.hxx> +#include <comphelper/mediadescriptor.hxx> +#include <comphelper/seqstream.hxx> +#include <comphelper/sequence.hxx> +#include <connectivity/dbexception.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <rtl/digest.h> +#include <sfx2/signaturestate.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <tools/errcode.hxx> +#include <tools/urlobj.hxx> +#include <unotools/sharedunocomponent.hxx> + +#include <algorithm> + +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::view; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::reflection; +using namespace ::com::sun::star::script; +using namespace ::cppu; +using namespace ::osl; +using namespace ::dbtools; +using namespace ::comphelper; +namespace css = ::com::sun::star; + +namespace dbaccess +{ + +//============================================================ +//= VosMutexFacade +//============================================================ +VosMutexFacade::VosMutexFacade( ::osl::Mutex& _rMutex ) + :m_rMutex( _rMutex ) +{ +} + +void SAL_CALL VosMutexFacade::acquire() +{ + m_rMutex.acquire(); +} + +sal_Bool SAL_CALL VosMutexFacade::tryToAcquire() +{ + return m_rMutex.tryToAcquire(); +} + +void SAL_CALL VosMutexFacade::release() +{ + m_rMutex.release(); +} + +//============================================================ +//= DocumentStorageAccess +//============================================================ +DBG_NAME( DocumentStorageAccess ) +class DocumentStorageAccess : public ::cppu::WeakImplHelper2< XDocumentSubStorageSupplier + , XTransactionListener > +{ + typedef ::std::map< ::rtl::OUString, Reference< XStorage > > NamedStorages; + + ::osl::Mutex m_aMutex; + /// all sub storages which we ever gave to the outer world + NamedStorages m_aExposedStorages; + ODatabaseModelImpl* m_pModelImplementation; + bool m_bPropagateCommitToRoot; + bool m_bDisposingSubStorages; + +public: + DocumentStorageAccess( ODatabaseModelImpl& _rModelImplementation ) + :m_pModelImplementation( &_rModelImplementation ) + ,m_bPropagateCommitToRoot( true ) + ,m_bDisposingSubStorages( false ) + { + DBG_CTOR( DocumentStorageAccess, NULL ); + } + +protected: + ~DocumentStorageAccess() + { + DBG_DTOR( DocumentStorageAccess, NULL ); + } + +public: + void dispose(); + + // XDocumentSubStorageSupplier + virtual Reference< XStorage > SAL_CALL getDocumentSubStorage( const ::rtl::OUString& aStorageName, ::sal_Int32 _nMode ) throw (RuntimeException); + virtual Sequence< ::rtl::OUString > SAL_CALL getDocumentSubStoragesNames( ) throw (IOException, RuntimeException); + + // XTransactionListener + virtual void SAL_CALL preCommit( const ::com::sun::star::lang::EventObject& aEvent ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL commited( const ::com::sun::star::lang::EventObject& aEvent ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL preRevert( const ::com::sun::star::lang::EventObject& aEvent ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL reverted( const ::com::sun::star::lang::EventObject& aEvent ) throw (::com::sun::star::uno::RuntimeException); + + // XEventListener + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); + + /// disposes all storages managed by this instance + void disposeStorages(); + + /// disposes all known sub storages + void commitStorages() SAL_THROW(( IOException, RuntimeException )); + + /// commits the dedicated "database" storage + bool commitEmbeddedStorage( bool _bPreventRootCommits ); + +private: + /** opens the sub storage with the given name, in the given mode + */ + Reference< XStorage > impl_openSubStorage_nothrow( const ::rtl::OUString& _rStorageName, sal_Int32 _nMode ); + + void impl_suspendCommitPropagation() + { + OSL_ENSURE( m_bPropagateCommitToRoot, "DocumentStorageAccess::impl_suspendCommitPropagation: already suspended" ); + m_bPropagateCommitToRoot = false; + } + void impl_resumeCommitPropagation() + { + OSL_ENSURE( !m_bPropagateCommitToRoot, "DocumentStorageAccess::impl_resumeCommitPropagation: not suspended" ); + m_bPropagateCommitToRoot = true; + } + +}; + +void DocumentStorageAccess::dispose() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + for ( NamedStorages::iterator loop = m_aExposedStorages.begin(); + loop != m_aExposedStorages.end(); + ++loop + ) + { + try + { + Reference< XTransactionBroadcaster > xBroadcaster( loop->second, UNO_QUERY ); + if ( xBroadcaster.is() ) + xBroadcaster->removeTransactionListener( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + m_aExposedStorages.clear(); + + m_pModelImplementation = NULL; +} + +Reference< XStorage > DocumentStorageAccess::impl_openSubStorage_nothrow( const ::rtl::OUString& _rStorageName, sal_Int32 _nDesiredMode ) +{ + OSL_ENSURE( _rStorageName.getLength(),"ODatabaseModelImpl::impl_openSubStorage_nothrow: Invalid storage name!" ); + + Reference< XStorage > xStorage; + try + { + Reference< XStorage > xRootStorage( m_pModelImplementation->getOrCreateRootStorage() ); + if ( xRootStorage.is() ) + { + sal_Int32 nRealMode = m_pModelImplementation->m_bDocumentReadOnly ? ElementModes::READ : _nDesiredMode; + if ( nRealMode == ElementModes::READ ) + { + Reference< XNameAccess > xSubStorageNames( xRootStorage, UNO_QUERY ); + if ( xSubStorageNames.is() && !xSubStorageNames->hasByName( _rStorageName ) ) + return xStorage; + } + + xStorage = xRootStorage->openStorageElement( _rStorageName, nRealMode ); + + Reference< XTransactionBroadcaster > xBroad( xStorage, UNO_QUERY ); + if ( xBroad.is() ) + xBroad->addTransactionListener( this ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return xStorage; +} + +void DocumentStorageAccess::disposeStorages() +{ + m_bDisposingSubStorages = true; + + NamedStorages::iterator aEnd = m_aExposedStorages.end(); + for ( NamedStorages::iterator aIter = m_aExposedStorages.begin(); + aIter != aEnd ; + ++aIter + ) + { + try + { + ::comphelper::disposeComponent( aIter->second ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + m_aExposedStorages.clear(); + + m_bDisposingSubStorages = false; +} + +void DocumentStorageAccess::commitStorages() SAL_THROW(( IOException, RuntimeException )) +{ + try + { + for ( NamedStorages::const_iterator aIter = m_aExposedStorages.begin(); + aIter != m_aExposedStorages.end(); + ++aIter + ) + { + tools::stor::commitStorageIfWriteable( aIter->second ); + } + } + catch(const WrappedTargetException&) + { + // WrappedTargetException not allowed to leave + throw IOException(); + } +} + +bool DocumentStorageAccess::commitEmbeddedStorage( bool _bPreventRootCommits ) +{ + if ( _bPreventRootCommits ) + impl_suspendCommitPropagation(); + + bool bSuccess = false; + try + { + NamedStorages::const_iterator pos = m_aExposedStorages.find( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "database" ) ) ); + if ( pos != m_aExposedStorages.end() ) + bSuccess = tools::stor::commitStorageIfWriteable( pos->second ); + } + catch( Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + if ( _bPreventRootCommits ) + impl_resumeCommitPropagation(); + + return bSuccess; + +} + +Reference< XStorage > SAL_CALL DocumentStorageAccess::getDocumentSubStorage( const ::rtl::OUString& aStorageName, ::sal_Int32 _nDesiredMode ) throw (RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + NamedStorages::iterator pos = m_aExposedStorages.find( aStorageName ); + if ( pos == m_aExposedStorages.end() ) + { + Reference< XStorage > xResult = impl_openSubStorage_nothrow( aStorageName, _nDesiredMode ); + pos = m_aExposedStorages.insert( NamedStorages::value_type( aStorageName, xResult ) ).first; + } + + return pos->second; +} + +Sequence< ::rtl::OUString > SAL_CALL DocumentStorageAccess::getDocumentSubStoragesNames( ) throw (IOException, RuntimeException) +{ + Reference< XStorage > xRootStor( m_pModelImplementation->getRootStorage() ); + if ( !xRootStor.is() ) + return Sequence< ::rtl::OUString >(); + + ::std::vector< ::rtl::OUString > aNames; + + Reference< XNameAccess > xNames( xRootStor, UNO_QUERY_THROW ); + Sequence< ::rtl::OUString > aElementNames( xNames->getElementNames() ); + for ( sal_Int32 i=0; i<aElementNames.getLength(); ++i ) + { + if ( xRootStor->isStorageElement( aElementNames[i] ) ) + aNames.push_back( aElementNames[i] ); + } + return aNames.empty() + ? Sequence< ::rtl::OUString >() + : Sequence< ::rtl::OUString >( &aNames[0], aNames.size() ); +} + +void SAL_CALL DocumentStorageAccess::preCommit( const css::lang::EventObject& /*aEvent*/ ) throw (Exception, RuntimeException) +{ + // not interested in +} + +void SAL_CALL DocumentStorageAccess::commited( const css::lang::EventObject& aEvent ) throw (RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pModelImplementation ) + m_pModelImplementation->setModified( sal_True ); + + if ( m_pModelImplementation && m_bPropagateCommitToRoot ) + { + Reference< XStorage > xStorage( aEvent.Source, UNO_QUERY ); + + // check if this is the dedicated "database" sub storage + NamedStorages::const_iterator pos = m_aExposedStorages.find( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "database" ) ) ); + if ( ( pos != m_aExposedStorages.end() ) + && ( pos->second == xStorage ) + ) + { + // if so, also commit the root storage + m_pModelImplementation->commitRootStorage(); + } + } +} + +void SAL_CALL DocumentStorageAccess::preRevert( const css::lang::EventObject& /*aEvent*/ ) throw (Exception, RuntimeException) +{ + // not interested in +} + +void SAL_CALL DocumentStorageAccess::reverted( const css::lang::EventObject& /*aEvent*/ ) throw (RuntimeException) +{ + // not interested in +} + +void SAL_CALL DocumentStorageAccess::disposing( const css::lang::EventObject& Source ) throw ( RuntimeException ) +{ + OSL_ENSURE( Reference< XStorage >( Source.Source, UNO_QUERY ).is(), "DocumentStorageAccess::disposing: No storage? What's this?" ); + + if ( m_bDisposingSubStorages ) + return; + + for ( NamedStorages::iterator find = m_aExposedStorages.begin(); + find != m_aExposedStorages.end(); + ++find + ) + if ( find->second == Source.Source ) + { + m_aExposedStorages.erase( find ); + break; + } +} + +//============================================================ +//= ODatabaseModelImpl +//============================================================ +DBG_NAME(ODatabaseModelImpl) + +ODatabaseModelImpl::ODatabaseModelImpl( const Reference< XMultiServiceFactory >& _rxFactory, ODatabaseContext& _rDBContext ) + :m_xModel() + ,m_xDataSource() + ,m_pStorageAccess( NULL ) + ,m_aMutex() + ,m_aMutexFacade( m_aMutex ) + ,m_aContainer(4) + ,m_aMacroMode( *this ) + ,m_nImposedMacroExecMode( MacroExecMode::NEVER_EXECUTE ) + ,m_pDBContext( &_rDBContext ) + ,m_refCount(0) + ,m_aEmbeddedMacros() + ,m_bModificationLock( false ) + ,m_bDocumentInitialized( false ) + ,m_aContext( _rxFactory ) + ,m_nLoginTimeout(0) + ,m_bReadOnly(sal_False) + ,m_bPasswordRequired(sal_False) + ,m_bSuppressVersionColumns(sal_True) + ,m_bModified(sal_False) + ,m_bDocumentReadOnly(sal_False) + ,m_pSharedConnectionManager(NULL) + ,m_nControllerLockCount(0) +{ + // some kind of default + DBG_CTOR(ODatabaseModelImpl,NULL); + m_sConnectURL = ::rtl::OUString::createFromAscii("jdbc:"); + m_aTableFilter.realloc(1); + m_aTableFilter[0] = ::rtl::OUString::createFromAscii("%"); + impl_construct_nothrow(); +} + +ODatabaseModelImpl::ODatabaseModelImpl( + const ::rtl::OUString& _rRegistrationName, + const Reference< XMultiServiceFactory >& _rxFactory, + ODatabaseContext& _rDBContext + ) + :m_xModel() + ,m_xDataSource() + ,m_pStorageAccess( NULL ) + ,m_aMutex() + ,m_aMutexFacade( m_aMutex ) + ,m_aContainer(4) + ,m_aMacroMode( *this ) + ,m_nImposedMacroExecMode( MacroExecMode::NEVER_EXECUTE ) + ,m_pDBContext( &_rDBContext ) + ,m_refCount(0) + ,m_aEmbeddedMacros() + ,m_bModificationLock( false ) + ,m_bDocumentInitialized( false ) + ,m_aContext( _rxFactory ) + ,m_sName(_rRegistrationName) + ,m_nLoginTimeout(0) + ,m_bReadOnly(sal_False) + ,m_bPasswordRequired(sal_False) + ,m_bSuppressVersionColumns(sal_True) + ,m_bModified(sal_False) + ,m_bDocumentReadOnly(sal_False) + ,m_pSharedConnectionManager(NULL) + ,m_nControllerLockCount(0) +{ + DBG_CTOR(ODatabaseModelImpl,NULL); + impl_construct_nothrow(); +} + +ODatabaseModelImpl::~ODatabaseModelImpl() +{ + DBG_DTOR(ODatabaseModelImpl,NULL); +} + +void ODatabaseModelImpl::impl_construct_nothrow() +{ + // create the property bag to hold the settings (also known as "Info" property) + try + { + // the set of property value types in the bag is limited: + Sequence< Type > aAllowedTypes(6); + Type* pAllowedType = aAllowedTypes.getArray(); + *pAllowedType++ = ::getCppuType( static_cast< sal_Bool* >( NULL ) ); + *pAllowedType++ = ::getCppuType( static_cast< double* >( NULL ) ); + *pAllowedType++ = ::getCppuType( static_cast< ::rtl::OUString* >( NULL ) ); + *pAllowedType++ = ::getCppuType( static_cast< sal_Int32* >( NULL ) ); + *pAllowedType++ = ::getCppuType( static_cast< sal_Int16* >( NULL ) ); + *pAllowedType++ = ::getCppuType( static_cast< Sequence< Any >* >( NULL ) ); + + Sequence< Any > aInitArgs( 2 ); + aInitArgs[0] <<= NamedValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AutomaticAddition" ) ), + makeAny( (sal_Bool)sal_True ) + ); + aInitArgs[1] <<= NamedValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AllowedTypes" ) ), + makeAny( aAllowedTypes ) + ); + + m_xSettings.set( m_aContext.createComponentWithArguments( "com.sun.star.beans.PropertyBag", aInitArgs ), UNO_QUERY_THROW ); + + // insert the default settings + Reference< XPropertyContainer > xContainer( m_xSettings, UNO_QUERY_THROW ); + Reference< XSet > xSettingsSet( m_xSettings, UNO_QUERY_THROW ); + const AsciiPropertyValue* pSettings = getDefaultDataSourceSettings(); + for ( ; pSettings->AsciiName; ++pSettings ) + { + if ( !pSettings->DefaultValue.hasValue() ) + { + Property aProperty( + ::rtl::OUString::createFromAscii( pSettings->AsciiName ), + -1, + pSettings->ValueType, + PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT | PropertyAttribute::MAYBEVOID + ); + xSettingsSet->insert( makeAny( aProperty ) ); + } + else + { + xContainer->addProperty( + ::rtl::OUString::createFromAscii( pSettings->AsciiName ), + PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT, + pSettings->DefaultValue + ); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + m_pDBContext->appendAtTerminateListener(*this); +} + +namespace +{ + ::rtl::OUString lcl_getContainerStorageName_throw( ODatabaseModelImpl::ObjectType _eType ) + { + const sal_Char* pAsciiName( NULL ); + switch ( _eType ) + { + case ODatabaseModelImpl::E_FORM: pAsciiName = "forms"; break; + case ODatabaseModelImpl::E_REPORT: pAsciiName = "reports"; break; + case ODatabaseModelImpl::E_QUERY: pAsciiName = "queries"; break; + case ODatabaseModelImpl::E_TABLE: pAsciiName = "tables"; break; + default: + throw RuntimeException(); + } + return ::rtl::OUString::createFromAscii( pAsciiName ); + } + + bool lcl_hasObjectWithMacros_throw( const ODefinitionContainer_Impl& _rObjectDefinitions, const Reference< XStorage >& _rxContainerStorage ) + { + bool bSomeDocHasMacros = false; + + for ( ODefinitionContainer_Impl::const_iterator object = _rObjectDefinitions.begin(); + ( object != _rObjectDefinitions.end() ) && !bSomeDocHasMacros; + ++object + ) + { +#if OSL_DEBUG_LEVEL > 0 + const ::rtl::OUString& rName( object->first ); (void)rName; +#endif + + const TContentPtr& rDefinition( object->second ); + const ::rtl::OUString& rPersistentName( rDefinition->m_aProps.sPersistentName ); + + if ( !rPersistentName.getLength() ) + { // it's a logical sub folder used to organize the real objects + const ODefinitionContainer_Impl& rSubFoldersObjectDefinitions( dynamic_cast< const ODefinitionContainer_Impl& >( *rDefinition.get() ) ); + bSomeDocHasMacros = lcl_hasObjectWithMacros_throw( rSubFoldersObjectDefinitions, _rxContainerStorage ); + continue; + } + + bSomeDocHasMacros = ODatabaseModelImpl::objectHasMacros( _rxContainerStorage, rPersistentName ); + } + return bSomeDocHasMacros; + } + + bool lcl_hasObjectsWithMacros_nothrow( ODatabaseModelImpl& _rModel, const ODatabaseModelImpl::ObjectType _eType ) + { + bool bSomeDocHasMacros = false; + + const OContentHelper_Impl& rContainerData( *_rModel.getObjectContainer( _eType ).get() ); + const ODefinitionContainer_Impl& rObjectDefinitions = dynamic_cast< const ODefinitionContainer_Impl& >( rContainerData ); + + try + { + Reference< XStorage > xContainerStorage( _rModel.getStorage( _eType, ElementModes::READWRITE ) ); + // note the READWRITE here: If the storage already existed before, then the OpenMode will + // be ignored, anyway. + // If the storage did not yet exist, then it will be created. If the database document + // is read-only, the OpenMode will be automatically downgraded to READ. Otherwise, + // the storage will in fact be created as READWRITE. While this is not strictly necessary + // for this particular use case here, it is required since the storage is *cached*, and + // later use cases will need the READWRITE mode. + + if ( xContainerStorage.is() ) + bSomeDocHasMacros = lcl_hasObjectWithMacros_throw( rObjectDefinitions, xContainerStorage ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + // be on the safe side: If we can't reliably determine whether there are macros, + // assume there actually are. Better this way, than the other way round. + bSomeDocHasMacros = true; + } + + return bSomeDocHasMacros; + } +} + +bool ODatabaseModelImpl::objectHasMacros( const Reference< XStorage >& _rxContainerStorage, const ::rtl::OUString& _rPersistentName ) +{ + OSL_PRECOND( _rxContainerStorage.is(), "ODatabaseModelImpl::objectHasMacros: this will crash!" ); + + bool bHasMacros = true; + try + { + if ( !_rxContainerStorage->hasByName( _rPersistentName ) ) + return false; + + Reference< XStorage > xObjectStor( _rxContainerStorage->openStorageElement( + _rPersistentName, ElementModes::READ ) ); + + bHasMacros = ::sfx2::DocumentMacroMode::storageHasMacros( xObjectStor ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return bHasMacros; +} + +void ODatabaseModelImpl::reset() +{ + m_bReadOnly = sal_False; + ::std::vector< TContentPtr > aEmptyContainers( 4 ); + m_aContainer.swap( aEmptyContainers ); + + if ( m_pStorageAccess ) + { + m_pStorageAccess->dispose(); + m_pStorageAccess->release(); + m_pStorageAccess = NULL; + } +} + +void SAL_CALL ODatabaseModelImpl::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException) +{ + Reference<XConnection> xCon(Source.Source,UNO_QUERY); + if ( xCon.is() ) + { + bool bStore = false; + OWeakConnectionArray::iterator aEnd = m_aConnections.end(); + for (OWeakConnectionArray::iterator i = m_aConnections.begin(); aEnd != i; ++i) + { + if ( xCon == i->get() ) + { + *i = OWeakConnection(); + bStore = true; + break; + } + } + + if ( bStore ) + commitRootStorage(); + } + else + { + OSL_ENSURE( false, "ODatabaseModelImpl::disposing: where does this come from?" ); + } +} + +void ODatabaseModelImpl::clearConnections() +{ + OWeakConnectionArray aConnections; + aConnections.swap( m_aConnections ); + + Reference< XConnection > xConn; + OWeakConnectionArray::iterator aEnd = aConnections.end(); + for ( OWeakConnectionArray::iterator i = aConnections.begin(); aEnd != i; ++i ) + { + xConn = *i; + if ( xConn.is() ) + { + try + { + xConn->close(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + + m_pSharedConnectionManager = NULL; + m_xSharedConnectionManager = NULL; +} + +void ODatabaseModelImpl::dispose() +{ + // dispose the data source and the model + try + { + Reference< XDataSource > xDS( m_xDataSource ); + ::comphelper::disposeComponent( xDS ); + + Reference< XModel > xModel( m_xModel ); + ::comphelper::disposeComponent( xModel ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + m_xDataSource = WeakReference<XDataSource>(); + m_xModel = WeakReference< XModel >(); + + ::std::vector<TContentPtr>::iterator aIter = m_aContainer.begin(); + ::std::vector<TContentPtr>::iterator aEnd = m_aContainer.end(); + for (;aIter != aEnd ; ++aIter) + { + if ( aIter->get() ) + (*aIter)->m_pDataSource = NULL; + } + m_aContainer.clear(); + + clearConnections(); + + m_xNumberFormatsSupplier = NULL; + + try + { + sal_Bool bCouldStore = commitEmbeddedStorage( true ); + // "true" means that committing the embedded storage should not trigger committing the root + // storage. This is because we are going to commit the root storage ourself, anyway + disposeStorages(); + if ( bCouldStore ) + commitRootStorage(); + + impl_switchToStorage_throw( NULL ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + if ( m_pStorageAccess ) + { + m_pStorageAccess->dispose(); + m_pStorageAccess->release(); + m_pStorageAccess = NULL; + } +} + +const Reference< XNumberFormatsSupplier > & ODatabaseModelImpl::getNumberFormatsSupplier() +{ + if (!m_xNumberFormatsSupplier.is()) + { + // the arguments : the locale of the current user + UserInformation aUserInfo; + Sequence< Any > aArguments(1); + aArguments.getArray()[0] <<= aUserInfo.getUserLanguage(); + + m_xNumberFormatsSupplier.set( + m_aContext.createComponentWithArguments( "com.sun.star.util.NumberFormatsSupplier", aArguments ), UNO_QUERY_THROW ); + DBG_ASSERT(m_xNumberFormatsSupplier.is(), "ODatabaseModelImpl::getNumberFormatsSupplier : could not instantiate the formats supplier !"); + } + return m_xNumberFormatsSupplier; +} + +void ODatabaseModelImpl::setDocFileLocation( const ::rtl::OUString& i_rLoadedFrom ) +{ + ENSURE_OR_THROW( i_rLoadedFrom.getLength(), "invalid URL" ); + m_sDocFileLocation = i_rLoadedFrom; +} + +void ODatabaseModelImpl::setResource( const ::rtl::OUString& i_rDocumentURL, const Sequence< PropertyValue >& _rArgs ) +{ + ENSURE_OR_THROW( i_rDocumentURL.getLength(), "invalid URL" ); + + ::comphelper::NamedValueCollection aMediaDescriptor( _rArgs ); +#if OSL_DEBUG_LEVEL > 0 + if ( aMediaDescriptor.has( "SalvagedFile" ) ) + { + ::rtl::OUString sSalvagedFile( aMediaDescriptor.getOrDefault( "SalvagedFile", ::rtl::OUString() ) ); + // If SalvagedFile is an empty string, this indicates "the document is being recovered, but i_rDocumentURL already + // is the real document URL, not the temporary document location" + if ( !sSalvagedFile.getLength() ) + sSalvagedFile = i_rDocumentURL; + + OSL_ENSURE( sSalvagedFile == i_rDocumentURL, "ODatabaseModelImpl::setResource: inconsistency!" ); + // nowadays, setResource should only be called with the logical URL of the document + } +#endif + + m_aMediaDescriptor = stripLoadArguments( aMediaDescriptor ); + + impl_switchToLogicalURL( i_rDocumentURL ); +} + +::comphelper::NamedValueCollection ODatabaseModelImpl::stripLoadArguments( const ::comphelper::NamedValueCollection& _rArguments ) +{ + OSL_ENSURE( !_rArguments.has( "Model" ), "ODatabaseModelImpl::stripLoadArguments: this is suspicious (1)!" ); + OSL_ENSURE( !_rArguments.has( "ViewName" ), "ODatabaseModelImpl::stripLoadArguments: this is suspicious (2)!" ); + + ::comphelper::NamedValueCollection aMutableArgs( _rArguments ); + aMutableArgs.remove( "Model" ); + aMutableArgs.remove( "ViewName" ); + return aMutableArgs; +} + +void ODatabaseModelImpl::disposeStorages() SAL_THROW(()) +{ + getDocumentStorageAccess()->disposeStorages(); +} + +Reference< XSingleServiceFactory > ODatabaseModelImpl::createStorageFactory() const +{ + return Reference< XSingleServiceFactory >( m_aContext.createComponent( "com.sun.star.embed.StorageFactory" ), UNO_QUERY_THROW ); +} + +void ODatabaseModelImpl::commitRootStorage() +{ + Reference< XStorage > xStorage( getOrCreateRootStorage() ); +#if OSL_DEBUG_LEVEL > 0 + bool bSuccess = +#endif + commitStorageIfWriteable_ignoreErrors( xStorage ); + OSL_ENSURE( bSuccess || !xStorage.is(), + "ODatabaseModelImpl::commitRootStorage: could commit the storage!" ); +} + +Reference< XStorage > ODatabaseModelImpl::getOrCreateRootStorage() +{ + if ( !m_xDocumentStorage.is() ) + { + Reference< XSingleServiceFactory> xStorageFactory = createStorageFactory(); + if ( xStorageFactory.is() ) + { + Any aSource; + aSource = m_aMediaDescriptor.get( "Stream" ); + if ( !aSource.hasValue() ) + aSource = m_aMediaDescriptor.get( "InputStream" ); + if ( !aSource.hasValue() && m_sDocFileLocation.getLength() ) + aSource <<= m_sDocFileLocation; + // TODO: shouldn't we also check URL? + + OSL_ENSURE( aSource.hasValue(), "ODatabaseModelImpl::getOrCreateRootStorage: no source to create the storage from!" ); + + if ( aSource.hasValue() ) + { + Sequence< Any > aStorageCreationArgs(2); + aStorageCreationArgs[0] = aSource; + aStorageCreationArgs[1] <<= ElementModes::READWRITE; + + Reference< XStorage > xDocumentStorage; + try + { + xDocumentStorage.set( xStorageFactory->createInstanceWithArguments( aStorageCreationArgs ), UNO_QUERY_THROW ); + } + catch( const Exception& ) + { + m_bDocumentReadOnly = sal_True; + aStorageCreationArgs[1] <<= ElementModes::READ; + try + { + xDocumentStorage.set( xStorageFactory->createInstanceWithArguments( aStorageCreationArgs ), UNO_QUERY_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + impl_switchToStorage_throw( xDocumentStorage ); + } + } + } + return m_xDocumentStorage.getTyped(); +} + +DocumentStorageAccess* ODatabaseModelImpl::getDocumentStorageAccess() +{ + if ( !m_pStorageAccess ) + { + m_pStorageAccess = new DocumentStorageAccess( *this ); + m_pStorageAccess->acquire(); + } + return m_pStorageAccess; +} + +void ODatabaseModelImpl::modelIsDisposing( const bool _wasInitialized, ResetModelAccess ) +{ + m_xModel = Reference< XModel >(); + + // Basic libraries and Dialog libraries are a model facet, though held at this impl class. + // They automatically dispose themself when the model they belong to is being disposed. + // So, to not be tempted to do anything with them, again, we reset them. + m_xBasicLibraries.clear(); + m_xDialogLibraries.clear(); + + m_bDocumentInitialized = _wasInitialized; +} + +Reference< XDocumentSubStorageSupplier > ODatabaseModelImpl::getDocumentSubStorageSupplier() +{ + return getDocumentStorageAccess(); +} + +bool ODatabaseModelImpl::commitEmbeddedStorage( bool _bPreventRootCommits ) +{ + return getDocumentStorageAccess()->commitEmbeddedStorage( _bPreventRootCommits ); +} + +bool ODatabaseModelImpl::commitStorageIfWriteable_ignoreErrors( const Reference< XStorage >& _rxStorage ) SAL_THROW(()) +{ + bool bSuccess = false; + try + { + bSuccess = tools::stor::commitStorageIfWriteable( _rxStorage ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return bSuccess; +} + +void ODatabaseModelImpl::setModified( sal_Bool _bModified ) +{ + if ( isModifyLocked() ) + return; + + try + { + Reference< XModifiable > xModi( m_xModel.get(), UNO_QUERY ); + if ( xModi.is() ) + xModi->setModified( _bModified ); + else + m_bModified = _bModified; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +Reference<XDataSource> ODatabaseModelImpl::getOrCreateDataSource() +{ + Reference<XDataSource> xDs = m_xDataSource; + if ( !xDs.is() ) + { + xDs = new ODatabaseSource(this); + m_xDataSource = xDs; + } + return xDs; +} + +Reference< XModel> ODatabaseModelImpl::getModel_noCreate() const +{ + return m_xModel; +} + +Reference< XModel > ODatabaseModelImpl::createNewModel_deliverOwnership( bool _bInitialize ) +{ + Reference< XModel > xModel( m_xModel ); + OSL_PRECOND( !xModel.is(), "ODatabaseModelImpl::createNewModel_deliverOwnership: not to be called if there already is a model!" ); + if ( !xModel.is() ) + { + bool bHadModelBefore = m_bDocumentInitialized; + + xModel = ODatabaseDocument::createDatabaseDocument( this, ODatabaseDocument::FactoryAccess() ); + m_xModel = xModel; + + try + { + Reference< XSet > xModelCollection; + if ( m_aContext.createComponent( "com.sun.star.frame.GlobalEventBroadcaster", xModelCollection ) ) + xModelCollection->insert( makeAny( xModel ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + if ( bHadModelBefore ) + { + // do an attachResources + // In case the document is loaded regularly, this is not necessary, as our loader will do it. + // However, in case that the document is implicitly created by asking the data source for the document, + // then nobody would call the doc's attachResource. So, we do it here, to ensure it's in a proper + // state, fires all events, and so on. + // #i105505# / 2009-10-02 / frank.schoenheit@sun.com + xModel->attachResource( xModel->getURL(), m_aMediaDescriptor.getPropertyValues() ); + } + + if ( _bInitialize ) + { + try + { + Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW ); + xLoad->initNew(); + } + catch( RuntimeException& ) { throw; } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + return xModel; +} + +oslInterlockedCount SAL_CALL ODatabaseModelImpl::acquire() +{ + return osl_incrementInterlockedCount(&m_refCount); +} + +oslInterlockedCount SAL_CALL ODatabaseModelImpl::release() +{ + if ( osl_decrementInterlockedCount(&m_refCount) == 0 ) + { + acquire(); // prevent multiple releases + m_pDBContext->removeFromTerminateListener(*this); + dispose(); + m_pDBContext->storeTransientProperties(*this); + revokeDataSource(); + delete this; + return 0; + } + return m_refCount; +} + +void ODatabaseModelImpl::commitStorages() SAL_THROW(( IOException, RuntimeException )) +{ + getDocumentStorageAccess()->commitStorages(); +} + +Reference< XStorage > ODatabaseModelImpl::getStorage( const ObjectType _eType, const sal_Int32 _nDesiredMode ) +{ + return getDocumentStorageAccess()->getDocumentSubStorage( getObjectContainerStorageName( _eType ), _nDesiredMode ); +} + +const AsciiPropertyValue* ODatabaseModelImpl::getDefaultDataSourceSettings() +{ + static const AsciiPropertyValue aKnownSettings[] = + { + // known JDBC settings + AsciiPropertyValue( "JavaDriverClass", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "JavaDriverClassPath", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "IgnoreCurrency", makeAny( (sal_Bool)sal_False ) ), + // known settings for file-based drivers + AsciiPropertyValue( "Extension", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "CharSet", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "HeaderLine", makeAny( (sal_Bool)sal_True ) ), + AsciiPropertyValue( "FieldDelimiter", makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "," ) ) ) ), + AsciiPropertyValue( "StringDelimiter", makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "\"" ) ) ) ), + AsciiPropertyValue( "DecimalDelimiter", makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "." ) ) ) ), + AsciiPropertyValue( "ThousandDelimiter", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "ShowDeleted", makeAny( (sal_Bool)sal_False ) ), + // known ODBC settings + AsciiPropertyValue( "SystemDriverSettings", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "UseCatalog", makeAny( (sal_Bool)sal_False ) ), + AsciiPropertyValue( "TypeInfoSettings", makeAny( Sequence< Any >()) ), + // settings related to auto increment handling + AsciiPropertyValue( "AutoIncrementCreation", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "AutoRetrievingStatement", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "IsAutoRetrievingEnabled", makeAny( (sal_Bool)sal_False ) ), + // known Adabas D driver setting + AsciiPropertyValue( "ShutdownDatabase", makeAny( (sal_Bool)sal_False ) ), + AsciiPropertyValue( "DataCacheSizeIncrement", makeAny( (sal_Int32)20 ) ), + AsciiPropertyValue( "DataCacheSize", makeAny( (sal_Int32)20 ) ), + AsciiPropertyValue( "ControlUser", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "ControlPassword", makeAny( ::rtl::OUString() ) ), + // known LDAP driver settings + AsciiPropertyValue( "HostName", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "PortNumber", makeAny( (sal_Int32)389 ) ), + AsciiPropertyValue( "BaseDN", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "MaxRowCount", makeAny( (sal_Int32)100 ) ), + // known MySQLNative driver settings + AsciiPropertyValue( "LocalSocket", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "NamedPipe", makeAny( ::rtl::OUString() ) ), + // misc known driver settings + AsciiPropertyValue( "ParameterNameSubstitution", makeAny( (sal_Bool)sal_False ) ), + AsciiPropertyValue( "AddIndexAppendix", makeAny( (sal_Bool)sal_True ) ), + AsciiPropertyValue( "IgnoreDriverPrivileges", makeAny( (sal_Bool)sal_True ) ), + AsciiPropertyValue( "ImplicitCatalogRestriction", ::cppu::UnoType< ::rtl::OUString >::get() ), + AsciiPropertyValue( "ImplicitSchemaRestriction", ::cppu::UnoType< ::rtl::OUString >::get() ), + AsciiPropertyValue( "PrimaryKeySupport", ::cppu::UnoType< sal_Bool >::get() ), + AsciiPropertyValue( "ShowColumnDescription", makeAny( (sal_Bool)sal_False ) ), + // known SDB level settings + AsciiPropertyValue( "NoNameLengthLimit", makeAny( (sal_Bool)sal_False ) ), + AsciiPropertyValue( "AppendTableAliasName", makeAny( (sal_Bool)sal_False ) ), + AsciiPropertyValue( "GenerateASBeforeCorrelationName", makeAny( (sal_Bool)sal_True ) ), + AsciiPropertyValue( "ColumnAliasInOrderBy", makeAny( (sal_Bool)sal_True ) ), + AsciiPropertyValue( "EnableSQL92Check", makeAny( (sal_Bool)sal_False ) ), + AsciiPropertyValue( "BooleanComparisonMode", makeAny( BooleanComparisonMode::EQUAL_INTEGER ) ), + AsciiPropertyValue( "TableTypeFilterMode", makeAny( (sal_Int32)3 ) ), + AsciiPropertyValue( "RespectDriverResultSetType", makeAny( (sal_Bool)sal_False ) ), + AsciiPropertyValue( "UseSchemaInSelect", makeAny( (sal_Bool)sal_True ) ), + AsciiPropertyValue( "UseCatalogInSelect", makeAny( (sal_Bool)sal_True ) ), + AsciiPropertyValue( "EnableOuterJoinEscape", makeAny( (sal_Bool)sal_True ) ), + AsciiPropertyValue( "PreferDosLikeLineEnds", makeAny( (sal_Bool)sal_False ) ), + AsciiPropertyValue( "FormsCheckRequiredFields", makeAny( (sal_Bool)sal_True ) ), + AsciiPropertyValue( "EscapeDateTime", makeAny( (sal_Bool)sal_True ) ), + + // known services to handle database tasks + AsciiPropertyValue( "TableAlterationServiceName", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "TableRenameServiceName", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "ViewAlterationServiceName", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "ViewAccessServiceName", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "CommandDefinitions", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "Forms", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "Reports", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "KeyAlterationServiceName", makeAny( ::rtl::OUString() ) ), + AsciiPropertyValue( "IndexAlterationServiceName", makeAny( ::rtl::OUString() ) ), + + AsciiPropertyValue() + }; + return aKnownSettings; +} + +TContentPtr& ODatabaseModelImpl::getObjectContainer( ObjectType _eType ) +{ + OSL_PRECOND( _eType >= E_FORM && _eType <= E_TABLE, "ODatabaseModelImpl::getObjectContainer: illegal index!" ); + TContentPtr& rContentPtr = m_aContainer[ _eType ]; + + if ( !rContentPtr.get() ) + { + rContentPtr = TContentPtr( new ODefinitionContainer_Impl ); + rContentPtr->m_pDataSource = this; + rContentPtr->m_aProps.aTitle = lcl_getContainerStorageName_throw( _eType ); + } + return rContentPtr; +} + +void ODatabaseModelImpl::revokeDataSource() const +{ + if ( m_pDBContext && m_sDocumentURL.getLength() ) + m_pDBContext->revokeDatabaseDocument( *this ); +} + +bool ODatabaseModelImpl::adjustMacroMode_AutoReject() +{ + return m_aMacroMode.adjustMacroMode( NULL ); +} + +bool ODatabaseModelImpl::checkMacrosOnLoading() +{ + Reference< XInteractionHandler > xInteraction; + xInteraction = m_aMediaDescriptor.getOrDefault( "InteractionHandler", xInteraction ); + return m_aMacroMode.checkMacrosOnLoading( xInteraction ); +} + +void ODatabaseModelImpl::resetMacroExecutionMode() +{ + m_aMacroMode = ::sfx2::DocumentMacroMode( *this ); +} + +Reference< XStorageBasedLibraryContainer > ODatabaseModelImpl::getLibraryContainer( bool _bScript ) +{ + Reference< XStorageBasedLibraryContainer >& rxContainer( _bScript ? m_xBasicLibraries : m_xDialogLibraries ); + if ( rxContainer.is() ) + return rxContainer; + + Reference< XStorageBasedDocument > xDocument( getModel_noCreate(), UNO_QUERY_THROW ); + // this is only to be called if there already exists a document model - in fact, it is + // to be called by the document model only + + try + { + Reference< XStorageBasedLibraryContainer > (*Factory)( const Reference< XComponentContext >&, const Reference< XStorageBasedDocument >&) + = _bScript ? &DocumentScriptLibraryContainer::create : &DocumentDialogLibraryContainer::create; + + rxContainer.set( + (*Factory)( m_aContext.getUNOContext(), xDocument ), + UNO_QUERY_THROW + ); + } + catch( const RuntimeException& ) + { + throw; + } + catch( const Exception& ) + { + throw WrappedTargetRuntimeException( + ::rtl::OUString(), + xDocument, + ::cppu::getCaughtException() + ); + } + return rxContainer; +} + +void ODatabaseModelImpl::storeLibraryContainersTo( const Reference< XStorage >& _rxToRootStorage ) +{ + if ( m_xBasicLibraries.is() ) + m_xBasicLibraries->storeLibrariesToStorage( _rxToRootStorage ); + + if ( m_xDialogLibraries.is() ) + m_xDialogLibraries->storeLibrariesToStorage( _rxToRootStorage ); +} + +Reference< XStorage > ODatabaseModelImpl::switchToStorage( const Reference< XStorage >& _rxNewRootStorage ) +{ + if ( !_rxNewRootStorage.is() ) + throw IllegalArgumentException(); + + return impl_switchToStorage_throw( _rxNewRootStorage ); +} + +namespace +{ + void lcl_modifyListening( ::sfx2::IModifiableDocument& _rDocument, + const Reference< XStorage >& _rxStorage, ::rtl::Reference< ::sfx2::DocumentStorageModifyListener >& _inout_rListener, + ::osl::SolarMutex& _rMutex, bool _bListen ) + { + Reference< XModifiable > xModify( _rxStorage, UNO_QUERY ); + OSL_ENSURE( xModify.is() || !_rxStorage.is(), "lcl_modifyListening: storage can't notify us!" ); + + if ( xModify.is() && !_bListen && _inout_rListener.is() ) + { + xModify->removeModifyListener( _inout_rListener.get() ); + } + + if ( _inout_rListener.is() ) + { + _inout_rListener->dispose(); + _inout_rListener = NULL; + } + + if ( xModify.is() && _bListen ) + { + _inout_rListener = new ::sfx2::DocumentStorageModifyListener( _rDocument, _rMutex ); + xModify->addModifyListener( _inout_rListener.get() ); + } + } +} + +namespace +{ + static void lcl_rebaseScriptStorage_throw( const Reference< XStorageBasedLibraryContainer >& _rxContainer, + const Reference< XStorage >& _rxNewRootStorage ) + { + if ( _rxContainer.is() ) + { + if ( _rxNewRootStorage.is() ) + _rxContainer->setRootStorage( _rxNewRootStorage ); +// else + // TODO: what to do here? dispose the container? + } + } +} + +Reference< XStorage > ODatabaseModelImpl::impl_switchToStorage_throw( const Reference< XStorage >& _rxNewRootStorage ) +{ + // stop listening for modifications at the old storage + lcl_modifyListening( *this, m_xDocumentStorage.getTyped(), m_pStorageModifyListener, m_aMutexFacade, false ); + + // set new storage + m_xDocumentStorage.reset( _rxNewRootStorage, SharedStorage::TakeOwnership ); + + // start listening for modifications + lcl_modifyListening( *this, m_xDocumentStorage.getTyped(), m_pStorageModifyListener, m_aMutexFacade, true ); + + // forward new storage to Basic and Dialog library containers + lcl_rebaseScriptStorage_throw( m_xBasicLibraries, m_xDocumentStorage.getTyped() ); + lcl_rebaseScriptStorage_throw( m_xDialogLibraries, m_xDocumentStorage.getTyped() ); + + m_bReadOnly = !tools::stor::storageIsWritable_nothrow( m_xDocumentStorage.getTyped() ); + // TODO: our data source, if it exists, must broadcast the change of its ReadOnly property + + return m_xDocumentStorage.getTyped(); +} + +void ODatabaseModelImpl::impl_switchToLogicalURL( const ::rtl::OUString& i_rDocumentURL ) +{ + if ( i_rDocumentURL == m_sDocumentURL ) + return; + + const ::rtl::OUString sOldURL( m_sDocumentURL ); + // update our name, if necessary + if ( ( m_sName == m_sDocumentURL ) // our name is our old URL + || ( !m_sName.getLength() ) // we do not have a name, yet (i.e. are not registered at the database context) + ) + { + INetURLObject aURL( i_rDocumentURL ); + if ( aURL.GetProtocol() != INET_PROT_NOT_VALID ) + { + m_sName = i_rDocumentURL; + // TODO: our data source must broadcast the change of the Name property + } + } + + // remember URL + m_sDocumentURL = i_rDocumentURL; + + // update our location, if necessary + if ( m_sDocFileLocation.getLength() == 0 ) + m_sDocFileLocation = m_sDocumentURL; + + // register at the database context, or change registration + if ( m_pDBContext ) + { + if ( sOldURL.getLength() ) + m_pDBContext->databaseDocumentURLChange( sOldURL, m_sDocumentURL ); + else + m_pDBContext->registerDatabaseDocument( *this ); + } +} + +::rtl::OUString ODatabaseModelImpl::getObjectContainerStorageName( const ObjectType _eType ) +{ + return lcl_getContainerStorageName_throw( _eType ); +} + +sal_Int16 ODatabaseModelImpl::getCurrentMacroExecMode() const +{ + sal_Int16 nCurrentMode = MacroExecMode::NEVER_EXECUTE; + try + { + nCurrentMode = m_aMediaDescriptor.getOrDefault( "MacroExecutionMode", nCurrentMode ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return nCurrentMode; +} + +sal_Bool ODatabaseModelImpl::setCurrentMacroExecMode( sal_uInt16 nMacroMode ) +{ + m_aMediaDescriptor.put( "MacroExecutionMode", nMacroMode ); + return sal_True; +} + +::rtl::OUString ODatabaseModelImpl::getDocumentLocation() const +{ + return getURL(); + // formerly, we returned getDocFileLocation here, which is the location of the file from which we + // recovered the "real" document. + // However, during CWS autorecovery evolving, we clarified (with MAV/MT) the role of XModel::getURL and + // XStorable::getLocation. In this course, we agreed that for a macro security check, the *document URL* + // (not the recovery file URL) is to be used: The recovery file lies in the backup folder, and by definition, + // this folder is considered to be secure. So, the document URL needs to be used to decide about the security. +} + +Reference< XStorage > ODatabaseModelImpl::getZipStorageToSign() +{ + // we do not support signing the scripting storages, so we're allowed to + // return <NULL/> here. + return Reference< XStorage >(); +} + +ODatabaseModelImpl::EmbeddedMacros ODatabaseModelImpl::determineEmbeddedMacros() +{ + if ( !m_aEmbeddedMacros ) + { + if ( ::sfx2::DocumentMacroMode::storageHasMacros( const_cast< ODatabaseModelImpl* >( this )->getOrCreateRootStorage() ) ) + { + m_aEmbeddedMacros.reset( eDocumentWideMacros ); + } + else if ( lcl_hasObjectsWithMacros_nothrow( const_cast< ODatabaseModelImpl& >( *this ), E_FORM ) + || lcl_hasObjectsWithMacros_nothrow( const_cast< ODatabaseModelImpl& >( *this ), E_REPORT ) + ) + { + m_aEmbeddedMacros.reset( eSubDocumentMacros ); + } + else + { + m_aEmbeddedMacros.reset( eNoMacros ); + } + } + return *m_aEmbeddedMacros; +} + +sal_Bool ODatabaseModelImpl::documentStorageHasMacros() const +{ + const_cast< ODatabaseModelImpl* >( this )->determineEmbeddedMacros(); + return ( *m_aEmbeddedMacros != eNoMacros ); +} + +Reference< XEmbeddedScripts > ODatabaseModelImpl::getEmbeddedDocumentScripts() const +{ + return Reference< XEmbeddedScripts >( getModel_noCreate(), UNO_QUERY ); +} + +sal_Int16 ODatabaseModelImpl::getScriptingSignatureState() +{ + // no support for signatures at the moment + return SIGNATURESTATE_NOSIGNATURES; +} + +sal_Bool ODatabaseModelImpl::hasTrustedScriptingSignature( sal_Bool /*bAllowUIToAddAuthor*/ ) +{ + // no support for signatures at the moment + return sal_False; +} + +void ODatabaseModelImpl::showBrokenSignatureWarning( const Reference< XInteractionHandler >& /*_rxInteraction*/ ) const +{ + OSL_ENSURE( false, "ODatabaseModelImpl::showBrokenSignatureWarning: signatures can't be broken - we do not support them!" ); +} + +void ODatabaseModelImpl::storageIsModified() +{ + setModified( sal_True ); +} + +ModelDependentComponent::ModelDependentComponent( const ::rtl::Reference< ODatabaseModelImpl >& _model ) + :m_pImpl( _model ) + ,m_aMutex( _model->getSharedMutex() ) +{ +} + +ModelDependentComponent::~ModelDependentComponent() +{ +} + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/ModelImpl.hxx b/dbaccess/source/core/dataaccess/ModelImpl.hxx new file mode 100644 index 000000000000..223654c38b85 --- /dev/null +++ b/dbaccess/source/core/dataaccess/ModelImpl.hxx @@ -0,0 +1,644 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 _DBA_COREDATAACCESS_MODELIMPL_HXX_ +#define _DBA_COREDATAACCESS_MODELIMPL_HXX_ + +#include "apitools.hxx" +#include "bookmarkcontainer.hxx" +#include "ContentHelper.hxx" +#include "core_resource.hxx" +#include "documentevents.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/container/XContainerListener.hpp> +#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp> +#include <com/sun/star/document/XEventListener.hpp> +#include <com/sun/star/document/XStorageBasedDocument.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/embed/XTransactionListener.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/lang/NotInitializedException.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/sdb/XBookmarksSupplier.hpp> +#include <com/sun/star/sdb/XCompletedConnection.hpp> +#include <com/sun/star/sdb/XFormDocumentsSupplier.hpp> +#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp> +#include <com/sun/star/sdb/XReportDocumentsSupplier.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/sdbc/XIsolatedConnection.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/util/XCloseable.hpp> +#include <com/sun/star/util/XFlushable.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/util/XRefreshable.hpp> +#include <com/sun/star/sdb/XDocumentDataSource.hpp> +#include <com/sun/star/frame/DoubleInitializationException.hpp> +/** === end UNO includes === **/ + +#include <comphelper/broadcasthelper.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/proparrhlp.hxx> +#include <comphelper/sharedmutex.hxx> +#include <connectivity/CommonTools.hxx> +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/weakref.hxx> +#include <sfx2/docmacromode.hxx> +#include <sfx2/docstoragemodifylistener.hxx> +#include <tools/string.hxx> +#include <unotools/sharedunocomponent.hxx> +#include <osl/mutex.hxx> +#include <rtl/ref.hxx> + +#include <memory> + +namespace comphelper +{ + class NamedValueCollection; +} + +//........................................................................ +namespace dbaccess +{ +//........................................................................ + +typedef ::com::sun::star::uno::WeakReference< ::com::sun::star::sdbc::XConnection > OWeakConnection; +typedef std::vector< OWeakConnection > OWeakConnectionArray; + +struct AsciiPropertyValue +{ + // note: the canonic member order would be AsciiName / DefaultValue, but + // this crashes on unxlngi6.pro, since there's a bug which somehow results in + // getDefaultDataSourceSettings returning corrupted Any instances then. + ::com::sun::star::uno::Any DefaultValue; + const sal_Char* AsciiName; + const ::com::sun::star::uno::Type& ValueType; + + AsciiPropertyValue() + :DefaultValue( ) + ,AsciiName( NULL ) + ,ValueType( ::cppu::UnoType< ::cppu::UnoVoidType >::get() ) + { + } + + AsciiPropertyValue( const sal_Char* _pAsciiName, const ::com::sun::star::uno::Any& _rDefaultValue ) + :DefaultValue( _rDefaultValue ) + ,AsciiName( _pAsciiName ) + ,ValueType( _rDefaultValue.getValueType() ) + { + OSL_ENSURE( ValueType.getTypeClass() != ::com::sun::star::uno::TypeClass_VOID, + "AsciiPropertyValue::AsciiPropertyValue: NULL values not allowed here, use the other CTOR for this!" ); + } + AsciiPropertyValue( const sal_Char* _pAsciiName, const ::com::sun::star::uno::Type& _rValeType ) + :DefaultValue() + ,AsciiName( _pAsciiName ) + ,ValueType( _rValeType ) + { + OSL_ENSURE( ValueType.getTypeClass() != ::com::sun::star::uno::TypeClass_VOID, + "AsciiPropertyValue::AsciiPropertyValue: VOID property values not supported!" ); + } +}; + +class ODatabaseContext; +class OSharedConnectionManager; + +//============================================================ +//= VosMutexFacade +//============================================================ +/** a class which provides an IMutex interface to an OSL-based mutex +*/ +class VosMutexFacade : public ::osl::SolarMutex +{ +public: + /** beware of life time: the mutex you pass here must live as least as long + as the VosMutexFacade instance lives. + */ + VosMutexFacade( ::osl::Mutex& _rMutex ); + + // IMutex + virtual void SAL_CALL acquire(); + virtual sal_Bool SAL_CALL tryToAcquire(); + virtual void SAL_CALL release(); + +private: + ::osl::Mutex& m_rMutex; +}; + + +//============================================================ +//= ODatabaseModelImpl +//============================================================ +typedef ::utl::SharedUNOComponent< ::com::sun::star::embed::XStorage > SharedStorage; + +class ODatabaseContext; +class DocumentStorageAccess; +class OSharedConnectionManager; +class ODatabaseModelImpl :public ::rtl::IReference + ,public ::sfx2::IMacroDocumentAccess + ,public ::sfx2::IModifiableDocument +{ +public: + enum ObjectType + { + E_FORM = 0, + E_REPORT = 1, + E_QUERY = 2, + E_TABLE = 3 + }; + + enum EmbeddedMacros + { + // the database document (storage) itself contains macros + eDocumentWideMacros, + // there are sub document( storage)s containing macros + eSubDocumentMacros, + // there are no known macro( storage)s + eNoMacros + }; + +private: + OModuleClient m_aModuleClient; + ::com::sun::star::uno::WeakReference< ::com::sun::star::frame::XModel > m_xModel; + ::com::sun::star::uno::WeakReference< ::com::sun::star::sdbc::XDataSource > m_xDataSource; + + DocumentStorageAccess* m_pStorageAccess; + ::comphelper::SharedMutex m_aMutex; + VosMutexFacade m_aMutexFacade; + ::std::vector< TContentPtr > m_aContainer; // one for each ObjectType + ::sfx2::DocumentMacroMode m_aMacroMode; + sal_Int16 m_nImposedMacroExecMode; + + ::com::sun::star::uno::Reference< ::com::sun::star::script::XStorageBasedLibraryContainer > m_xBasicLibraries; + ::com::sun::star::uno::Reference< ::com::sun::star::script::XStorageBasedLibraryContainer > m_xDialogLibraries; + + SharedStorage m_xDocumentStorage; + ::rtl::Reference< ::sfx2::DocumentStorageModifyListener > m_pStorageModifyListener; + ODatabaseContext* m_pDBContext; + DocumentEventsData m_aDocumentEvents; + + ::comphelper::NamedValueCollection m_aMediaDescriptor; + /// the URL the document was loaded from + ::rtl::OUString m_sDocFileLocation; + + oslInterlockedCount m_refCount; + + /// do we have any object (forms/reports) which contains macros? + ::boost::optional< EmbeddedMacros > m_aEmbeddedMacros; + + /// true if setting the Modified flag of the document is currently locked + bool m_bModificationLock; + + /// true if and only if a database document existed previously (though meanwhile disposed), and was already initialized + bool m_bDocumentInitialized; + + /** the URL which the document should report as it's URL + + This might differ from ->m_sDocFileLocation in case the document was loaded + as part of a crash recovery process. In this case, ->m_sDocFileLocation points to + the temporary file where the DB had been saved to, after a crash. + ->m_sDocumentURL then is the URL of the document which actually had + been recovered. + */ + ::rtl::OUString m_sDocumentURL; + +public: + OWeakConnectionArray m_aConnections; + const ::comphelper::ComponentContext m_aContext; + +public: + ::com::sun::star::uno::WeakReference< ::com::sun::star::container::XNameAccess > m_xCommandDefinitions; + ::com::sun::star::uno::WeakReference< ::com::sun::star::container::XNameAccess > m_xTableDefinitions; + + ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatsSupplier > + m_xNumberFormatsSupplier; + ::rtl::OUString m_sConnectURL; + ::rtl::OUString m_sName; // transient, our creator has to tell us the title + ::rtl::OUString m_sUser; + ::rtl::OUString m_aPassword; // transient ! + ::rtl::OUString m_sFailedPassword; + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue> + m_aLayoutInformation; + sal_Int32 m_nLoginTimeout; + sal_Bool m_bReadOnly : 1; + sal_Bool m_bPasswordRequired : 1; + sal_Bool m_bSuppressVersionColumns : 1; + sal_Bool m_bModified : 1; + sal_Bool m_bDocumentReadOnly : 1; + ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyAccess > + m_xSettings; + ::com::sun::star::uno::Sequence< ::rtl::OUString > m_aTableFilter; + ::com::sun::star::uno::Sequence< ::rtl::OUString > m_aTableTypeFilter; + OSharedConnectionManager* m_pSharedConnectionManager; + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener > + m_xSharedConnectionManager; + sal_uInt16 m_nControllerLockCount; + + void reset(); + + /** determines whether the database document has an embedded data storage + */ + inline bool isEmbeddedDatabase() const { return ( m_sConnectURL.compareToAscii( "sdbc:embedded:", 14 ) == 0 ); } + + /** stores the embedded storage ("database") + + @param _bPreventRootCommits + Normally, committing the embedded storage results in also commiting the root storage + - this is an automatism for data safety reasons. + If you pass <TRUE/> here, committing the root storage is prevented for this particular + call. + @return <TRUE/> if the storage could be commited, otherwise <FALSE/> + */ + bool commitEmbeddedStorage( bool _bPreventRootCommits = false ); + + /// commits all sub storages + void commitStorages() + SAL_THROW(( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException )); + + ODatabaseModelImpl( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxFactory, + ODatabaseContext& _pDBContext + ); + virtual ~ODatabaseModelImpl(); + + ODatabaseModelImpl( + const ::rtl::OUString& _rRegistrationName, + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxFactory, + ODatabaseContext& _rDBContext + ); + + // XEventListener + void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw(::com::sun::star::uno::RuntimeException); + + void setModified( sal_Bool bModified ); + + void dispose(); + + inline ::rtl::OUString getURL() const { return m_sDocumentURL; } + inline ::rtl::OUString getDocFileLocation() const { return m_sDocFileLocation; } + + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > + getStorage( + const ObjectType _eType, const sal_Int32 _nDesiredMode = ::com::sun::star::embed::ElementModes::READWRITE ); + +// helper + const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatsSupplier >& + getNumberFormatsSupplier(); + + DocumentEventsData& + getDocumentEvents() { return m_aDocumentEvents; } + + const ::comphelper::NamedValueCollection& + getMediaDescriptor() const { return m_aMediaDescriptor; } + + void setResource( + const ::rtl::OUString& _rURL, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& _rArgs + ); + void setDocFileLocation( + const ::rtl::OUString& i_rLoadedFrom + ); + + static ::comphelper::NamedValueCollection + stripLoadArguments( const ::comphelper::NamedValueCollection& _rArguments ); + +// other stuff + void flushTables(); + + // disposes all elements in m_aStorages, and clears it + void disposeStorages() SAL_THROW(()); + + /// creates a ->com::sun::star::embed::StorageFactory + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XSingleServiceFactory > + createStorageFactory() const; + + /// commits our storage + void commitRootStorage(); + + /// commits a given storage if it's not readonly, ignoring (but asserting) all errors + static bool commitStorageIfWriteable_ignoreErrors( + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& _rxStorage + ) + SAL_THROW(()); + + void clearConnections(); + + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > getOrCreateRootStorage(); + inline ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > getRootStorage() const { return m_xDocumentStorage.getTyped(); } + inline void resetRootStroage() { impl_switchToStorage_throw( NULL ); } + + /** returns the data source. If it doesn't exist it will be created + */ + ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XDataSource> getOrCreateDataSource(); + + /** returns the model, if there already exists one + */ + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel > getModel_noCreate() const; + + /** returns a new ->ODatabaseDocument + + @param _bInitializeIfNecessary + calls XLoadable::initNew on the newly created model, if necessary + + @precond + No ->ODatabaseDocument exists so far + + @seealso + getModel_noCreate + */ + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel > createNewModel_deliverOwnership( bool _bInitialize ); + + struct ResetModelAccess { friend class ODatabaseDocument; private: ResetModelAccess() { } }; + + /** resets the model to NULL + + Only to be called when the model is being disposed + */ + void modelIsDisposing( const bool _wasInitialized, ResetModelAccess ); + + bool hadInitializedDocument() const { return m_bDocumentInitialized; } + + DocumentStorageAccess* + getDocumentStorageAccess(); + + ::com::sun::star::uno::Reference< ::com::sun::star::document::XDocumentSubStorageSupplier > + getDocumentSubStorageSupplier(); + + inline const ::comphelper::SharedMutex& getSharedMutex() const { return m_aMutex; } + + /** @see osl_incrementInterlockedCount. + */ + virtual oslInterlockedCount SAL_CALL acquire(); + + /** @see osl_decrementInterlockedCount. + */ + virtual oslInterlockedCount SAL_CALL release(); + + /// returns a all known data source settings, including their default values + static const AsciiPropertyValue* getDefaultDataSourceSettings(); + + /** retrieves the requested container of objects (forms/reports/tables/queries) + */ + TContentPtr& getObjectContainer( const ObjectType _eType ); + + /** returns the name of the storage which is used to stored objects of the given type, if applicable + */ + static ::rtl::OUString + getObjectContainerStorageName( const ObjectType _eType ); + + /** revokes the data source registration at the database context + */ + void revokeDataSource() const; + + /** determines whether a given object storage contains macros + */ + static bool objectHasMacros( + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& _rxContainerStorage, + const ::rtl::OUString& _rPersistentName + ); + + /** determines which kind of embedded macros are present in the document + */ + EmbeddedMacros determineEmbeddedMacros(); + + /** checks our document's macro execution mode, using the interaction handler as supplied with our + load arguments + */ + bool checkMacrosOnLoading(); + + /** adjusts our document's macro execution mode, without using any UI, assuming the user + would reject execution of macros, if she would have been asked. + + If checkMacrosOnLoading has been called before (and thus the macro execution mode + is already adjusted), then the current execution mode is simply returned. + + @return + whether or not macro execution is allowed + */ + bool adjustMacroMode_AutoReject(); + + /** resets our macro execute mode, so next time the checkMacrosOnLoading is called, it will + behave as if it has never been called before + */ + void resetMacroExecutionMode(); + + /** ensures that ->m_xBasicLibraries resp. m_xDialogLibraries exists + + @return + the requested library container. Is never <NULL/>. + + @throws RuntimeException + if something does wrong, which indicates a server error in the installation + */ + ::com::sun::star::uno::Reference< ::com::sun::star::script::XStorageBasedLibraryContainer > + getLibraryContainer( bool _bScript ); + + /** lets our library containers store themself into the given root storage + */ + void storeLibraryContainersTo( const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& _rxToRootStorage ); + + /** rebases the document to the given storage + + No actual committing, copying, saving, whatsoever happens. The storage is just remembered as the documents + new storage, nothing more. + + @throws ::com::sun::star::lang::IllegalArgumentException + if the given storage is <NULL/> + @throws ::com::sun::star::lang::RuntimeException + if any of the invoked operations does so + */ + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > + switchToStorage( + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& _rxNewRootStorage + ); + + /** returns the macro mode imposed by an external instance, which passed it to attachResource + */ + sal_Int16 getImposedMacroExecMode() const + { + return m_nImposedMacroExecMode; + } + void setImposedMacroExecMode( const sal_Int16 _nMacroMode ) + { + m_nImposedMacroExecMode = _nMacroMode; + } + +public: + // IMacroDocumentAccess overridables + virtual sal_Int16 getCurrentMacroExecMode() const; + virtual sal_Bool setCurrentMacroExecMode( sal_uInt16 ); + virtual ::rtl::OUString getDocumentLocation() const; + virtual ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > getZipStorageToSign(); + virtual sal_Bool documentStorageHasMacros() const; + virtual ::com::sun::star::uno::Reference< ::com::sun::star::document::XEmbeddedScripts > getEmbeddedDocumentScripts() const; + virtual sal_Int16 getScriptingSignatureState(); + virtual sal_Bool hasTrustedScriptingSignature( sal_Bool bAllowUIToAddAuthor ); + virtual void showBrokenSignatureWarning( const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& _rxInteraction ) const; + + // IModifiableDocument + virtual void storageIsModified(); + + // don't use directly, use the ModifyLock class instead + void lockModify() { m_bModificationLock = true; } + void unlockModify() { m_bModificationLock = false; } + bool isModifyLocked() const { return m_bModificationLock; } + +private: + void impl_construct_nothrow(); + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > + impl_switchToStorage_throw( const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& _rxNewRootStorage ); + + /** switches to the given document URL, which denotes the logical URL of the document, not necessariy the + URL where the doc was loaded/recovered from + */ + void impl_switchToLogicalURL( + const ::rtl::OUString& i_rDocumentURL + ); + +}; + +/** a small base class for UNO components whose functionality depends on a ODatabaseModelImpl +*/ +class ModelDependentComponent +{ +protected: + ::rtl::Reference< ODatabaseModelImpl > m_pImpl; + mutable ::comphelper::SharedMutex m_aMutex; + +protected: + ModelDependentComponent( const ::rtl::Reference< ODatabaseModelImpl >& _model ); + virtual ~ModelDependentComponent(); + + /** returns the component itself + */ + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > getThis() const = 0; + + inline ::osl::Mutex& getMutex() const + { + return m_aMutex; + } + +public: + struct GuardAccess { friend class ModelMethodGuard; private: GuardAccess() { } }; + + /** returns the mutex used for thread safety + + @throws ::com::sun::star::lang::DisposedException + if m_pImpl is <NULL/>. Usually, you will set this member in your derived + component's <code>dispose</code> method to <NULL/>. + */ + inline ::osl::Mutex& getMutex( GuardAccess ) const + { + return getMutex(); + } + inline ::rtl::Reference< ODatabaseModelImpl > getImpl( GuardAccess ) + { + return m_pImpl; + } + + /// checks whether the component is already disposed, throws a DisposedException if so + inline void checkDisposed() const + { + if ( !m_pImpl.is() ) + throw ::com::sun::star::lang::DisposedException( ::rtl::OUString::createFromAscii( "Component is already disposed." ), getThis() ); + } + + inline void lockModify() + { + m_pImpl->lockModify(); + } + + inline void unlockModify() + { + m_pImpl->unlockModify(); + } +}; + +class ModifyLock +{ +public: + ModifyLock( ModelDependentComponent& _component ) + :m_rComponent( _component ) + { + m_rComponent.lockModify(); + } + + ~ModifyLock() + { + m_rComponent.unlockModify(); + } + +private: + ModelDependentComponent& m_rComponent; +}; + +/** a guard for public methods of objects dependent on a ODatabaseModelImpl instance + + Just put this guard onto the stack at the beginning of your method. Don't bother yourself + with a MutexGuard, checks for being disposed, and the like. +*/ +class ModelMethodGuard : public ::osl::ResettableMutexGuard +{ +private: + typedef ::osl::ResettableMutexGuard BaseMutexGuard; + +public: + /** constructs the guard + + @param _component + the component whose functionality depends on a ODatabaseModelImpl instance + + @throws ::com::sun::star::lang::DisposedException + If the given component is already disposed + */ + ModelMethodGuard( const ModelDependentComponent& _component ) + :BaseMutexGuard( _component.getMutex( ModelDependentComponent::GuardAccess() ) ) + { + _component.checkDisposed(); + } + + ~ModelMethodGuard() + { + } +}; + +//........................................................................ +} // namespace dbaccess +//........................................................................ + +#endif // _DBA_COREDATAACCESS_DATALINK_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/SharedConnection.cxx b/dbaccess/source/core/dataaccess/SharedConnection.cxx new file mode 100644 index 000000000000..eaa2628648f2 --- /dev/null +++ b/dbaccess/source/core/dataaccess/SharedConnection.cxx @@ -0,0 +1,168 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" +#include "SharedConnection.hxx" +#include <tools/debug.hxx> + + +namespace dbaccess +{ + using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +// using namespace ::com::sun::star::reflection; +using namespace connectivity; + +DBG_NAME(OSharedConnection) +OSharedConnection::OSharedConnection(Reference< XAggregation >& _rxProxyConnection) + : OSharedConnection_BASE(m_aMutex) +{ + DBG_CTOR(OSharedConnection,NULL); + setDelegation(_rxProxyConnection,m_refCount); +} + +OSharedConnection::~OSharedConnection() +{ + DBG_DTOR(OSharedConnection,NULL); +} + +void SAL_CALL OSharedConnection::disposing(void) +{ + OSharedConnection_BASE::disposing(); + OConnectionWrapper::disposing(); +} + +Reference< XStatement > SAL_CALL OSharedConnection::createStatement( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->createStatement(); +} + +Reference< XPreparedStatement > SAL_CALL OSharedConnection::prepareStatement( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->prepareStatement(sql); +} + +Reference< XPreparedStatement > SAL_CALL OSharedConnection::prepareCall( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->prepareCall(sql); +} + +::rtl::OUString SAL_CALL OSharedConnection::nativeSQL( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->nativeSQL(sql); +} + +sal_Bool SAL_CALL OSharedConnection::getAutoCommit( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->getAutoCommit(); +} + +void SAL_CALL OSharedConnection::commit( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + m_xConnection->commit(); +} + +void SAL_CALL OSharedConnection::rollback( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + m_xConnection->rollback(); +} + +sal_Bool SAL_CALL OSharedConnection::isClosed( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + return m_xConnection->isClosed(); +} + +Reference< XDatabaseMetaData > SAL_CALL OSharedConnection::getMetaData( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + + return m_xConnection->getMetaData(); +} + +sal_Bool SAL_CALL OSharedConnection::isReadOnly( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->isReadOnly(); +} + +::rtl::OUString SAL_CALL OSharedConnection::getCatalog( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->getCatalog(); +} + +sal_Int32 SAL_CALL OSharedConnection::getTransactionIsolation( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->getTransactionIsolation(); +} + +Reference< ::com::sun::star::container::XNameAccess > SAL_CALL OSharedConnection::getTypeMap( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->getTypeMap(); +} + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/SharedConnection.hxx b/dbaccess/source/core/dataaccess/SharedConnection.hxx new file mode 100644 index 000000000000..4d21609d8d2c --- /dev/null +++ b/dbaccess/source/core/dataaccess/SharedConnection.hxx @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 DBA_CORE_SHARED_CONNECTION_HXX +#define DBA_CORE_SHARED_CONNECTION_HXX + +#include "connectivity/ConnectionWrapper.hxx" +#include <cppuhelper/component.hxx> +#include <connectivity/CommonTools.hxx> +#include <cppuhelper/compbase1.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp> +#include <com/sun/star/sdb/XCommandPreparation.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <comphelper/sequence.hxx> + + +namespace dbaccess +{ + //======================================================================================= + //= OSharedConnection: This class implements a simple forwarding of connection calls. + //= All methods will be forwarded with exception of the set methods, which are not allowed + //= to be called on shared connections. Instances of this class will be created when the + //= datasource is asked for not isolated connection. + //======================================================================================= + typedef ::cppu::WeakComponentImplHelper1< ::com::sun::star::sdbc::XConnection + > OSharedConnection_BASE; + typedef ::connectivity::OConnectionWrapper OSharedConnection_BASE2; + + class OSharedConnection : public ::comphelper::OBaseMutex + , public OSharedConnection_BASE + , public OSharedConnection_BASE2 + { + protected: + virtual void SAL_CALL disposing(void); + virtual ~OSharedConnection(); + public: + OSharedConnection(::com::sun::star::uno::Reference< ::com::sun::star::uno::XAggregation >& _rxProxyConnection); + + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL acquire() throw() { OSharedConnection_BASE::acquire(); } + virtual void SAL_CALL release() throw() { OSharedConnection_BASE::release(); } + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes( ) throw (::com::sun::star::uno::RuntimeException) + { + return ::comphelper::concatSequences( + OSharedConnection_BASE::getTypes(), + OSharedConnection_BASE2::getTypes() + ); + } + + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& _rType ) throw (::com::sun::star::uno::RuntimeException) + { + ::com::sun::star::uno::Any aReturn = OSharedConnection_BASE::queryInterface(_rType); + if ( !aReturn.hasValue() ) + aReturn = OSharedConnection_BASE2::queryInterface(_rType); + return aReturn; + } + + // XCloseable + virtual void SAL_CALL close( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException) + { + { + ::osl::MutexGuard aGuard( m_aMutex ); + ::connectivity::checkDisposed(rBHelper.bDisposed); + } + dispose(); + } + + // XConnection + virtual void SAL_CALL setAutoCommit( sal_Bool /*autoCommit*/ ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException) + { + throw ::com::sun::star::sdbc::SQLException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("This call is not allowed when sharing connections.")),*this,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("S10000")),0,::com::sun::star::uno::Any()); + } + virtual void SAL_CALL setReadOnly( sal_Bool /*readOnly*/ ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException) + { + throw ::com::sun::star::sdbc::SQLException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("This call is not allowed when sharing connections.")),*this,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("S10000")),0,::com::sun::star::uno::Any()); + } + virtual void SAL_CALL setCatalog( const ::rtl::OUString& /*catalog*/ ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException) + { + throw ::com::sun::star::sdbc::SQLException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("This call is not allowed when sharing connections.")),*this,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("S10000")),0,::com::sun::star::uno::Any()); + } + virtual void SAL_CALL setTransactionIsolation( sal_Int32 /*level*/ ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException) + { + throw ::com::sun::star::sdbc::SQLException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("This call is not allowed when sharing connections.")),*this,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("S10000")),0,::com::sun::star::uno::Any()); + } + virtual void SAL_CALL setTypeMap( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >& /*typeMap*/ ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException) + { + throw ::com::sun::star::sdbc::SQLException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("This call is not allowed when sharing connections.")),*this,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("S10000")),0,::com::sun::star::uno::Any()); + } + // XConnection + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XStatement > SAL_CALL createStatement( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const ::rtl::OUString& sql ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XPreparedStatement > SAL_CALL prepareCall( const ::rtl::OUString& sql ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL nativeSQL( const ::rtl::OUString& sql ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL getAutoCommit( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL commit( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL rollback( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isClosed( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isReadOnly( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getCatalog( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getTypeMap( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + }; + +#ifdef IMPLEMENT_GET_IMPLEMENTATION_ID + IMPLEMENT_GET_IMPLEMENTATION_ID( OSharedConnection ); +#endif + +} // namespace dbaccess + +#endif // DBA_CORE_SHARED_CONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/bookmarkcontainer.cxx b/dbaccess/source/core/dataaccess/bookmarkcontainer.cxx new file mode 100644 index 000000000000..9caf1a583dc7 --- /dev/null +++ b/dbaccess/source/core/dataaccess/bookmarkcontainer.cxx @@ -0,0 +1,371 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +#include "bookmarkcontainer.hxx" +#include "dbastrings.hrc" +#include "apitools.hxx" +#include "core_resource.hxx" +#include "core_resource.hrc" + +#include <tools/debug.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/enumhelper.hxx> +#include <comphelper/extract.hxx> +#include <com/sun/star/lang/XComponent.hpp> +#include <comphelper/types.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::osl; +using namespace ::comphelper; +using namespace ::cppu; + +namespace dbaccess +{ + +//========================================================================== +//= OBookmarkContainer +//========================================================================== +DBG_NAME(OBookmarkContainer) + +OBookmarkContainer::OBookmarkContainer(OWeakObject& _rParent, Mutex& _rMutex) + :m_rParent(_rParent) + ,m_aContainerListeners(_rMutex) + ,m_rMutex(_rMutex) +{ + DBG_CTOR(OBookmarkContainer, NULL); +} + +void OBookmarkContainer::dispose() +{ + MutexGuard aGuard(m_rMutex); + + // say our listeners goobye + EventObject aEvt(*this); + m_aContainerListeners.disposeAndClear(aEvt); + + // remove our elements + m_aBookmarksIndexed.clear(); + m_aBookmarks.clear(); +} + +void SAL_CALL OBookmarkContainer::acquire( ) throw() +{ + m_rParent.acquire(); +} + +void SAL_CALL OBookmarkContainer::release( ) throw() +{ + m_rParent.release(); +} + +OBookmarkContainer::~OBookmarkContainer() +{ + DBG_DTOR(OBookmarkContainer, NULL); +} + +// XServiceInfo +::rtl::OUString SAL_CALL OBookmarkContainer::getImplementationName( ) throw(RuntimeException) +{ + return ::rtl::OUString::createFromAscii("com.sun.star.comp.dba.OBookmarkContainer"); +} + +sal_Bool SAL_CALL OBookmarkContainer::supportsService( const ::rtl::OUString& _rServiceName ) throw (RuntimeException) +{ + MutexGuard aGuard(m_rMutex); + checkValid(sal_False); + return findValue(getSupportedServiceNames(), _rServiceName, sal_True).getLength() != 0; +} + +Sequence< ::rtl::OUString > SAL_CALL OBookmarkContainer::getSupportedServiceNames( ) throw(RuntimeException) +{ + Sequence< ::rtl::OUString > aReturn(1); + aReturn.getArray()[0] = ::rtl::OUString::createFromAscii("com.sun.star.sdb.DefinitionContainer"); + return aReturn; +} + +// XNameContainer +void SAL_CALL OBookmarkContainer::insertByName( const ::rtl::OUString& _rName, const Any& aElement ) throw(IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException) +{ + MutexGuard aGuard(m_rMutex); + checkValid(sal_True); + + if (checkExistence(_rName)) + throw ElementExistException(); + + if (0 == _rName.getLength()) + throw IllegalArgumentException(); + + // approve the new object + ::rtl::OUString sNewLink; + if (!(aElement >>= sNewLink)) + throw IllegalArgumentException(); + + + implAppend(_rName, sNewLink); + + // notify the listeners + if (m_aContainerListeners.getLength()) + { + ContainerEvent aEvent(*this, makeAny(_rName), makeAny(sNewLink), Any()); + OInterfaceIteratorHelper aListenerIterator(m_aContainerListeners); + while (aListenerIterator.hasMoreElements()) + static_cast< XContainerListener* >(aListenerIterator.next())->elementInserted(aEvent); + } +} + +void SAL_CALL OBookmarkContainer::removeByName( const ::rtl::OUString& _rName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException) +{ + ::rtl::OUString sOldBookmark; + { + MutexGuard aGuard(m_rMutex); + checkValid(sal_True); + + // check the arguments + if (!_rName.getLength()) + throw IllegalArgumentException(); + + if (!checkExistence(_rName)) + throw NoSuchElementException(); + + // the old element (for the notifications) + sOldBookmark = m_aBookmarks[_rName]; + + // do the removal + implRemove(_rName); + } + + // notify the listeners + if (m_aContainerListeners.getLength()) + { + ContainerEvent aEvent(*this, makeAny(_rName), makeAny(sOldBookmark), Any()); + OInterfaceIteratorHelper aListenerIterator(m_aContainerListeners); + while (aListenerIterator.hasMoreElements()) + static_cast< XContainerListener* >(aListenerIterator.next())->elementRemoved(aEvent); + } +} + +// XNameReplace +void SAL_CALL OBookmarkContainer::replaceByName( const ::rtl::OUString& _rName, const Any& aElement ) throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException) +{ + ClearableMutexGuard aGuard(m_rMutex); + checkValid(sal_True); + + // check the arguments + if (!_rName.getLength()) + throw IllegalArgumentException(); + + // do we have such an element? + if (!checkExistence(_rName)) + throw NoSuchElementException(); + + // approve the new object + ::rtl::OUString sNewLink; + if (!(aElement >>= sNewLink)) + throw IllegalArgumentException(); + + // the old element (for the notifications) + ::rtl::OUString sOldLink = m_aBookmarks[_rName]; + + // do the replace + implReplace(_rName, sNewLink); + + // notify the listeners + aGuard.clear(); + if (m_aContainerListeners.getLength()) + { + ContainerEvent aEvent(*this, makeAny(_rName), makeAny(sNewLink), makeAny(sOldLink)); + OInterfaceIteratorHelper aListenerIterator(m_aContainerListeners); + while (aListenerIterator.hasMoreElements()) + static_cast< XContainerListener* >(aListenerIterator.next())->elementReplaced(aEvent); + } +} + +void SAL_CALL OBookmarkContainer::addContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException) +{ + MutexGuard aGuard(m_rMutex); + if (_rxListener.is()) + m_aContainerListeners.addInterface(_rxListener); +} + +void SAL_CALL OBookmarkContainer::removeContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException) +{ + MutexGuard aGuard(m_rMutex); + if (_rxListener.is()) + m_aContainerListeners.removeInterface(_rxListener); +} + +// XElementAccess +Type SAL_CALL OBookmarkContainer::getElementType( ) throw (RuntimeException) +{ + MutexGuard aGuard(m_rMutex); + checkValid(sal_False); + return ::getCppuType( static_cast< ::rtl::OUString* >(NULL) ); +} + +sal_Bool SAL_CALL OBookmarkContainer::hasElements( ) throw (RuntimeException) +{ + MutexGuard aGuard(m_rMutex); + checkValid(sal_False); + return !m_aBookmarks.empty(); +} + +// XEnumerationAccess +Reference< XEnumeration > SAL_CALL OBookmarkContainer::createEnumeration( ) throw(RuntimeException) +{ + MutexGuard aGuard(m_rMutex); + checkValid(sal_False); + return new ::comphelper::OEnumerationByIndex(static_cast<XIndexAccess*>(this)); +} + +// XIndexAccess +sal_Int32 SAL_CALL OBookmarkContainer::getCount( ) throw(RuntimeException) +{ + MutexGuard aGuard(m_rMutex); + checkValid(sal_False); + return m_aBookmarks.size(); +} + +Any SAL_CALL OBookmarkContainer::getByIndex( sal_Int32 _nIndex ) throw(IndexOutOfBoundsException, WrappedTargetException, RuntimeException) +{ + MutexGuard aGuard(m_rMutex); + checkValid(sal_False); + + if ((_nIndex < 0) || (_nIndex >= (sal_Int32)m_aBookmarksIndexed.size())) + throw IndexOutOfBoundsException(); + + return makeAny(m_aBookmarksIndexed[_nIndex]->second); +} + +Any SAL_CALL OBookmarkContainer::getByName( const ::rtl::OUString& _rName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException) +{ + MutexGuard aGuard(m_rMutex); + checkValid(sal_False); + + if (!checkExistence(_rName)) + throw NoSuchElementException(); + + return makeAny(m_aBookmarks[_rName]); +} + +Sequence< ::rtl::OUString > SAL_CALL OBookmarkContainer::getElementNames( ) throw(RuntimeException) +{ + MutexGuard aGuard(m_rMutex); + checkValid(sal_False); + + Sequence< ::rtl::OUString > aNames(m_aBookmarks.size()); + ::rtl::OUString* pNames = aNames.getArray(); + ; + for ( ConstMapIteratorVectorIterator aNameIter = m_aBookmarksIndexed.begin(); + aNameIter != m_aBookmarksIndexed.end(); + ++pNames, ++aNameIter + ) + { + *pNames = (*aNameIter)->first; + } + + return aNames; +} + +sal_Bool SAL_CALL OBookmarkContainer::hasByName( const ::rtl::OUString& _rName ) throw(RuntimeException) +{ + MutexGuard aGuard(m_rMutex); + checkValid(sal_False); + + return checkExistence(_rName); +} + +void OBookmarkContainer::implRemove(const ::rtl::OUString& _rName) +{ + MutexGuard aGuard(m_rMutex); + + // look for the name in the index access vector + MapString2StringIterator aMapPos = m_aBookmarks.end(); + for ( MapIteratorVectorIterator aSearch = m_aBookmarksIndexed.begin(); + aSearch != m_aBookmarksIndexed.end(); + ++aSearch + ) + { +#ifdef DBG_UTIL + ::rtl::OUString sName = (*aSearch)->first; +#endif + if ((*aSearch)->first == _rName) + { + aMapPos = *aSearch; + m_aBookmarksIndexed.erase(aSearch); + break; + } + } + + if (m_aBookmarks.end() == aMapPos) + { + DBG_ERROR("OBookmarkContainer::implRemove: inconsistence!"); + return; + } + + // remove the map entries + m_aBookmarks.erase(aMapPos); +} + +void OBookmarkContainer::implAppend(const ::rtl::OUString& _rName, const ::rtl::OUString& _rDocumentLocation) +{ + MutexGuard aGuard(m_rMutex); + + OSL_ENSURE(m_aBookmarks.find(_rName) == m_aBookmarks.end(),"Bookmark already known!"); + m_aBookmarksIndexed.push_back(m_aBookmarks.insert( MapString2String::value_type(_rName,_rDocumentLocation)).first); +} + +void OBookmarkContainer::implReplace(const ::rtl::OUString& _rName, const ::rtl::OUString& _rNewLink) +{ + MutexGuard aGuard(m_rMutex); + DBG_ASSERT(checkExistence(_rName), "OBookmarkContainer::implReplace : invalid name !"); + + m_aBookmarks[_rName] = _rNewLink; +} + +void OBookmarkContainer::checkValid(sal_Bool /*_bIntendWriteAccess*/) const throw (RuntimeException, DisposedException) +{ +} + +Reference< XInterface > SAL_CALL OBookmarkContainer::getParent( ) throw (RuntimeException) +{ + return m_rParent; +} + +void SAL_CALL OBookmarkContainer::setParent( const Reference< XInterface >& /*Parent*/ ) throw (NoSupportException, RuntimeException) +{ + throw NoSupportException(); +} + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/bookmarkcontainer.hxx b/dbaccess/source/core/dataaccess/bookmarkcontainer.hxx new file mode 100644 index 000000000000..648d5654d114 --- /dev/null +++ b/dbaccess/source/core/dataaccess/bookmarkcontainer.hxx @@ -0,0 +1,179 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 _DBA_CORE_BOOKMARKCONTAINER_HXX_ +#define _DBA_CORE_BOOKMARKCONTAINER_HXX_ + +#include <cppuhelper/interfacecontainer.hxx> +#include <cppuhelper/implbase6.hxx> +#include <comphelper/stl_types.hxx> +#include <osl/mutex.hxx> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/DisposedException.hpp> + +namespace dbaccess +{ + +//========================================================================== +//= OBookmarkContainer - base class of collections of database definition +//= documents +//========================================================================== +typedef ::cppu::WeakImplHelper6 < + ::com::sun::star::container::XIndexAccess + , ::com::sun::star::container::XNameContainer + , ::com::sun::star::container::XEnumerationAccess + , ::com::sun::star::container::XContainer + , ::com::sun::star::lang::XServiceInfo + , ::com::sun::star::container::XChild + > OBookmarkContainer_Base; + +class OBookmarkContainer + :public OBookmarkContainer_Base +{ +protected: + DECLARE_STL_USTRINGACCESS_MAP(::rtl::OUString, MapString2String); + DECLARE_STL_VECTOR(MapString2StringIterator, MapIteratorVector); + + MapString2String m_aBookmarks; // the bookmarks itself + MapIteratorVector m_aBookmarksIndexed; // for index access to the + +protected: + ::cppu::OWeakObject& m_rParent; // for the ref counting + ::cppu::OInterfaceContainerHelper + m_aContainerListeners; + ::osl::Mutex& m_rMutex; + + +public: + /** constructs the container.<BR> + after the construction of the object the creator has to call <code>initialize</code>. + @param _rParent the parent object which is used for ref counting + @param _rMutex the parent's mutex object for access safety + */ + OBookmarkContainer( + ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex + ); + + /** looks like the dtor ... + */ + virtual ~OBookmarkContainer(); + +// ::com::sun::star::uno::XInterface + virtual void SAL_CALL acquire( ) throw(); + virtual void SAL_CALL release( ) throw(); + +// ::com::sun::star::lang::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); + +// ::com::sun::star::container::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); + +// ::com::sun::star::container::XEnumerationAccess + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL createEnumeration( ) throw(::com::sun::star::uno::RuntimeException); + +// ::com::sun::star::container::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); + +// ::com::sun::star::container::XNameContainer + virtual void SAL_CALL insertByName( const ::rtl::OUString& _rName, 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& _rName ) throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + +// ::com::sun::star::container::XNameReplace + virtual void SAL_CALL replaceByName( const ::rtl::OUString& _rName, 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); + +// ::com::sun::star::container::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); + +// ::com::sun::star::container::XContainer + virtual void SAL_CALL addContainerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XContainerListener >& xListener ) throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeContainerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XContainerListener >& xListener ) throw(::com::sun::star::uno::RuntimeException); + +// ::com::sun::star::container::XChild + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL getParent( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setParent( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& Parent ) throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + +// helper + /** tell the container to free all resources. After that it's in a state like after the construction, i.e. + you may call <code>initialize</code> again (maybe with another configuration node). + */ + virtual void dispose(); + + +protected: + /** checks whether the object is basically alive, i.e. it has been fully initialized (@see initialize) and + not disposed (@see dispose) + @param _bIntendWriteAccess determines whether or not the caller intends to modify the configuration. + if sal_True and the configuration is readonly, a runtime exception with + a description string is thrown. + */ + void checkValid(sal_Bool _bIntendWriteAccess) const throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::DisposedException); + + /** quickly checks if there already is an element with a given name. No access to the configuration occures, i.e. + if there is such an object which is not already loaded, it won't be loaded now. + @param _rName the object name to check + @return sal_True if there already exists such an object + */ + inline sal_Bool checkExistence(const ::rtl::OUString& _rName); + + void implAppend( + const ::rtl::OUString& _rName, + const ::rtl::OUString& _rDocumentLocation + ); + + void implRemove(const ::rtl::OUString& _rName); + + void implReplace( + const ::rtl::OUString& _rName, + const ::rtl::OUString& _rNewLink); + +}; + +inline sal_Bool OBookmarkContainer::checkExistence(const ::rtl::OUString& _rName) +{ + return m_aBookmarks.find(_rName) != m_aBookmarks.end(); +} + +} // namespace dbaccess + +#endif // _DBA_CORE_BOOKMARKCONTAINER_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/commandcontainer.cxx b/dbaccess/source/core/dataaccess/commandcontainer.cxx new file mode 100644 index 000000000000..3394cd0f0ca4 --- /dev/null +++ b/dbaccess/source/core/dataaccess/commandcontainer.cxx @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +#include "commandcontainer.hxx" +#include "commanddefinition.hxx" + +#include <tools/debug.hxx> +#include "dbastrings.hrc" + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::ucb; +using namespace ::osl; +using namespace ::comphelper; +using namespace ::cppu; + +namespace dbaccess +{ + +//========================================================================== +//= OCommandContainer +//========================================================================== +DBG_NAME(OCommandContainer) + +OCommandContainer::OCommandContainer( const Reference< ::com::sun::star::lang::XMultiServiceFactory >& _xORB + ,const Reference< XInterface >& _xParentContainer + ,const TContentPtr& _pImpl + ,sal_Bool _bTables + ) + :ODefinitionContainer(_xORB,_xParentContainer,_pImpl,!_bTables) + ,m_bTables(_bTables) +{ + DBG_CTOR(OCommandContainer, NULL); +} + +OCommandContainer::~OCommandContainer() +{ + DBG_DTOR(OCommandContainer, NULL); +} + +IMPLEMENT_FORWARD_XINTERFACE2( OCommandContainer,ODefinitionContainer,OCommandContainer_BASE) +IMPLEMENT_TYPEPROVIDER2(OCommandContainer,ODefinitionContainer,OCommandContainer_BASE); + +Reference< XContent > OCommandContainer::createObject( const ::rtl::OUString& _rName) +{ + const ODefinitionContainer_Impl& rDefinitions( getDefinitions() ); + OSL_ENSURE( rDefinitions.find(_rName) != rDefinitions.end(), "OCommandContainer::createObject: Invalid entry in map!" ); + + const TContentPtr& pElementContent( rDefinitions.find( _rName )->second ); + if ( m_bTables ) + return new OComponentDefinition( *this, _rName, m_aContext.getLegacyServiceFactory(), pElementContent, m_bTables ); + return new OCommandDefinition( *this, _rName, m_aContext.getLegacyServiceFactory(), pElementContent ); +} + +Reference< XInterface > SAL_CALL OCommandContainer::createInstanceWithArguments(const Sequence< Any >& /*aArguments*/ ) throw (Exception, RuntimeException) +{ + return createInstance( ); +} + +Reference< XInterface > SAL_CALL OCommandContainer::createInstance( ) throw (Exception, RuntimeException) +{ + return m_aContext.createComponent( (::rtl::OUString)( m_bTables ? SERVICE_SDB_TABLEDEFINITION : SERVICE_SDB_COMMAND_DEFINITION ) ); +} + +::rtl::OUString OCommandContainer::determineContentType() const +{ + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.org.openoffice.DatabaseCommandDefinitionContainer" ) ); +} + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/commandcontainer.hxx b/dbaccess/source/core/dataaccess/commandcontainer.hxx new file mode 100644 index 000000000000..a425d7795dbe --- /dev/null +++ b/dbaccess/source/core/dataaccess/commandcontainer.hxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 _DBA_COREDATAACCESS_COMMANDCONTAINER_HXX_ +#define _DBA_COREDATAACCESS_COMMANDCONTAINER_HXX_ + +#include "definitioncontainer.hxx" + +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +#include <cppuhelper/implbase1.hxx> + +namespace dbaccess +{ +//========================================================================== +//= OCommandContainer +//========================================================================== + +typedef ::cppu::ImplHelper1 < ::com::sun::star::lang::XSingleServiceFactory + > OCommandContainer_BASE; + +class OCommandContainer : public ODefinitionContainer + ,public OCommandContainer_BASE +{ + sal_Bool m_bTables; + +public: + /** constructs the container.<BR> + */ + OCommandContainer( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _xORB + ,const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _xParentContainer + ,const TContentPtr& _pImpl + ,sal_Bool _bTables + ); + + DECLARE_XINTERFACE( ) + DECLARE_TYPEPROVIDER( ); + + // XSingleServiceFactory + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstance( ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstanceWithArguments( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + +protected: + virtual ~OCommandContainer(); + + // ODefinitionContainer + virtual ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContent > createObject(const ::rtl::OUString& _rName); + +protected: + // OContentHelper overridables + virtual ::rtl::OUString determineContentType() const; +}; + +} // namespace dbaccess + + +#endif // _DBA_COREDATAACCESS_COMMANDCONTAINER_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/commanddefinition.cxx b/dbaccess/source/core/dataaccess/commanddefinition.cxx new file mode 100644 index 000000000000..6cfd9231560f --- /dev/null +++ b/dbaccess/source/core/dataaccess/commanddefinition.cxx @@ -0,0 +1,167 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +#include "commanddefinition.hxx" +#include "apitools.hxx" +#include "dbastrings.hrc" +#include "module_dba.hxx" + +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> + +#include <tools/debug.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/componentcontext.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::osl; +using namespace ::comphelper; +using namespace ::cppu; + +namespace dbaccess +{ + +//========================================================================== +//= OCommandDefinition +//========================================================================== +extern "C" void SAL_CALL createRegistryInfo_OCommandDefinition() +{ + static ::dba::OAutoRegistration< OCommandDefinition > aAutoRegistration; +} + +DBG_NAME(OCommandDefinition) + +void OCommandDefinition::registerProperties() +{ + OCommandDefinition_Impl& rCommandDefinition( getCommandDefinition() ); + registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND, + &rCommandDefinition.m_sCommand, ::getCppuType(&rCommandDefinition.m_sCommand)); + + registerProperty(PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND, + &rCommandDefinition.m_bEscapeProcessing, ::getBooleanCppuType()); + + registerProperty(PROPERTY_UPDATE_TABLENAME, PROPERTY_ID_UPDATE_TABLENAME, PropertyAttribute::BOUND, + &rCommandDefinition.m_sUpdateTableName, ::getCppuType(&rCommandDefinition.m_sUpdateTableName)); + + registerProperty(PROPERTY_UPDATE_SCHEMANAME, PROPERTY_ID_UPDATE_SCHEMANAME, PropertyAttribute::BOUND, + &rCommandDefinition.m_sUpdateSchemaName, ::getCppuType(&rCommandDefinition.m_sUpdateSchemaName)); + + registerProperty(PROPERTY_UPDATE_CATALOGNAME, PROPERTY_ID_UPDATE_CATALOGNAME, PropertyAttribute::BOUND, + &rCommandDefinition.m_sUpdateCatalogName, ::getCppuType(&rCommandDefinition.m_sUpdateCatalogName)); + registerProperty(PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, PropertyAttribute::BOUND, + &rCommandDefinition.m_aLayoutInformation, ::getCppuType(&rCommandDefinition.m_aLayoutInformation)); +} + +OCommandDefinition::OCommandDefinition(const Reference< XMultiServiceFactory >& _xORB + ,const Reference< XInterface >& _rxContainer + ,const TContentPtr& _pImpl) + :OComponentDefinition(_xORB,_rxContainer,_pImpl,sal_False) +{ + DBG_CTOR(OCommandDefinition, NULL); + registerProperties(); +} + +OCommandDefinition::~OCommandDefinition() +{ + DBG_DTOR(OCommandDefinition, NULL); +} + +OCommandDefinition::OCommandDefinition( const Reference< XInterface >& _rxContainer + ,const ::rtl::OUString& _rElementName + ,const Reference< XMultiServiceFactory >& _xORB + ,const TContentPtr& _pImpl) + :OComponentDefinition(_rxContainer,_rElementName,_xORB,_pImpl,sal_False) +{ + DBG_CTOR(OCommandDefinition, NULL); + registerProperties(); +} + +IMPLEMENT_IMPLEMENTATION_ID(OCommandDefinition); +IMPLEMENT_GETTYPES2(OCommandDefinition,OCommandDefinition_Base,OComponentDefinition); +IMPLEMENT_FORWARD_XINTERFACE2( OCommandDefinition,OComponentDefinition,OCommandDefinition_Base) +IMPLEMENT_PROPERTYCONTAINER_DEFAULTS2(OCommandDefinition,OCommandDefinition_PROP) + +::rtl::OUString OCommandDefinition::getImplementationName_static( ) throw(RuntimeException) +{ + return ::rtl::OUString::createFromAscii("com.sun.star.comp.dba.OCommandDefinition"); +} + +::rtl::OUString SAL_CALL OCommandDefinition::getImplementationName( ) throw(RuntimeException) +{ + return getImplementationName_static(); +} + +Sequence< ::rtl::OUString > OCommandDefinition::getSupportedServiceNames_static( ) throw(RuntimeException) +{ + Sequence< ::rtl::OUString > aServices(3); + aServices.getArray()[0] = SERVICE_SDB_QUERYDEFINITION; + aServices.getArray()[1] = SERVICE_SDB_COMMAND_DEFINITION; + aServices.getArray()[2] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.Content")); + return aServices; +} + +Sequence< ::rtl::OUString > SAL_CALL OCommandDefinition::getSupportedServiceNames( ) throw(RuntimeException) +{ + return getSupportedServiceNames_static(); +} + +Reference< XInterface > OCommandDefinition::Create(const Reference< XComponentContext >& _rxContext) +{ + ::comphelper::ComponentContext aContext( _rxContext ); + return *(new OCommandDefinition( aContext.getLegacyServiceFactory(), NULL, TContentPtr( new OCommandDefinition_Impl ) ) ); +} + +void SAL_CALL OCommandDefinition::rename( const ::rtl::OUString& newName ) throw (SQLException, ElementExistException, RuntimeException) +{ + try + { + sal_Int32 nHandle = PROPERTY_ID_NAME; + osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex); + Any aOld = makeAny(m_pImpl->m_aProps.aTitle); + aGuard.clear(); + Any aNew = makeAny(newName); + fire(&nHandle, &aNew, &aOld, 1, sal_True ); + + m_pImpl->m_aProps.aTitle = newName; + fire(&nHandle, &aNew, &aOld, 1, sal_False ); + } + catch(const PropertyVetoException&) + { + throw ElementExistException(newName,*this); + } +} + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/commanddefinition.hxx b/dbaccess/source/core/dataaccess/commanddefinition.hxx new file mode 100644 index 000000000000..b823c08f86d2 --- /dev/null +++ b/dbaccess/source/core/dataaccess/commanddefinition.hxx @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 _DBA_COREDATAACESS_COMMANDDEFINITION_HXX_ +#define _DBA_COREDATAACESS_COMMANDDEFINITION_HXX_ + +#include "commandbase.hxx" +#include <comphelper/propertycontainer.hxx> +#include "apitools.hxx" +#include <comphelper/uno3.hxx> +#include <com/sun/star/sdbcx/XRename.hpp> +#include <cppuhelper/implbase1.hxx> +#include <comphelper/proparrhlp.hxx> +#include "datasettings.hxx" +#include <com/sun/star/container/XNameAccess.hpp> +#include "ContentHelper.hxx" +#include "ComponentDefinition.hxx" + + +//........................................................................ +namespace dbaccess +{ +//........................................................................ + +//========================================================================= +//= OCommandDefinition - a database "document" which describes a query +//========================================================================= + class OCommandDefinition_Impl : public OComponentDefinition_Impl + ,public OCommandBase + { + public: + }; + +typedef ::cppu::ImplHelper1 < ::com::sun::star::sdbcx::XRename + > OCommandDefinition_Base; +class OCommandDefinition; +typedef ::comphelper::OPropertyArrayUsageHelper< OCommandDefinition > + OCommandDefinition_PROP; + +class OCommandDefinition :public OComponentDefinition + ,public OCommandDefinition_Base + ,public OCommandDefinition_PROP +{ +protected: + virtual ~OCommandDefinition(); + + OCommandDefinition(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& + ,const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _xParentContainer + ,const TContentPtr& _pImpl + ); + + inline const OCommandDefinition_Impl& getCommandDefinition() const { return dynamic_cast< const OCommandDefinition_Impl& >( *m_pImpl.get() ); } + inline OCommandDefinition_Impl& getCommandDefinition() { return dynamic_cast< OCommandDefinition_Impl& >( *m_pImpl.get() ); } + +public: + + OCommandDefinition( + const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxContainer + ,const ::rtl::OUString& _rElementName + ,const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& + ,const TContentPtr& _pImpl + ); + +// com::sun::star::lang::XTypeProvider + DECLARE_TYPEPROVIDER( ); + +// ::com::sun::star::uno::XInterface + DECLARE_XINTERFACE( ) + +// ::com::sun::star::lang::XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw(::com::sun::star::uno::RuntimeException); + +// ::com::sun::star::lang::XServiceInfo - static methods + 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 >&); + + // XRename + virtual void SAL_CALL rename( const ::rtl::OUString& newName ) throw (::com::sun::star::sdbc::SQLException, ::com::sun::star::container::ElementExistException, ::com::sun::star::uno::RuntimeException); + + // OPropertySetHelper + DECLARE_PROPERTYCONTAINER_DEFAULTS( ); + +private: + // helper + void registerProperties(); +}; + +//........................................................................ +} // namespace dbaccess +//........................................................................ + +#endif // _DBA_COREDATAACESS_COMMANDDEFINITION_HXX_ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/connection.cxx b/dbaccess/source/core/dataaccess/connection.cxx new file mode 100644 index 000000000000..490d0c47ffe0 --- /dev/null +++ b/dbaccess/source/core/dataaccess/connection.cxx @@ -0,0 +1,894 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +#include "connection.hxx" +#include "dbastrings.hrc" +#include "datasource.hxx" +#include "core_resource.hrc" +#include "core_resource.hxx" +#include "statement.hxx" +#include "preparedstatement.hxx" +#include "callablestatement.hxx" +#include "ContainerMediator.hxx" +#include "SingleSelectQueryComposer.hxx" +#include "querycomposer.hxx" +#include "sdbcoretools.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdbc/XDriverAccess.hpp> +#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp> +#include <com/sun/star/reflection/XProxyFactory.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +/** === end UNO includes === **/ +#include <connectivity/dbtools.hxx> +#include <connectivity/dbmetadata.hxx> +#include <connectivity/dbexception.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <comphelper/extract.hxx> +#include <comphelper/uno3.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <rtl/logfile.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdb::application; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::reflection; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::graphic; +using namespace ::osl; +using namespace ::comphelper; +using namespace ::cppu; +using namespace ::dbtools; + +using ::com::sun::star::sdb::tools::XTableName; +using ::com::sun::star::sdb::tools::XObjectNames; +using ::com::sun::star::sdb::tools::XDataSourceMetaData; + +namespace dbaccess +{ + +//========================================================================== +// XServiceInfo +rtl::OUString OConnection::getImplementationName( ) throw(RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getImplementationName" ); + return rtl::OUString::createFromAscii("com.sun.star.comp.dbaccess.Connection"); +} + +sal_Bool OConnection::supportsService( const ::rtl::OUString& _rServiceName ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::supportsService" ); + return findValue(getSupportedServiceNames(), _rServiceName, sal_True).getLength() != 0; +} + +Sequence< ::rtl::OUString > OConnection::getSupportedServiceNames( ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getSupportedServiceNames" ); + Sequence< ::rtl::OUString > aSupported = OConnectionWrapper::getSupportedServiceNames(); + + if ( 0 == findValue( aSupported, SERVICE_SDB_CONNECTION, sal_True ).getLength() ) + { + sal_Int32 nLen = aSupported.getLength(); + aSupported.realloc( nLen + 1 ); + aSupported[ nLen ] = SERVICE_SDB_CONNECTION; + } + + return aSupported; +} + +// XCloseable +void OConnection::close(void) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::close" ); + // being closed is the same as being disposed + dispose(); +} + +sal_Bool OConnection::isClosed(void) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::isClosed" ); + MutexGuard aGuard(m_aMutex); + return !m_xMasterConnection.is(); +} + +// XConnection +Reference< XStatement > OConnection::createStatement(void) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::createStatement" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + + Reference< XStatement > xStatement; + Reference< XStatement > xMasterStatement = m_xMasterConnection->createStatement(); + if ( xMasterStatement.is() ) + { + xStatement = new OStatement(this, xMasterStatement); + m_aStatements.push_back(WeakReferenceHelper(xStatement)); + } + return xStatement; +} +Reference< XPreparedStatement > OConnection::prepareStatement(const rtl::OUString& sql) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::prepareStatement" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + + // TODO convert the SQL to SQL the driver understands + Reference< XPreparedStatement > xStatement; + Reference< XPreparedStatement > xMasterStatement = m_xMasterConnection->prepareStatement(sql); + if ( xMasterStatement.is() ) + { + xStatement = new OPreparedStatement(this, xMasterStatement); + m_aStatements.push_back(WeakReferenceHelper(xStatement)); + } + return xStatement; +} + +Reference< XPreparedStatement > OConnection::prepareCall(const rtl::OUString& sql) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::prepareCall" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + + Reference< XPreparedStatement > xStatement; + Reference< XPreparedStatement > xMasterStatement = m_xMasterConnection->prepareCall(sql); + if ( xMasterStatement.is() ) + { + xStatement = new OCallableStatement(this, xMasterStatement); + m_aStatements.push_back(WeakReferenceHelper(xStatement)); + } + return xStatement; +} + +rtl::OUString OConnection::nativeSQL(const rtl::OUString& sql) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::nativeSQL" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + return m_xMasterConnection->nativeSQL(sql); +} + +void OConnection::setAutoCommit(sal_Bool autoCommit) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::setAutoCommit" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + m_xMasterConnection->setAutoCommit(autoCommit); +} + +sal_Bool OConnection::getAutoCommit(void) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getAutoCommit" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + return m_xMasterConnection->getAutoCommit(); +} + +void OConnection::commit(void) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::commit" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + m_xMasterConnection->commit(); +} + +void OConnection::rollback(void) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::rollback" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + m_xMasterConnection->rollback(); +} + +Reference< XDatabaseMetaData > OConnection::getMetaData(void) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getMetaData" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + return m_xMasterConnection->getMetaData(); +} + +void OConnection::setReadOnly(sal_Bool readOnly) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::setReadOnly" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + m_xMasterConnection->setReadOnly(readOnly); +} + +sal_Bool OConnection::isReadOnly(void) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::isReadOnly" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + return m_xMasterConnection->isReadOnly(); +} + +void OConnection::setCatalog(const rtl::OUString& catalog) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::setCatalog" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + m_xMasterConnection->setCatalog(catalog); +} + +rtl::OUString OConnection::getCatalog(void) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getCatalog" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + return m_xMasterConnection->getCatalog(); +} + +void OConnection::setTransactionIsolation(sal_Int32 level) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::setTransactionIsolation" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + m_xMasterConnection->setTransactionIsolation(level); +} + +sal_Int32 OConnection::getTransactionIsolation(void) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getTransactionIsolation" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + return m_xMasterConnection->getTransactionIsolation(); +} + +Reference< XNameAccess > OConnection::getTypeMap(void) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getTypeMap" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + return m_xMasterConnection->getTypeMap(); +} + +void OConnection::setTypeMap(const Reference< XNameAccess > & typeMap) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::setTypeMap" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + m_xMasterConnection->setTypeMap(typeMap); +} +//========================================================================== +//= OConnection +//========================================================================== +DBG_NAME(OConnection) + +OConnection::OConnection(ODatabaseSource& _rDB + , Reference< XConnection >& _rxMaster + , const Reference< XMultiServiceFactory >& _rxORB) + :OSubComponent(m_aMutex, static_cast< OWeakObject* >(&_rDB)) + // as the queries reroute their refcounting to us, this m_aMutex is okey. If the queries + // container would do it's own refcounting, it would have to aquire m_pMutex + // same for tables + ,m_aTableFilter(_rDB.m_pImpl->m_aTableFilter) + ,m_aTableTypeFilter(_rDB.m_pImpl->m_aTableTypeFilter) + ,m_aContext( _rxORB ) + ,m_xMasterConnection(_rxMaster) + ,m_pTables(NULL) + ,m_pViews(NULL) + ,m_aWarnings( Reference< XWarningsSupplier >( _rxMaster, UNO_QUERY ) ) + ,m_nInAppend(0) + ,m_bSupportsViews(sal_False) + ,m_bSupportsUsers(sal_False) + ,m_bSupportsGroups(sal_False) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::OConnection" ); + DBG_CTOR(OConnection,NULL); + osl_incrementInterlockedCount(&m_refCount); + + try + { + Reference< XProxyFactory > xProxyFactory( + _rxORB->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.reflection.ProxyFactory"))),UNO_QUERY); + Reference<XAggregation> xAgg = xProxyFactory->createProxy(_rxMaster.get()); + setDelegation(xAgg,m_refCount); + DBG_ASSERT(m_xConnection.is(), "OConnection::OConnection : invalid master connection !"); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + + m_xTableUIProvider = m_xTableUIProvider.query( m_xMasterConnection ); + + try + { + m_xQueries = new OQueryContainer(Reference< XNameContainer >(_rDB.getQueryDefinitions( ),UNO_QUERY), this,_rxORB, &m_aWarnings); + + sal_Bool bCase = sal_True; + Reference<XDatabaseMetaData> xMeta; + try + { + xMeta = getMetaData(); + bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(); + } + catch(SQLException&) + { + } + Reference< XNameContainer > xTableDefinitions(_rDB.getTables(),UNO_QUERY); + m_pTables = new OTableContainer( *this, m_aMutex, this, bCase, xTableDefinitions, this, &m_aWarnings,m_nInAppend ); + + // check if we supports types + if ( xMeta.is() ) + { + Reference<XResultSet> xRes = xMeta->getTableTypes(); + if(xRes.is()) + { + ::rtl::OUString sView(RTL_CONSTASCII_USTRINGPARAM("VIEW")); + Reference<XRow> xRow(xRes,UNO_QUERY); + while(xRes->next()) + { + ::rtl::OUString sValue = xRow->getString(1); + if( !xRow->wasNull() && sValue == sView) + { + m_bSupportsViews = sal_True; + break; + } + } + } + // some dbs don't support this type so we should ask if a XViewsSupplier is supported + if(!m_bSupportsViews) + { + Reference< XViewsSupplier > xMaster(getMasterTables(),UNO_QUERY); + + if (xMaster.is() && xMaster->getViews().is()) + m_bSupportsViews = sal_True; + } + if(m_bSupportsViews) + { + m_pViews = new OViewContainer(*this, m_aMutex, this, bCase,this,&m_aWarnings,m_nInAppend); + m_pViews->addContainerListener(m_pTables); + m_pTables->addContainerListener(m_pViews); + } + m_bSupportsUsers = Reference< XUsersSupplier> (getMasterTables(),UNO_QUERY).is(); + m_bSupportsGroups = Reference< XGroupsSupplier> (getMasterTables(),UNO_QUERY).is(); + + impl_checkTableQueryNames_nothrow(); + } + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + osl_decrementInterlockedCount( &m_refCount ); +} + +OConnection::~OConnection() +{ + delete m_pTables; + delete m_pViews; + DBG_DTOR(OConnection,NULL); +} + +// XWarningsSupplier +Any SAL_CALL OConnection::getWarnings() throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getWarnings" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + return m_aWarnings.getWarnings(); +} + +void SAL_CALL OConnection::clearWarnings( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::clearWarnings" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + m_aWarnings.clearWarnings(); +} + +namespace +{ + struct CompareTypeByName : public ::std::binary_function< Type, Type, bool > + { + bool operator() ( const Type& _rLHS, const Type& _rRHS ) const + { + return _rLHS.getTypeName() < _rRHS.getTypeName(); + } + }; + typedef ::std::set< Type, CompareTypeByName > TypeBag; + + void lcl_copyTypes( TypeBag& _out_rTypes, const Sequence< Type >& _rTypes ) + { + ::std::copy( _rTypes.getConstArray(), _rTypes.getConstArray() + _rTypes.getLength(), + ::std::insert_iterator< TypeBag >( _out_rTypes, _out_rTypes.begin() ) ); + } +} + +// com::sun::star::lang::XTypeProvider +Sequence< Type > OConnection::getTypes() throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getTypes" ); + TypeBag aNormalizedTypes; + + lcl_copyTypes( aNormalizedTypes, OSubComponent::getTypes() ); + lcl_copyTypes( aNormalizedTypes, OConnection_Base::getTypes() ); + lcl_copyTypes( aNormalizedTypes, ::connectivity::OConnectionWrapper::getTypes() ); + + if ( !m_bSupportsViews ) + aNormalizedTypes.erase( XViewsSupplier::static_type() ); + if ( !m_bSupportsUsers ) + aNormalizedTypes.erase( XUsersSupplier::static_type() ); + if ( !m_bSupportsGroups ) + aNormalizedTypes.erase( XGroupsSupplier::static_type() ); + + Sequence< Type > aSupportedTypes( aNormalizedTypes.size() ); + ::std::copy( aNormalizedTypes.begin(), aNormalizedTypes.end(), aSupportedTypes.getArray() ); + return aSupportedTypes; +} + +Sequence< sal_Int8 > OConnection::getImplementationId() throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getImplementationId" ); + return getUnoTunnelImplementationId(); +} + +// com::sun::star::uno::XInterface +Any OConnection::queryInterface( const Type & rType ) throw (RuntimeException) +{ + if ( !m_bSupportsViews && rType.equals( XViewsSupplier::static_type() ) ) + return Any(); + else if ( !m_bSupportsUsers && rType.equals( XUsersSupplier::static_type() ) ) + return Any(); + else if ( !m_bSupportsGroups && rType.equals( XGroupsSupplier::static_type() ) ) + return Any(); + Any aReturn = OSubComponent::queryInterface( rType ); + if (!aReturn.hasValue()) + { + aReturn = OConnection_Base::queryInterface( rType ); + if (!aReturn.hasValue()) + aReturn = OConnectionWrapper::queryInterface( rType ); + } + return aReturn; +} + +void OConnection::acquire() throw () +{ + // include this one when you want to see who calls it (call graph) + OSubComponent::acquire(); +} + +void OConnection::release() throw () +{ + // include this one when you want to see who calls it (call graph) + OSubComponent::release(); +} + +// OSubComponent +void OConnection::disposing() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::disposing" ); + MutexGuard aGuard(m_aMutex); + + OSubComponent::disposing(); + OConnectionWrapper::disposing(); + + OWeakRefArrayIterator aEnd = m_aStatements.end(); + for (OWeakRefArrayIterator i = m_aStatements.begin(); aEnd != i; ++i) + { + Reference<XComponent> xComp(i->get(),UNO_QUERY); + ::comphelper::disposeComponent(xComp); + } + m_aStatements.clear(); + m_xMasterTables = NULL; + + if(m_pTables) + m_pTables->dispose(); + if(m_pViews) + m_pViews->dispose(); + + ::comphelper::disposeComponent(m_xQueries); + + OWeakRefArrayIterator aComposerEnd = m_aComposers.end(); + for (OWeakRefArrayIterator j = m_aComposers.begin(); aComposerEnd != j; ++j) + { + Reference<XComponent> xComp(j->get(),UNO_QUERY); + ::comphelper::disposeComponent(xComp); + } + + m_aComposers.clear(); + + try + { + if (m_xMasterConnection.is()) + m_xMasterConnection->close(); + } + catch(Exception) + { + } + m_xMasterConnection = NULL; +} + +// XChild +Reference< XInterface > OConnection::getParent(void) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getParent" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + return m_xParent; +} + +void OConnection::setParent(const Reference< XInterface > & /*Parent*/) throw( NoSupportException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::setParent" ); + throw NoSupportException(); +} + +// XSQLQueryComposerFactory +Reference< XSQLQueryComposer > OConnection::createQueryComposer(void) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::createQueryComposer" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + + // Reference< XNumberFormatsSupplier > xSupplier = pParent->getNumberFormatsSupplier(); + Reference< XSQLQueryComposer > xComposer( new OQueryComposer( this ) ); + m_aComposers.push_back(WeakReferenceHelper(xComposer)); + return xComposer; +} + +void OConnection::impl_fillTableFilter() +{ + Reference<XPropertySet> xProp(getParent(),UNO_QUERY); + if ( xProp.is() ) + { + xProp->getPropertyValue(PROPERTY_TABLEFILTER) >>= m_aTableFilter; + xProp->getPropertyValue(PROPERTY_TABLETYPEFILTER) >>= m_aTableTypeFilter; + } +} + +void OConnection::refresh(const Reference< XNameAccess >& _rToBeRefreshed) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::refresh" ); + if ( _rToBeRefreshed == Reference< XNameAccess >(m_pTables) ) + { + if (m_pTables && !m_pTables->isInitialized()) + { + impl_fillTableFilter(); + // check if our "master connection" can supply tables + getMasterTables(); + + if (m_xMasterTables.is() && m_xMasterTables->getTables().is()) + { // yes -> wrap them + m_pTables->construct(m_xMasterTables->getTables(),m_aTableFilter, m_aTableTypeFilter); + } + else + { // no -> use an own container + m_pTables->construct(m_aTableFilter, m_aTableTypeFilter); + } + } + } + else if ( _rToBeRefreshed == Reference< XNameAccess >(m_pViews) ) + { + if (m_pViews && !m_pViews->isInitialized()) + { + impl_fillTableFilter(); + // check if our "master connection" can supply tables + Reference< XViewsSupplier > xMaster(getMasterTables(),UNO_QUERY); + + if (xMaster.is() && xMaster->getViews().is()) + m_pViews->construct(xMaster->getViews(),m_aTableFilter, m_aTableTypeFilter); + else + m_pViews->construct(m_aTableFilter, m_aTableTypeFilter); + } + } +} + +// XTablesSupplier +Reference< XNameAccess > OConnection::getTables() throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getTables" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + + refresh(m_pTables); + + return m_pTables; +} + +Reference< XNameAccess > SAL_CALL OConnection::getViews( ) throw(RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getViews" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + + refresh(m_pViews); + + return m_pViews; +} +// XQueriesSupplier +Reference< XNameAccess > OConnection::getQueries(void) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getQueries" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + + return m_xQueries; +} + +// ::com::sun::star::sdb::XCommandPreparation +Reference< XPreparedStatement > SAL_CALL OConnection::prepareCommand( const ::rtl::OUString& command, sal_Int32 commandType ) throw(::com::sun::star::sdbc::SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::prepareCommand" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + + rtl::OUString aStatement; + switch (commandType) + { + case CommandType::TABLE: + { + aStatement = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SELECT * FROM ")); + + ::rtl::OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents( getMetaData(), command, sCatalog, sSchema, sTable, ::dbtools::eInDataManipulation ); + aStatement += ::dbtools::composeTableNameForSelect( this, sCatalog, sSchema, sTable ); + } + break; + case CommandType::QUERY: + if ( m_xQueries->hasByName(command) ) + { + Reference< XPropertySet > xQuery(m_xQueries->getByName(command),UNO_QUERY); + xQuery->getPropertyValue(PROPERTY_COMMAND) >>= aStatement; + } + break; + default: + aStatement = command; + } + // TODO EscapeProcessing + return prepareStatement(aStatement); +} + +Reference< XInterface > SAL_CALL OConnection::createInstance( const ::rtl::OUString& _sServiceSpecifier ) throw (Exception, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::createInstance" ); + Reference< XServiceInfo > xRet; + if ( ( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER == _sServiceSpecifier ) + || ( _sServiceSpecifier.equalsAscii( "com.sun.star.sdb.SingleSelectQueryAnalyzer" ) ) + ) + { + xRet = new OSingleSelectQueryComposer( getTables(),this, m_aContext ); + m_aComposers.push_back(WeakReferenceHelper(xRet)); + } + else + { + if ( _sServiceSpecifier.getLength() ) + { + TSupportServices::iterator aFind = m_aSupportServices.find(_sServiceSpecifier); + if ( aFind == m_aSupportServices.end() ) + { + Sequence<Any> aArgs(1); + Reference<XConnection> xMy(this); + aArgs[0] <<= NamedValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ActiveConnection")),makeAny(xMy)); + aFind = m_aSupportServices.insert(TSupportServices::value_type(_sServiceSpecifier,m_aContext.createComponentWithArguments(_sServiceSpecifier,aArgs))).first; + } + return aFind->second; + } + } + return Reference< XInterface >(xRet,UNO_QUERY); +} + +Reference< XInterface > SAL_CALL OConnection::createInstanceWithArguments( const ::rtl::OUString& _sServiceSpecifier, const Sequence< Any >& /*Arguments*/ ) throw (Exception, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::createInstanceWithArguments" ); + return createInstance(_sServiceSpecifier); +} + +Sequence< ::rtl::OUString > SAL_CALL OConnection::getAvailableServiceNames( ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getAvailableServiceNames" ); + Sequence< ::rtl::OUString > aRet(1); + aRet[0] = SERVICE_NAME_SINGLESELECTQUERYCOMPOSER; + return aRet; +} + +Reference< XTablesSupplier > OConnection::getMasterTables() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getMasterTables" ); +// check if out "master connection" can supply tables + if(!m_xMasterTables.is()) + { + try + { + Reference<XDatabaseMetaData> xMeta = getMetaData(); + if ( xMeta.is() ) + m_xMasterTables = ::dbtools::getDataDefinitionByURLAndConnection( xMeta->getURL(), m_xMasterConnection, m_aContext.getLegacyServiceFactory() ); + } + catch(SQLException&) + { + } + } + return m_xMasterTables; +} + +// XUsersSupplier +Reference< XNameAccess > SAL_CALL OConnection::getUsers( ) throw(RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getUsers" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + + Reference<XUsersSupplier> xUsr(getMasterTables(),UNO_QUERY); + return xUsr.is() ? xUsr->getUsers() : Reference< XNameAccess >(); +} + +// XGroupsSupplier +Reference< XNameAccess > SAL_CALL OConnection::getGroups( ) throw(RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getGroups" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + Reference<XGroupsSupplier> xGrp(getMasterTables(),UNO_QUERY); + return xGrp.is() ? xGrp->getGroups() : Reference< XNameAccess >(); +} + +void OConnection::impl_loadConnectionTools_throw() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::impl_loadConnectionTools_throw" ); + Sequence< Any > aArguments( 1 ); + aArguments[0] <<= NamedValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Connection" ) ), makeAny( Reference< XConnection >( this ) ) ); + + if ( !m_aContext.createComponentWithArguments( "com.sun.star.sdb.tools.ConnectionTools", aArguments, m_xConnectionTools ) ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "service not registered: com.sun.star.sdb.tools.ConnectionTools" ) ), *this ); +} + +Reference< XTableName > SAL_CALL OConnection::createTableName( ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::createTableName" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + impl_loadConnectionTools_throw(); + + return m_xConnectionTools->createTableName(); +} + +Reference< XObjectNames > SAL_CALL OConnection::getObjectNames( ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getObjectNames" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + impl_loadConnectionTools_throw(); + + return m_xConnectionTools->getObjectNames(); +} + +Reference< XDataSourceMetaData > SAL_CALL OConnection::getDataSourceMetaData( ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getDataSourceMetaData" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + impl_loadConnectionTools_throw(); + + return m_xConnectionTools->getDataSourceMetaData(); +} + +Reference< ::com::sun::star::container::XNameAccess > SAL_CALL OConnection::getFieldsByCommandDescriptor( ::sal_Int32 commandType, const ::rtl::OUString& command, ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& keepFieldsAlive ) throw (::com::sun::star::sdbc::SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getFieldsByCommandDescriptor" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + impl_loadConnectionTools_throw(); + + return m_xConnectionTools->getFieldsByCommandDescriptor(commandType,command,keepFieldsAlive); +} + +Reference< XSingleSelectQueryComposer > SAL_CALL OConnection::getComposer( ::sal_Int32 commandType, const ::rtl::OUString& command ) throw (::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getComposer" ); + MutexGuard aGuard(m_aMutex); + checkDisposed(); + impl_loadConnectionTools_throw(); + + return m_xConnectionTools->getComposer(commandType,command); +} + +void OConnection::impl_checkTableQueryNames_nothrow() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::impl_checkTableQueryNames_nothrow" ); + DatabaseMetaData aMeta( static_cast< XConnection* >( this ) ); + if ( !aMeta.supportsSubqueriesInFrom() ) + // nothing to do + return; + + try + { + Reference< XNameAccess > xTables( getTables() ); + Sequence< ::rtl::OUString > aTableNames( xTables->getElementNames() ); + ::std::set< ::rtl::OUString > aSortedTableNames( aTableNames.getConstArray(), aTableNames.getConstArray() + aTableNames.getLength() ); + + Reference< XNameAccess > xQueries( getQueries() ); + Sequence< ::rtl::OUString > aQueryNames( xQueries->getElementNames() ); + + for ( const ::rtl::OUString* pQueryName = aQueryNames.getConstArray(); + pQueryName != aQueryNames.getConstArray() + aQueryNames.getLength(); + ++pQueryName + ) + { + if ( aSortedTableNames.find( *pQueryName ) != aSortedTableNames.end() ) + { + ::rtl::OUString sConflictWarning( DBACORE_RESSTRING( RID_STR_CONFLICTING_NAMES ) ); + m_aWarnings.appendWarning( sConflictWarning, "01SB0", *this ); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +Reference< XGraphic > SAL_CALL OConnection::getTableIcon( const ::rtl::OUString& _TableName, ::sal_Int32 _ColorMode ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getTableIcon" ); + Reference< XGraphic > xReturn; + + // ask our aggregate + if ( m_xTableUIProvider.is() ) + xReturn = m_xTableUIProvider->getTableIcon( _TableName, _ColorMode ); + + // ask ourself + // well, we don't have own functionality here ... + // In the future, we might decide to delegate the complete handling to this interface. + // In this case, we would need to load the icon here. + + return xReturn; +} + +Reference< XInterface > SAL_CALL OConnection::getTableEditor( const Reference< XDatabaseDocumentUI >& _DocumentUI, const ::rtl::OUString& _TableName ) throw (IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getTableEditor" ); + Reference< XInterface > xReturn; + + // ask our aggregate + if ( m_xTableUIProvider.is() ) + xReturn = m_xTableUIProvider->getTableEditor( _DocumentUI, _TableName ); + + // ask ourself + // well, we don't have own functionality here ... + // In the future, we might decide to delegate the complete handling to this interface. + // In this case, we would need to instantiate an css.sdb.TableDesign here. + + return xReturn; +} + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/connection.hxx b/dbaccess/source/core/dataaccess/connection.hxx new file mode 100644 index 000000000000..2918d4f74192 --- /dev/null +++ b/dbaccess/source/core/dataaccess/connection.hxx @@ -0,0 +1,254 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 _DBA_CORE_CONNECTION_HXX_ +#define _DBA_CORE_CONNECTION_HXX_ + +#include "apitools.hxx" +#include "querycontainer.hxx" +#include "tablecontainer.hxx" +#include "viewcontainer.hxx" +#include "RefreshListener.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp> +#include <com/sun/star/sdb/XCommandPreparation.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/sdbcx/XUsersSupplier.hpp> +#include <com/sun/star/sdbcx/XGroupsSupplier.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/sdb/tools/XConnectionTools.hpp> +#include <com/sun/star/sdb/application/XTableUIProvider.hpp> +/** === end UNO includes === **/ + +#if ! defined(INCLUDED_COMPHELPER_IMPLBASE_VAR_HXX_14) +#define INCLUDED_COMPHELPER_IMPLBASE_VAR_HXX_14 +#define COMPHELPER_IMPLBASE_INTERFACE_NUMBER 14 +#include <comphelper/implbase_var.hxx> +#endif +#include <comphelper/componentcontext.hxx> +#include <comphelper/stl_types.hxx> +#include <connectivity/ConnectionWrapper.hxx> +#include <connectivity/warningscontainer.hxx> + +//........................................................................ +namespace dbaccess +{ +//........................................................................ + +//========================================================================== +//========================================================================== +typedef ::comphelper::ImplHelper14 < ::com::sun::star::container::XChild + , ::com::sun::star::sdbcx::XTablesSupplier + , ::com::sun::star::sdbcx::XViewsSupplier + , ::com::sun::star::sdbc::XConnection + , ::com::sun::star::sdbc::XWarningsSupplier + , ::com::sun::star::sdb::XQueriesSupplier + , ::com::sun::star::sdb::XSQLQueryComposerFactory + , ::com::sun::star::sdb::XCommandPreparation + , ::com::sun::star::lang::XServiceInfo + , ::com::sun::star::lang::XMultiServiceFactory + , ::com::sun::star::sdbcx::XUsersSupplier + , ::com::sun::star::sdbcx::XGroupsSupplier + , ::com::sun::star::sdb::tools::XConnectionTools + , ::com::sun::star::sdb::application::XTableUIProvider + > OConnection_Base; + +class ODatabaseSource; +//========================================================================== +//= OConnection +//========================================================================== +class OConnection :public ::comphelper::OBaseMutex + ,public OSubComponent + ,public ::connectivity::OConnectionWrapper + ,public OConnection_Base + ,public IRefreshListener +{ +protected: + ::com::sun::star::uno::Reference< ::com::sun::star::sdbcx::XTablesSupplier > + m_xMasterTables; // just to avoid the recreation of the catalog + OWeakRefArray m_aStatements; + ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > + m_xQueries; + OWeakRefArray m_aComposers; + + // the filter as set on the parent data link at construction of the connection + ::com::sun::star::uno::Sequence< ::rtl::OUString > m_aTableFilter; + ::com::sun::star::uno::Sequence< ::rtl::OUString > m_aTableTypeFilter; + ::comphelper::ComponentContext m_aContext; + ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection > m_xMasterConnection; + ::com::sun::star::uno::Reference< ::com::sun::star::sdb::tools::XConnectionTools > m_xConnectionTools; + ::com::sun::star::uno::Reference< ::com::sun::star::sdb::application::XTableUIProvider > m_xTableUIProvider; + + // defines the helper services for example to query the command of a view + // @ see com.sun.star.sdb.tools.XViewAccess + DECLARE_STL_USTRINGACCESS_MAP( ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>, TSupportServices); + TSupportServices m_aSupportServices; + + + OTableContainer* m_pTables; + OViewContainer* m_pViews; + ::dbtools::WarningsContainer m_aWarnings; + oslInterlockedCount m_nInAppend; + sal_Bool m_bSupportsViews; // true when the getTableTypes return "VIEW" as type + sal_Bool m_bSupportsUsers; + sal_Bool m_bSupportsGroups; + +protected: + virtual ~OConnection(); +public: + OConnection(ODatabaseSource& _rDB + ,::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxMaster + ,const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxORB); + +// com::sun::star::lang::XTypeProvider + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes() throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() throw (::com::sun::star::uno::RuntimeException); + +// com::sun::star::uno::XInterface + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL acquire() throw( ); + virtual void SAL_CALL release() throw( ); + +// OComponentHelper + virtual void SAL_CALL disposing(void); + +// ::com::sun::star::container::XChild + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL getParent( ) throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setParent( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& Parent ) throw(::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + +// ::com::sun::star::sdbcx::XTablesSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getTables( ) throw(::com::sun::star::uno::RuntimeException); +// ::com::sun::star::sdbcx::XViewsSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getViews( ) throw(::com::sun::star::uno::RuntimeException); + +// ::com::sun::star::sdb::XQueriesSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getQueries( ) throw(::com::sun::star::uno::RuntimeException); + +// ::com::sun::star::sdb::XSQLQueryComposerFactory + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XSQLQueryComposer > SAL_CALL createQueryComposer( ) throw(::com::sun::star::uno::RuntimeException); + +// ::com::sun::star::sdb::XCommandPreparation + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XPreparedStatement > SAL_CALL prepareCommand( const ::rtl::OUString& command, sal_Int32 commandType ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + +// ::com::sun::star::sdbc::XWarningsSupplier + virtual ::com::sun::star::uno::Any SAL_CALL getWarnings( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL clearWarnings( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + +// ::com::sun::star::lang::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); + +// XConnection + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XStatement > SAL_CALL createStatement( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const ::rtl::OUString& sql ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XPreparedStatement > SAL_CALL prepareCall( const ::rtl::OUString& sql ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL nativeSQL( const ::rtl::OUString& sql ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL getAutoCommit( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL commit( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL rollback( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isClosed( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isReadOnly( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setCatalog( const ::rtl::OUString& catalog ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getCatalog( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getTypeMap( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setTypeMap( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >& typeMap ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + +// ::com::sun::star::sdbc::XCloseable + virtual void SAL_CALL close( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + + // XMultiServiceFactory + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstance( const ::rtl::OUString& aServiceSpecifier ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstanceWithArguments( const ::rtl::OUString& ServiceSpecifier, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Arguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getAvailableServiceNames( ) throw (::com::sun::star::uno::RuntimeException); + + // XUsersSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getUsers( ) throw(::com::sun::star::uno::RuntimeException); + // XGroupsSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getGroups( ) throw(::com::sun::star::uno::RuntimeException); + + // XConnectionTools + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdb::tools::XTableName > SAL_CALL createTableName( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdb::tools::XObjectNames > SAL_CALL getObjectNames( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdb::tools::XDataSourceMetaData > SAL_CALL getDataSourceMetaData( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getFieldsByCommandDescriptor( ::sal_Int32 commandType, const ::rtl::OUString& command, ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& keepFieldsAlive ) throw (::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XSingleSelectQueryComposer > SAL_CALL getComposer( ::sal_Int32 commandType, const ::rtl::OUString& command ) throw (::com::sun::star::uno::RuntimeException); + + // XTableUIProvider + virtual ::com::sun::star::uno::Reference< ::com::sun::star::graphic::XGraphic > SAL_CALL getTableIcon( const ::rtl::OUString& TableName, ::sal_Int32 ColorMode ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL getTableEditor( const ::com::sun::star::uno::Reference< ::com::sun::star::sdb::application::XDatabaseDocumentUI >& DocumentUI, const ::rtl::OUString& TableName ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // IRefreshListener + virtual void refresh(const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >& _rToBeRefreshed); + +protected: + inline void checkDisposed() throw (::com::sun::star::lang::DisposedException) + { + if ( rBHelper.bDisposed || !m_xConnection.is() ) + throw ::com::sun::star::lang::DisposedException(); + } + + ::com::sun::star::uno::Reference< ::com::sun::star::sdbcx::XTablesSupplier > getMasterTables(); + +private: + /** checks whether or not there are naming conflicts between tables and queries + */ + void impl_checkTableQueryNames_nothrow(); + + /** loads the XConnectionTools implementation which we forward the respective functionality to + + @throws ::com::sun::star::uno::RuntimeException + if the implementation cannot be loaded + + @postcond + m_xConnectionTools is nol <NULL/> + */ + void impl_loadConnectionTools_throw(); + + /** reads the table filter and table type filter from the datasourfce + */ + void impl_fillTableFilter(); +}; + +//........................................................................ +} // namespace dbaccess +//........................................................................ + +#endif // _DBA_CORE_CONNECTION_HXX_ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx b/dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx new file mode 100644 index 000000000000..0a5432f79db7 --- /dev/null +++ b/dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx @@ -0,0 +1,328 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +#include "dbastrings.hrc" +#include "module_dba.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdb/XDataAccessDescriptorFactory.hpp> +/** === end UNO includes === **/ + +#include <comphelper/broadcasthelper.hxx> +#include <comphelper/componentcontext.hxx> +#include <comphelper/proparrhlp.hxx> +#include <comphelper/propertycontainer.hxx> +#include <comphelper/uno3.hxx> +#include <cppuhelper/implbase1.hxx> +#include <cppuhelper/implbase2.hxx> + +//........................................................................ +namespace dbaccess +{ +//........................................................................ + + /** === 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::lang::XServiceInfo; + using ::com::sun::star::lang::XMultiServiceFactory; + using ::com::sun::star::beans::XPropertySetInfo; + using ::com::sun::star::beans::Property; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::sdbc::XResultSet; + using ::com::sun::star::sdb::XDataAccessDescriptorFactory; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::beans::PropertyValue; + /** === end UNO using === **/ + + namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute; + namespace CommandType = ::com::sun::star::sdb::CommandType; + + //==================================================================== + //= DataAccessDescriptor + //==================================================================== + typedef ::comphelper::OMutexAndBroadcastHelper DataAccessDescriptor_MutexBase; + + typedef ::cppu::WeakImplHelper1 < XServiceInfo + > DataAccessDescriptor_TypeBase; + + typedef ::comphelper::OPropertyContainer DataAccessDescriptor_PropertyBase; + + class DataAccessDescriptor :public DataAccessDescriptor_MutexBase + ,public DataAccessDescriptor_TypeBase + ,public DataAccessDescriptor_PropertyBase + ,public ::comphelper::OPropertyArrayUsageHelper< DataAccessDescriptor > + { + public: + DataAccessDescriptor( const ::comphelper::ComponentContext& _rContext ); + + // UNO + DECLARE_XINTERFACE() + DECLARE_XTYPEPROVIDER() + + // 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); + + protected: + ~DataAccessDescriptor(); + + protected: + // XPropertySet + virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() throw(RuntimeException); + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper(); + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const; + + private: + ::comphelper::ComponentContext m_aContext; + + // </properties> + ::rtl::OUString m_sDataSourceName; + ::rtl::OUString m_sDatabaseLocation; + ::rtl::OUString m_sConnectionResource; + Sequence< PropertyValue > m_aConnectionInfo; + Reference< XConnection > m_xActiveConnection; + ::rtl::OUString m_sCommand; + sal_Int32 m_nCommandType; + ::rtl::OUString m_sFilter; + ::rtl::OUString m_sOrder; + ::rtl::OUString m_sHavingClause; + ::rtl::OUString m_sGroupBy; + sal_Bool m_bEscapeProcessing; + Reference< XResultSet > m_xResultSet; + Sequence< Any > m_aSelection; + sal_Bool m_bBookmarkSelection; + ::rtl::OUString m_sColumnName; + Reference< XPropertySet > m_xColumn; + // </properties> + }; + +#define REGISTER_PROPERTY( propname, member ) \ + registerProperty( PROPERTY_##propname, PROPERTY_ID_##propname, PropertyAttribute::BOUND, &member, ::getCppuType( &member ) ) + + DataAccessDescriptor::DataAccessDescriptor( const ::comphelper::ComponentContext& _rContext ) + :DataAccessDescriptor_MutexBase() + ,DataAccessDescriptor_TypeBase() + ,DataAccessDescriptor_PropertyBase( m_aBHelper ) + ,m_aContext( _rContext ) + ,m_sDataSourceName() + ,m_sDatabaseLocation() + ,m_sConnectionResource() + ,m_aConnectionInfo() + ,m_xActiveConnection() + ,m_sCommand() + ,m_nCommandType( CommandType::COMMAND ) + ,m_sFilter() + ,m_sOrder() + ,m_sHavingClause() + ,m_sGroupBy() + ,m_bEscapeProcessing( sal_True ) + ,m_xResultSet() + ,m_aSelection() + ,m_bBookmarkSelection( sal_True ) + ,m_sColumnName() + ,m_xColumn() + { + REGISTER_PROPERTY( DATASOURCENAME, m_sDataSourceName ); + REGISTER_PROPERTY( DATABASE_LOCATION, m_sDatabaseLocation ); + REGISTER_PROPERTY( CONNECTION_RESOURCE, m_sConnectionResource ); + REGISTER_PROPERTY( CONNECTION_INFO, m_aConnectionInfo ); + REGISTER_PROPERTY( ACTIVE_CONNECTION, m_xActiveConnection ); + REGISTER_PROPERTY( COMMAND, m_sCommand ); + REGISTER_PROPERTY( COMMAND_TYPE, m_nCommandType ); + REGISTER_PROPERTY( FILTER, m_sFilter ); + REGISTER_PROPERTY( ORDER, m_sOrder ); + REGISTER_PROPERTY( HAVING_CLAUSE, m_sHavingClause ); + REGISTER_PROPERTY( GROUP_BY, m_sGroupBy ); + REGISTER_PROPERTY( ESCAPE_PROCESSING, m_bEscapeProcessing ); + REGISTER_PROPERTY( RESULT_SET, m_xResultSet ); + REGISTER_PROPERTY( SELECTION, m_aSelection ); + REGISTER_PROPERTY( BOOKMARK_SELECTION, m_bBookmarkSelection ); + REGISTER_PROPERTY( COLUMN_NAME, m_sColumnName ); + REGISTER_PROPERTY( COLUMN, m_xColumn ); + } + + DataAccessDescriptor::~DataAccessDescriptor() + { + } + + IMPLEMENT_FORWARD_XINTERFACE2( DataAccessDescriptor, DataAccessDescriptor_TypeBase, DataAccessDescriptor_PropertyBase ); + + IMPLEMENT_FORWARD_XTYPEPROVIDER2( DataAccessDescriptor, DataAccessDescriptor_TypeBase, DataAccessDescriptor_PropertyBase ); + + ::rtl::OUString SAL_CALL DataAccessDescriptor::getImplementationName() throw (RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.dba.DataAccessDescriptor" ) ); + } + + ::sal_Bool SAL_CALL DataAccessDescriptor::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 DataAccessDescriptor::getSupportedServiceNames( ) throw (RuntimeException) + { + Sequence< ::rtl::OUString > aServices(1); + aServices[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.DataAccessDescriptor" ) ); + return aServices; + } + + Reference< XPropertySetInfo > SAL_CALL DataAccessDescriptor::getPropertySetInfo() throw(RuntimeException) + { + Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + + ::cppu::IPropertyArrayHelper& DataAccessDescriptor::getInfoHelper() + { + return *getArrayHelper(); + } + + ::cppu::IPropertyArrayHelper* DataAccessDescriptor::createArrayHelper( ) const + { + Sequence< Property > aProps; + describeProperties( aProps ); + return new ::cppu::OPropertyArrayHelper( aProps ); + } + + //==================================================================== + //= DataAccessDescriptorFactory + //==================================================================== + typedef ::cppu::WeakImplHelper2 < XServiceInfo + , XDataAccessDescriptorFactory + > DataAccessDescriptorFactory_Base; + class DataAccessDescriptorFactory : public DataAccessDescriptorFactory_Base + { + public: + // 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); + + // XServiceInfo - static versions + static Sequence< ::rtl::OUString > getSupportedServiceNames_static(void) throw( RuntimeException ); + static ::rtl::OUString getImplementationName_static(void) throw( RuntimeException ); + static Reference< XInterface > Create(const Reference< XComponentContext >& _rxContext); + static ::rtl::OUString getSingletonName_static(); + + // XDataAccessDescriptorFactory + virtual Reference< XPropertySet > SAL_CALL createDataAccessDescriptor( ) throw (RuntimeException); + + protected: + DataAccessDescriptorFactory( const Reference< XComponentContext >& _rxContext ); + ~DataAccessDescriptorFactory(); + + private: + ::comphelper::ComponentContext m_aContext; + }; + + DataAccessDescriptorFactory::DataAccessDescriptorFactory( const Reference< XComponentContext >& _rxContext ) + :m_aContext( _rxContext ) + { + } + + DataAccessDescriptorFactory::~DataAccessDescriptorFactory() + { + } + + ::rtl::OUString DataAccessDescriptorFactory::getSingletonName_static() + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.DataAccessDescriptorFactory" ) ); + } + + Sequence< ::rtl::OUString > DataAccessDescriptorFactory::getSupportedServiceNames_static() throw( RuntimeException ) + { + Sequence< ::rtl::OUString > aServices(1); + aServices[0] = getSingletonName_static(); + return aServices; + } + + ::rtl::OUString DataAccessDescriptorFactory::getImplementationName_static() throw( RuntimeException ) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.dba.DataAccessDescriptorFactory" ) ); + } + + Reference< XInterface > DataAccessDescriptorFactory::Create( const Reference< XComponentContext >& _rxContext ) + { + return *( new DataAccessDescriptorFactory( _rxContext ) ); + } + + ::rtl::OUString SAL_CALL DataAccessDescriptorFactory::getImplementationName() throw (RuntimeException) + { + return getImplementationName_static(); + } + + ::sal_Bool SAL_CALL DataAccessDescriptorFactory::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 DataAccessDescriptorFactory::getSupportedServiceNames( ) throw (RuntimeException) + { + return getSupportedServiceNames_static(); + } + + Reference< XPropertySet > SAL_CALL DataAccessDescriptorFactory::createDataAccessDescriptor( ) throw (RuntimeException) + { + return new DataAccessDescriptor( m_aContext ); + } + +} // namespace dbaccess + +extern "C" void SAL_CALL createRegistryInfo_DataAccessDescriptorFactory() +{ + static ::dba::OSingletonRegistration< ::dbaccess::DataAccessDescriptorFactory > aAutoRegistration; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/databasecontext.cxx b/dbaccess/source/core/dataaccess/databasecontext.cxx new file mode 100644 index 000000000000..6fcf10a307d1 --- /dev/null +++ b/dbaccess/source/core/dataaccess/databasecontext.cxx @@ -0,0 +1,770 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +#include "apitools.hxx" +#include "core_resource.hrc" +#include "core_resource.hxx" +#include "databasecontext.hxx" +#include "databasedocument.hxx" +#include "databaseregistrations.hxx" +#include "datasource.hxx" +#include "dbastrings.hrc" +#include "module_dba.hxx" + +/** === being UNO includes === **/ +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/document/MacroExecMode.hpp> +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/document/XImporter.hpp> +#include <com/sun/star/frame/XDesktop.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XModel2.hpp> +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/registry/InvalidRegistryException.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/task/InteractionClassification.hpp> +#include <com/sun/star/ucb/InteractiveIOException.hpp> +#include <com/sun/star/ucb/IOErrorCode.hpp> +#include <com/sun/star/util/XCloseable.hpp> +/** === end UNO includes === **/ + +#include <basic/basmgr.hxx> +#include <comphelper/enumhelper.hxx> +#include <comphelper/evtlistenerhlp.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/implbase1.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <svl/filenotation.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <tools/fsys.hxx> +#include <tools/urlobj.hxx> +#include <ucbhelper/content.hxx> +#include <unotools/confignode.hxx> +#include <unotools/pathoptions.hxx> +#include <unotools/sharedunocomponent.hxx> +#include <list> +#include <boost/bind.hpp> + +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::registry; +using namespace ::com::sun::star; +using namespace ::cppu; +using namespace ::osl; +using namespace ::utl; + +using ::com::sun::star::task::InteractionClassification_ERROR; +using ::com::sun::star::ucb::IOErrorCode_NO_FILE; +using ::com::sun::star::ucb::InteractiveIOException; +using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING; +using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING_PATH; + + +extern "C" void SAL_CALL createRegistryInfo_ODatabaseContext() +{ + static ::dba::OLegacySingletonRegistration< ::dbaccess::ODatabaseContext > aODatabaseContext_AutoRegistration; +} + +namespace dbaccess +{ + + typedef ::cppu::WeakImplHelper1 < XTerminateListener + > DatabaseDocumentLoader_Base; + class DatabaseDocumentLoader : public DatabaseDocumentLoader_Base + { + private: + Reference< XDesktop > m_xDesktop; + ::std::list< const ODatabaseModelImpl* > m_aDatabaseDocuments; + + public: + DatabaseDocumentLoader( const comphelper::ComponentContext& _aContext); + + inline void append(const ODatabaseModelImpl& _rModelImpl ) + { + m_aDatabaseDocuments.push_back(&_rModelImpl); + } + inline void remove(const ODatabaseModelImpl& _rModelImpl) { m_aDatabaseDocuments.remove(&_rModelImpl); } + + private: + // XTerminateListener + virtual void SAL_CALL queryTermination( const lang::EventObject& Event ) throw (TerminationVetoException, RuntimeException); + virtual void SAL_CALL notifyTermination( const lang::EventObject& Event ) throw (RuntimeException); + // XEventListener + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); + }; + + DatabaseDocumentLoader::DatabaseDocumentLoader( const comphelper::ComponentContext& _aContext ) + { + acquire(); + try + { + m_xDesktop.set( _aContext.createComponent( (rtl::OUString)SERVICE_FRAME_DESKTOP ), UNO_QUERY_THROW ); + m_xDesktop->addTerminateListener( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + struct TerminateFunctor : ::std::unary_function<ODatabaseModelImpl* , void> + { + void operator()( const ODatabaseModelImpl* _pModelImpl ) const + { + try + { + const Reference< XModel2> xModel( _pModelImpl ->getModel_noCreate(),UNO_QUERY_THROW ); + if ( !xModel->getControllers()->hasMoreElements() ) + { + Reference<util::XCloseable> xCloseable(xModel,UNO_QUERY_THROW); + xCloseable->close(sal_False); + } // if ( !xModel->getControllers()->hasMoreElements() ) + } + catch(const CloseVetoException&) + { + throw TerminationVetoException(); + } + } + }; + + void SAL_CALL DatabaseDocumentLoader::queryTermination( const lang::EventObject& /*Event*/ ) throw (TerminationVetoException, RuntimeException) + { + ::std::list< const ODatabaseModelImpl* > aCopy(m_aDatabaseDocuments); + ::std::for_each(aCopy.begin(),aCopy.end(),TerminateFunctor()); + } + + void SAL_CALL DatabaseDocumentLoader::notifyTermination( const lang::EventObject& /*Event*/ ) throw (RuntimeException) + { + } + + void SAL_CALL DatabaseDocumentLoader::disposing( const lang::EventObject& /*Source*/ ) throw (RuntimeException) + { + } + +//= ODatabaseContext +//========================================================================== + +ODatabaseContext::ODatabaseContext( const Reference< XComponentContext >& _rxContext ) + :DatabaseAccessContext_Base(m_aMutex) + ,m_aContext( _rxContext ) + ,m_aContainerListeners(m_aMutex) +{ + m_pDatabaseDocumentLoader = new DatabaseDocumentLoader( m_aContext ); + ::basic::BasicManagerRepository::registerCreationListener( *this ); + + osl_incrementInterlockedCount( &m_refCount ); + { + m_xDBRegistrationAggregate.set( createDataSourceRegistrations( m_aContext ), UNO_SET_THROW ); + m_xDatabaseRegistrations.set( m_xDBRegistrationAggregate, UNO_QUERY_THROW ); + + m_xDBRegistrationAggregate->setDelegator( *this ); + } + osl_decrementInterlockedCount( &m_refCount ); +} + +ODatabaseContext::~ODatabaseContext() +{ + ::basic::BasicManagerRepository::revokeCreationListener( *this ); + if ( m_pDatabaseDocumentLoader ) + m_pDatabaseDocumentLoader->release(); + + m_xDBRegistrationAggregate->setDelegator( NULL ); + m_xDBRegistrationAggregate.clear(); + m_xDatabaseRegistrations.clear(); +} + +// Helper +rtl::OUString ODatabaseContext::getImplementationName_static() throw( RuntimeException ) + +{ + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.dba.ODatabaseContext")); +} + +Reference< XInterface > ODatabaseContext::Create(const Reference< XComponentContext >& _rxContext) +{ + return *( new ODatabaseContext( _rxContext ) ); +} + +Sequence< rtl::OUString > ODatabaseContext::getSupportedServiceNames_static(void) throw( RuntimeException ) +{ + Sequence< ::rtl::OUString > aSNS( 1 ); + aSNS[0] = SERVICE_SDB_DATABASECONTEXT; + return aSNS; +} + +// XServiceInfo +rtl::OUString ODatabaseContext::getImplementationName( ) throw(RuntimeException) +{ + return getImplementationName_static(); +} + +sal_Bool ODatabaseContext::supportsService( const ::rtl::OUString& _rServiceName ) throw (RuntimeException) +{ + return ::comphelper::findValue(getSupportedServiceNames(), _rServiceName, sal_True).getLength() != 0; +} + +Sequence< ::rtl::OUString > ODatabaseContext::getSupportedServiceNames( ) throw (RuntimeException) +{ + return getSupportedServiceNames_static(); +} + +Reference< XInterface > ODatabaseContext::impl_createNewDataSource() +{ + ::rtl::Reference<ODatabaseModelImpl> pImpl( new ODatabaseModelImpl( m_aContext.getLegacyServiceFactory(), *this ) ); + Reference< XDataSource > xDataSource( pImpl->getOrCreateDataSource() ); + + return xDataSource.get(); +} + +Reference< XInterface > SAL_CALL ODatabaseContext::createInstance( ) throw (Exception, RuntimeException) +{ + // for convenience of the API user, we ensure the document is fully initialized (effectively: XLoadable::initNew + // has been called at the DatabaseDocument). + return impl_createNewDataSource(); +} + +Reference< XInterface > SAL_CALL ODatabaseContext::createInstanceWithArguments( const Sequence< Any >& _rArguments ) throw (Exception, RuntimeException) +{ + ::comphelper::NamedValueCollection aArgs( _rArguments ); + ::rtl::OUString sURL = aArgs.getOrDefault( (::rtl::OUString)INFO_POOLURL, ::rtl::OUString() ); + + Reference< XInterface > xDataSource; + if ( sURL.getLength() ) + xDataSource = getObject( sURL ); + + if ( !xDataSource.is() ) + xDataSource = impl_createNewDataSource(); + + return xDataSource; +} + +// DatabaseAccessContext_Base +void ODatabaseContext::disposing() +{ + // notify our listener + com::sun::star::lang::EventObject aDisposeEvent(static_cast< XContainer* >(this)); + m_aContainerListeners.disposeAndClear(aDisposeEvent); + + // dispose the data sources + ObjectCache::iterator aEnd = m_aDatabaseObjects.end(); + for ( ObjectCache::iterator aIter = m_aDatabaseObjects.begin(); + aIter != aEnd; + ++aIter + ) + { + aIter->second->dispose(); + } + m_aDatabaseObjects.clear(); +} + +// XNamingService +Reference< XInterface > ODatabaseContext::getRegisteredObject(const rtl::OUString& _rName) throw( Exception, RuntimeException ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed); + + ::rtl::OUString sURL( getDatabaseLocation( _rName ) ); + + if ( !sURL.getLength() ) + // there is a registration for this name, but no URL + throw IllegalArgumentException(); + + // check if URL is already loaded + Reference< XInterface > xExistent = getObject( sURL ); + if ( xExistent.is() ) + return xExistent; + + return loadObjectFromURL( _rName, sURL ); +} + +Reference< XInterface > ODatabaseContext::loadObjectFromURL(const ::rtl::OUString& _rName,const ::rtl::OUString& _sURL) +{ + INetURLObject aURL( _sURL ); + if ( aURL.GetProtocol() == INET_PROT_NOT_VALID ) + throw NoSuchElementException( _rName, *this ); + + try + { + ::ucbhelper::Content aContent( _sURL, NULL ); + if ( !aContent.isDocument() ) + throw InteractiveIOException( + _sURL, *this, InteractionClassification_ERROR, IOErrorCode_NO_FILE + ); + } + catch ( const InteractiveIOException& e ) + { + if ( ( e.Code == IOErrorCode_NO_FILE ) + || ( e.Code == IOErrorCode_NOT_EXISTING ) + || ( e.Code == IOErrorCode_NOT_EXISTING_PATH ) + ) + { + // #i40463# #i39187# + String sErrorMessage( DBACORE_RESSTRING( RID_STR_FILE_DOES_NOT_EXIST ) ); + ::svt::OFileNotation aTransformer( _sURL ); + sErrorMessage.SearchAndReplaceAscii( "$file$", aTransformer.get( ::svt::OFileNotation::N_SYSTEM ) ); + + SQLException aError; + aError.Message = sErrorMessage; + + throw WrappedTargetException( _sURL, *this, makeAny( aError ) ); + } + throw WrappedTargetException( _sURL, *this, ::cppu::getCaughtException() ); + } + catch( const Exception& ) + { + throw WrappedTargetException( _sURL, *this, ::cppu::getCaughtException() ); + } + + OSL_ENSURE( m_aDatabaseObjects.find( _sURL ) == m_aDatabaseObjects.end(), + "ODatabaseContext::loadObjectFromURL: not intended for already-cached objects!" ); + + ::rtl::Reference< ODatabaseModelImpl > pModelImpl; + { + pModelImpl.set( new ODatabaseModelImpl( _rName, m_aContext.getLegacyServiceFactory(), *this ) ); + + Reference< XModel > xModel( pModelImpl->createNewModel_deliverOwnership( false ), UNO_SET_THROW ); + Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW ); + + ::comphelper::NamedValueCollection aArgs; + aArgs.put( "URL", _sURL ); + aArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG ); + aArgs.put( "InteractionHandler", m_aContext.createComponent( "com.sun.star.task.InteractionHandler" ) ); + + Sequence< PropertyValue > aResource( aArgs.getPropertyValues() ); + xLoad->load( aResource ); + xModel->attachResource( _sURL, aResource ); + + ::utl::CloseableComponent aEnsureClose( xModel ); + } + + setTransientProperties( _sURL, *pModelImpl ); + + return pModelImpl->getOrCreateDataSource().get(); +} + +void ODatabaseContext::appendAtTerminateListener(const ODatabaseModelImpl& _rDataSourceModel) +{ + m_pDatabaseDocumentLoader->append(_rDataSourceModel); +} + +void ODatabaseContext::removeFromTerminateListener(const ODatabaseModelImpl& _rDataSourceModel) +{ + m_pDatabaseDocumentLoader->remove(_rDataSourceModel); +} + +void ODatabaseContext::setTransientProperties(const ::rtl::OUString& _sURL, ODatabaseModelImpl& _rDataSourceModel ) +{ + if ( m_aDatasourceProperties.end() == m_aDatasourceProperties.find(_sURL) ) + return; + try + { + ::rtl::OUString sAuthFailedPassword; + Reference< XPropertySet > xDSProps( _rDataSourceModel.getOrCreateDataSource(), UNO_QUERY_THROW ); + const Sequence< PropertyValue >& rSessionPersistentProps = m_aDatasourceProperties[_sURL]; + const PropertyValue* pProp = rSessionPersistentProps.getConstArray(); + const PropertyValue* pPropsEnd = rSessionPersistentProps.getConstArray() + rSessionPersistentProps.getLength(); + for ( ; pProp != pPropsEnd; ++pProp ) + { + if ( pProp->Name.equalsAscii( "AuthFailedPassword" ) ) + { + OSL_VERIFY( pProp->Value >>= sAuthFailedPassword ); + } + else + { + xDSProps->setPropertyValue( pProp->Name, pProp->Value ); + } + } + + _rDataSourceModel.m_sFailedPassword = sAuthFailedPassword; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +void ODatabaseContext::registerObject(const rtl::OUString& _rName, const Reference< XInterface > & _rxObject) throw( Exception, RuntimeException ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed); + + if ( !_rName.getLength() ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); + + Reference< XDocumentDataSource > xDocDataSource( _rxObject, UNO_QUERY ); + Reference< XModel > xModel( xDocDataSource.is() ? xDocDataSource->getDatabaseDocument() : Reference< XOfficeDatabaseDocument >(), UNO_QUERY ); + if ( !xModel.is() ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 2 ); + + ::rtl::OUString sURL = xModel->getURL(); + if ( !sURL.getLength() ) + throw IllegalArgumentException( DBACORE_RESSTRING( RID_STR_DATASOURCE_NOT_STORED ), *this, 2 ); + + registerDatabaseLocation( _rName, sURL ); + + ODatabaseSource::setName( xDocDataSource, _rName, ODatabaseSource::DBContextAccess() ); + + // notify our container listeners + ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_rName), makeAny(_rxObject), Any()); + m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent ); +} + +void ODatabaseContext::storeTransientProperties( ODatabaseModelImpl& _rModelImpl) +{ + Reference< XPropertySet > xSource( _rModelImpl.getOrCreateDataSource(), UNO_QUERY ); + ::comphelper::NamedValueCollection aRememberProps; + + try + { + // get the info about the properties, check which ones are transient and not readonly + Reference< XPropertySetInfo > xSetInfo; + if (xSource.is()) + xSetInfo = xSource->getPropertySetInfo(); + Sequence< Property > aProperties; + if (xSetInfo.is()) + aProperties = xSetInfo->getProperties(); + + if (aProperties.getLength()) + { + const Property* pProperties = aProperties.getConstArray(); + for ( sal_Int32 i=0; i<aProperties.getLength(); ++i, ++pProperties ) + { + if ( ( ( pProperties->Attributes & PropertyAttribute::TRANSIENT) != 0 ) + && ( ( pProperties->Attributes & PropertyAttribute::READONLY) == 0 ) + ) + { + // found such a property + aRememberProps.put( pProperties->Name, xSource->getPropertyValue( pProperties->Name ) ); + } + } + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + // additionally, remember the "failed password", which is not available as property + // #i86178# / 2008-02-19 / frank.schoenheit@sun.com + aRememberProps.put( "AuthFailedPassword", _rModelImpl.m_sFailedPassword ); + + ::rtl::OUString sDocumentURL( _rModelImpl.getURL() ); + if ( m_aDatabaseObjects.find( sDocumentURL ) != m_aDatabaseObjects.end() ) + { + m_aDatasourceProperties[ sDocumentURL ] = aRememberProps.getPropertyValues(); + } + else if ( m_aDatabaseObjects.find( _rModelImpl.m_sName ) != m_aDatabaseObjects.end() ) + { + OSL_ENSURE( false, "ODatabaseContext::storeTransientProperties: a database document register by name? This shouldn't happen anymore!" ); + // all the code should have been changed so that registration is by URL only + m_aDatasourceProperties[ _rModelImpl.m_sName ] = aRememberProps.getPropertyValues(); + } + else + { + OSL_ENSURE( ( sDocumentURL.getLength() == 0 ) && ( _rModelImpl.m_sName.getLength() == 0 ), + "ODatabaseContext::storeTransientProperties: a non-empty data source which I do not know?!" ); + } +} + +void SAL_CALL ODatabaseContext::addContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException) +{ + m_aContainerListeners.addInterface(_rxListener); +} + +void SAL_CALL ODatabaseContext::removeContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException) +{ + m_aContainerListeners.removeInterface(_rxListener); +} + +void ODatabaseContext::revokeObject(const rtl::OUString& _rName) throw( Exception, RuntimeException ) +{ + ClearableMutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed); + + ::rtl::OUString sURL = getDatabaseLocation( _rName ); + + revokeDatabaseLocation( _rName ); + // will throw if something goes wrong + + if ( m_aDatabaseObjects.find( _rName ) != m_aDatabaseObjects.end() ) + { + m_aDatasourceProperties[ sURL ] = m_aDatasourceProperties[ _rName ]; + } + + // check if URL is already loaded + ObjectCacheIterator aExistent = m_aDatabaseObjects.find( sURL ); + if ( aExistent != m_aDatabaseObjects.end() ) + m_aDatabaseObjects.erase( aExistent ); + + // notify our container listeners + ContainerEvent aEvent( *this, makeAny( _rName ), Any(), Any() ); + aGuard.clear(); + m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvent ); +} + +::sal_Bool SAL_CALL ODatabaseContext::hasRegisteredDatabase( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, RuntimeException) +{ + return m_xDatabaseRegistrations->hasRegisteredDatabase( _Name ); +} + +Sequence< ::rtl::OUString > SAL_CALL ODatabaseContext::getRegistrationNames() throw (RuntimeException) +{ + return m_xDatabaseRegistrations->getRegistrationNames(); +} + +::rtl::OUString SAL_CALL ODatabaseContext::getDatabaseLocation( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException) +{ + return m_xDatabaseRegistrations->getDatabaseLocation( _Name ); +} + +void SAL_CALL ODatabaseContext::registerDatabaseLocation( const ::rtl::OUString& _Name, const ::rtl::OUString& _Location ) throw (IllegalArgumentException, ElementExistException, RuntimeException) +{ + m_xDatabaseRegistrations->registerDatabaseLocation( _Name, _Location ); +} + +void SAL_CALL ODatabaseContext::revokeDatabaseLocation( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException) +{ + m_xDatabaseRegistrations->revokeDatabaseLocation( _Name ); +} + +void SAL_CALL ODatabaseContext::changeDatabaseLocation( const ::rtl::OUString& _Name, const ::rtl::OUString& _NewLocation ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException) +{ + m_xDatabaseRegistrations->changeDatabaseLocation( _Name, _NewLocation ); +} + +::sal_Bool SAL_CALL ODatabaseContext::isDatabaseRegistrationReadOnly( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException) +{ + return m_xDatabaseRegistrations->isDatabaseRegistrationReadOnly( _Name ); +} + +void SAL_CALL ODatabaseContext::addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& _Listener ) throw (RuntimeException) +{ + m_xDatabaseRegistrations->addDatabaseRegistrationsListener( _Listener ); +} + +void SAL_CALL ODatabaseContext::removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& _Listener ) throw (RuntimeException) +{ + m_xDatabaseRegistrations->removeDatabaseRegistrationsListener( _Listener ); +} + +// ::com::sun::star::container::XElementAccess +Type ODatabaseContext::getElementType( ) throw(RuntimeException) +{ + return::getCppuType(static_cast<Reference<XDataSource>*>(NULL)); +} + +sal_Bool ODatabaseContext::hasElements(void) throw( RuntimeException ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed); + + return 0 != getElementNames().getLength(); +} + +// ::com::sun::star::container::XEnumerationAccess +Reference< ::com::sun::star::container::XEnumeration > ODatabaseContext::createEnumeration(void) throw( RuntimeException ) +{ + MutexGuard aGuard(m_aMutex); + return new ::comphelper::OEnumerationByName(static_cast<XNameAccess*>(this)); +} + +// ::com::sun::star::container::XNameAccess +Any ODatabaseContext::getByName(const rtl::OUString& _rName) throw( NoSuchElementException, + WrappedTargetException, RuntimeException ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed); + if ( !_rName.getLength() ) + throw NoSuchElementException(_rName, *this); + + try + { + Reference< XInterface > xExistent = getObject( _rName ); + if ( xExistent.is() ) + return makeAny( xExistent ); + + // see whether this is an registered name + ::rtl::OUString sURL; + if ( hasRegisteredDatabase( _rName ) ) + { + sURL = getDatabaseLocation( _rName ); + // is the object cached under its URL? + xExistent = getObject( sURL ); + } + else + // interpret the name as URL + sURL = _rName; + + if ( !xExistent.is() ) + // try to load this as URL + xExistent = loadObjectFromURL( _rName, sURL ); + return makeAny( xExistent ); + } + catch (NoSuchElementException&) + { // let these exceptions through + throw; + } + catch (WrappedTargetException&) + { // let these exceptions through + throw; + } + catch (RuntimeException&) + { // let these exceptions through + throw; + } + catch (Exception& e) + { // exceptions other than the speciafied ones -> wrap + Any aError = ::cppu::getCaughtException(); + throw WrappedTargetException(_rName, *this, aError ); + } +} + +Sequence< rtl::OUString > ODatabaseContext::getElementNames(void) throw( RuntimeException ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed); + + return getRegistrationNames(); +} + +sal_Bool ODatabaseContext::hasByName(const rtl::OUString& _rName) throw( RuntimeException ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed); + + return hasRegisteredDatabase( _rName ); +} + +Reference< XInterface > ODatabaseContext::getObject( const ::rtl::OUString& _rURL ) +{ + ObjectCacheIterator aFind = m_aDatabaseObjects.find( _rURL ); + Reference< XInterface > xExistent; + if ( aFind != m_aDatabaseObjects.end() ) + xExistent = aFind->second->getOrCreateDataSource(); + return xExistent; +} + +void ODatabaseContext::registerDatabaseDocument( ODatabaseModelImpl& _rModelImpl ) +{ + ::rtl::OUString sURL( _rModelImpl.getURL() ); +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE( "DatabaseContext: registering %s", ::rtl::OUStringToOString( sURL, RTL_TEXTENCODING_UTF8 ).getStr() ); +#endif + if ( m_aDatabaseObjects.find( sURL ) == m_aDatabaseObjects.end() ) + { + m_aDatabaseObjects[ sURL ] = &_rModelImpl; + setTransientProperties( sURL, _rModelImpl ); + } + else + OSL_ENSURE( false, "ODatabaseContext::registerDatabaseDocument: already have an object registered for this URL!" ); +} + +void ODatabaseContext::revokeDatabaseDocument( const ODatabaseModelImpl& _rModelImpl ) +{ + ::rtl::OUString sURL( _rModelImpl.getURL() ); +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE( "DatabaseContext: deregistering %s", ::rtl::OUStringToOString( sURL, RTL_TEXTENCODING_UTF8 ).getStr() ); +#endif + m_aDatabaseObjects.erase( sURL ); +} + +void ODatabaseContext::databaseDocumentURLChange( const ::rtl::OUString& _rOldURL, const ::rtl::OUString& _rNewURL ) +{ +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE( "DatabaseContext: changing registration from %s to %s", + ::rtl::OUStringToOString( _rOldURL, RTL_TEXTENCODING_UTF8 ).getStr(), + ::rtl::OUStringToOString( _rNewURL, RTL_TEXTENCODING_UTF8 ).getStr() ); +#endif + ObjectCache::iterator oldPos = m_aDatabaseObjects.find( _rOldURL ); + ENSURE_OR_THROW( oldPos != m_aDatabaseObjects.end(), "illegal old database document URL" ); + ObjectCache::iterator newPos = m_aDatabaseObjects.find( _rNewURL ); + ENSURE_OR_THROW( newPos == m_aDatabaseObjects.end(), "illegal new database document URL" ); + + m_aDatabaseObjects[ _rNewURL ] = oldPos->second; + m_aDatabaseObjects.erase( oldPos ); +} + +sal_Int64 SAL_CALL ODatabaseContext::getSomething( const Sequence< sal_Int8 >& rId ) throw(RuntimeException) +{ + if (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(), rId.getConstArray(), 16 ) ) + return reinterpret_cast<sal_Int64>(this); + + return 0; +} + +Sequence< sal_Int8 > ODatabaseContext::getUnoTunnelImplementationId() +{ + static ::cppu::OImplementationId * pId = 0; + if (! pId) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if (! pId) + { + static ::cppu::OImplementationId aId; + pId = &aId; + } + } + return pId->getImplementationId(); +} + +void ODatabaseContext::onBasicManagerCreated( const Reference< XModel >& _rxForDocument, BasicManager& _rBasicManager ) +{ + // if it's a database document ... + Reference< XOfficeDatabaseDocument > xDatabaseDocument( _rxForDocument, UNO_QUERY ); + // ... or a sub document of a database document ... + if ( !xDatabaseDocument.is() ) + { + Reference< XChild > xDocAsChild( _rxForDocument, UNO_QUERY ); + if ( xDocAsChild.is() ) + xDatabaseDocument.set( xDocAsChild->getParent(), UNO_QUERY ); + } + + // ... whose BasicManager has just been created, then add the global DatabaseDocument variable to its scope. + if ( xDatabaseDocument.is() ) + _rBasicManager.SetGlobalUNOConstant( "ThisDatabaseDocument", makeAny( xDatabaseDocument ) ); +} + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/databasecontext.hxx b/dbaccess/source/core/dataaccess/databasecontext.hxx new file mode 100644 index 000000000000..71d5fb4ebc23 --- /dev/null +++ b/dbaccess/source/core/dataaccess/databasecontext.hxx @@ -0,0 +1,214 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 _DBA_COREDATAACCESS_DATABASECONTEXT_HXX_ +#define _DBA_COREDATAACCESS_DATABASECONTEXT_HXX_ + +#include "ModelImpl.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/container/ElementExistException.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/sdb/XDatabaseEnvironment.hpp> +#include <com/sun/star/sdb/XDatabaseRegistrations.hpp> +#include <com/sun/star/uno/XNamingService.hpp> +#include <com/sun/star/uno/XAggregation.hpp> +/** === end UNO includes === **/ + +#include <basic/basicmanagerrepository.hxx> +#include <comphelper/componentcontext.hxx> +#include <comphelper/stl_types.hxx> +#include <cppuhelper/compbase8.hxx> +#include <cppuhelper/interfacecontainer.hxx> + +#include <boost/shared_ptr.hpp> + +// needed for registration +namespace com { namespace sun { namespace star { + namespace lang + { + class XMultiServiceFactory; + class IllegalArgumentException; + } +} } } + +//........................................................................ +namespace dbaccess +{ +//........................................................................ +class DatabaseDocumentLoader; +//============================================================ +//= ODatabaseContext +//============================================================ +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > + ODatabaseContext_CreateInstance(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >&); + +typedef ::cppu::WeakComponentImplHelper8 < ::com::sun::star::lang::XServiceInfo + , ::com::sun::star::container::XEnumerationAccess + , ::com::sun::star::container::XNameAccess + , ::com::sun::star::uno::XNamingService + , ::com::sun::star::container::XContainer + , ::com::sun::star::lang::XSingleServiceFactory + , ::com::sun::star::lang::XUnoTunnel + , ::com::sun::star::sdb::XDatabaseRegistrations + > DatabaseAccessContext_Base; + +class ODatabaseContext :public DatabaseAccessContext_Base + ,public ::basic::BasicManagerCreationListener +{ +private: + /** loads the given object from the given URL + @throws WrappedTargetException + if an error occurs accessing the URL via the UCB + */ + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > loadObjectFromURL(const ::rtl::OUString& _rName,const ::rtl::OUString& _sURL); + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > getObject( const ::rtl::OUString& _rURL ); + + /** sets all properties which were transient at the data source. e.g. password + @param _sURL The file URL of the data source + @param _xObject The data source itself. + */ + void setTransientProperties(const ::rtl::OUString& _sURL, ODatabaseModelImpl& _rDataSourceModel ); + + /** creates a new data source + */ + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > + impl_createNewDataSource(); + +protected: + ::osl::Mutex m_aMutex; + ::comphelper::ComponentContext m_aContext; + + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XAggregation > + m_xDBRegistrationAggregate; + ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XDatabaseRegistrations > + m_xDatabaseRegistrations; + + DECLARE_STL_USTRINGACCESS_MAP( ODatabaseModelImpl*, ObjectCache ); + ObjectCache m_aDatabaseObjects; + + DECLARE_STL_USTRINGACCESS_MAP( ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >, PropertyCache ); + PropertyCache m_aDatasourceProperties; + // as we hold our data sources weak, we have to cache all properties on the data sources which are + // transient but stored as long as the session lasts. The database context is the session (as it lives + // as long as the session does), but the data sources may die before the session does, and then be + // recreated afterwards. So it's our (the context's) responsibility to store the session-persistent + // properties. + + ::cppu::OInterfaceContainerHelper m_aContainerListeners; + DatabaseDocumentLoader* m_pDatabaseDocumentLoader; + +public: + ODatabaseContext( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& ); + virtual ~ODatabaseContext(); + + + // OComponentHelper + virtual void SAL_CALL disposing(void); + + // XSingleServiceFactory + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstance( ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstanceWithArguments( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& _rArguments ) 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); + + // XServiceInfo - static methods + 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 >&); + + // 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); + + // XEnumerationAccess + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL createEnumeration( ) throw(::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); + + // XNamingService + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL getRegisteredObject( const ::rtl::OUString& Name ) throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL registerObject( const ::rtl::OUString& Name, const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& Object ) throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL revokeObject( const ::rtl::OUString& Name ) throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + + // XDatabaseRegistrations + virtual ::sal_Bool SAL_CALL hasRegisteredDatabase( const ::rtl::OUString& Name ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getRegistrationNames() throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getDatabaseLocation( const ::rtl::OUString& Name ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL registerDatabaseLocation( const ::rtl::OUString& Name, const ::rtl::OUString& Location ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::ElementExistException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL revokeDatabaseLocation( const ::rtl::OUString& Name ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::IllegalAccessException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL changeDatabaseLocation( const ::rtl::OUString& Name, const ::rtl::OUString& NewLocation ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::IllegalAccessException, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL isDatabaseRegistrationReadOnly( const ::rtl::OUString& Name ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addDatabaseRegistrationsListener( const ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XDatabaseRegistrationsListener >& Listener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeDatabaseRegistrationsListener( const ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XDatabaseRegistrationsListener >& Listener ) throw (::com::sun::star::uno::RuntimeException); + + // XContainer + virtual void SAL_CALL addContainerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XContainerListener >& xListener ) throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeContainerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XContainerListener >& xListener ) throw(::com::sun::star::uno::RuntimeException); + + // com::sun::star::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException); + static ::com::sun::star::uno::Sequence< sal_Int8 > getUnoTunnelImplementationId(); + + void registerDatabaseDocument( ODatabaseModelImpl& _rModelImpl); + void revokeDatabaseDocument( const ODatabaseModelImpl& _rModelImpl); + void databaseDocumentURLChange(const ::rtl::OUString& _sOldName, const ::rtl::OUString& _sNewName); + void storeTransientProperties( ODatabaseModelImpl& _rModelImpl); + void appendAtTerminateListener(const ODatabaseModelImpl& _rDataSourceModel); + void removeFromTerminateListener(const ODatabaseModelImpl& _rDataSourceModel); + +private: + // BasicManagerCreationListener + virtual void onBasicManagerCreated( + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel >& _rxForDocument, + BasicManager& _rBasicManager + ); +}; + +//........................................................................ +} // namespace dbaccess +//........................................................................ + +#endif // _DBA_COREDATAACCESS_DATABASECONTEXT_HXX_ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/databasedocument.cxx b/dbaccess/source/core/dataaccess/databasedocument.cxx new file mode 100644 index 000000000000..46a82018781f --- /dev/null +++ b/dbaccess/source/core/dataaccess/databasedocument.cxx @@ -0,0 +1,2092 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +#include "core_resource.hxx" +#include "core_resource.hrc" +#include "datasource.hxx" +#include "databasedocument.hxx" +#include "dbastrings.hrc" +#include "module_dba.hxx" +#include "documenteventexecutor.hxx" +#include "databasecontext.hxx" +#include "documentcontainer.hxx" +#include "sdbcoretools.hxx" +#include "recovery/dbdocrecovery.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/beans/Optional.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/document/XImporter.hpp> +#include <com/sun/star/embed/EntryInitModes.hpp> +#include <com/sun/star/embed/XEmbedPersist.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/embed/XTransactionBroadcaster.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/script/provider/XScriptProviderFactory.hpp> +#include <com/sun/star/task/ErrorCodeIOException.hpp> +#include <com/sun/star/task/XStatusIndicator.hpp> +#include <com/sun/star/task/XStatusIndicatorFactory.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/ui/XUIConfigurationStorage.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp> +/** === end UNO includes === **/ + +#include <comphelper/documentconstants.hxx> +#include <comphelper/enumhelper.hxx> +#include <comphelper/genericpropertyset.hxx> +#include <comphelper/interaction.hxx> +#include <comphelper/mediadescriptor.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/numberedcollection.hxx> +#include <comphelper/property.hxx> +#include <comphelper/storagehelper.hxx> +#include <comphelper/genericpropertyset.hxx> +#include <comphelper/property.hxx> + +#include <connectivity/dbtools.hxx> + +#include <cppuhelper/exc_hlp.hxx> +#include <framework/titlehelper.hxx> +#include <unotools/saveopt.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <tools/errcode.hxx> +#include <tools/urlobj.hxx> + +#include <boost/bind.hpp> + +#include <algorithm> +#include <functional> +#include <list> + +#define MAP_LEN(x) x, sizeof(x) - 1 + +#define MAP_LEN(x) x, sizeof(x) - 1 + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::view; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::script; +using namespace ::com::sun::star::script::provider; +using namespace ::com::sun::star::ui; +using namespace ::cppu; +using namespace ::osl; + +using ::com::sun::star::awt::XWindow; +using ::com::sun::star::ucb::XContent; +using ::com::sun::star::sdb::application::XDatabaseDocumentUI; + +namespace dbaccess +{ + +//============================================================ +//= ViewMonitor +//============================================================ + +bool ViewMonitor::onControllerConnected( const Reference< XController >& _rxController ) +{ + bool bFirstControllerEver = ( m_bEverHadController == false ); + m_bEverHadController = true; + + m_xLastConnectedController = _rxController; + m_bLastIsFirstEverController = bFirstControllerEver; + + return bFirstControllerEver; +} + +bool ViewMonitor::onSetCurrentController( const Reference< XController >& _rxController ) +{ + // we interpret this as "loading the document (including UI) is finished", + // if and only if this is the controller which was last connected, and it was the + // first controller ever connected + bool bLoadFinished = ( _rxController == m_xLastConnectedController ) && m_bLastIsFirstEverController; + + // notify the respective events + if ( bLoadFinished ) + m_rEventNotifier.notifyDocumentEventAsync( m_bIsNewDocument ? "OnNew" : "OnLoad" ); + + return bLoadFinished; +} + +//============================================================ +//= ODatabaseDocument +//============================================================ +DBG_NAME(ODatabaseDocument) + +extern "C" void SAL_CALL createRegistryInfo_ODatabaseDocument() +{ + static ::dba::OAutoRegistration< ODatabaseDocument > aAutoRegistration; +} + +ODatabaseDocument::ODatabaseDocument(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl ) + :ModelDependentComponent( _pImpl ) + ,ODatabaseDocument_OfficeDocument( getMutex() ) + ,m_aModifyListeners( getMutex() ) + ,m_aCloseListener( getMutex() ) + ,m_aStorageListeners( getMutex() ) + ,m_pEventContainer( new DocumentEvents( *this, getMutex(), _pImpl->getDocumentEvents() ) ) + ,m_pEventExecutor( NULL ) // initialized below, ref-count-protected + ,m_aEventNotifier( *this, getMutex() ) + ,m_aViewMonitor( m_aEventNotifier ) + ,m_eInitState( NotInitialized ) + ,m_bClosing( false ) + ,m_bAllowDocumentScripting( false ) + ,m_bHasBeenRecovered( false ) +{ + DBG_CTOR(ODatabaseDocument,NULL); + OSL_TRACE( "DD: ctor: %p: %p", this, m_pImpl.get() ); + + osl_incrementInterlockedCount( &m_refCount ); + { + impl_reparent_nothrow( m_xForms ); + impl_reparent_nothrow( m_xReports ); + impl_reparent_nothrow( m_pImpl->m_xTableDefinitions ); + impl_reparent_nothrow( m_pImpl->m_xCommandDefinitions ); + + m_pEventExecutor = new DocumentEventExecutor( m_pImpl->m_aContext, this ); + } + osl_decrementInterlockedCount( &m_refCount ); + + // if there previously was a document instance for the same Impl which was already initialized, + // then consider ourself initialized, too. + // #i94840# + if ( m_pImpl->hadInitializedDocument() ) + { + // Note we set our init-state to "Initializing", not "Initialized". We're created from inside the ModelImpl, + // which is expected to call attachResource in case there was a previous incarnation of the document, + // so we can properly finish our initialization then. + impl_setInitializing(); + + if ( m_pImpl->getURL().getLength() ) + { + // if the previous incarnation of the DatabaseDocument already had an URL, then creating this incarnation + // here is effectively loading the document. + // #i105505# / 2009-10-01 / frank.schoenheit@sun.com + m_aViewMonitor.onLoadedDocument(); + } + } +} + +ODatabaseDocument::~ODatabaseDocument() +{ + OSL_TRACE( "DD: dtor: %p: %p", this, m_pImpl.get() ); + DBG_DTOR(ODatabaseDocument,NULL); + if ( !ODatabaseDocument_OfficeDocument::rBHelper.bInDispose && !ODatabaseDocument_OfficeDocument::rBHelper.bDisposed ) + { + acquire(); + dispose(); + } + + delete m_pEventContainer, m_pEventContainer = NULL; +} + +Any SAL_CALL ODatabaseDocument::queryInterface( const Type& _rType ) throw (RuntimeException) +{ + // strip XEmbeddedScripts and XScriptInvocationContext if we have any form/report + // which already contains macros. In this case, the database document itself is not + // allowed to contain macros, too. + if ( !m_bAllowDocumentScripting + && ( _rType.equals( XEmbeddedScripts::static_type() ) + || _rType.equals( XScriptInvocationContext::static_type() ) + ) + ) + return Any(); + + Any aReturn = ODatabaseDocument_OfficeDocument::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ODatabaseDocument_Title::queryInterface(_rType); + return aReturn; +} + +void SAL_CALL ODatabaseDocument::acquire( ) throw () +{ + ODatabaseDocument_OfficeDocument::acquire(); +} + +void SAL_CALL ODatabaseDocument::release( ) throw () +{ + ODatabaseDocument_OfficeDocument::release(); +} + +Sequence< Type > SAL_CALL ODatabaseDocument::getTypes( ) throw (RuntimeException) +{ + Sequence< Type > aTypes = ::comphelper::concatSequences( + ODatabaseDocument_OfficeDocument::getTypes(), + ODatabaseDocument_Title::getTypes() + ); + + // strip XEmbeddedScripts and XScriptInvocationContext if we have any form/report + // which already contains macros. In this case, the database document itself is not + // allowed to contain macros, too. + if ( !m_bAllowDocumentScripting ) + { + Sequence< Type > aStrippedTypes( aTypes.getLength() ); + Type* pStripTo( aStrippedTypes.getArray() ); + + // strip XEmbeddedScripts, and immediately re-assign to aTypes + aTypes = Sequence< Type >( + pStripTo, + ::std::remove_copy_if( + aTypes.getConstArray(), + aTypes.getConstArray() + aTypes.getLength(), + pStripTo, + ::std::bind2nd( ::std::equal_to< Type >(), XEmbeddedScripts::static_type() ) + ) - pStripTo + ); + + // strip XScriptInvocationContext, and immediately re-assign to aTypes + aTypes = Sequence< Type >( + pStripTo, + ::std::remove_copy_if( + aTypes.getConstArray(), + aTypes.getConstArray() + aTypes.getLength(), + pStripTo, + ::std::bind2nd( ::std::equal_to< Type >(), XScriptInvocationContext::static_type() ) + ) - pStripTo + ); + } + + return aTypes; +} + +Sequence< sal_Int8 > SAL_CALL ODatabaseDocument::getImplementationId( ) throw (RuntimeException) +{ + static ::cppu::OImplementationId * pId = 0; + if (! pId) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if (! pId) + { + static ::cppu::OImplementationId aId; + pId = &aId; + } + } + return pId->getImplementationId(); +} + +// local functions +namespace +{ + Reference< XStatusIndicator > lcl_extractStatusIndicator( const ::comphelper::NamedValueCollection& _rArguments ) + { + Reference< XStatusIndicator > xStatusIndicator; + return _rArguments.getOrDefault( "StatusIndicator", xStatusIndicator ); + } + + static void lcl_triggerStatusIndicator_throw( const ::comphelper::NamedValueCollection& _rArguments, DocumentGuard& _rGuard, const bool _bStart ) + { + Reference< XStatusIndicator > xStatusIndicator( lcl_extractStatusIndicator( _rArguments ) ); + if ( !xStatusIndicator.is() ) + return; + + _rGuard.clear(); + try + { + if ( _bStart ) + xStatusIndicator->start( ::rtl::OUString(), (sal_Int32)1000000 ); + else + xStatusIndicator->end(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + _rGuard.reset(); + // note that |reset| can throw a DisposedException + } + + static void lcl_extractStatusIndicator( const ::comphelper::NamedValueCollection& _rArguments, Sequence< Any >& _rCallArgs ) + { + Reference< XStatusIndicator > xStatusIndicator( lcl_extractStatusIndicator( _rArguments ) ); + if ( !xStatusIndicator.is() ) + return; + + sal_Int32 nLength = _rCallArgs.getLength(); + _rCallArgs.realloc( nLength + 1 ); + _rCallArgs[ nLength ] <<= xStatusIndicator; + } + + static void lcl_extractAndStartStatusIndicator( const ::comphelper::NamedValueCollection& _rArguments, Reference< XStatusIndicator >& _rxStatusIndicator, + Sequence< Any >& _rCallArgs ) + { + _rxStatusIndicator = lcl_extractStatusIndicator( _rArguments ); + if ( !_rxStatusIndicator.is() ) + return; + + try + { + _rxStatusIndicator->start( ::rtl::OUString(), (sal_Int32)1000000 ); + + sal_Int32 nLength = _rCallArgs.getLength(); + _rCallArgs.realloc( nLength + 1 ); + _rCallArgs[ nLength ] <<= _rxStatusIndicator; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + static Sequence< PropertyValue > lcl_appendFileNameToDescriptor( const ::comphelper::NamedValueCollection& _rDescriptor, const ::rtl::OUString _rURL ) + { + ::comphelper::NamedValueCollection aMutableDescriptor( _rDescriptor ); + if ( _rURL.getLength() ) + { + aMutableDescriptor.put( "FileName", _rURL ); + aMutableDescriptor.put( "URL", _rURL ); + } + return aMutableDescriptor.getPropertyValues(); + } +} + +void ODatabaseDocument::impl_setInitialized() +{ + m_eInitState = Initialized; + + // start event notifications + m_aEventNotifier.onDocumentInitialized(); +} + +void ODatabaseDocument::impl_reset_nothrow() +{ + try + { + m_pImpl->clearConnections(); + m_pImpl->disposeStorages(); + m_pImpl->resetRootStroage(); + + clearObjectContainer( m_xForms ); + clearObjectContainer( m_xReports ); + clearObjectContainer( m_pImpl->m_xTableDefinitions ); + clearObjectContainer( m_pImpl->m_xCommandDefinitions ); + + m_eInitState = NotInitialized; + + m_pImpl->reset(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + m_pImpl->m_bDocumentReadOnly = sal_False; +} + +void ODatabaseDocument::impl_import_nolck_throw( const ::comphelper::ComponentContext _rContext, const Reference< XInterface >& _rxTargetComponent, + const ::comphelper::NamedValueCollection& _rResource ) +{ + Sequence< Any > aFilterCreationArgs; + Reference< XStatusIndicator > xStatusIndicator; + lcl_extractAndStartStatusIndicator( _rResource, xStatusIndicator, aFilterCreationArgs ); + + /** property map for import info set */ + comphelper::PropertyMapEntry aExportInfoMap[] = + { + { MAP_LEN( "BaseURI"), 0,&::getCppuType( (::rtl::OUString *)0 ),beans::PropertyAttribute::MAYBEVOID, 0 }, + { MAP_LEN( "StreamName"), 0,&::getCppuType( (::rtl::OUString *)0 ),beans::PropertyAttribute::MAYBEVOID, 0 }, + { NULL, 0, 0, NULL, 0, 0 } + }; + uno::Reference< beans::XPropertySet > xInfoSet( comphelper::GenericPropertySet_CreateInstance( new comphelper::PropertySetInfo( aExportInfoMap ) ) ); + xInfoSet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("BaseURI")), uno::makeAny(_rResource.getOrDefault("URL",::rtl::OUString()))); + xInfoSet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("StreamName")), uno::makeAny(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("content.xml")))); + + const sal_Int32 nCount = aFilterCreationArgs.getLength(); + aFilterCreationArgs.realloc(nCount + 1); + aFilterCreationArgs[nCount] <<= xInfoSet; + + Reference< XImporter > xImporter( + _rContext.createComponentWithArguments( "com.sun.star.comp.sdb.DBFilter", aFilterCreationArgs ), + UNO_QUERY_THROW ); + + Reference< XComponent > xComponent( _rxTargetComponent, UNO_QUERY_THROW ); + xImporter->setTargetDocument( xComponent ); + + Reference< XFilter > xFilter( xImporter, UNO_QUERY_THROW ); + Sequence< PropertyValue > aFilterArgs( ODatabaseModelImpl::stripLoadArguments( _rResource ).getPropertyValues() ); + xFilter->filter( aFilterArgs ); + + if ( xStatusIndicator.is() ) + xStatusIndicator->end(); +} + +void SAL_CALL ODatabaseDocument::initNew( ) throw (DoubleInitializationException, IOException, Exception, RuntimeException) +{ + // SYNCHRONIZED -> + DocumentGuard aGuard( *this, DocumentGuard::InitMethod ); + + impl_reset_nothrow(); + + impl_setInitializing(); + + // create a temporary storage + Reference< XStorage > xTempStor( ::comphelper::OStorageHelper::GetTemporaryStorage( + m_pImpl->m_aContext.getLegacyServiceFactory() ) ); + + // store therein + impl_storeToStorage_throw( xTempStor, Sequence< PropertyValue >(), aGuard ); + + // let the impl know we're now based on this storage + m_pImpl->switchToStorage( xTempStor ); + + // for the newly created document, allow document-wide scripting + m_bAllowDocumentScripting = true; + + impl_setInitialized(); + + m_aEventNotifier.notifyDocumentEventAsync( "OnTitleChanged" ); + + impl_setModified_nothrow( sal_False, aGuard ); + // <- SYNCHRONIZED + + m_aEventNotifier.notifyDocumentEvent( "OnCreate" ); + + impl_notifyStorageChange_nolck_nothrow( xTempStor ); +} + +void SAL_CALL ODatabaseDocument::load( const Sequence< PropertyValue >& _Arguments ) throw (DoubleInitializationException, IOException, Exception, RuntimeException) +{ + // SYNCHRONIZED -> + DocumentGuard aGuard( *this, DocumentGuard::InitMethod ); + + impl_reset_nothrow(); + + ::comphelper::NamedValueCollection aResource( _Arguments ); + if ( aResource.has( "FileName" ) && !aResource.has( "URL" ) ) + // FileName is the compatibility name for URL, so we might have clients passing + // a FileName only. However, some of our code works with the URL only, so ensure + // we have one. + aResource.put( "URL", aResource.get( "FileName" ) ); + if ( aResource.has( "URL" ) && !aResource.has( "FileName" ) ) + // similar ... just in case there is legacy code which expects a FileName only + aResource.put( "FileName", aResource.get( "URL" ) ); + + // now that somebody (perhaps) told us an macro execution mode, remember it as + // ImposedMacroExecMode + m_pImpl->setImposedMacroExecMode( + aResource.getOrDefault( "MacroExecutionMode", m_pImpl->getImposedMacroExecMode() ) ); + + impl_setInitializing(); + try + { + aGuard.clear(); + impl_import_nolck_throw( m_pImpl->m_aContext, *this, aResource ); + aGuard.reset(); + } + catch( const Exception& ) + { + impl_reset_nothrow(); + throw; + } + // tell our view monitor that the document has been loaded - this way it will fire the proper + // event (OnLoad instead of OnCreate) later on + m_aViewMonitor.onLoadedDocument(); + + // note that we do *not* call impl_setInitialized() here: The initialization is only complete + // when the XModel::attachResource has been called, not sooner. + + impl_setModified_nothrow( sal_False, aGuard ); + // <- SYNCHRONIZED +} + +namespace +{ + bool lcl_hasAnyModifiedSubComponent_throw( const Reference< XController >& i_rController ) + { + Reference< XDatabaseDocumentUI > xDatabaseUI( i_rController, UNO_QUERY_THROW ); + + Sequence< Reference< XComponent > > aComponents( xDatabaseUI->getSubComponents() ); + const Reference< XComponent >* component = aComponents.getConstArray(); + const Reference< XComponent >* componentsEnd = aComponents.getConstArray() + aComponents.getLength(); + + bool isAnyModified = false; + for ( ; component != componentsEnd; ++component ) + { + Reference< XModifiable > xModify( *component, UNO_QUERY ); + if ( xModify.is() ) + { + isAnyModified = xModify->isModified(); + continue; + } + + // TODO: clarify: anything else to care for? Both the sub componbents with and without model + // should support the XModifiable interface, so I think nothing more is needed here. + OSL_ENSURE( false, "lcl_hasAnyModifiedSubComponent_throw: anything left to do here?" ); + } + + return isAnyModified; + } +} + +::sal_Bool SAL_CALL ODatabaseDocument::wasModifiedSinceLastSave() throw ( RuntimeException ) +{ + DocumentGuard aGuard( *this ); + + // The implementation here is somewhat sloppy, in that it returns whether *any* part of the whole + // database document, including opened sub components, is modified. This is more than what is requested: + // We need to return <TRUE/> if the doc itself, or any of the opened sub components, has been modified + // since the last call to any of the save* methods, or since the document has been loaded/created. + // However, the API definition explicitly allows to be that sloppy ... + + if ( isModified() ) + return sal_True; + + // auto recovery is an "UI feature", it is to restore the UI the user knows. Thus, + // we ask our connected controllers, not simply our existing form/report definitions. + // (There is some information which even cannot be obtained without asking the controller. + // For instance, newly created, but not yet saved, forms/reports are acessible via the + // controller only, but not via the model.) + + try + { + for ( Controllers::const_iterator ctrl = m_aControllers.begin(); + ctrl != m_aControllers.end(); + ++ctrl + ) + { + if ( lcl_hasAnyModifiedSubComponent_throw( *ctrl ) ) + return sal_True; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return sal_False; +} + +void SAL_CALL ODatabaseDocument::storeToRecoveryFile( const ::rtl::OUString& i_TargetLocation, const Sequence< PropertyValue >& i_MediaDescriptor ) throw ( RuntimeException, IOException, WrappedTargetException ) +{ + DocumentGuard aGuard( *this ); + ModifyLock aLock( *this ); + + try + { + // create a storage for the target location + Reference< XStorage > xTargetStorage( impl_createStorageFor_throw( i_TargetLocation ) ); + + // first store the document as a whole into this storage + impl_storeToStorage_throw( xTargetStorage, i_MediaDescriptor, aGuard ); + + // save the sub components which need saving + DatabaseDocumentRecovery aDocRecovery( m_pImpl->m_aContext); + aDocRecovery.saveModifiedSubComponents( xTargetStorage, m_aControllers ); + + // commit the root storage + tools::stor::commitStorageIfWriteable( xTargetStorage ); + } + catch( const Exception& ) + { + Any aError = ::cppu::getCaughtException(); + if ( aError.isExtractableTo( ::cppu::UnoType< IOException >::get() ) + || aError.isExtractableTo( ::cppu::UnoType< RuntimeException >::get() ) + || aError.isExtractableTo( ::cppu::UnoType< WrappedTargetException >::get() ) + ) + { + // allowed to leave + throw; + } + + throw WrappedTargetException( ::rtl::OUString(), *this, aError ); + } +} + +void SAL_CALL ODatabaseDocument::recoverFromFile( const ::rtl::OUString& i_SourceLocation, const ::rtl::OUString& i_SalvagedFile, const Sequence< PropertyValue >& i_MediaDescriptor ) throw ( RuntimeException, IOException, WrappedTargetException ) +{ + DocumentGuard aGuard( *this, DocumentGuard::InitMethod ); + + if ( i_SourceLocation.getLength() == 0 ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); + + try + { + // load the document itself, by simply delegating to our "load" method + + // our load implementation expects the SalvagedFile and URL to be in the media descriptor + ::comphelper::NamedValueCollection aMediaDescriptor( i_MediaDescriptor ); + aMediaDescriptor.put( "SalvagedFile", i_SalvagedFile ); + aMediaDescriptor.put( "URL", i_SourceLocation ); + + aGuard.clear(); // (load has an own guarding scheme) + load( aMediaDescriptor.getPropertyValues() ); + + // Without a controller, we are unable to recover the sub components, as they're always tied to a controller. + // So, everything else is done when the first controller is connected. + m_bHasBeenRecovered = true; + + // tell the impl that we've been loaded from the given location + m_pImpl->setDocFileLocation( i_SourceLocation ); + + // by definition (of XDocumentRecovery), we're responsible for delivering a fully-initialized document, + // which includes an attachResource call. + const ::rtl::OUString sLogicalDocumentURL( i_SalvagedFile.getLength() ? i_SalvagedFile : i_SourceLocation ); + impl_attachResource( sLogicalDocumentURL, aMediaDescriptor.getPropertyValues(), aGuard ); + // <- SYNCHRONIZED + } + catch( const Exception& ) + { + Any aError = ::cppu::getCaughtException(); + if ( aError.isExtractableTo( ::cppu::UnoType< IOException >::get() ) + || aError.isExtractableTo( ::cppu::UnoType< RuntimeException >::get() ) + || aError.isExtractableTo( ::cppu::UnoType< WrappedTargetException >::get() ) + ) + { + // allowed to leave + throw; + } + + throw WrappedTargetException( ::rtl::OUString(), *this, aError ); + } +} + +// XModel +sal_Bool SAL_CALL ODatabaseDocument::attachResource( const ::rtl::OUString& _rURL, const Sequence< PropertyValue >& _rArguments ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit ); + return impl_attachResource( _rURL, _rArguments, aGuard ); +} + +sal_Bool ODatabaseDocument::impl_attachResource( const ::rtl::OUString& i_rLogicalDocumentURL, + const Sequence< PropertyValue >& i_rMediaDescriptor, DocumentGuard& _rDocGuard ) +{ + if ( ( i_rLogicalDocumentURL == getURL() ) + && ( i_rMediaDescriptor.getLength() == 1 ) + && ( i_rMediaDescriptor[0].Name.compareToAscii( "BreakMacroSignature" ) == 0 ) + ) + { + // this is a BAD hack of the Basic importer code ... there should be a dedicated API for this, + // not this bad mis-using of existing interfaces + return sal_False; + // (we do not support macro signatures, so we can ignore this call) + } + + // if no URL has been provided, the caller was lazy enough to not call our getURL - which is not allowed anymore, + // now since getURL and getLocation both return the same, so calling one of those should be simple. + ::rtl::OUString sDocumentURL( i_rLogicalDocumentURL ); + OSL_ENSURE( sDocumentURL.getLength(), "ODatabaseDocument::impl_attachResource: invalid URL!" ); + if ( !sDocumentURL.getLength() ) + sDocumentURL = getURL(); + + m_pImpl->setResource( sDocumentURL, i_rMediaDescriptor ); + + if ( impl_isInitializing() ) + { // this means we've just been loaded, and this is the attachResource call which follows + // the load call. + impl_setInitialized(); + + // determine whether the document as a whole, or sub documents, have macros. Especially the latter + // controls the availability of our XEmbeddedScripts and XScriptInvocationContext interfaces, and we + // should know this before anybody actually uses the object. + m_bAllowDocumentScripting = ( m_pImpl->determineEmbeddedMacros() != ODatabaseModelImpl::eSubDocumentMacros ); + + _rDocGuard.clear(); + // <- SYNCHRONIZED + m_aEventNotifier.notifyDocumentEvent( "OnLoadFinished" ); + } + + return sal_True; +} + +::rtl::OUString SAL_CALL ODatabaseDocument::getURL( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit ); + return m_pImpl->getURL(); +} + +Sequence< PropertyValue > SAL_CALL ODatabaseDocument::getArgs( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit ); + return m_pImpl->getMediaDescriptor().getPropertyValues(); +} + +void SAL_CALL ODatabaseDocument::connectController( const Reference< XController >& _xController ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + +#if OSL_DEBUG_LEVEL > 0 + for ( Controllers::const_iterator controller = m_aControllers.begin(); + controller != m_aControllers.end(); + ++controller + ) + { + OSL_ENSURE( *controller != _xController, "ODatabaseDocument::connectController: this controller is already connected!" ); + } +#endif + + m_aControllers.push_back( _xController ); + + m_aEventNotifier.notifyDocumentEventAsync( "OnViewCreated", Reference< XController2 >( _xController, UNO_QUERY ) ); + + bool bFirstControllerEver = m_aViewMonitor.onControllerConnected( _xController ); + if ( !bFirstControllerEver ) + return; + + // check/adjust our macro mode. + m_pImpl->checkMacrosOnLoading(); +} + +void SAL_CALL ODatabaseDocument::disconnectController( const Reference< XController >& _xController ) throw (RuntimeException) +{ + bool bNotifyViewClosed = false; + bool bLastControllerGone = false; + bool bIsClosing = false; + + // SYNCHRONIZED -> + { + DocumentGuard aGuard( *this ); + + Controllers::iterator pos = ::std::find( m_aControllers.begin(), m_aControllers.end(), _xController ); + OSL_ENSURE( pos != m_aControllers.end(), "ODatabaseDocument::disconnectController: don't know this controller!" ); + if ( pos != m_aControllers.end() ) + { + m_aControllers.erase( pos ); + bNotifyViewClosed = true; + } + + if ( m_xCurrentController == _xController ) + m_xCurrentController = NULL; + + bLastControllerGone = m_aControllers.empty(); + bIsClosing = m_bClosing; + } + // <- SYNCHRONIZED + + if ( bNotifyViewClosed ) + m_aEventNotifier.notifyDocumentEvent( "OnViewClosed", Reference< XController2 >( _xController, UNO_QUERY ) ); + + if ( bLastControllerGone && !bIsClosing ) + { + // if this was the last view, close the document as a whole + // #i51157# / 2006-03-16 / frank.schoenheit@sun.com + try + { + close( sal_True ); + } + catch( const CloseVetoException& ) + { + // okay, somebody vetoed and took ownership + } + } +} + +void SAL_CALL ODatabaseDocument::lockControllers( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + + ++m_pImpl->m_nControllerLockCount; +} + +void SAL_CALL ODatabaseDocument::unlockControllers( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + + --m_pImpl->m_nControllerLockCount; +} + +sal_Bool SAL_CALL ODatabaseDocument::hasControllersLocked( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + + return m_pImpl->m_nControllerLockCount != 0; +} + +Reference< XController > SAL_CALL ODatabaseDocument::getCurrentController() throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + + return m_xCurrentController.is() ? m_xCurrentController : ( m_aControllers.empty() ? Reference< XController >() : *m_aControllers.begin() ); +} + +void SAL_CALL ODatabaseDocument::setCurrentController( const Reference< XController >& _xController ) throw (NoSuchElementException, RuntimeException) +{ + DocumentGuard aGuard( *this ); + + m_xCurrentController = _xController; + + if ( !m_aViewMonitor.onSetCurrentController( _xController ) ) + return; + + // check if there are sub components to recover from our document storage + bool bAttemptRecovery = m_bHasBeenRecovered; + if ( !bAttemptRecovery && m_pImpl->getMediaDescriptor().has( "ForceRecovery" ) ) + // do not use getOrDefault, it will throw for invalid types, which is not desired here + m_pImpl->getMediaDescriptor().get( "ForceRecovery" ) >>= bAttemptRecovery; + + if ( !bAttemptRecovery ) + return; + + try + { + DatabaseDocumentRecovery aDocRecovery( m_pImpl->m_aContext ); + aDocRecovery.recoverSubDocuments( m_pImpl->getRootStorage(), _xController ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +Reference< XInterface > SAL_CALL ODatabaseDocument::getCurrentSelection( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + + Reference< XInterface > xRet; + Reference< XSelectionSupplier > xDocView( getCurrentController(), UNO_QUERY ); + if ( xDocView.is() ) + xRet.set(xDocView->getSelection(),UNO_QUERY); + + return xRet; +} + +// XStorable +sal_Bool SAL_CALL ODatabaseDocument::hasLocation( ) throw (RuntimeException) +{ + return getLocation().getLength() > 0; +} + +::rtl::OUString SAL_CALL ODatabaseDocument::getLocation( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit ); + return m_pImpl->getURL(); + // both XStorable::getLocation and XModel::getURL have to return the URL of the document, *not* + // the location of the file which the docunment was possibly recovered from (which would be getDocFileLocation) +} + +sal_Bool SAL_CALL ODatabaseDocument::isReadonly( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit ); + return m_pImpl->m_bDocumentReadOnly; +} + +void SAL_CALL ODatabaseDocument::store( ) throw (IOException, RuntimeException) +{ + DocumentGuard aGuard( *this ); + + ::rtl::OUString sDocumentURL( m_pImpl->getURL() ); + if ( sDocumentURL.getLength() ) + { + if ( m_pImpl->getDocFileLocation() == m_pImpl->getURL() ) + if ( m_pImpl->m_bDocumentReadOnly ) + throw IOException(); + + impl_storeAs_throw( m_pImpl->getURL(), m_pImpl->getMediaDescriptor(), SAVE, aGuard ); + return; + } + + // if we have no URL, but did survive the DocumentGuard above, then we've been inited via XLoadable::initNew, + // i.e. we're based on a temporary storage + OSL_ENSURE( m_pImpl->getDocFileLocation().getLength() == 0, "ODatabaseDocument::store: unexpected URL inconsistency!" ); + + try + { + impl_storeToStorage_throw( m_pImpl->getRootStorage(), m_pImpl->getMediaDescriptor().getPropertyValues(), aGuard ); + } + catch( const Exception& ) + { + Any aError = ::cppu::getCaughtException(); + if ( aError.isExtractableTo( ::cppu::UnoType< IOException >::get() ) + || aError.isExtractableTo( ::cppu::UnoType< RuntimeException >::get() ) + ) + { + // allowed to leave + throw; + } + impl_throwIOExceptionCausedBySave_throw( aError, ::rtl::OUString() ); + } +} + +void ODatabaseDocument::impl_throwIOExceptionCausedBySave_throw( const Any& i_rError, const ::rtl::OUString& i_rTargetURL ) const +{ + ::rtl::OUString sErrorMessage = extractExceptionMessage( m_pImpl->m_aContext, i_rError ); + sErrorMessage = ResourceManager::loadString( + RID_STR_ERROR_WHILE_SAVING, + "$location$", i_rTargetURL, + "$message$", sErrorMessage + ); + throw IOException( sErrorMessage, *const_cast< ODatabaseDocument* >( this ) ); +} + +void ODatabaseDocument::impl_storeAs_throw( const ::rtl::OUString& _rURL, const ::comphelper::NamedValueCollection& _rArguments, + const StoreType _eType, DocumentGuard& _rGuard ) throw ( IOException, RuntimeException ) +{ + OSL_PRECOND( ( _eType == SAVE ) || ( _eType == SAVE_AS ), + "ODatabaseDocument::impl_storeAs_throw: you introduced a new type which cannot be handled here!" ); + + // if we're in the process of initializing the document (which effectively means it is an implicit + // initialization triggered in storeAsURL), the we do not notify events, since to an observer, the SaveAs + // should not be noticable + bool bIsInitializationProcess = impl_isInitializing(); + + if ( !bIsInitializationProcess ) + { + _rGuard.clear(); + m_aEventNotifier.notifyDocumentEvent( _eType == SAVE ? "OnSave" : "OnSaveAs", NULL, makeAny( _rURL ) ); + _rGuard.reset(); + } + + Reference< XStorage > xNewRootStorage; + // will be non-NULL if our storage changed + + try + { + ModifyLock aLock( *this ); + // ignore all changes of our "modified" state during storing + + sal_Bool bLocationChanged = ( _rURL != m_pImpl->getDocFileLocation() ); + if ( bLocationChanged ) + { + // create storage for target URL + Reference< XStorage > xTargetStorage( impl_createStorageFor_throw( _rURL ) ); + + if ( m_pImpl->isEmbeddedDatabase() ) + m_pImpl->clearConnections(); + + // commit everything + m_pImpl->commitEmbeddedStorage(); + m_pImpl->commitStorages(); + + // copy own storage to target storage + Reference< XStorage > xCurrentStorage( m_pImpl->getRootStorage() ); + if ( xCurrentStorage.is() ) + xCurrentStorage->copyToStorage( xTargetStorage ); + + m_pImpl->disposeStorages(); + + // each and every document definition obtained via m_xForms and m_xReports depends + // on the sub storages which we just disposed. So, dispose the forms/reports collections, too. + // This ensures that they're re-created when needed. + clearObjectContainer( m_xForms ); + clearObjectContainer( m_xReports ); + + xNewRootStorage = m_pImpl->switchToStorage( xTargetStorage ); + + m_pImpl->m_bDocumentReadOnly = sal_False; + } + + // store to current storage + Reference< XStorage > xCurrentStorage( m_pImpl->getOrCreateRootStorage(), UNO_QUERY_THROW ); + Sequence< PropertyValue > aMediaDescriptor( lcl_appendFileNameToDescriptor( _rArguments, _rURL ) ); + impl_storeToStorage_throw( xCurrentStorage, aMediaDescriptor, _rGuard ); + + // success - tell our impl + m_pImpl->setDocFileLocation( _rURL ); + m_pImpl->setResource( _rURL, aMediaDescriptor ); + + // if we are in an initialization process, then this is finished, now that we stored the document + if ( bIsInitializationProcess ) + impl_setInitialized(); + } + catch( const Exception& ) + { + Any aError = ::cppu::getCaughtException(); + + // notify the failure + if ( !bIsInitializationProcess ) + m_aEventNotifier.notifyDocumentEventAsync( _eType == SAVE ? "OnSaveFailed" : "OnSaveAsFailed", NULL, makeAny( _rURL ) ); + + if ( aError.isExtractableTo( ::cppu::UnoType< IOException >::get() ) + || aError.isExtractableTo( ::cppu::UnoType< RuntimeException >::get() ) + ) + { + // allowed to leave + throw; + } + + impl_throwIOExceptionCausedBySave_throw( aError, _rURL ); + } + + // notify the document event + if ( !bIsInitializationProcess ) + m_aEventNotifier.notifyDocumentEventAsync( _eType == SAVE ? "OnSaveDone" : "OnSaveAsDone", NULL, makeAny( _rURL ) ); + + // reset our "modified" flag, and clear the guard + impl_setModified_nothrow( sal_False, _rGuard ); + // <- SYNCHRONIZED + + // notify storage listeners + if ( xNewRootStorage.is() ) + impl_notifyStorageChange_nolck_nothrow( xNewRootStorage ); +} + +Reference< XStorage > ODatabaseDocument::impl_createStorageFor_throw( const ::rtl::OUString& _rURL ) const +{ + Reference < ::com::sun::star::ucb::XSimpleFileAccess > xTempAccess; + m_pImpl->m_aContext.createComponent( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ,xTempAccess); + Reference< io::XStream > xStream = xTempAccess->openFileReadWrite( _rURL ); + Reference< io::XTruncate > xTruncate(xStream,UNO_QUERY); + if ( xTruncate.is() ) + { + xTruncate->truncate(); + } + Sequence<Any> aParam(2); + aParam[0] <<= xStream; + aParam[1] <<= ElementModes::READWRITE | ElementModes::TRUNCATE; + + Reference< XSingleServiceFactory > xStorageFactory( m_pImpl->createStorageFactory(), UNO_SET_THROW ); + return Reference< XStorage >( xStorageFactory->createInstanceWithArguments( aParam ), UNO_QUERY_THROW ); +} + +void SAL_CALL ODatabaseDocument::storeAsURL( const ::rtl::OUString& _rURL, const Sequence< PropertyValue >& _rArguments ) throw (IOException, RuntimeException) +{ + // SYNCHRONIZED -> + DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit ); + + // Normally, a document initialization is done via XLoadable::load or XLoadable::initNew. For convenience + // reasons, and to not break existing API clients, it's allowed to call storeAsURL without having initialized + // the document, in which case the initialization will be done implicitly. + bool bImplicitInitialization = !impl_isInitialized(); + // implicit initialization while another initialization is just running is not possible + if ( bImplicitInitialization && impl_isInitializing() ) + throw DoubleInitializationException(); + + if ( bImplicitInitialization ) + impl_setInitializing(); + + try + { + impl_storeAs_throw( _rURL, _rArguments, SAVE_AS, aGuard ); + // <- SYNCHRONIZED + + // impl_storeAs_throw cleared the lock on our mutex, but the below lines need this lock + // SYNCHRONIZED -> + aGuard.reset(); + + // our title might have changed, potentially at least + // Sadly, we cannot check this: Calling getTitle here and now would not deliver + // an up-to-date result, as the call is delegated to our TitleHelper instance, which itself + // updates its title only if it gets the OnSaveAsDone event (which was sent asynchronously + // by impl_storeAs_throw). So, we simply notify always, and also asynchronously + m_aEventNotifier.notifyDocumentEventAsync( "OnTitleChanged" ); + } + catch( const Exception& ) + { + impl_reset_nothrow(); + throw; + } + + if ( bImplicitInitialization ) + m_bAllowDocumentScripting = true; + + aGuard.clear(); + // <- SYNCHRONIZED + + if ( bImplicitInitialization ) + m_aEventNotifier.notifyDocumentEvent( "OnCreate" ); +} + +void ODatabaseDocument::impl_storeToStorage_throw( const Reference< XStorage >& _rxTargetStorage, const Sequence< PropertyValue >& _rMediaDescriptor, + DocumentGuard& _rDocGuard ) const +{ + if ( !_rxTargetStorage.is() ) + throw IllegalArgumentException( ::rtl::OUString(), *const_cast< ODatabaseDocument* >( this ), 1 ); + + if ( !m_pImpl.is() ) + throw DisposedException( ::rtl::OUString(), *const_cast< ODatabaseDocument* >( this ) ); + + try + { + // commit everything + m_pImpl->commitEmbeddedStorage(); + m_pImpl->commitStorages(); + + // copy own storage to target storage + if ( impl_isInitialized() ) + { + Reference< XStorage > xCurrentStorage( m_pImpl->getOrCreateRootStorage(), UNO_QUERY_THROW ); + if ( xCurrentStorage != _rxTargetStorage ) + xCurrentStorage->copyToStorage( _rxTargetStorage ); + } + + // write into target storage + ::comphelper::NamedValueCollection aWriteArgs( _rMediaDescriptor ); + lcl_triggerStatusIndicator_throw( aWriteArgs, _rDocGuard, true ); + impl_writeStorage_throw( _rxTargetStorage, aWriteArgs ); + lcl_triggerStatusIndicator_throw( aWriteArgs, _rDocGuard, false ); + + // commit target storage + OSL_VERIFY( tools::stor::commitStorageIfWriteable( _rxTargetStorage ) ); + } + catch( const IOException& ) { throw; } + catch( const RuntimeException& ) { throw; } + catch ( const Exception& e ) + { + throw IOException( e.Message, *const_cast< ODatabaseDocument* >( this ) ); + } +} + +void SAL_CALL ODatabaseDocument::storeToURL( const ::rtl::OUString& _rURL, const Sequence< PropertyValue >& _rArguments ) throw (IOException, RuntimeException) +{ + DocumentGuard aGuard( *this ); + ModifyLock aLock( *this ); + + { + aGuard.clear(); + m_aEventNotifier.notifyDocumentEvent( "OnSaveTo", NULL, makeAny( _rURL ) ); + aGuard.reset(); + } + + try + { + // create storage for target URL + Reference< XStorage > xTargetStorage( impl_createStorageFor_throw( _rURL ) ); + + // extend media descriptor with URL + Sequence< PropertyValue > aMediaDescriptor( lcl_appendFileNameToDescriptor( _rArguments, _rURL ) ); + + // store to this storage + impl_storeToStorage_throw( xTargetStorage, aMediaDescriptor, aGuard ); + } + catch( const Exception& ) + { + Any aError = ::cppu::getCaughtException(); + m_aEventNotifier.notifyDocumentEventAsync( "OnSaveToFailed", NULL, aError ); + + if ( aError.isExtractableTo( ::cppu::UnoType< IOException >::get() ) + || aError.isExtractableTo( ::cppu::UnoType< RuntimeException >::get() ) + ) + { + // allowed to leave + throw; + } + + impl_throwIOExceptionCausedBySave_throw( aError, _rURL ); + } + + m_aEventNotifier.notifyDocumentEventAsync( "OnSaveToDone", NULL, makeAny( _rURL ) ); +} + +// XModifyBroadcaster +void SAL_CALL ODatabaseDocument::addModifyListener( const Reference< XModifyListener >& _xListener ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + m_aModifyListeners.addInterface(_xListener); +} + +void SAL_CALL ODatabaseDocument::removeModifyListener( const Reference< XModifyListener >& _xListener ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + m_aModifyListeners.removeInterface(_xListener); +} + +// XModifiable +sal_Bool SAL_CALL ODatabaseDocument::isModified( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + + return m_pImpl->m_bModified; +} + +void SAL_CALL ODatabaseDocument::setModified( sal_Bool _bModified ) throw (PropertyVetoException, RuntimeException) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit ); + if ( impl_isInitialized() ) + impl_setModified_nothrow( _bModified, aGuard ); + // it's allowed to call setModified without the document being initialized already. In this case, + // we simply ignore the call - when the initialization is finished, the respective code will set + // a proper "modified" flag +} + +void ODatabaseDocument::impl_setModified_nothrow( sal_Bool _bModified, DocumentGuard& _rGuard ) +{ + // SYNCHRONIZED -> + bool bModifiedChanged = ( m_pImpl->m_bModified != _bModified ) && ( !m_pImpl->isModifyLocked() ); + + if ( bModifiedChanged ) + { + m_pImpl->m_bModified = _bModified; + m_aEventNotifier.notifyDocumentEventAsync( "OnModifyChanged" ); + } + _rGuard.clear(); + // <- SYNCHRONIZED + + if ( bModifiedChanged ) + { + lang::EventObject aEvent( *this ); + m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent ); + } +} + +// ::com::sun::star::document::XEventBroadcaster +void SAL_CALL ODatabaseDocument::addEventListener(const uno::Reference< document::XEventListener >& _Listener ) throw (uno::RuntimeException) +{ + m_aEventNotifier.addLegacyEventListener( _Listener ); +} + +void SAL_CALL ODatabaseDocument::removeEventListener( const uno::Reference< document::XEventListener >& _Listener ) throw (uno::RuntimeException) +{ + m_aEventNotifier.removeLegacyEventListener( _Listener ); +} + +void SAL_CALL ODatabaseDocument::addDocumentEventListener( const Reference< XDocumentEventListener >& _Listener ) throw (RuntimeException) +{ + m_aEventNotifier.addDocumentEventListener( _Listener ); +} + +void SAL_CALL ODatabaseDocument::removeDocumentEventListener( const Reference< XDocumentEventListener >& _Listener ) throw (RuntimeException) +{ + m_aEventNotifier.removeDocumentEventListener( _Listener ); +} + +void SAL_CALL ODatabaseDocument::notifyDocumentEvent( const ::rtl::OUString& _EventName, const Reference< XController2 >& _ViewController, const Any& _Supplement ) throw (IllegalArgumentException, NoSupportException, RuntimeException) +{ + if ( !_EventName.getLength() ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); + + // SYNCHRONIZED -> + DocumentGuard aGuard( *this ); + + if ( !DocumentEvents::needsSynchronousNotification( _EventName ) ) + { + m_aEventNotifier.notifyDocumentEventAsync( _EventName, _ViewController, _Supplement ); + return; + } + aGuard.clear(); + // <- SYNCHRONIZED + + m_aEventNotifier.notifyDocumentEvent( _EventName, _ViewController, _Supplement ); +} + +Sequence< PropertyValue > SAL_CALL ODatabaseDocument::getPrinter( ) throw (RuntimeException) +{ + DBG_ERROR( "ODatabaseDocument::getPrinter: not supported!" ); + return Sequence< PropertyValue >(); +} + +void SAL_CALL ODatabaseDocument::setPrinter( const Sequence< PropertyValue >& /*aPrinter*/ ) throw (IllegalArgumentException, RuntimeException) +{ + DBG_ERROR( "ODatabaseDocument::setPrinter: not supported!" ); +} + +void SAL_CALL ODatabaseDocument::print( const Sequence< PropertyValue >& /*xOptions*/ ) throw (IllegalArgumentException, RuntimeException) +{ + DBG_ERROR( "ODatabaseDocument::print: not supported!" ); +} + +void ODatabaseDocument::impl_reparent_nothrow( const WeakReference< XNameAccess >& _rxContainer ) +{ + Reference< XChild > xChild( _rxContainer.get(), UNO_QUERY ); + if ( xChild.is() ) + xChild->setParent( *this ); +} + +void ODatabaseDocument::clearObjectContainer( WeakReference< XNameAccess >& _rxContainer) +{ + Reference< XNameAccess > xContainer = _rxContainer; + ::comphelper::disposeComponent( xContainer ); + + Reference< XChild > xChild( _rxContainer.get(),UNO_QUERY ); + if ( xChild.is() ) + xChild->setParent( NULL ); + _rxContainer = Reference< XNameAccess >(); +} + +Reference< XNameAccess > ODatabaseDocument::impl_getDocumentContainer_throw( ODatabaseModelImpl::ObjectType _eType ) +{ + if ( ( _eType != ODatabaseModelImpl::E_FORM ) && ( _eType != ODatabaseModelImpl::E_REPORT ) ) + throw IllegalArgumentException(); + + bool bFormsContainer = _eType == ODatabaseModelImpl::E_FORM; + + WeakReference< XNameAccess >& rContainerRef( bFormsContainer ? m_xForms : m_xReports ); + Reference< XNameAccess > xContainer = rContainerRef; + if ( !xContainer.is() ) + { + Any aValue; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xMy(*this); + if ( dbtools::getDataSourceSetting(xMy,bFormsContainer ? "Forms" : "Reports",aValue) ) + { + ::rtl::OUString sSupportService; + aValue >>= sSupportService; + if ( sSupportService.getLength() ) + { + Sequence<Any> aArgs(1); + aArgs[0] <<= NamedValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DatabaseDocument")),makeAny(xMy)); + xContainer.set(m_pImpl->m_aContext.createComponentWithArguments(sSupportService,aArgs),UNO_QUERY); + rContainerRef = xContainer; + } + } + if ( !xContainer.is() ) + { + TContentPtr& rContainerData( m_pImpl->getObjectContainer( _eType ) ); + rContainerRef = xContainer = new ODocumentContainer( m_pImpl->m_aContext.getLegacyServiceFactory(), *this, rContainerData, bFormsContainer ); + } + impl_reparent_nothrow( xContainer ); + } + return xContainer; +} + +void ODatabaseDocument::impl_closeControllerFrames_nolck_throw( sal_Bool _bDeliverOwnership ) +{ + Controllers aCopy = m_aControllers; + + Controllers::iterator aEnd = aCopy.end(); + for ( Controllers::iterator aIter = aCopy.begin(); aIter != aEnd ; ++aIter ) + { + if ( !aIter->is() ) + continue; + + try + { + Reference< XCloseable> xFrame( (*aIter)->getFrame(), UNO_QUERY ); + if ( xFrame.is() ) + xFrame->close( _bDeliverOwnership ); + } + catch( const CloseVetoException& ) { throw; } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } +} + +struct DisposeControllerFrame : public ::std::unary_function< Reference< XController >, void > +{ + void operator()( const Reference< XController >& _rxController ) const + { + try + { + if ( !_rxController.is() ) + return; + + Reference< XFrame > xFrame( _rxController->getFrame() ); + ::comphelper::disposeComponent( xFrame ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + }; +}; + +void ODatabaseDocument::impl_disposeControllerFrames_nothrow() +{ + Controllers aCopy; + aCopy.swap( m_aControllers ); // ensure m_aControllers is empty afterwards + ::std::for_each( aCopy.begin(), aCopy.end(), DisposeControllerFrame() ); +} + +void SAL_CALL ODatabaseDocument::close( sal_Bool _bDeliverOwnership ) throw (CloseVetoException, RuntimeException) +{ + // nearly everything below can/must be done without our mutex locked, the below is just for + // the checks for being disposed and the like + // SYNCHRONIZED -> + { + DocumentGuard aGuard( *this ); + m_bClosing = true; + } + // <- SYNCHRONIZED + + try + { + // allow listeners to veto + lang::EventObject aEvent( *this ); + m_aCloseListener.forEach< XCloseListener >( + boost::bind( &XCloseListener::queryClosing, _1, boost::cref( aEvent ), boost::cref( _bDeliverOwnership ) ) ); + + // notify that we're going to unload + m_aEventNotifier.notifyDocumentEvent( "OnPrepareUnload" ); + + impl_closeControllerFrames_nolck_throw( _bDeliverOwnership ); + + m_aCloseListener.notifyEach( &XCloseListener::notifyClosing, (const lang::EventObject&)aEvent ); + + dispose(); + } + catch ( const Exception& ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_bClosing = false; + throw; + } + + // SYNCHRONIZED -> + ::osl::MutexGuard aGuard( m_aMutex ); + m_bClosing = false; + // <- SYNCHRONIZED +} + +void SAL_CALL ODatabaseDocument::addCloseListener( const Reference< ::com::sun::star::util::XCloseListener >& Listener ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + m_aCloseListener.addInterface(Listener); +} + +void SAL_CALL ODatabaseDocument::removeCloseListener( const Reference< ::com::sun::star::util::XCloseListener >& Listener ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + m_aCloseListener.removeInterface(Listener); +} + +Reference< XNameAccess > SAL_CALL ODatabaseDocument::getFormDocuments( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit ); + return impl_getDocumentContainer_throw( ODatabaseModelImpl::E_FORM ); +} + +Reference< XNameAccess > SAL_CALL ODatabaseDocument::getReportDocuments( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit ); + return impl_getDocumentContainer_throw( ODatabaseModelImpl::E_REPORT ); +} + +void ODatabaseDocument::WriteThroughComponent( const Reference< XComponent >& xComponent, const sal_Char* pStreamName, + const sal_Char* pServiceName, const Sequence< Any >& _rArguments, const Sequence< PropertyValue >& rMediaDesc, + const Reference<XStorage>& _xStorageToSaveTo ) const +{ + OSL_ENSURE( pStreamName, "Need stream name!" ); + OSL_ENSURE( pServiceName, "Need service name!" ); + + // open stream + ::rtl::OUString sStreamName = ::rtl::OUString::createFromAscii( pStreamName ); + Reference< XStream > xStream = _xStorageToSaveTo->openStreamElement( sStreamName, ElementModes::READWRITE | ElementModes::TRUNCATE ); + if ( !xStream.is() ) + return; + + Reference< XOutputStream > xOutputStream( xStream->getOutputStream() ); + OSL_ENSURE( xOutputStream.is(), "Can't create output stream in package!" ); + if ( !xOutputStream.is() ) + return; + + Reference< XSeekable > xSeek( xOutputStream, UNO_QUERY ); + if ( xSeek.is() ) + xSeek->seek(0); + + Reference< XPropertySet > xStreamProp( xOutputStream, UNO_QUERY_THROW ); + xStreamProp->setPropertyValue( INFO_MEDIATYPE, makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "text/xml" ) ) ) ); + xStreamProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Compressed" ) ), makeAny( (sal_Bool)sal_True ) ); + + // write the stuff + WriteThroughComponent( xOutputStream, xComponent, pServiceName, _rArguments, rMediaDesc ); +} + +void ODatabaseDocument::WriteThroughComponent( const Reference< XOutputStream >& xOutputStream, + const Reference< XComponent >& xComponent, const sal_Char* pServiceName, const Sequence< Any >& _rArguments, + const Sequence< PropertyValue >& rMediaDesc ) const +{ + OSL_ENSURE( xOutputStream.is(), "I really need an output stream!" ); + OSL_ENSURE( xComponent.is(), "Need component!" ); + OSL_ENSURE( NULL != pServiceName, "Need component name!" ); + + // get component + Reference< XActiveDataSource > xSaxWriter; + OSL_VERIFY( m_pImpl->m_aContext.createComponent( "com.sun.star.xml.sax.Writer", xSaxWriter ) ); + if ( !xSaxWriter.is() ) + return; + + // connect XML writer to output stream + xSaxWriter->setOutputStream( xOutputStream ); + + // prepare arguments (prepend doc handler to given arguments) + Reference< XDocumentHandler > xDocHandler( xSaxWriter,UNO_QUERY); + Sequence<Any> aArgs( 1 + _rArguments.getLength() ); + aArgs[0] <<= xDocHandler; + for ( sal_Int32 i = 0; i < _rArguments.getLength(); ++i ) + aArgs[ i+1 ] = _rArguments[i]; + + // get filter component + Reference< XExporter > xExporter; + OSL_VERIFY( m_pImpl->m_aContext.createComponentWithArguments( pServiceName, aArgs, xExporter ) ); + if ( !xExporter.is() ) + return; + + // connect model and filter + xExporter->setSourceDocument( xComponent ); + + // filter + Reference< XFilter > xFilter( xExporter, UNO_QUERY_THROW ); + xFilter->filter( rMediaDesc ); +} + +void ODatabaseDocument::impl_writeStorage_throw( const Reference< XStorage >& _rxTargetStorage, const ::comphelper::NamedValueCollection& _rMediaDescriptor ) const +{ + // extract status indicator + Sequence< Any > aDelegatorArguments; + lcl_extractStatusIndicator( _rMediaDescriptor, aDelegatorArguments ); + + /** property map for export info set */ + comphelper::PropertyMapEntry aExportInfoMap[] = + { + { MAP_LEN( "BaseURI"), 0,&::getCppuType( (::rtl::OUString *)0 ),beans::PropertyAttribute::MAYBEVOID, 0 }, + { MAP_LEN( "StreamName"), 0,&::getCppuType( (::rtl::OUString *)0 ),beans::PropertyAttribute::MAYBEVOID, 0 }, + { MAP_LEN( "UsePrettyPrinting" ), 0, &::getCppuType((sal_Bool*)0), beans::PropertyAttribute::MAYBEVOID, 0}, + { NULL, 0, 0, NULL, 0, 0 } + }; + uno::Reference< beans::XPropertySet > xInfoSet( comphelper::GenericPropertySet_CreateInstance( new comphelper::PropertySetInfo( aExportInfoMap ) ) ); + + SvtSaveOptions aSaveOpt; + xInfoSet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("UsePrettyPrinting")), uno::makeAny(aSaveOpt.IsPrettyPrinting())); + if ( aSaveOpt.IsSaveRelFSys() ) + xInfoSet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("BaseURI")), uno::makeAny(_rMediaDescriptor.getOrDefault("URL",::rtl::OUString()))); + + ::rtl::OUString aVersion; + SvtSaveOptions::ODFDefaultVersion nDefVersion = aSaveOpt.GetODFDefaultVersion(); + + // older versions can not have this property set, it exists only starting from ODF1.2 + if ( nDefVersion >= SvtSaveOptions::ODFVER_012 ) + aVersion = ODFVER_012_TEXT; + + if ( aVersion.getLength() ) + { + try + { + xInfoSet->setPropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Version" )), uno::makeAny( aVersion ) ); + } + catch( uno::Exception& ) + { + } + } + + sal_Int32 nArgsLen = aDelegatorArguments.getLength(); + aDelegatorArguments.realloc(nArgsLen+1); + aDelegatorArguments[nArgsLen++] <<= xInfoSet; + + Reference< XPropertySet > xProp( _rxTargetStorage, UNO_QUERY_THROW ); + xProp->setPropertyValue( INFO_MEDIATYPE, makeAny( (rtl::OUString)MIMETYPE_OASIS_OPENDOCUMENT_DATABASE ) ); + + Reference< XComponent > xComponent( *const_cast< ODatabaseDocument* >( this ), UNO_QUERY_THROW ); + + Sequence< PropertyValue > aMediaDescriptor; + _rMediaDescriptor >>= aMediaDescriptor; + + xInfoSet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("StreamName")), uno::makeAny(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("settings.xml")))); + WriteThroughComponent( xComponent, "settings.xml", "com.sun.star.comp.sdb.XMLSettingsExporter", + aDelegatorArguments, aMediaDescriptor, _rxTargetStorage ); + + xInfoSet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("StreamName")), uno::makeAny(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("content.xml")))); + WriteThroughComponent( xComponent, "content.xml", "com.sun.star.comp.sdb.DBExportFilter", + aDelegatorArguments, aMediaDescriptor, _rxTargetStorage ); + + m_pImpl->storeLibraryContainersTo( _rxTargetStorage ); +} + +Reference< XUIConfigurationManager > SAL_CALL ODatabaseDocument::getUIConfigurationManager( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + + if ( !m_xUIConfigurationManager.is() ) + { + m_pImpl->m_aContext.createComponent( "com.sun.star.ui.UIConfigurationManager", m_xUIConfigurationManager ); + Reference< XUIConfigurationStorage > xUIConfigStorage( m_xUIConfigurationManager, UNO_QUERY ); + if ( xUIConfigStorage.is() ) + { + rtl::OUString aUIConfigFolderName( RTL_CONSTASCII_USTRINGPARAM( "Configurations2" )); + Reference< XStorage > xConfigStorage; + + // First try to open with READWRITE and then READ + xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, ElementModes::READWRITE ); + if ( xConfigStorage.is() ) + { + rtl::OUString aUIConfigMediaType( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.sun.xml.ui.configuration" )); + rtl::OUString aMediaType; + Reference< XPropertySet > xPropSet( xConfigStorage, UNO_QUERY ); + Any a = xPropSet->getPropertyValue( INFO_MEDIATYPE ); + if ( !( a >>= aMediaType ) || ( aMediaType.getLength() == 0 )) + { + a <<= aUIConfigMediaType; + xPropSet->setPropertyValue( INFO_MEDIATYPE, a ); + } + } + else + xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, ElementModes::READ ); + + // initialize ui configuration manager with document substorage + xUIConfigStorage->setStorage( xConfigStorage ); + } + } + + return m_xUIConfigurationManager; +} + +Reference< XStorage > SAL_CALL ODatabaseDocument::getDocumentSubStorage( const ::rtl::OUString& aStorageName, sal_Int32 nMode ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + + Reference< XDocumentSubStorageSupplier > xStorageAccess( m_pImpl->getDocumentSubStorageSupplier() ); + return xStorageAccess->getDocumentSubStorage( aStorageName, nMode ); +} + +Sequence< ::rtl::OUString > SAL_CALL ODatabaseDocument::getDocumentSubStoragesNames( ) throw (::com::sun::star::io::IOException, RuntimeException) +{ + Reference< XDocumentSubStorageSupplier > xStorageAccess( m_pImpl->getDocumentSubStorageSupplier() ); + return xStorageAccess->getDocumentSubStoragesNames(); +} + +void ODatabaseDocument::impl_notifyStorageChange_nolck_nothrow( const Reference< XStorage >& _rxNewRootStorage ) +{ + Reference< XInterface > xMe( *const_cast< ODatabaseDocument* >( this ) ); + + m_aStorageListeners.forEach< XStorageChangeListener >( + boost::bind( &XStorageChangeListener::notifyStorageChange, _1, boost::cref( xMe ), boost::cref( _rxNewRootStorage ) ) ); +} + +void ODatabaseDocument::disposing() +{ + OSL_TRACE( "DD: disp: %p: %p", this, m_pImpl.get() ); + if ( !m_pImpl.is() ) + { + // this means that we're already disposed + DBG_ASSERT( ODatabaseDocument_OfficeDocument::rBHelper.bDisposed, "ODatabaseDocument::disposing: no impl anymore, but not yet disposed!" ); + return; + } + + if ( impl_isInitialized() ) + m_aEventNotifier.notifyDocumentEvent( "OnUnload" ); + + Reference< XModel > xHoldAlive( this ); + + m_aEventNotifier.disposing(); + + lang::EventObject aDisposeEvent(static_cast<XWeak*>(this)); + m_aModifyListeners.disposeAndClear( aDisposeEvent ); + m_aCloseListener.disposeAndClear( aDisposeEvent ); + m_aStorageListeners.disposeAndClear( aDisposeEvent ); + + // this is the list of objects which we currently hold as member. Upon resetting + // those members, we can (potentially) release the last reference to them, in which + // case they will be deleted - if they're C++ implementations, that is :). + // Some of those implementations are offending enough to require the SolarMutex, which + // means we should not release the last reference while our own mutex is locked ... + ::std::list< Reference< XInterface > > aKeepAlive; + + // SYNCHRONIZED -> + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + + DBG_ASSERT( m_aControllers.empty(), "ODatabaseDocument::disposing: there still are controllers!" ); + // normally, nobody should explicitly dispose, but only XCloseable::close the document. And upon + // closing, our controllers are closed, too + + aKeepAlive.push_back( m_xUIConfigurationManager ); + m_xUIConfigurationManager = NULL; + + clearObjectContainer( m_xForms ); + clearObjectContainer( m_xReports ); + + // reset the macro mode: in case the our impl struct stays alive (e.g. because our DataSource + // object still exists), and somebody subsequently re-opens the document, we want to have + // the security warning, again. + m_pImpl->resetMacroExecutionMode(); + + // similar argueing for our ViewMonitor + m_aViewMonitor.reset(); + + // tell our Impl to forget us + m_pImpl->modelIsDisposing( impl_isInitialized(), ODatabaseModelImpl::ResetModelAccess() ); + + // now, at the latest, the controller array should be empty. Controllers are + // expected to listen for our disposal, and disconnect then + DBG_ASSERT( m_aControllers.empty(), "ODatabaseDocument::disposing: there still are controllers!" ); + impl_disposeControllerFrames_nothrow(); + + aKeepAlive.push_back( m_xModuleManager ); + m_xModuleManager.clear(); + + aKeepAlive.push_back( m_xTitleHelper ); + m_xTitleHelper.clear(); + + m_pImpl.clear(); + + aGuard.clear(); + // <- SYNCHRONIZED + + aKeepAlive.clear(); +} + +// XComponent +void SAL_CALL ODatabaseDocument::dispose( ) throw (RuntimeException) +{ + ::cppu::WeakComponentImplHelperBase::dispose(); +} + +void SAL_CALL ODatabaseDocument::addEventListener( const Reference< lang::XEventListener >& _xListener ) throw (RuntimeException) +{ + ::cppu::WeakComponentImplHelperBase::addEventListener( _xListener ); +} + +void SAL_CALL ODatabaseDocument::removeEventListener( const Reference< lang::XEventListener >& _xListener ) throw (RuntimeException) +{ + ::cppu::WeakComponentImplHelperBase::removeEventListener( _xListener ); +} + +// XServiceInfo +rtl::OUString ODatabaseDocument::getImplementationName( ) throw(RuntimeException) +{ + return getImplementationName_static(); +} + +rtl::OUString ODatabaseDocument::getImplementationName_static( ) throw(RuntimeException) +{ + return rtl::OUString::createFromAscii("com.sun.star.comp.dba.ODatabaseDocument"); +} + +Sequence< ::rtl::OUString > ODatabaseDocument::getSupportedServiceNames( ) throw (RuntimeException) +{ + return getSupportedServiceNames_static(); +} + +Reference< XInterface > ODatabaseDocument::Create( const Reference< XComponentContext >& _rxContext ) +{ + ::comphelper::ComponentContext aContext( _rxContext ); + Reference< XUnoTunnel > xDBContextTunnel( aContext.createComponent( (::rtl::OUString)SERVICE_SDB_DATABASECONTEXT ), UNO_QUERY_THROW ); + ODatabaseContext* pContext = reinterpret_cast< ODatabaseContext* >( xDBContextTunnel->getSomething( ODatabaseContext::getUnoTunnelImplementationId() ) ); + + ::rtl::Reference<ODatabaseModelImpl> pImpl( new ODatabaseModelImpl( aContext.getLegacyServiceFactory(), *pContext ) ); + Reference< XModel > xModel( pImpl->createNewModel_deliverOwnership( false ) ); + return xModel.get(); +} + +Sequence< ::rtl::OUString > ODatabaseDocument::getSupportedServiceNames_static( ) throw (RuntimeException) +{ + Sequence< ::rtl::OUString > aSNS( 2 ); + aSNS[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sdb.OfficeDatabaseDocument")); + aSNS[1] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.document.OfficeDocument")); + return aSNS; +} + +sal_Bool ODatabaseDocument::supportsService( const ::rtl::OUString& _rServiceName ) throw (RuntimeException) +{ + return ::comphelper::findValue(getSupportedServiceNames(), _rServiceName, sal_True).getLength() != 0; +} + +Reference< XDataSource > SAL_CALL ODatabaseDocument::getDataSource() throw (RuntimeException) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit ); + return m_pImpl->getOrCreateDataSource(); +} + +void SAL_CALL ODatabaseDocument::loadFromStorage( const Reference< XStorage >& /*xStorage*/, const Sequence< PropertyValue >& /*aMediaDescriptor*/ ) throw (IllegalArgumentException, DoubleInitializationException, IOException, Exception, RuntimeException) +{ + DocumentGuard aGuard( *this ); + + throw Exception( + DBACORE_RESSTRING( RID_STR_NO_EMBEDDING ), + *this + ); +} + +void SAL_CALL ODatabaseDocument::storeToStorage( const Reference< XStorage >& _rxStorage, const Sequence< PropertyValue >& _rMediaDescriptor ) throw (IllegalArgumentException, IOException, Exception, RuntimeException) +{ + DocumentGuard aGuard( *this ); + impl_storeToStorage_throw( _rxStorage, _rMediaDescriptor, aGuard ); +} + +void SAL_CALL ODatabaseDocument::switchToStorage( const Reference< XStorage >& _rxNewRootStorage ) throw (IllegalArgumentException, IOException, Exception, RuntimeException) +{ + DocumentGuard aGuard( *this ); + + Reference< XStorage > xNewRootStorage( m_pImpl->switchToStorage( _rxNewRootStorage ) ); + + aGuard.clear(); + impl_notifyStorageChange_nolck_nothrow( xNewRootStorage ); +} + +Reference< XStorage > SAL_CALL ODatabaseDocument::getDocumentStorage( ) throw (IOException, Exception, RuntimeException) +{ + DocumentGuard aGuard( *this ); + return m_pImpl->getOrCreateRootStorage(); +} + +void SAL_CALL ODatabaseDocument::addStorageChangeListener( const Reference< XStorageChangeListener >& _Listener ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + m_aStorageListeners.addInterface( _Listener ); +} + +void SAL_CALL ODatabaseDocument::removeStorageChangeListener( const Reference< XStorageChangeListener >& _Listener ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + m_aStorageListeners.addInterface( _Listener ); +} + +Reference< XStorageBasedLibraryContainer > SAL_CALL ODatabaseDocument::getBasicLibraries() throw (RuntimeException) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit ); + return m_pImpl->getLibraryContainer( true ); +} + +Reference< XStorageBasedLibraryContainer > SAL_CALL ODatabaseDocument::getDialogLibraries() throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + return m_pImpl->getLibraryContainer( false ); +} + +::sal_Bool SAL_CALL ODatabaseDocument::getAllowMacroExecution() throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + return m_pImpl->adjustMacroMode_AutoReject(); +} + +Reference< XEmbeddedScripts > SAL_CALL ODatabaseDocument::getScriptContainer() throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + return this; +} + +Reference< provider::XScriptProvider > SAL_CALL ODatabaseDocument::getScriptProvider( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + + Reference< XScriptProvider > xScriptProvider( m_xScriptProvider ); + if ( !xScriptProvider.is() ) + { + Reference < XScriptProviderFactory > xFactory( + m_pImpl->m_aContext.getSingleton( "com.sun.star.script.provider.theMasterScriptProviderFactory" ), UNO_QUERY_THROW ); + + Any aScriptProviderContext; + if ( m_bAllowDocumentScripting ) + aScriptProviderContext <<= Reference< XModel >( this ); + + xScriptProvider.set( xFactory->createScriptProvider( aScriptProviderContext ), UNO_SET_THROW ); + m_xScriptProvider = xScriptProvider; + } + + return xScriptProvider; +} + +Reference< XNameReplace > SAL_CALL ODatabaseDocument::getEvents( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit ); + return m_pEventContainer; +} + +void SAL_CALL ODatabaseDocument::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException) +{ + if ( m_pImpl.is() ) + m_pImpl->disposing(Source); +} + +Reference< XInterface > ODatabaseDocument::getThis() const +{ + return *const_cast< ODatabaseDocument* >( this ); +} + +struct CreateAny : public ::std::unary_function< Reference<XController>, Any> +{ + Any operator() (const Reference<XController>& lhs) const + { + return makeAny(lhs); + } +}; + +// XModel2 +Reference< XEnumeration > SAL_CALL ODatabaseDocument::getControllers( ) throw (RuntimeException) +{ + DocumentGuard aGuard( *this ); + uno::Sequence< Any> aController( m_aControllers.size() ); + ::std::transform( m_aControllers.begin(), m_aControllers.end(), aController.getArray(), CreateAny() ); + return new ::comphelper::OAnyEnumeration(aController); +} + +Sequence< ::rtl::OUString > SAL_CALL ODatabaseDocument::getAvailableViewControllerNames( ) throw (RuntimeException) +{ + Sequence< ::rtl::OUString > aNames(1); + aNames[0] = SERVICE_SDB_APPLICATIONCONTROLLER; + return aNames; +} + +Reference< XController2 > SAL_CALL ODatabaseDocument::createDefaultViewController( const Reference< XFrame >& _Frame ) throw (IllegalArgumentException, Exception, RuntimeException) +{ + return createViewController( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Default" ) ), + Sequence< PropertyValue >(), + _Frame + ); +} + +Reference< XController2 > SAL_CALL ODatabaseDocument::createViewController( const ::rtl::OUString& _ViewName, const Sequence< PropertyValue >& _Arguments, const Reference< XFrame >& _Frame ) throw (IllegalArgumentException, Exception, RuntimeException) +{ + if ( !_ViewName.equalsAscii( "Default" ) && !_ViewName.equalsAscii( "Preview" ) ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); + if ( !_Frame.is() ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 3 ); + + DocumentGuard aGuard( *this ); + ::comphelper::ComponentContext aContext( m_pImpl->m_aContext ); + aGuard.clear(); + + Reference< XController2 > xController; + aContext.createComponent( "org.openoffice.comp.dbu.OApplicationController", xController ); + + ::comphelper::NamedValueCollection aInitArgs( _Arguments ); + aInitArgs.put( "Frame", _Frame ); + if ( _ViewName.equalsAscii( "Preview" ) ) + aInitArgs.put( "Preview", sal_Bool( sal_True ) ); + Reference< XInitialization > xInitController( xController, UNO_QUERY_THROW ); + xInitController->initialize( aInitArgs.getWrappedPropertyValues() ); + + return xController; +} + +Reference< XTitle > ODatabaseDocument::impl_getTitleHelper_throw() +{ + if ( ! m_xTitleHelper.is ()) + { + Reference< XUntitledNumbers > xDesktop( + m_pImpl->m_aContext.createComponent( "com.sun.star.frame.Desktop" ), + UNO_QUERY_THROW ); + uno::Reference< frame::XModel > xThis (getThis(), uno::UNO_QUERY_THROW); + + ::framework::TitleHelper* pHelper = new ::framework::TitleHelper(m_pImpl->m_aContext.getLegacyServiceFactory()); + m_xTitleHelper.set(static_cast< ::cppu::OWeakObject* >(pHelper), uno::UNO_QUERY_THROW); + pHelper->setOwner (xThis ); + pHelper->connectWithUntitledNumbers (xDesktop); + } + + return m_xTitleHelper; +} + +uno::Reference< frame::XUntitledNumbers > ODatabaseDocument::impl_getUntitledHelper_throw(const uno::Reference< uno::XInterface >& _xComponent) +{ + if ( !m_xModuleManager.is() ) + m_xModuleManager.set( m_pImpl->m_aContext.createComponent( "com.sun.star.frame.ModuleManager" ), UNO_QUERY_THROW ); + + ::rtl::OUString sModuleId; + try + { + sModuleId = m_xModuleManager->identify( _xComponent ); + } + catch(uno::Exception) + { + // ni + } + uno::Reference< frame::XUntitledNumbers > xNumberedControllers; + + TNumberedController::iterator aFind = m_aNumberedControllers.find(sModuleId); + if ( aFind == m_aNumberedControllers.end() ) + { + uno::Reference< frame::XModel > xThis(static_cast< frame::XModel* >(this), uno::UNO_QUERY_THROW); + ::comphelper::NumberedCollection* pHelper = new ::comphelper::NumberedCollection(); + xNumberedControllers.set(static_cast< ::cppu::OWeakObject* >(pHelper), uno::UNO_QUERY_THROW); + + pHelper->setOwner (xThis); + //pHelper->setUntitledPrefix (::rtl::OUString::createFromAscii(" : ")); + + m_aNumberedControllers.insert(TNumberedController::value_type(sModuleId,xNumberedControllers)); + } + else + xNumberedControllers = aFind->second; + + return xNumberedControllers; +} + +// css.frame.XTitle +::rtl::OUString SAL_CALL ODatabaseDocument::getTitle() + throw (uno::RuntimeException) +{ + // SYNCHRONIZED -> + DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit ); + return impl_getTitleHelper_throw()->getTitle(); +} + +// css.frame.XTitle +void SAL_CALL ODatabaseDocument::setTitle( const ::rtl::OUString& sTitle ) + throw (uno::RuntimeException) +{ + // SYNCHRONIZED -> + DocumentGuard aGuard( *this ); + impl_getTitleHelper_throw()->setTitle( sTitle ); + m_aEventNotifier.notifyDocumentEventAsync( "OnTitleChanged" ); + // <- SYNCHRONIZED +} + +// css.frame.XTitleChangeBroadcaster +void SAL_CALL ODatabaseDocument::addTitleChangeListener( const uno::Reference< frame::XTitleChangeListener >& xListener ) + throw (uno::RuntimeException) +{ + // SYNCHRONIZED -> + DocumentGuard aGuard( *this ); + + uno::Reference< frame::XTitleChangeBroadcaster > xBroadcaster( impl_getTitleHelper_throw(), uno::UNO_QUERY_THROW ); + xBroadcaster->addTitleChangeListener( xListener ); +} + +// css.frame.XTitleChangeBroadcaster +void SAL_CALL ODatabaseDocument::removeTitleChangeListener( const uno::Reference< frame::XTitleChangeListener >& xListener ) + throw (uno::RuntimeException) +{ + // SYNCHRONIZED -> + DocumentGuard aGuard( *this ); + + uno::Reference< frame::XTitleChangeBroadcaster > xBroadcaster( impl_getTitleHelper_throw(), uno::UNO_QUERY_THROW ); + xBroadcaster->removeTitleChangeListener( xListener ); +} + +// css.frame.XUntitledNumbers +::sal_Int32 SAL_CALL ODatabaseDocument::leaseNumber( const uno::Reference< uno::XInterface >& xComponent ) + throw (lang::IllegalArgumentException, + uno::RuntimeException ) +{ + DocumentGuard aGuard( *this ); + return impl_getUntitledHelper_throw(xComponent)->leaseNumber (xComponent); +} + +// css.frame.XUntitledNumbers +void SAL_CALL ODatabaseDocument::releaseNumber( ::sal_Int32 nNumber ) + throw (lang::IllegalArgumentException, + uno::RuntimeException ) +{ + DocumentGuard aGuard( *this ); + impl_getUntitledHelper_throw()->releaseNumber (nNumber); +} + +// css.frame.XUntitledNumbers +void SAL_CALL ODatabaseDocument::releaseNumberForComponent( const uno::Reference< uno::XInterface >& xComponent ) + throw (lang::IllegalArgumentException, + uno::RuntimeException ) +{ + DocumentGuard aGuard( *this ); + impl_getUntitledHelper_throw(xComponent)->releaseNumberForComponent (xComponent); +} + +// css.frame.XUntitledNumbers +::rtl::OUString SAL_CALL ODatabaseDocument::getUntitledPrefix() throw (uno::RuntimeException) +{ + return ::rtl::OUString();/*RTL_CONSTASCII_USTRINGPARAM(" : "));*/ +} + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/databasedocument.hxx b/dbaccess/source/core/dataaccess/databasedocument.hxx new file mode 100644 index 000000000000..9659c033260c --- /dev/null +++ b/dbaccess/source/core/dataaccess/databasedocument.hxx @@ -0,0 +1,709 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 _DBA_COREDATAACCESS_DATABASEDOCUMENT_HXX_ +#define _DBA_COREDATAACCESS_DATABASEDOCUMENT_HXX_ + +#include "ModelImpl.hxx" +#include "documenteventnotifier.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp> +#include <com/sun/star/frame/XModel2.hpp> +#include <com/sun/star/frame/XTitle.hpp> +#include <com/sun/star/frame/XTitleChangeBroadcaster.hpp> +#include <com/sun/star/frame/XUntitledNumbers.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/sdb/XReportDocumentsSupplier.hpp> +#include <com/sun/star/sdb/XFormDocumentsSupplier.hpp> +#include <com/sun/star/util/XCloseable.hpp> +#include <com/sun/star/view/XPrintable.hpp> +#include <com/sun/star/frame/XModuleManager.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp> +#include <com/sun/star/embed/XTransactionListener.hpp> +#include <com/sun/star/document/XStorageBasedDocument.hpp> +#include <com/sun/star/document/XEmbeddedScripts.hpp> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/document/XScriptInvocationContext.hpp> +#include <com/sun/star/script/XStorageBasedLibraryContainer.hpp> +#include <com/sun/star/script/provider/XScriptProviderSupplier.hpp> +#include <com/sun/star/frame/XLoadable.hpp> +#include <com/sun/star/document/XEventBroadcaster.hpp> +#include <com/sun/star/document/XDocumentEventBroadcaster.hpp> +#include <com/sun/star/document/XDocumentRecovery.hpp> +/** === end UNO includes === **/ + +#if ! defined(INCLUDED_COMPHELPER_IMPLBASE_VAR_HXX_17) +#define INCLUDED_COMPHELPER_IMPLBASE_VAR_HXX_17 +#define COMPHELPER_IMPLBASE_INTERFACE_NUMBER 17 +#include <comphelper/implbase_var.hxx> +#endif + +#include <cppuhelper/compbase10.hxx> +#include <cppuhelper/implbase3.hxx> +#include <rtl/ref.hxx> + +#include <boost/shared_ptr.hpp> +#include <boost/noncopyable.hpp> + +namespace comphelper { + class NamedValueCollection; +} + +//........................................................................ +namespace dbaccess +{ +//........................................................................ + +class DocumentEvents; +class DocumentEventExecutor; +class DocumentGuard; + +typedef ::std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController > > Controllers; + +//============================================================ +//= ViewMonitor +//============================================================ +/** helper class monitoring the views of a document, and firing appropriate events + when views are attached / detached +*/ +class ViewMonitor : public boost::noncopyable +{ +public: + ViewMonitor( DocumentEventNotifier& _rEventNotifier ) + :m_rEventNotifier( _rEventNotifier ) + ,m_bIsNewDocument( true ) + ,m_bEverHadController( false ) + ,m_bLastIsFirstEverController( false ) + ,m_xLastConnectedController() + { + } + + void reset() + { + m_bEverHadController = false; + m_bLastIsFirstEverController = false; + m_xLastConnectedController.clear(); + } + + /** to be called when a view (aka controller) has been connected to the document + @return + <TRUE/> if and only if this was the first-ever controller connected to the document + */ + bool onControllerConnected( + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController >& _rxController + ); + + /** to be called when a controller is set as current controller + @return <TRUE/> + if and only if the controller connection indicates that loading the document is finished. This + is the case if the given controller has previously been connected, and it was the first controller + ever for which this happened. + */ + bool onSetCurrentController( + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController >& _rxController + ); + + void onLoadedDocument() { m_bIsNewDocument = false; } + +private: + DocumentEventNotifier& m_rEventNotifier; + bool m_bIsNewDocument; + bool m_bEverHadController; + bool m_bLastIsFirstEverController; + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController > + m_xLastConnectedController; +}; + +//============================================================ +//= ODatabaseDocument +//============================================================ +typedef ::comphelper::WeakComponentImplHelper17 < ::com::sun::star::frame::XModel2 + , ::com::sun::star::util::XModifiable + , ::com::sun::star::frame::XStorable + , ::com::sun::star::document::XEventBroadcaster + , ::com::sun::star::document::XDocumentEventBroadcaster + , ::com::sun::star::view::XPrintable + , ::com::sun::star::util::XCloseable + , ::com::sun::star::lang::XServiceInfo + , ::com::sun::star::sdb::XOfficeDatabaseDocument + , ::com::sun::star::ui::XUIConfigurationManagerSupplier + , ::com::sun::star::document::XStorageBasedDocument + , ::com::sun::star::document::XEmbeddedScripts + , ::com::sun::star::document::XScriptInvocationContext + , ::com::sun::star::script::provider::XScriptProviderSupplier + , ::com::sun::star::document::XEventsSupplier + , ::com::sun::star::frame::XLoadable + , ::com::sun::star::document::XDocumentRecovery + > ODatabaseDocument_OfficeDocument; + +typedef ::cppu::ImplHelper3< ::com::sun::star::frame::XTitle + , ::com::sun::star::frame::XTitleChangeBroadcaster + , ::com::sun::star::frame::XUntitledNumbers + > ODatabaseDocument_Title; + +class ODatabaseDocument :public ModelDependentComponent // ModelDependentComponent must be first! + ,public ODatabaseDocument_OfficeDocument + ,public ODatabaseDocument_Title +{ + enum InitState + { + NotInitialized, + Initializing, + Initialized + }; + + DECLARE_STL_USTRINGACCESS_MAP(::com::sun::star::uno::Reference< ::com::sun::star::frame::XUntitledNumbers >,TNumberedController); + ::com::sun::star::uno::Reference< ::com::sun::star::ui::XUIConfigurationManager> m_xUIConfigurationManager; + + ::cppu::OInterfaceContainerHelper m_aModifyListeners; + ::cppu::OInterfaceContainerHelper m_aCloseListener; + ::cppu::OInterfaceContainerHelper m_aStorageListeners; + + DocumentEvents* m_pEventContainer; + ::rtl::Reference< DocumentEventExecutor > m_pEventExecutor; + DocumentEventNotifier m_aEventNotifier; + + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController > m_xCurrentController; + Controllers m_aControllers; + ViewMonitor m_aViewMonitor; + + ::com::sun::star::uno::WeakReference< ::com::sun::star::container::XNameAccess > m_xForms; + ::com::sun::star::uno::WeakReference< ::com::sun::star::container::XNameAccess > m_xReports; + ::com::sun::star::uno::WeakReference< ::com::sun::star::script::provider::XScriptProvider > m_xScriptProvider; + + /** @short such module manager is used to classify new opened documents. */ + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModuleManager > m_xModuleManager; + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XTitle > m_xTitleHelper; + TNumberedController m_aNumberedControllers; + + /** true if and only if the DatabaseDocument's "initNew" or "load" have been called (or, well, + the document has be initialized implicitly - see storeAsURL + */ + InitState m_eInitState; + bool m_bClosing; + bool m_bAllowDocumentScripting; + bool m_bHasBeenRecovered; + + enum StoreType { SAVE, SAVE_AS }; + /** stores the document to the given URL, rebases it to the respective new storage, if necessary, resets + the modified flag, and notifies any listeners as required + + @param _rURL + the URL to store the document to + @param _rArguments + arguments for storing the document (MediaDescriptor) + @param _eType + the type of the store process (Save or SaveAs). The method will automatically + notify the proper events for this type. + @param _rGuard + the instance lock to be released before doing synchronous notifications + */ + void impl_storeAs_throw( + const ::rtl::OUString& _rURL, + const ::comphelper::NamedValueCollection& _rArguments, + const StoreType _eType, + DocumentGuard& _rGuard + ) + throw ( ::com::sun::star::io::IOException + , ::com::sun::star::uno::RuntimeException ); + + /** notifies our storage change listeners that our underlying storage changed + + @param _rxNewRootStorage + the new root storage to be notified. If <NULL/>, it is assumed that no storage change actually + happened, and the listeners are not notified. + */ + void impl_notifyStorageChange_nolck_nothrow( + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& _rxNewRootStorage + ); + + /// write a single XML stream into the package + void WriteThroughComponent( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > & xComponent, /// the component we export + const sal_Char* pStreamName, /// the stream name + const sal_Char* pServiceName, /// service name of the component + const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any> & rArguments, /// the argument (XInitialization) + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue> & rMediaDesc,/// output descriptor + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& _xStorageToSaveTo + ) const; + + + /// write a single output stream + /// (to be called either directly or by WriteThroughComponent(...)) + void WriteThroughComponent( + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream >& xOutputStream, + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& xComponent, + const sal_Char* pServiceName, + const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& rArguments, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue> & rMediaDesc + ) const; + + /** writes the content and settings + @param sURL + The URL + @param lArguments + The media descriptor + @param _xStorageToSaveTo + The storage which should be used for saving + */ + void impl_writeStorage_throw( + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& _rxTargetStorage, + const ::comphelper::NamedValueCollection& _rMediaDescriptor + ) const; + + // ModelDependentComponent overridables + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > getThis() const; + + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XTitle > impl_getTitleHelper_throw(); + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XUntitledNumbers > impl_getUntitledHelper_throw( + const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _xComponent = ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >()); + +private: + ODatabaseDocument(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl); + // Do NOT create those documents directly, always use ODatabaseModelImpl::getModel. Reason is that + // ODatabaseDocument requires clear ownership, and in turn lifetime synchronisation with the ModelImpl. + // If you create a ODatabaseDocument directly, you might easily create a leak. + // #i50905# / 2005-06-20 / frank.schonheit@sun.com + +protected: + virtual void SAL_CALL disposing(); + + virtual ~ODatabaseDocument(); + +public: + struct FactoryAccess { friend class ODatabaseModelImpl; private: FactoryAccess() { } }; + static ODatabaseDocument* createDatabaseDocument( const ::rtl::Reference<ODatabaseModelImpl>& _pImpl, FactoryAccess /*accessControl*/ ) + { + return new ODatabaseDocument( _pImpl ); + } + + // 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); + + // ::com::sun::star::lang::XServiceInfo - static methods + 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 >&); + + // XInterface + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface(const ::com::sun::star::uno::Type& _rType) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL acquire( ) throw (); + virtual void SAL_CALL release( ) throw (); + + // XTypeProvider + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) throw (::com::sun::star::uno::RuntimeException); + + // XEventListener + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw(::com::sun::star::uno::RuntimeException); + + // 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); + + // XModel + virtual sal_Bool SAL_CALL attachResource( const ::rtl::OUString& URL, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& Arguments ) throw (::com::sun::star::uno::RuntimeException) ; + virtual ::rtl::OUString SAL_CALL getURL( ) throw (::com::sun::star::uno::RuntimeException) ; + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getArgs( ) throw (::com::sun::star::uno::RuntimeException) ; + virtual void SAL_CALL connectController( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController >& Controller ) throw (::com::sun::star::uno::RuntimeException) ; + virtual void SAL_CALL disconnectController( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController >& Controller ) throw (::com::sun::star::uno::RuntimeException) ; + virtual void SAL_CALL lockControllers( ) throw (::com::sun::star::uno::RuntimeException) ; + virtual void SAL_CALL unlockControllers( ) throw (::com::sun::star::uno::RuntimeException) ; + virtual sal_Bool SAL_CALL hasControllersLocked( ) throw (::com::sun::star::uno::RuntimeException) ; + virtual ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController > SAL_CALL getCurrentController( ) throw (::com::sun::star::uno::RuntimeException) ; + virtual void SAL_CALL setCurrentController( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController >& Controller ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException) ; + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL getCurrentSelection( ) throw (::com::sun::star::uno::RuntimeException) ; + + // XModel2 + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL getControllers( ) throw (::com::sun::star::uno::RuntimeException) ; + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getAvailableViewControllerNames( ) throw (::com::sun::star::uno::RuntimeException) ; + virtual ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController2 > SAL_CALL createDefaultViewController( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& Frame ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException) ; + virtual ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController2 > SAL_CALL createViewController( const ::rtl::OUString& ViewName, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& Arguments, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& Frame ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException) ; + + // XStorable + virtual sal_Bool SAL_CALL hasLocation( ) throw (::com::sun::star::uno::RuntimeException) ; + virtual ::rtl::OUString SAL_CALL getLocation( ) throw (::com::sun::star::uno::RuntimeException) ; + virtual sal_Bool SAL_CALL isReadonly( ) throw (::com::sun::star::uno::RuntimeException) ; + virtual void SAL_CALL store( ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) ; + virtual void SAL_CALL storeAsURL( const ::rtl::OUString& sURL, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& lArguments ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) ; + virtual void SAL_CALL storeToURL( const ::rtl::OUString& sURL, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& lArguments ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) ; + + // XModifyBroadcaster + virtual void SAL_CALL addModifyListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyListener >& aListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeModifyListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyListener >& aListener ) throw (::com::sun::star::uno::RuntimeException); + + // ::com::sun::star::util::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) ; + + // XEventBroadcaster + virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::document::XEventListener >& aListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::document::XEventListener >& aListener ) throw (::com::sun::star::uno::RuntimeException); + + // XDocumentEventBroadcaster + virtual void SAL_CALL addDocumentEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::document::XDocumentEventListener >& _Listener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeDocumentEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::document::XDocumentEventListener >& _Listener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL notifyDocumentEvent( const ::rtl::OUString& _EventName, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController2 >& _ViewController, const ::com::sun::star::uno::Any& _Supplement ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + + // XPrintable + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getPrinter( ) throw (::com::sun::star::uno::RuntimeException) ; + virtual void SAL_CALL setPrinter( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aPrinter ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) ; + virtual void SAL_CALL print( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& xOptions ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) ; + + // XFormDocumentsSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getFormDocuments( ) throw (::com::sun::star::uno::RuntimeException); + + // XReportDocumentsSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getReportDocuments( ) throw (::com::sun::star::uno::RuntimeException); + + // XCloseable + virtual void SAL_CALL close( sal_Bool DeliverOwnership ) throw (::com::sun::star::util::CloseVetoException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addCloseListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloseListener >& Listener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeCloseListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloseListener >& Listener ) throw (::com::sun::star::uno::RuntimeException); + + // XUIConfigurationManagerSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::ui::XUIConfigurationManager > SAL_CALL getUIConfigurationManager( ) throw (::com::sun::star::uno::RuntimeException); + + // XDocumentSubStorageSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > SAL_CALL getDocumentSubStorage( const ::rtl::OUString& aStorageName, sal_Int32 nMode ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getDocumentSubStoragesNames( ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + // XOfficeDatabaseDocument + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XDataSource > SAL_CALL getDataSource() throw (::com::sun::star::uno::RuntimeException); + + // XStorageBasedDocument + virtual void SAL_CALL loadFromStorage( const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xStorage, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aMediaDescriptor ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::frame::DoubleInitializationException, ::com::sun::star::io::IOException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL storeToStorage( const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xStorage, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aMediaDescriptor ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL switchToStorage( const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xStorage ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > SAL_CALL getDocumentStorage( ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addStorageChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::document::XStorageChangeListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeStorageChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::document::XStorageChangeListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + + // XEmbeddedScripts + virtual ::com::sun::star::uno::Reference< ::com::sun::star::script::XStorageBasedLibraryContainer > SAL_CALL getBasicLibraries() throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::script::XStorageBasedLibraryContainer > SAL_CALL getDialogLibraries() throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL getAllowMacroExecution() throw (::com::sun::star::uno::RuntimeException); + + // XScriptInvocationContext + virtual ::com::sun::star::uno::Reference< ::com::sun::star::document::XEmbeddedScripts > SAL_CALL getScriptContainer() throw (::com::sun::star::uno::RuntimeException); + + // XScriptProviderSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::script::provider::XScriptProvider > SAL_CALL getScriptProvider( ) throw (::com::sun::star::uno::RuntimeException); + + // XEventsSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameReplace > SAL_CALL getEvents( ) throw (::com::sun::star::uno::RuntimeException); + + // XLoadable + virtual void SAL_CALL initNew( ) throw (::com::sun::star::frame::DoubleInitializationException, ::com::sun::star::io::IOException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL load( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& lArguments ) throw (::com::sun::star::frame::DoubleInitializationException, ::com::sun::star::io::IOException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + + // css.document.XDocumentRecovery + virtual ::sal_Bool SAL_CALL wasModifiedSinceLastSave() throw ( ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL storeToRecoveryFile( const ::rtl::OUString& i_TargetLocation, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& i_MediaDescriptor ) throw ( ::com::sun::star::uno::RuntimeException, ::com::sun::star::io::IOException, ::com::sun::star::lang::WrappedTargetException ); + virtual void SAL_CALL recoverFromFile( const ::rtl::OUString& i_SourceLocation, const ::rtl::OUString& i_SalvagedFile, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& i_MediaDescriptor ) throw ( ::com::sun::star::uno::RuntimeException, ::com::sun::star::io::IOException, ::com::sun::star::lang::WrappedTargetException ); + + // XTitle + virtual ::rtl::OUString SAL_CALL getTitle( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setTitle( const ::rtl::OUString& sTitle ) throw (::com::sun::star::uno::RuntimeException); + + // XTitleChangeBroadcaster + virtual void SAL_CALL addTitleChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XTitleChangeListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeTitleChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XTitleChangeListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + + // XUntitledNumbers + virtual ::sal_Int32 SAL_CALL leaseNumber( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& xComponent ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL releaseNumber( ::sal_Int32 nNumber ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL releaseNumberForComponent( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& xComponent ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getUntitledPrefix( ) throw (::com::sun::star::uno::RuntimeException); + + /** clears the given object container + + Clearing is done via disposal - the method calls XComponent::dispose at the given object, + which must be one of our impl's or our object containers (m_xForms, m_xReports, + m_xTableDefinitions, m_xCommandDefinitions) + + @param _rxContainer + the container to clear + */ + static void clearObjectContainer( + ::com::sun::star::uno::WeakReference< ::com::sun::star::container::XNameAccess >& _rxContainer); + + /** checks whether the component is already initialized, throws a NotInitializedException if not + */ + inline void checkInitialized() const + { + if ( !impl_isInitialized() ) + throw ::com::sun::star::lang::NotInitializedException( ::rtl::OUString(), getThis() ); + } + + /** checks the document is currently in the initialization phase, or already initialized. + Throws NotInitializedException if not so. + */ + inline void checkNotUninitilized() const + { + if ( impl_isInitialized() || impl_isInitializing() ) + // fine + return; + + throw ::com::sun::star::lang::NotInitializedException( ::rtl::OUString(), getThis() ); + } + + /** checks whether the document is currently being initialized, or already initialized, + throws a DoubleInitializationException if so + */ + inline void checkNotInitialized() const + { + if ( impl_isInitializing() || impl_isInitialized() ) + throw ::com::sun::star::frame::DoubleInitializationException( ::rtl::OUString(), getThis() ); + } + +private: + /** returns whether the model is currently being initialized + */ + bool impl_isInitializing() const { return m_eInitState == Initializing; } + + /** returns whether the model is already initialized, i.e. the XModel's "initNew" or "load" methods have been called + */ + bool impl_isInitialized() const { return m_eInitState == Initialized; } + + /// tells the model it is being initialized now + void impl_setInitializing() { m_eInitState = Initializing; } + + /// tells the model its initialization is done + void impl_setInitialized(); + + /** closes the frames of all connected controllers + + @param _bDeliverOwnership + determines if the ownership should be transfered to the component which + possibly vetos the closing + + @raises ::com::sun::star::util::CloseVetoException + if the closing was vetoed by any instance + */ + void impl_closeControllerFrames_nolck_throw( sal_Bool _bDeliverOwnership ); + + /** disposes the frames of all controllers which are still left in m_aControllers. + */ + void impl_disposeControllerFrames_nothrow(); + + /** does a reparenting at the given object container to ourself + + Calls XChild::setParent at the given object, which must be one of our impl's or our + object containers (m_xForms, m_xReports, m_xTableDefinitions, m_xCommandDefinitions) + */ + void impl_reparent_nothrow( const ::com::sun::star::uno::WeakReference< ::com::sun::star::container::XNameAccess >& _rxContainer ); + + /** retrieves the forms or reports contained, creates and initializes it, if necessary + + @raises DisposedException + if the instance is already disposed + @raises IllegalArgumentException + if <arg>_eType</arg> is not ODatabaseModelImpl::E_FORM and not ODatabaseModelImpl::E_REPORT + */ + ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > + impl_getDocumentContainer_throw( ODatabaseModelImpl::ObjectType _eType ); + + /** resets everything + + @precond + m_pImpl is not <NULLL/> + */ + void + impl_reset_nothrow(); + + /** imports the document from the given resource. + */ + static void + impl_import_nolck_throw( + const ::comphelper::ComponentContext _rContext, + const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxTargetComponent, + const ::comphelper::NamedValueCollection& _rResource + ); + + /** creates a storage for the given URL, truncating it if a file with this name already exists + + @throws Exception + if creating the storage failed + + @return + the newly created storage for the file at the given URL + */ + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > + impl_createStorageFor_throw( + const ::rtl::OUString& _rURL + ) const; + + /** sets our "modified" flag + + will notify all our respective listeners, if the "modified" state actually changed + + @param _bModified + the (new) flag indicating whether the document is currently modified or not + @param _rGuard + the guard for our instance. At method entry, the guard must hold the lock. At the moment + of method leave, the lock will be released. + @precond + our mutex is locked + @postcond + our mutex is not locked + */ + void impl_setModified_nothrow( sal_Bool _bModified, DocumentGuard& _rGuard ); + + /** stores the document to the given storage + + Note that the document is actually not rebased to this storage, it just stores a copy of itself + to the given target storage. + + @param _rxTargetStorage + denotes the storage to store the document into + @param _rMediaDescriptor + contains additional parameters for storing the document + @param _rDocGuard + a guard which holds the (only) lock to the document, and which will be temporarily + released where necessary (e.g. for notifications, or calling into other components) + + @throws ::com::sun::star::uno::IllegalArgumentException + if the given storage is <NULL/>. + + @throws ::com::sun::star::uno::RuntimeException + when any of the used operations throws it + + @throws ::com::sun::star::io::IOException + when any of the used operations throws it, or any other exception occurs which is no + RuntimeException and no IOException + */ + void impl_storeToStorage_throw( + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& _rxTargetStorage, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& _rMediaDescriptor, + DocumentGuard& _rDocGuard + ) const; + + + /** impl-version of attachResource + + @param i_rLogicalDocumentURL + denotes the logical URL of the document, to be reported by getURL/getLocation + @param i_rMediaDescriptor + denotes additional document parameters + @param _rDocGuard + is the guard which currently protects the document instance + */ + sal_Bool impl_attachResource( + const ::rtl::OUString& i_rLogicalDocumentURL, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& i_rMediaDescriptor, + DocumentGuard& _rDocGuard + ); + + /** throws an IOException with the message as defined in the RID_STR_ERROR_WHILE_SAVING resource, wrapping + the given caught non-IOException error + */ + void impl_throwIOExceptionCausedBySave_throw( + const ::com::sun::star::uno::Any& i_rError, + const ::rtl::OUString& i_rTargetURL + ) const; +}; + +/** an extended version of the ModelMethodGuard, which also cares for the initialization state + of the document +*/ +class DocumentGuard : private ModelMethodGuard +{ +public: + enum MethodType + { + // a method which is to initialize the document + InitMethod, + // a default method + DefaultMethod, + // a method which is used (externally) during the initialization phase + MethodUsedDuringInit, + // a method which does not need initialization - use with care! + MethodWithoutInit + }; + + /** constructs the guard + + @param _document + the ODatabaseDocument instance + + @throws ::com::sun::star::lang::DisposedException + If the given component is already disposed + + @throws ::com::sun::star::frame::DoubleInitializationException + if _eType is InitMethod, and the given component is already initialized, or currently being initialized. + + @throws ::com::sun::star::lang::NotInitializedException + if _eType is DefaultMethod, and the given component is not yet initialized; or if _eType + is MethodUsedDuringInit, and the component is still uninitialized, and not in the initialization + phase currently. + */ + DocumentGuard( const ODatabaseDocument& _document, MethodType _eType = DefaultMethod ) + :ModelMethodGuard( _document ) + ,m_document( _document ) + { + switch ( _eType ) + { + case InitMethod: m_document.checkNotInitialized(); break; + case DefaultMethod: m_document.checkInitialized(); break; + case MethodUsedDuringInit: m_document.checkNotUninitilized(); break; + case MethodWithoutInit: break; + } + } + + ~DocumentGuard() + { + } + + void clear() + { + ModelMethodGuard::clear(); + } + void reset() + { + ModelMethodGuard::reset(); + m_document.checkDisposed(); + } + +private: + + const ODatabaseDocument& m_document; +}; + +} // namespace dbaccess +#endif // _DBA_COREDATAACCESS_DATABASEDOCUMENT_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/databaseregistrations.cxx b/dbaccess/source/core/dataaccess/databaseregistrations.cxx new file mode 100644 index 000000000000..83b6d482b769 --- /dev/null +++ b/dbaccess/source/core/dataaccess/databaseregistrations.cxx @@ -0,0 +1,377 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * 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_dbaccess.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/sdb/XDatabaseRegistrations.hpp> +/** === end UNO includes === **/ + +#include <comphelper/componentcontext.hxx> +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/interfacecontainer.hxx> +#include <cppuhelper/implbase1.hxx> +#include <rtl/ustrbuf.hxx> +#include <unotools/pathoptions.hxx> +#include <tools/urlobj.hxx> +#include <unotools/confignode.hxx> + +namespace dbaccess +{ + /** === 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::NoSuchElementException; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::lang::IllegalAccessException; + using ::com::sun::star::container::ElementExistException; + using ::com::sun::star::sdb::XDatabaseRegistrations; + using ::com::sun::star::sdb::XDatabaseRegistrationsListener; + using ::com::sun::star::sdb::DatabaseRegistrationEvent; + using ::com::sun::star::uno::XAggregation; + /** === end UNO using === **/ + + static const ::rtl::OUString& getConfigurationRootPath() + { + static ::rtl::OUString s_sNodeName = ::rtl::OUString::createFromAscii("org.openoffice.Office.DataAccess/RegisteredNames"); + return s_sNodeName; + } + + const ::rtl::OUString& getLocationNodeName() + { + static ::rtl::OUString s_sNodeName = ::rtl::OUString::createFromAscii( "Location" ); + return s_sNodeName; + } + + const ::rtl::OUString& getNameNodeName() + { + static ::rtl::OUString s_sNodeName = ::rtl::OUString::createFromAscii( "Name" ); + return s_sNodeName; + } + + //==================================================================== + //= DatabaseRegistrations - declaration + //==================================================================== + typedef ::cppu::WeakAggImplHelper1 < XDatabaseRegistrations + > DatabaseRegistrations_Base; + class DatabaseRegistrations :public ::cppu::BaseMutex + ,public DatabaseRegistrations_Base + { + public: + DatabaseRegistrations( const ::comphelper::ComponentContext& _rxContext ); + + protected: + ~DatabaseRegistrations(); + + public: + virtual ::sal_Bool SAL_CALL hasRegisteredDatabase( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, RuntimeException); + virtual Sequence< ::rtl::OUString > SAL_CALL getRegistrationNames() throw (RuntimeException); + virtual ::rtl::OUString SAL_CALL getDatabaseLocation( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException); + virtual void SAL_CALL registerDatabaseLocation( const ::rtl::OUString& _Name, const ::rtl::OUString& _Location ) throw (IllegalArgumentException, ElementExistException, RuntimeException); + virtual void SAL_CALL revokeDatabaseLocation( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException); + virtual void SAL_CALL changeDatabaseLocation( const ::rtl::OUString& Name, const ::rtl::OUString& NewLocation ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException); + virtual ::sal_Bool SAL_CALL isDatabaseRegistrationReadOnly( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException); + virtual void SAL_CALL addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener ) throw (RuntimeException); + virtual void SAL_CALL removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener ) throw (RuntimeException); + + private: + ::utl::OConfigurationNode + impl_checkValidName_throw( const ::rtl::OUString& _rName, const bool _bMustExist ); + + void impl_checkValidLocation_throw( const ::rtl::OUString& _rLocation ); + + /** retrieves the configuration node whose "Name" sub node has the given value + + Since we separated the name of the registration node from the "Name" value of the registration, we cannot + simply do a "getByName" (equivalent) when we want to retrieve the node for a given registration name. + Instead, we must search all nodes. + + If _bMustExist is <TRUE/>, and a node with the given display name does not exist, then a NoSuchElementException + is thrown. + + If _bMustExist is <FALSE/>, and a node with the given name already exists, then a ElementExistException is + thrown. + + In either case, if no exception is thrown, then a valid node is returned: If the node existed and was allowed + to exist, it is returned, if the node did not yet exist, and was required to not exist, a new node is created. + However, in this case the root node is not yet committed. + */ + ::utl::OConfigurationNode + impl_getNodeForName_throw( const ::rtl::OUString& _rName, const bool _bMustExist ); + + ::utl::OConfigurationNode + impl_getNodeForName_nothrow( const ::rtl::OUString& _rName ); + + private: + ::comphelper::ComponentContext m_aContext; + ::utl::OConfigurationTreeRoot m_aConfigurationRoot; + ::cppu::OInterfaceContainerHelper m_aRegistrationListeners; + }; + + //==================================================================== + //= DatabaseRegistrations - implementation + //==================================================================== + DatabaseRegistrations::DatabaseRegistrations( const ::comphelper::ComponentContext& _rxContext ) + :m_aContext( _rxContext ) + ,m_aConfigurationRoot() + ,m_aRegistrationListeners( m_aMutex ) + { + m_aConfigurationRoot = ::utl::OConfigurationTreeRoot::createWithServiceFactory( + m_aContext.getLegacyServiceFactory(), getConfigurationRootPath(), -1, ::utl::OConfigurationTreeRoot::CM_UPDATABLE ); + } + + DatabaseRegistrations::~DatabaseRegistrations() + { + } + + ::utl::OConfigurationNode DatabaseRegistrations::impl_getNodeForName_nothrow( const ::rtl::OUString& _rName ) + { + Sequence< ::rtl::OUString > aNames( m_aConfigurationRoot.getNodeNames() ); + for ( const ::rtl::OUString* pName = aNames.getConstArray(); + pName != aNames.getConstArray() + aNames.getLength(); + ++pName + ) + { + ::utl::OConfigurationNode aNodeForName = m_aConfigurationRoot.openNode( *pName ); + + ::rtl::OUString sTestName; + OSL_VERIFY( aNodeForName.getNodeValue( getNameNodeName() ) >>= sTestName ); + if ( sTestName == _rName ) + return aNodeForName; + } + return ::utl::OConfigurationNode(); + } + + ::utl::OConfigurationNode DatabaseRegistrations::impl_getNodeForName_throw( const ::rtl::OUString& _rName, const bool _bMustExist ) + { + ::utl::OConfigurationNode aNodeForName( impl_getNodeForName_nothrow( _rName ) ); + + if ( aNodeForName.isValid() ) + { + if ( !_bMustExist ) + throw ElementExistException( _rName, *this ); + + return aNodeForName; + } + + if ( _bMustExist ) + throw NoSuchElementException( _rName, *this ); + + ::rtl::OUString sNewNodeName; + { + ::rtl::OUStringBuffer aNewNodeName; + aNewNodeName.appendAscii( "org.openoffice." ); + aNewNodeName.append( _rName ); + + // make unique + ::rtl::OUStringBuffer aReset( aNewNodeName ); + sNewNodeName = aNewNodeName.makeStringAndClear(); + sal_Int32 i=2; + while ( m_aConfigurationRoot.hasByName( sNewNodeName ) ) + { + aNewNodeName = aReset; + aNewNodeName.appendAscii( " " ); + aNewNodeName.append( i ); + sNewNodeName = aNewNodeName.makeStringAndClear(); + } + } + + ::utl::OConfigurationNode aNewNode( m_aConfigurationRoot.createNode( sNewNodeName ) ); + aNewNode.setNodeValue( getNameNodeName(), makeAny( _rName ) ); + return aNewNode; + } + + ::utl::OConfigurationNode DatabaseRegistrations::impl_checkValidName_throw( const ::rtl::OUString& _rName, const bool _bMustExist ) + { + if ( !m_aConfigurationRoot.isValid() ) + throw RuntimeException( ::rtl::OUString(), *this ); + + if ( !_rName.getLength() ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); + + return impl_getNodeForName_throw( _rName, _bMustExist ); + } + + void DatabaseRegistrations::impl_checkValidLocation_throw( const ::rtl::OUString& _rLocation ) + { + if ( !_rLocation.getLength() ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 2 ); + + INetURLObject aURL( _rLocation ); + if ( aURL.GetProtocol() == INET_PROT_NOT_VALID ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 2 ); + } + + ::sal_Bool SAL_CALL DatabaseRegistrations::hasRegisteredDatabase( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + ::utl::OConfigurationNode aNodeForName = impl_getNodeForName_nothrow( _Name ); + return aNodeForName.isValid(); + } + + Sequence< ::rtl::OUString > SAL_CALL DatabaseRegistrations::getRegistrationNames() throw (RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_aConfigurationRoot.isValid() ) + throw RuntimeException( ::rtl::OUString(), *this ); + + Sequence< ::rtl::OUString > aProgrammaticNames( m_aConfigurationRoot.getNodeNames() ); + Sequence< ::rtl::OUString > aDisplayNames( aProgrammaticNames.getLength() ); + ::rtl::OUString* pDisplayName = aDisplayNames.getArray(); + + for ( const ::rtl::OUString* pName = aProgrammaticNames.getConstArray(); + pName != aProgrammaticNames.getConstArray() + aProgrammaticNames.getLength(); + ++pName, ++pDisplayName + ) + { + ::utl::OConfigurationNode aRegistrationNode = m_aConfigurationRoot.openNode( *pName ); + OSL_VERIFY( aRegistrationNode.getNodeValue( getNameNodeName() ) >>= *pDisplayName ); + } + + return aDisplayNames; + } + + ::rtl::OUString SAL_CALL DatabaseRegistrations::getDatabaseLocation( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + ::utl::OConfigurationNode aNodeForName = impl_checkValidName_throw( _Name, true ); + + ::rtl::OUString sLocation; + OSL_VERIFY( aNodeForName.getNodeValue( getLocationNodeName() ) >>= sLocation ); + sLocation = SvtPathOptions().SubstituteVariable( sLocation ); + + return sLocation; + } + + void SAL_CALL DatabaseRegistrations::registerDatabaseLocation( const ::rtl::OUString& _Name, const ::rtl::OUString& _Location ) throw (IllegalArgumentException, ElementExistException, RuntimeException) + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + + // check + impl_checkValidLocation_throw( _Location ); + ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw( _Name, false ); + + // register + aDataSourceRegistration.setNodeValue( getLocationNodeName(), makeAny( _Location ) ); + m_aConfigurationRoot.commit(); + + // notify + DatabaseRegistrationEvent aEvent( *this, _Name, ::rtl::OUString(), _Location ); + aGuard.clear(); + m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::registeredDatabaseLocation, aEvent ); + } + + void SAL_CALL DatabaseRegistrations::revokeDatabaseLocation( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException) + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + + // check + ::utl::OConfigurationNode aNodeForName = impl_checkValidName_throw( _Name, true ); + + // obtain properties for notification + ::rtl::OUString sLocation; + OSL_VERIFY( aNodeForName.getNodeValue( getLocationNodeName() ) >>= sLocation ); + + // revoke + if ( aNodeForName.isReadonly() + || !m_aConfigurationRoot.removeNode( aNodeForName.getLocalName() ) + ) + throw IllegalAccessException( ::rtl::OUString(), *this ); + + m_aConfigurationRoot.commit(); + + // notify + DatabaseRegistrationEvent aEvent( *this, _Name, sLocation, ::rtl::OUString() ); + aGuard.clear(); + m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::revokedDatabaseLocation, aEvent ); + } + + void SAL_CALL DatabaseRegistrations::changeDatabaseLocation( const ::rtl::OUString& _Name, const ::rtl::OUString& _NewLocation ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException) + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + + // check + impl_checkValidLocation_throw( _NewLocation ); + ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw( _Name, true ); + + if ( aDataSourceRegistration.isReadonly() ) + throw IllegalAccessException( ::rtl::OUString(), *this ); + + // obtain properties for notification + ::rtl::OUString sOldLocation; + OSL_VERIFY( aDataSourceRegistration.getNodeValue( getLocationNodeName() ) >>= sOldLocation ); + + // change + aDataSourceRegistration.setNodeValue( getLocationNodeName(), makeAny( _NewLocation ) ); + m_aConfigurationRoot.commit(); + + // notify + DatabaseRegistrationEvent aEvent( *this, _Name, sOldLocation, _NewLocation ); + aGuard.clear(); + m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::changedDatabaseLocation, aEvent ); + } + + ::sal_Bool SAL_CALL DatabaseRegistrations::isDatabaseRegistrationReadOnly( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw( _Name, true ); + return aDataSourceRegistration.isReadonly(); + } + + void SAL_CALL DatabaseRegistrations::addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& _Listener ) throw (RuntimeException) + { + if ( _Listener.is() ) + m_aRegistrationListeners.addInterface( _Listener ); + } + + void SAL_CALL DatabaseRegistrations::removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& _Listener ) throw (RuntimeException) + { + if ( _Listener.is() ) + m_aRegistrationListeners.removeInterface( _Listener ); + } + + //==================================================================== + //= DatabaseRegistrations - factory + //==================================================================== + Reference< XAggregation > createDataSourceRegistrations( const ::comphelper::ComponentContext& _rxContext ) + { + return new DatabaseRegistrations( _rxContext ); + } + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/databaseregistrations.hxx b/dbaccess/source/core/dataaccess/databaseregistrations.hxx new file mode 100644 index 000000000000..f3213dba6823 --- /dev/null +++ b/dbaccess/source/core/dataaccess/databaseregistrations.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * 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 OOO_DATASOURCEREGISTRATIONS_HXX +#define OOO_DATASOURCEREGISTRATIONS_HXX + +/** === begin UNO includes === **/ +#include <com/sun/star/uno/XAggregation.hpp> +/** === end UNO includes === **/ + +namespace comphelper +{ + class ComponentContext; +} + +namespace dbaccess +{ + + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XAggregation > + createDataSourceRegistrations( const ::comphelper::ComponentContext& _rxContext ); + +} // namespace dbaccess + +#endif // OOO_DATASOURCEREGISTRATIONS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/datasource.cxx b/dbaccess/source/core/dataaccess/datasource.cxx new file mode 100644 index 000000000000..4577ebb077e9 --- /dev/null +++ b/dbaccess/source/core/dataaccess/datasource.cxx @@ -0,0 +1,1418 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +#include "datasource.hxx" +#include "module_dba.hxx" +#include "userinformation.hxx" +#include "commandcontainer.hxx" +#include "dbastrings.hrc" +#include "core_resource.hxx" +#include "core_resource.hrc" +#include "connection.hxx" +#include "SharedConnection.hxx" +#include "databasedocument.hxx" +#include "OAuthenticationContinuation.hxx" + + +/** === begin UNO includes === **/ +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyState.hpp> +#include <com/sun/star/beans/XPropertyContainer.hpp> +#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp> +#include <com/sun/star/document/XEventBroadcaster.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/reflection/XProxyFactory.hpp> +#include <com/sun/star/sdbc/XDriverAccess.hpp> +#include <com/sun/star/sdbc/XDriverManager.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/ucb/AuthenticationRequest.hpp> +#include <com/sun/star/ucb/XInteractionSupplyAuthentication.hpp> +#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/view/XPrintable.hpp> +/** === end UNO includes === **/ + +#include <comphelper/extract.hxx> +#include <comphelper/guarding.hxx> +#include <comphelper/interaction.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/property.hxx> +#include <comphelper/seqstream.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/string.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <tools/urlobj.hxx> +#include <typelib/typedescription.hxx> +#include <unotools/confignode.hxx> +#include <unotools/sharedunocomponent.hxx> +#include <rtl/logfile.hxx> +#include <rtl/digest.h> +#include <algorithm> + +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::reflection; +using namespace ::cppu; +using namespace ::osl; +using namespace ::dbtools; +using namespace ::comphelper; +namespace css = ::com::sun::star; + +namespace dbaccess +{ + +//============================================================ +//= FlushNotificationAdapter +//============================================================ +typedef ::cppu::WeakImplHelper1< XFlushListener > FlushNotificationAdapter_Base; +/** helper class which implements a XFlushListener, and forwards all + notification events to another XFlushListener + + The speciality is that the foreign XFlushListener instance, to which + the notifications are forwarded, is held weak. + + Thus, the class can be used with XFlushable instance which hold + their listeners with a hard reference, if you simply do not *want* + to be held hard-ref-wise. +*/ +class FlushNotificationAdapter : public FlushNotificationAdapter_Base +{ +private: + WeakReference< XFlushable > m_aBroadcaster; + WeakReference< XFlushListener > m_aListener; + +public: + static void installAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener ) + { + Reference< XFlushListener > xAdapter( new FlushNotificationAdapter( _rxBroadcaster, _rxListener ) ); + } + +protected: + FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener ); + ~FlushNotificationAdapter(); + + void SAL_CALL impl_dispose( bool _bRevokeListener ); + +protected: + // XFlushListener + virtual void SAL_CALL flushed( const ::com::sun::star::lang::EventObject& rEvent ) throw (::com::sun::star::uno::RuntimeException); + // XEventListener + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); +}; + +//------------------------------------------------------------ +DBG_NAME( FlushNotificationAdapter ) +//------------------------------------------------------------ +FlushNotificationAdapter::FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener ) + :m_aBroadcaster( _rxBroadcaster ) + ,m_aListener( _rxListener ) +{ + DBG_CTOR( FlushNotificationAdapter, NULL ); + DBG_ASSERT( _rxBroadcaster.is(), "FlushNotificationAdapter::FlushNotificationAdapter: invalid flushable!" ); + + osl_incrementInterlockedCount( &m_refCount ); + { + if ( _rxBroadcaster.is() ) + _rxBroadcaster->addFlushListener( this ); + } + osl_decrementInterlockedCount( &m_refCount ); + DBG_ASSERT( m_refCount == 1, "FlushNotificationAdapter::FlushNotificationAdapter: broadcaster isn't holding by hard ref!?" ); +} + +//------------------------------------------------------------ +FlushNotificationAdapter::~FlushNotificationAdapter() +{ + DBG_DTOR( FlushNotificationAdapter, NULL ); +} + +void SAL_CALL FlushNotificationAdapter::impl_dispose( bool _bRevokeListener ) +{ + Reference< XFlushListener > xKeepAlive( this ); + + if ( _bRevokeListener ) + { + Reference< XFlushable > xFlushable( m_aBroadcaster ); + if ( xFlushable.is() ) + xFlushable->removeFlushListener( this ); + } + + m_aListener = Reference< XFlushListener >(); + m_aBroadcaster = Reference< XFlushable >(); +} + +void SAL_CALL FlushNotificationAdapter::flushed( const EventObject& rEvent ) throw (RuntimeException) +{ + Reference< XFlushListener > xListener( m_aListener ); + if ( xListener.is() ) + xListener->flushed( rEvent ); + else + impl_dispose( true ); +} + +void SAL_CALL FlushNotificationAdapter::disposing( const EventObject& Source ) throw (RuntimeException) +{ + Reference< XFlushListener > xListener( m_aListener ); + if ( xListener.is() ) + xListener->disposing( Source ); + + impl_dispose( false ); +} + +OAuthenticationContinuation::OAuthenticationContinuation() + :m_bRemberPassword(sal_True), // TODO: a meaningfull default + m_bCanSetUserName(sal_True) +{ +} + +sal_Bool SAL_CALL OAuthenticationContinuation::canSetRealm( ) throw(RuntimeException) +{ + return sal_False; +} + +void SAL_CALL OAuthenticationContinuation::setRealm( const ::rtl::OUString& /*Realm*/ ) throw(RuntimeException) +{ + DBG_ERROR("OAuthenticationContinuation::setRealm: not supported!"); +} + +sal_Bool SAL_CALL OAuthenticationContinuation::canSetUserName( ) throw(RuntimeException) +{ + // we alwas allow this, even if the database document is read-only. In this case, + // it's simply that the user cannot store the new user name. + return m_bCanSetUserName; +} + +void SAL_CALL OAuthenticationContinuation::setUserName( const ::rtl::OUString& _rUser ) throw(RuntimeException) +{ + m_sUser = _rUser; +} + +sal_Bool SAL_CALL OAuthenticationContinuation::canSetPassword( ) throw(RuntimeException) +{ + return sal_True; +} + +void SAL_CALL OAuthenticationContinuation::setPassword( const ::rtl::OUString& _rPassword ) throw(RuntimeException) +{ + m_sPassword = _rPassword; +} + +Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberPasswordModes( RememberAuthentication& _reDefault ) throw(RuntimeException) +{ + Sequence< RememberAuthentication > aReturn(1); + _reDefault = aReturn[0] = RememberAuthentication_SESSION; + return aReturn; +} + +void SAL_CALL OAuthenticationContinuation::setRememberPassword( RememberAuthentication _eRemember ) throw(RuntimeException) +{ + m_bRemberPassword = (RememberAuthentication_NO != _eRemember); +} + +sal_Bool SAL_CALL OAuthenticationContinuation::canSetAccount( ) throw(RuntimeException) +{ + return sal_False; +} + +void SAL_CALL OAuthenticationContinuation::setAccount( const ::rtl::OUString& ) throw(RuntimeException) +{ + DBG_ERROR("OAuthenticationContinuation::setAccount: not supported!"); +} + +Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberAccountModes( RememberAuthentication& _reDefault ) throw(RuntimeException) +{ + Sequence < RememberAuthentication > aReturn(1); + aReturn[0] = RememberAuthentication_NO; + _reDefault = RememberAuthentication_NO; + return aReturn; +} + +void SAL_CALL OAuthenticationContinuation::setRememberAccount( RememberAuthentication /*Remember*/ ) throw(RuntimeException) +{ + DBG_ERROR("OAuthenticationContinuation::setRememberAccount: not supported!"); +} + +/** The class OSharedConnectionManager implements a structure to share connections. + It owns the master connections which will be disposed when the last connection proxy is gone. +*/ +typedef ::cppu::WeakImplHelper1< XEventListener > OConnectionHelper_BASE; +// need to hold the digest +struct TDigestHolder +{ + sal_uInt8 m_pBuffer[RTL_DIGEST_LENGTH_SHA1]; + TDigestHolder() + { + m_pBuffer[0] = 0; + } + +}; + +class OSharedConnectionManager : public OConnectionHelper_BASE +{ + + // contains the currently used master connections + typedef struct + { + Reference< XConnection > xMasterConnection; + oslInterlockedCount nALiveCount; + } TConnectionHolder; + + // the less-compare functor, used for the stl::map + struct TDigestLess : public ::std::binary_function< TDigestHolder, TDigestHolder, bool> + { + bool operator() (const TDigestHolder& x, const TDigestHolder& y) const + { + sal_uInt32 i; + for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i) + ; + return i < RTL_DIGEST_LENGTH_SHA1; + } + }; + + typedef ::std::map< TDigestHolder,TConnectionHolder,TDigestLess> TConnectionMap; // holds the master connections + typedef ::std::map< Reference< XConnection >,TConnectionMap::iterator> TSharedConnectionMap;// holds the shared connections + + ::osl::Mutex m_aMutex; + TConnectionMap m_aConnections; // remeber the master connection in conjunction with the digest + TSharedConnectionMap m_aSharedConnection; // the shared connections with conjunction with an iterator into the connections map + Reference< XProxyFactory > m_xProxyFactory; + +protected: + ~OSharedConnectionManager(); + +public: + OSharedConnectionManager(const Reference< XMultiServiceFactory >& _rxServiceFactory); + + void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException); + Reference<XConnection> getConnection( const rtl::OUString& url, + const rtl::OUString& user, + const rtl::OUString& password, + const Sequence< PropertyValue >& _aInfo, + ODatabaseSource* _pDataSource); + void addEventListener(const Reference<XConnection>& _rxConnection,TConnectionMap::iterator& _rIter); +}; + +DBG_NAME(OSharedConnectionManager) +OSharedConnectionManager::OSharedConnectionManager(const Reference< XMultiServiceFactory >& _rxServiceFactory) +{ + DBG_CTOR(OSharedConnectionManager,NULL); + m_xProxyFactory.set(_rxServiceFactory->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.reflection.ProxyFactory"))),UNO_QUERY); +} + +OSharedConnectionManager::~OSharedConnectionManager() +{ + DBG_DTOR(OSharedConnectionManager,NULL); +} + +void SAL_CALL OSharedConnectionManager::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + Reference<XConnection> xConnection(Source.Source,UNO_QUERY); + TSharedConnectionMap::iterator aFind = m_aSharedConnection.find(xConnection); + if ( m_aSharedConnection.end() != aFind ) + { + osl_decrementInterlockedCount(&aFind->second->second.nALiveCount); + if ( !aFind->second->second.nALiveCount ) + { + ::comphelper::disposeComponent(aFind->second->second.xMasterConnection); + m_aConnections.erase(aFind->second); + } + m_aSharedConnection.erase(aFind); + } +} + +Reference<XConnection> OSharedConnectionManager::getConnection( const rtl::OUString& url, + const rtl::OUString& user, + const rtl::OUString& password, + const Sequence< PropertyValue >& _aInfo, + ODatabaseSource* _pDataSource) +{ + MutexGuard aGuard(m_aMutex); + TConnectionMap::key_type nId; + Sequence< PropertyValue > aInfoCopy(_aInfo); + sal_Int32 nPos = aInfoCopy.getLength(); + aInfoCopy.realloc( nPos + 2 ); + aInfoCopy[nPos].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TableFilter")); + aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableFilter; + aInfoCopy[nPos].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TableTypeFilter")); + aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableTypeFilter; // #22377# OJ + + ::rtl::OUString sUser = user; + ::rtl::OUString sPassword = password; + if ((0 == sUser.getLength()) && (0 == sPassword.getLength()) && (0 != _pDataSource->m_pImpl->m_sUser.getLength())) + { // ease the usage of this method. data source which are intended to have a user automatically + // fill in the user/password combination if the caller of this method does not specify otherwise + // 86951 - 05/08/2001 - frank.schoenheit@germany.sun.com + sUser = _pDataSource->m_pImpl->m_sUser; + if (0 != _pDataSource->m_pImpl->m_aPassword.getLength()) + sPassword = _pDataSource->m_pImpl->m_aPassword; + } + + ::connectivity::OConnectionWrapper::createUniqueId(url,aInfoCopy,nId.m_pBuffer,sUser,sPassword); + TConnectionMap::iterator aIter = m_aConnections.find(nId); + + if ( m_aConnections.end() == aIter ) + { + TConnectionHolder aHolder; + aHolder.nALiveCount = 0; // will be incremented by addListener + aHolder.xMasterConnection = _pDataSource->buildIsolatedConnection(user,password); + aIter = m_aConnections.insert(TConnectionMap::value_type(nId,aHolder)).first; + } + + Reference<XConnection> xRet; + if ( aIter->second.xMasterConnection.is() ) + { + Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(aIter->second.xMasterConnection.get()); + xRet = new OSharedConnection(xConProxy); + m_aSharedConnection.insert(TSharedConnectionMap::value_type(xRet,aIter)); + addEventListener(xRet,aIter); + } + + return xRet; +} +void OSharedConnectionManager::addEventListener(const Reference<XConnection>& _rxConnection,TConnectionMap::iterator& _rIter) +{ + Reference<XComponent> xComp(_rxConnection,UNO_QUERY); + xComp->addEventListener(this); + OSL_ENSURE( m_aConnections.end() != _rIter , "Iterator is end!"); + osl_incrementInterlockedCount(&_rIter->second.nALiveCount); +} + +namespace +{ + Sequence< PropertyValue > lcl_filterDriverProperties( const Reference< XDriver >& _xDriver, const ::rtl::OUString& _sUrl, + const Sequence< PropertyValue >& _rDataSourceSettings, const AsciiPropertyValue* _pKnownSettings ) + { + if ( _xDriver.is() ) + { + Sequence< DriverPropertyInfo > aDriverInfo(_xDriver->getPropertyInfo(_sUrl,_rDataSourceSettings)); + + const PropertyValue* pDataSourceSetting = _rDataSourceSettings.getConstArray(); + const PropertyValue* pEnd = pDataSourceSetting + _rDataSourceSettings.getLength(); + + ::std::vector< PropertyValue > aRet; + + for ( ; pDataSourceSetting != pEnd ; ++pDataSourceSetting ) + { + sal_Bool bAllowSetting = sal_False; + const AsciiPropertyValue* pSetting = _pKnownSettings; + for ( ; pSetting->AsciiName; ++pSetting ) + { + if ( !pDataSourceSetting->Name.compareToAscii( pSetting->AsciiName ) ) + { // the particular data source setting is known + + const DriverPropertyInfo* pAllowedDriverSetting = aDriverInfo.getConstArray(); + const DriverPropertyInfo* pDriverSettingsEnd = pAllowedDriverSetting + aDriverInfo.getLength(); + for ( ; pAllowedDriverSetting != pDriverSettingsEnd; ++pAllowedDriverSetting ) + { + if ( !pAllowedDriverSetting->Name.compareToAscii( pSetting->AsciiName ) ) + { // the driver also allows this setting + bAllowSetting = sal_True; + break; + } + } + break; + } + } + if ( bAllowSetting || !pSetting->AsciiName ) + { // if the driver allows this particular setting, or if the setting is completely unknown, + // we pass it to the driver + aRet.push_back( *pDataSourceSetting ); + } + } + if ( !aRet.empty() ) + return Sequence< PropertyValue >(&(*aRet.begin()),aRet.size()); + } + return Sequence< PropertyValue >(); + } + + typedef ::std::map< ::rtl::OUString, sal_Int32 > PropertyAttributeCache; + + struct IsDefaultAndNotRemoveable : public ::std::unary_function< PropertyValue, bool > + { + private: + const PropertyAttributeCache& m_rAttribs; + + public: + IsDefaultAndNotRemoveable( const PropertyAttributeCache& _rAttribs ) : m_rAttribs( _rAttribs ) { } + + bool operator()( const PropertyValue& _rProp ) + { + if ( _rProp.State != PropertyState_DEFAULT_VALUE ) + return false; + + bool bRemoveable = true; + + PropertyAttributeCache::const_iterator pos = m_rAttribs.find( _rProp.Name ); + OSL_ENSURE( pos != m_rAttribs.end(), "IsDefaultAndNotRemoveable: illegal property name!" ); + if ( pos != m_rAttribs.end() ) + bRemoveable = ( ( pos->second & PropertyAttribute::REMOVEABLE ) != 0 ); + + return !bRemoveable; + } + }; +} +//============================================================ +//= ODatabaseContext +//============================================================ +DBG_NAME(ODatabaseSource) + +extern "C" void SAL_CALL createRegistryInfo_ODatabaseSource() +{ + static ::dba::OAutoRegistration< ODatabaseSource > aAutoRegistration; +} + +ODatabaseSource::ODatabaseSource(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl) + :ModelDependentComponent( _pImpl ) + ,ODatabaseSource_Base( getMutex() ) + ,OPropertySetHelper( ODatabaseSource_Base::rBHelper ) + ,m_aBookmarks( *this, getMutex() ) + ,m_aFlushListeners( getMutex() ) +{ + // some kind of default + DBG_CTOR(ODatabaseSource,NULL); + OSL_TRACE( "DS: ctor: %p: %p", this, m_pImpl.get() ); +} + +ODatabaseSource::~ODatabaseSource() +{ + OSL_TRACE( "DS: dtor: %p: %p", this, m_pImpl.get() ); + DBG_DTOR(ODatabaseSource,NULL); + if ( !ODatabaseSource_Base::rBHelper.bInDispose && !ODatabaseSource_Base::rBHelper.bDisposed ) + { + acquire(); + dispose(); + } +} + +void ODatabaseSource::setName( const Reference< XDocumentDataSource >& _rxDocument, const ::rtl::OUString& _rNewName, DBContextAccess ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::setName" ); + ODatabaseSource& rModelImpl = dynamic_cast< ODatabaseSource& >( *_rxDocument.get() ); + + ::osl::MutexGuard aGuard( rModelImpl.m_aMutex ); + if ( rModelImpl.m_pImpl.is() ) + rModelImpl.m_pImpl->m_sName = _rNewName; +} + +// com::sun::star::lang::XTypeProvider +Sequence< Type > ODatabaseSource::getTypes() throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getTypes" ); + OTypeCollection aPropertyHelperTypes( ::getCppuType( (const Reference< XFastPropertySet > *)0 ), + ::getCppuType( (const Reference< XPropertySet > *)0 ), + ::getCppuType( (const Reference< XMultiPropertySet > *)0 )); + + return ::comphelper::concatSequences( + ODatabaseSource_Base::getTypes(), + aPropertyHelperTypes.getTypes() + ); +} + +Sequence< sal_Int8 > ODatabaseSource::getImplementationId() throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getImplementationId" ); + static OImplementationId * pId = 0; + if (! pId) + { + MutexGuard aGuard( Mutex::getGlobalMutex() ); + if (! pId) + { + static OImplementationId aId; + pId = &aId; + } + } + return pId->getImplementationId(); +} + +// com::sun::star::uno::XInterface +Any ODatabaseSource::queryInterface( const Type & rType ) throw (RuntimeException) +{ + Any aIface = ODatabaseSource_Base::queryInterface( rType ); + if ( !aIface.hasValue() ) + aIface = ::cppu::OPropertySetHelper::queryInterface( rType ); + return aIface; +} + +void ODatabaseSource::acquire() throw () +{ + ODatabaseSource_Base::acquire(); +} + +void ODatabaseSource::release() throw () +{ + ODatabaseSource_Base::release(); +} + +void SAL_CALL ODatabaseSource::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException) +{ + if ( m_pImpl.is() ) + m_pImpl->disposing(Source); +} +// XServiceInfo +rtl::OUString ODatabaseSource::getImplementationName( ) throw(RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getImplementationName" ); + return getImplementationName_static(); +} + +rtl::OUString ODatabaseSource::getImplementationName_static( ) throw(RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getImplementationName_static" ); + return rtl::OUString::createFromAscii("com.sun.star.comp.dba.ODatabaseSource"); +} + +Sequence< ::rtl::OUString > ODatabaseSource::getSupportedServiceNames( ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getSupportedServiceNames" ); + return getSupportedServiceNames_static(); +} + +Reference< XInterface > ODatabaseSource::Create( const Reference< XComponentContext >& _rxContext ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::Create" ); + ::comphelper::ComponentContext aContext( _rxContext ); + Reference< XSingleServiceFactory > xDBContext( aContext.createComponent( (::rtl::OUString)SERVICE_SDB_DATABASECONTEXT ), UNO_QUERY_THROW ); + return xDBContext->createInstance(); +} + +Sequence< ::rtl::OUString > ODatabaseSource::getSupportedServiceNames_static( ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getSupportedServiceNames_static" ); + Sequence< ::rtl::OUString > aSNS( 2 ); + aSNS[0] = SERVICE_SDB_DATASOURCE; + aSNS[1] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sdb.DocumentDataSource")); + return aSNS; +} + +sal_Bool ODatabaseSource::supportsService( const ::rtl::OUString& _rServiceName ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::supportsService" ); + return ::comphelper::findValue(getSupportedServiceNames(), _rServiceName, sal_True).getLength() != 0; +} + +// OComponentHelper +void ODatabaseSource::disposing() +{ + OSL_TRACE( "DS: disp: %p, %p", this, m_pImpl.get() ); + ODatabaseSource_Base::WeakComponentImplHelperBase::disposing(); + OPropertySetHelper::disposing(); + + EventObject aDisposeEvent(static_cast<XWeak*>(this)); + m_aFlushListeners.disposeAndClear( aDisposeEvent ); + + ODatabaseDocument::clearObjectContainer(m_pImpl->m_xCommandDefinitions); + ODatabaseDocument::clearObjectContainer(m_pImpl->m_xTableDefinitions); + m_pImpl.clear(); +} + +Reference< XConnection > ODatabaseSource::buildLowLevelConnection(const ::rtl::OUString& _rUid, const ::rtl::OUString& _rPwd) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::buildLowLevelConnection" ); + Reference< XConnection > xReturn; + + Reference< XDriverManager > xManager; + if ( !m_pImpl->m_aContext.createComponent( "com.sun.star.sdbc.ConnectionPool", xManager ) ) + // no connection pool installed, fall back to driver manager + m_pImpl->m_aContext.createComponent( "com.sun.star.sdbc.DriverManager", xManager ); + + ::rtl::OUString sUser(_rUid); + ::rtl::OUString sPwd(_rPwd); + if ((0 == sUser.getLength()) && (0 == sPwd.getLength()) && (0 != m_pImpl->m_sUser.getLength())) + { // ease the usage of this method. data source which are intended to have a user automatically + // fill in the user/password combination if the caller of this method does not specify otherwise + sUser = m_pImpl->m_sUser; + if (0 != m_pImpl->m_aPassword.getLength()) + sPwd = m_pImpl->m_aPassword; + } + + sal_uInt16 nExceptionMessageId = RID_STR_COULDNOTCONNECT_UNSPECIFIED; + if (xManager.is()) + { + sal_Int32 nAdditionalArgs(0); + if (sUser.getLength()) ++nAdditionalArgs; + if (sPwd.getLength()) ++nAdditionalArgs; + + Sequence< PropertyValue > aUserPwd(nAdditionalArgs); + sal_Int32 nArgPos = 0; + if (sUser.getLength()) + { + aUserPwd[ nArgPos ].Name = ::rtl::OUString::createFromAscii("user"); + aUserPwd[ nArgPos ].Value <<= sUser; + ++nArgPos; + } + if (sPwd.getLength()) + { + aUserPwd[ nArgPos ].Name = ::rtl::OUString::createFromAscii("password"); + aUserPwd[ nArgPos ].Value <<= sPwd; + } + Reference< XDriver > xDriver; + try + { + Reference< XDriverAccess > xAccessDrivers( xManager, UNO_QUERY ); + if ( xAccessDrivers.is() ) + xDriver = xAccessDrivers->getDriverByURL( m_pImpl->m_sConnectURL ); + } + catch( const Exception& ) + { + DBG_ERROR( "ODatabaseSource::buildLowLevelConnection: got a strange exception while analyzing the error!" ); + } + if ( !xDriver.is() || !xDriver->acceptsURL( m_pImpl->m_sConnectURL ) ) + { + // Nowadays, it's allowed for a driver to be registered for a given URL, but actually not to accept it. + // This is because registration nowadays happens at compile time (by adding respective configuration data), + // but acceptance is decided at runtime. + nExceptionMessageId = RID_STR_COULDNOTCONNECT_NODRIVER; + } + else + { + Sequence< PropertyValue > aDriverInfo = lcl_filterDriverProperties( + xDriver, + m_pImpl->m_sConnectURL, + m_pImpl->m_xSettings->getPropertyValues(), + m_pImpl->getDefaultDataSourceSettings() + ); + + if ( m_pImpl->isEmbeddedDatabase() ) + { + sal_Int32 nCount = aDriverInfo.getLength(); + aDriverInfo.realloc(nCount + 2 ); + aDriverInfo[nCount].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("URL")); + aDriverInfo[nCount++].Value <<= m_pImpl->getURL(); + aDriverInfo[nCount].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Storage")); + Reference< css::document::XDocumentSubStorageSupplier> xDocSup( m_pImpl->getDocumentSubStorageSupplier() ); + aDriverInfo[nCount++].Value <<= xDocSup->getDocumentSubStorage(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("database")),ElementModes::READWRITE); + } + if (nAdditionalArgs) + xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL, ::comphelper::concatSequences(aUserPwd,aDriverInfo)); + else + xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL,aDriverInfo); + + if ( m_pImpl->isEmbeddedDatabase() ) + { + // see ODatabaseSource::flushed for comment on why we register as FlushListener + // at the connection + Reference< XFlushable > xFlushable( xReturn, UNO_QUERY ); + if ( xFlushable.is() ) + FlushNotificationAdapter::installAdapter( xFlushable, this ); + } + } + } + else + nExceptionMessageId = RID_STR_COULDNOTLOAD_MANAGER; + + if ( !xReturn.is() ) + { + ::rtl::OUString sMessage = DBACORE_RESSTRING( nExceptionMessageId ); + + SQLContext aContext; + aContext.Message = DBACORE_RESSTRING( RID_STR_CONNECTION_REQUEST ); + ::comphelper::string::searchAndReplaceAsciiI( aContext.Message, "$name$", m_pImpl->m_sConnectURL ); + + throwGenericSQLException( sMessage, static_cast< XDataSource* >( this ), makeAny( aContext ) ); + } + + return xReturn; +} + +// OPropertySetHelper +Reference< XPropertySetInfo > ODatabaseSource::getPropertySetInfo() throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getPropertySetInfo" ); + return createPropertySetInfo( getInfoHelper() ) ; +} + +// comphelper::OPropertyArrayUsageHelper +::cppu::IPropertyArrayHelper* ODatabaseSource::createArrayHelper( ) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::createArrayHelper" ); + BEGIN_PROPERTY_HELPER(13) + DECL_PROP1(INFO, Sequence< PropertyValue >, BOUND); + DECL_PROP1_BOOL(ISPASSWORDREQUIRED, BOUND); + DECL_PROP1_BOOL(ISREADONLY, READONLY); + DECL_PROP1(LAYOUTINFORMATION, Sequence< PropertyValue >, BOUND); + DECL_PROP1(NAME, ::rtl::OUString, READONLY); + DECL_PROP2_IFACE(NUMBERFORMATSSUPPLIER, XNumberFormatsSupplier, READONLY, TRANSIENT); + DECL_PROP1(PASSWORD, ::rtl::OUString, TRANSIENT); + DECL_PROP2_IFACE(SETTINGS, XPropertySet, BOUND, READONLY); + DECL_PROP1_BOOL(SUPPRESSVERSIONCL, BOUND); + DECL_PROP1(TABLEFILTER, Sequence< ::rtl::OUString >,BOUND); + DECL_PROP1(TABLETYPEFILTER, Sequence< ::rtl::OUString >,BOUND); + DECL_PROP1(URL, ::rtl::OUString, BOUND); + DECL_PROP1(USER, ::rtl::OUString, BOUND); + END_PROPERTY_HELPER(); +} + +// cppu::OPropertySetHelper +::cppu::IPropertyArrayHelper& ODatabaseSource::getInfoHelper() +{ + return *getArrayHelper(); +} + +sal_Bool ODatabaseSource::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue ) throw( IllegalArgumentException ) +{ + sal_Bool bModified(sal_False); + if ( m_pImpl.is() ) + { + switch (nHandle) + { + case PROPERTY_ID_TABLEFILTER: + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableFilter); + break; + case PROPERTY_ID_TABLETYPEFILTER: + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableTypeFilter); + break; + case PROPERTY_ID_USER: + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sUser); + break; + case PROPERTY_ID_PASSWORD: + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aPassword); + break; + case PROPERTY_ID_ISPASSWORDREQUIRED: + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bPasswordRequired); + break; + case PROPERTY_ID_SUPPRESSVERSIONCL: + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bSuppressVersionColumns); + break; + case PROPERTY_ID_LAYOUTINFORMATION: + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aLayoutInformation); + break; + case PROPERTY_ID_URL: + { + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sConnectURL); + } break; + case PROPERTY_ID_INFO: + { + Sequence<PropertyValue> aValues; + if (!(rValue >>= aValues)) + throw IllegalArgumentException(); + + const PropertyValue* valueEnd = aValues.getConstArray() + aValues.getLength(); + const PropertyValue* checkName = aValues.getConstArray(); + for ( ;checkName != valueEnd; ++checkName ) + { + if ( !checkName->Name.getLength() ) + throw IllegalArgumentException(); + } + + Sequence< PropertyValue > aSettings = m_pImpl->m_xSettings->getPropertyValues(); + bModified = aSettings.getLength() != aValues.getLength(); + if ( !bModified ) + { + const PropertyValue* pInfoIter = aSettings.getConstArray(); + const PropertyValue* checkValue = aValues.getConstArray(); + for ( ;!bModified && checkValue != valueEnd ; ++checkValue,++pInfoIter) + { + bModified = checkValue->Name != pInfoIter->Name; + if ( !bModified ) + { + bModified = !::comphelper::compare(checkValue->Value,pInfoIter->Value); + } + } + } + + rConvertedValue = rValue; + rOldValue <<= aSettings; + } + break; + default: + DBG_ERROR( "ODatabaseSource::convertFastPropertyValue: unknown or readonly Property!" ); + } + } + return bModified; +} + +namespace +{ + struct SelectPropertyName : public ::std::unary_function< PropertyValue, ::rtl::OUString > + { + public: + const ::rtl::OUString& operator()( const PropertyValue& _lhs ) + { + return _lhs.Name; + } + }; + + /** sets a new set of property values at a given property bag instance + + The methods takes a property bag, and a sequence of property values to set at this bag. + Upon return, every property which is not part of the given sequence is + <ul><li>removed from the bag, if it's a removeable property</li> + <li><em>or</em>reset to its default value, if it's not a removeable property</li> + </ul>. + + @param _rxPropertyBag + the property bag to operate on + @param _rAllNewPropertyValues + the new property values to set at the bag + */ + void lcl_setPropertyValues_resetOrRemoveOther( const Reference< XPropertyAccess >& _rxPropertyBag, const Sequence< PropertyValue >& _rAllNewPropertyValues ) + { + // sequences are ugly to operate on + typedef ::std::set< ::rtl::OUString > StringSet; + StringSet aToBeSetPropertyNames; + ::std::transform( + _rAllNewPropertyValues.getConstArray(), + _rAllNewPropertyValues.getConstArray() + _rAllNewPropertyValues.getLength(), + ::std::insert_iterator< StringSet >( aToBeSetPropertyNames, aToBeSetPropertyNames.end() ), + SelectPropertyName() + ); + + try + { + // obtain all properties currently known at the bag + Reference< XPropertySet > xPropertySet( _rxPropertyBag, UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xPSI( xPropertySet->getPropertySetInfo(), UNO_QUERY_THROW ); + Sequence< Property > aAllExistentProperties( xPSI->getProperties() ); + + Reference< XPropertyState > xPropertyState( _rxPropertyBag, UNO_QUERY_THROW ); + Reference< XPropertyContainer > xPropertyContainer( _rxPropertyBag, UNO_QUERY_THROW ); + + // loop through them, and reset resp. default properties which are not to be set + const Property* pExistentProperty( aAllExistentProperties.getConstArray() ); + const Property* pExistentPropertyEnd( aAllExistentProperties.getConstArray() + aAllExistentProperties.getLength() ); + for ( ; pExistentProperty != pExistentPropertyEnd; ++pExistentProperty ) + { + if ( aToBeSetPropertyNames.find( pExistentProperty->Name ) != aToBeSetPropertyNames.end() ) + continue; + + // this property is not to be set, but currently exists in the bag. + // -> Remove, respectively default, it + if ( ( pExistentProperty->Attributes & PropertyAttribute::REMOVEABLE ) != 0 ) + xPropertyContainer->removeProperty( pExistentProperty->Name ); + else + xPropertyState->setPropertyToDefault( pExistentProperty->Name ); + } + + // finally, set the new property values + _rxPropertyBag->setPropertyValues( _rAllNewPropertyValues ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } +} + +void ODatabaseSource::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) throw (Exception) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::setFastPropertyValue_NoBroadcast" ); + if ( m_pImpl.is() ) + { + switch(nHandle) + { + case PROPERTY_ID_TABLEFILTER: + rValue >>= m_pImpl->m_aTableFilter; + break; + case PROPERTY_ID_TABLETYPEFILTER: + rValue >>= m_pImpl->m_aTableTypeFilter; + break; + case PROPERTY_ID_USER: + rValue >>= m_pImpl->m_sUser; + // if the user name changed, reset the password + m_pImpl->m_aPassword = ::rtl::OUString(); + break; + case PROPERTY_ID_PASSWORD: + rValue >>= m_pImpl->m_aPassword; + break; + case PROPERTY_ID_ISPASSWORDREQUIRED: + m_pImpl->m_bPasswordRequired = any2bool(rValue); + break; + case PROPERTY_ID_SUPPRESSVERSIONCL: + m_pImpl->m_bSuppressVersionColumns = any2bool(rValue); + break; + case PROPERTY_ID_URL: + rValue >>= m_pImpl->m_sConnectURL; + break; + case PROPERTY_ID_INFO: + { + Sequence< PropertyValue > aInfo; + OSL_VERIFY( rValue >>= aInfo ); + lcl_setPropertyValues_resetOrRemoveOther( m_pImpl->m_xSettings, aInfo ); + } + break; + case PROPERTY_ID_LAYOUTINFORMATION: + rValue >>= m_pImpl->m_aLayoutInformation; + break; + } + m_pImpl->setModified(sal_True); + } +} + +void ODatabaseSource::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const +{ + //RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getFastPropertyValue" ); + if ( m_pImpl.is() ) + { + switch (nHandle) + { + case PROPERTY_ID_TABLEFILTER: + rValue <<= m_pImpl->m_aTableFilter; + break; + case PROPERTY_ID_TABLETYPEFILTER: + rValue <<= m_pImpl->m_aTableTypeFilter; + break; + case PROPERTY_ID_USER: + rValue <<= m_pImpl->m_sUser; + break; + case PROPERTY_ID_PASSWORD: + rValue <<= m_pImpl->m_aPassword; + break; + case PROPERTY_ID_ISPASSWORDREQUIRED: + rValue = bool2any(m_pImpl->m_bPasswordRequired); + break; + case PROPERTY_ID_SUPPRESSVERSIONCL: + rValue = bool2any(m_pImpl->m_bSuppressVersionColumns); + break; + case PROPERTY_ID_ISREADONLY: + rValue = bool2any(m_pImpl->m_bReadOnly); + break; + case PROPERTY_ID_INFO: + { + try + { + // collect the property attributes of all current settings + Reference< XPropertySet > xSettingsAsProps( m_pImpl->m_xSettings, UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xPST( xSettingsAsProps->getPropertySetInfo(), UNO_QUERY_THROW ); + Sequence< Property > aSettings( xPST->getProperties() ); + ::std::map< ::rtl::OUString, sal_Int32 > aPropertyAttributes; + for ( const Property* pSettings = aSettings.getConstArray(); + pSettings != aSettings.getConstArray() + aSettings.getLength(); + ++pSettings + ) + { + aPropertyAttributes[ pSettings->Name ] = pSettings->Attributes; + } + + // get all current settings with their values + Sequence< PropertyValue > aValues( m_pImpl->m_xSettings->getPropertyValues() ); + + // transform them so that only property values which fulfill certain + // criterions survive + Sequence< PropertyValue > aNonDefaultOrUserDefined( aValues.getLength() ); + const PropertyValue* pCopyEnd = ::std::remove_copy_if( + aValues.getConstArray(), + aValues.getConstArray() + aValues.getLength(), + aNonDefaultOrUserDefined.getArray(), + IsDefaultAndNotRemoveable( aPropertyAttributes ) + ); + aNonDefaultOrUserDefined.realloc( pCopyEnd - aNonDefaultOrUserDefined.getArray() ); + rValue <<= aNonDefaultOrUserDefined; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + break; + case PROPERTY_ID_SETTINGS: + rValue <<= m_pImpl->m_xSettings; + break; + case PROPERTY_ID_URL: + rValue <<= m_pImpl->m_sConnectURL; + break; + case PROPERTY_ID_NUMBERFORMATSSUPPLIER: + rValue <<= m_pImpl->getNumberFormatsSupplier(); + break; + case PROPERTY_ID_NAME: + rValue <<= m_pImpl->m_sName; + break; + case PROPERTY_ID_LAYOUTINFORMATION: + rValue <<= m_pImpl->m_aLayoutInformation; + break; + default: + DBG_ERROR("unknown Property"); + } + } +} + +// XDataSource +void ODatabaseSource::setLoginTimeout(sal_Int32 seconds) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::setLoginTimeout" ); + ModelMethodGuard aGuard( *this ); + m_pImpl->m_nLoginTimeout = seconds; +} + +sal_Int32 ODatabaseSource::getLoginTimeout(void) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getLoginTimeout" ); + ModelMethodGuard aGuard( *this ); + return m_pImpl->m_nLoginTimeout; +} + +// XCompletedConnection +Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::connectWithCompletion" ); + return connectWithCompletion(_rxHandler,sal_False); +} + +Reference< XConnection > ODatabaseSource::getConnection(const rtl::OUString& user, const rtl::OUString& password) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getConnection" ); + return getConnection(user,password,sal_False); +} + +Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnection( const ::rtl::OUString& user, const ::rtl::OUString& password ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getIsolatedConnection" ); + return getConnection(user,password,sal_True); +} + +Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnectionWithCompletion( const Reference< XInteractionHandler >& _rxHandler ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getIsolatedConnectionWithCompletion" ); + return connectWithCompletion(_rxHandler,sal_True); +} + +Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler,sal_Bool _bIsolated ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::connectWithCompletion" ); + ModelMethodGuard aGuard( *this ); + + if (!_rxHandler.is()) + { + DBG_ERROR("ODatabaseSource::connectWithCompletion: invalid interaction handler!"); + return getConnection(m_pImpl->m_sUser, m_pImpl->m_aPassword,_bIsolated); + } + + ::rtl::OUString sUser(m_pImpl->m_sUser), sPassword(m_pImpl->m_aPassword); + sal_Bool bNewPasswordGiven = sal_False; + + if (m_pImpl->m_bPasswordRequired && (0 == sPassword.getLength())) + { // we need a password, but don't have one yet. + // -> ask the user + + // build an interaction request + // two continuations (Ok and Cancel) + OInteractionAbort* pAbort = new OInteractionAbort; + OAuthenticationContinuation* pAuthenticate = new OAuthenticationContinuation; + + // the name which should be referred in the login dialog + ::rtl::OUString sServerName( m_pImpl->m_sName ); + INetURLObject aURLCheck( sServerName ); + if ( aURLCheck.GetProtocol() != INET_PROT_NOT_VALID ) + sServerName = aURLCheck.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_UNAMBIGUOUS ); + + // the request + AuthenticationRequest aRequest; + aRequest.ServerName = sServerName; + aRequest.HasRealm = aRequest.HasAccount = sal_False; + aRequest.HasUserName = aRequest.HasPassword = sal_True; + aRequest.UserName = m_pImpl->m_sUser; + aRequest.Password = m_pImpl->m_sFailedPassword.getLength() ? m_pImpl->m_sFailedPassword : m_pImpl->m_aPassword; + OInteractionRequest* pRequest = new OInteractionRequest(makeAny(aRequest)); + Reference< XInteractionRequest > xRequest(pRequest); + // some knittings + pRequest->addContinuation(pAbort); + pRequest->addContinuation(pAuthenticate); + + // handle the request + try + { + MutexRelease aRelease( getMutex() ); + // release the mutex when calling the handler, it may need to lock the SolarMutex + _rxHandler->handle(xRequest); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + + if (!pAuthenticate->wasSelected()) + return Reference< XConnection >(); + + // get the result + sUser = m_pImpl->m_sUser = pAuthenticate->getUser(); + sPassword = pAuthenticate->getPassword(); + + if (pAuthenticate->getRememberPassword()) + { + m_pImpl->m_aPassword = pAuthenticate->getPassword(); + bNewPasswordGiven = sal_True; + } + m_pImpl->m_sFailedPassword = ::rtl::OUString(); + } + + try + { + return getConnection(sUser, sPassword,_bIsolated); + } + catch(Exception&) + { + if (bNewPasswordGiven) + { + m_pImpl->m_sFailedPassword = m_pImpl->m_aPassword; + // assume that we had an authentication problem. Without this we may, after an unsucessful connect, while + // the user gave us a password an the order to remember it, never allow an password input again (at least + // not without restarting the session) + m_pImpl->m_aPassword = ::rtl::OUString(); + } + throw; + } +} + +Reference< XConnection > ODatabaseSource::buildIsolatedConnection(const rtl::OUString& user, const rtl::OUString& password) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::buildIsolatedConnection" ); + Reference< XConnection > xConn; + Reference< XConnection > xSdbcConn = buildLowLevelConnection(user, password); + DBG_ASSERT( xSdbcConn.is(), "ODatabaseSource::buildIsolatedConnection: invalid return value of buildLowLevelConnection!" ); + // buildLowLevelConnection is expected to always succeed + if ( xSdbcConn.is() ) + { + // build a connection server and return it (no stubs) + xConn = new OConnection(*this, xSdbcConn, m_pImpl->m_aContext.getLegacyServiceFactory()); + } + return xConn; +} + +Reference< XConnection > ODatabaseSource::getConnection(const rtl::OUString& user, const rtl::OUString& password,sal_Bool _bIsolated) throw( SQLException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getConnection" ); + ModelMethodGuard aGuard( *this ); + + Reference< XConnection > xConn; + if ( _bIsolated ) + { + xConn = buildIsolatedConnection(user,password); + } + else + { // create a new proxy for the connection + if ( !m_pImpl->m_xSharedConnectionManager.is() ) + { + m_pImpl->m_pSharedConnectionManager = new OSharedConnectionManager( m_pImpl->m_aContext.getLegacyServiceFactory() ); + m_pImpl->m_xSharedConnectionManager = m_pImpl->m_pSharedConnectionManager; + } + xConn = m_pImpl->m_pSharedConnectionManager->getConnection( + m_pImpl->m_sConnectURL, user, password, m_pImpl->m_xSettings->getPropertyValues(), this ); + } + + if ( xConn.is() ) + { + Reference< XComponent> xComp(xConn,UNO_QUERY); + if ( xComp.is() ) + xComp->addEventListener( static_cast< XContainerListener* >( this ) ); + m_pImpl->m_aConnections.push_back(OWeakConnection(xConn)); + } + + return xConn; +} + +Reference< XNameAccess > SAL_CALL ODatabaseSource::getBookmarks( ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getBookmarks" ); + ModelMethodGuard aGuard( *this ); + return static_cast< XNameContainer* >(&m_aBookmarks); +} + +Reference< XNameAccess > SAL_CALL ODatabaseSource::getQueryDefinitions( ) throw(RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getQueryDefinitions" ); + ModelMethodGuard aGuard( *this ); + + Reference< XNameAccess > xContainer = m_pImpl->m_xCommandDefinitions; + if ( !xContainer.is() ) + { + Any aValue; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xMy(*this); + if ( dbtools::getDataSourceSetting(xMy,"CommandDefinitions",aValue) ) + { + ::rtl::OUString sSupportService; + aValue >>= sSupportService; + if ( sSupportService.getLength() ) + { + Sequence<Any> aArgs(1); + aArgs[0] <<= NamedValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DataSource")),makeAny(xMy)); + xContainer.set(m_pImpl->m_aContext.createComponentWithArguments(sSupportService,aArgs),UNO_QUERY); + } + } + if ( !xContainer.is() ) + { + TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_QUERY ) ); + xContainer = new OCommandContainer( m_pImpl->m_aContext.getLegacyServiceFactory(), *this, rContainerData, sal_False ); + } + m_pImpl->m_xCommandDefinitions = xContainer; + } + return xContainer; +} + +// XTablesSupplier +Reference< XNameAccess > ODatabaseSource::getTables() throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getTables" ); + ModelMethodGuard aGuard( *this ); + + Reference< XNameAccess > xContainer = m_pImpl->m_xTableDefinitions; + if ( !xContainer.is() ) + { + TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_TABLE ) ); + xContainer = new OCommandContainer( m_pImpl->m_aContext.getLegacyServiceFactory(), *this, rContainerData, sal_True ); + m_pImpl->m_xTableDefinitions = xContainer; + } + return xContainer; +} + +void SAL_CALL ODatabaseSource::flush( ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::flush" ); + try + { + // SYNCHRONIZED -> + { + ModelMethodGuard aGuard( *this ); + + typedef ::utl::SharedUNOComponent< XModel, ::utl::CloseableComponent > SharedModel; + SharedModel xModel( m_pImpl->getModel_noCreate(), SharedModel::NoTakeOwnership ); + + if ( !xModel.is() ) + xModel.reset( m_pImpl->createNewModel_deliverOwnership( false ), SharedModel::TakeOwnership ); + + Reference< css::frame::XStorable> xStorable( xModel, UNO_QUERY_THROW ); + xStorable->store(); + } + // <- SYNCHRONIZED + + css::lang::EventObject aFlushedEvent(*this); + m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +void SAL_CALL ODatabaseSource::flushed( const EventObject& /*rEvent*/ ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::flushed" ); + ModelMethodGuard aGuard( *this ); + + // Okay, this is some hack. + // + // In general, we have the problem that embedded databases write into their underlying storage, which + // logically is one of our sub storage, and practically is a temporary file maintained by the + // package implementation. As long as we did not commit this storage and our main storage, + // the changes made by the embedded database engine are not really reflected in the database document + // file. This is Bad (TM) for a "real" database application - imagine somebody entering some + // data, and then crashing: For a database application, you would expect that the data still is present + // when you connect to the database next time. + // + // Since this is a conceptual problem as long as we do use those ZIP packages (in fact, we *cannot* + // provide the desired functionality as long as we do not have a package format which allows O(1) writes), + // we cannot completely fix this. However, we can relax the problem by commiting more often - often + // enough so that data loss is more seldom, and seldom enough so that there's no noticable performance + // decrease. + // + // For this, we introduced a few places which XFlushable::flush their connections, and register as + // XFlushListener at the embedded connection (which needs to provide the XFlushable functionality). + // Then, when the connection is flushed, we commit both the database storage and our main storage. + // + // #i55274# / 2005-09-30 / frank.schoenheit@sun.com + + OSL_ENSURE( m_pImpl->isEmbeddedDatabase(), "ODatabaseSource::flushed: no embedded database?!" ); + sal_Bool bWasModified = m_pImpl->m_bModified; + m_pImpl->commitEmbeddedStorage(); + m_pImpl->setModified( bWasModified ); +} + +void SAL_CALL ODatabaseSource::addFlushListener( const Reference< ::com::sun::star::util::XFlushListener >& _xListener ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::addFlushListener" ); + m_aFlushListeners.addInterface(_xListener); +} + +void SAL_CALL ODatabaseSource::removeFlushListener( const Reference< ::com::sun::star::util::XFlushListener >& _xListener ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::removeFlushListener" ); + m_aFlushListeners.removeInterface(_xListener); +} + +void SAL_CALL ODatabaseSource::elementInserted( const ContainerEvent& /*Event*/ ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::elementInserted" ); + ModelMethodGuard aGuard( *this ); + if ( m_pImpl.is() ) + m_pImpl->setModified(sal_True); +} + +void SAL_CALL ODatabaseSource::elementRemoved( const ContainerEvent& /*Event*/ ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::elementRemoved" ); + ModelMethodGuard aGuard( *this ); + if ( m_pImpl.is() ) + m_pImpl->setModified(sal_True); +} + +void SAL_CALL ODatabaseSource::elementReplaced( const ContainerEvent& /*Event*/ ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::elementReplaced" ); + ModelMethodGuard aGuard( *this ); + if ( m_pImpl.is() ) + m_pImpl->setModified(sal_True); +} + +// XDocumentDataSource +Reference< XOfficeDatabaseDocument > SAL_CALL ODatabaseSource::getDatabaseDocument() throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getDatabaseDocument" ); + ModelMethodGuard aGuard( *this ); + + Reference< XModel > xModel( m_pImpl->getModel_noCreate() ); + if ( !xModel.is() ) + xModel = m_pImpl->createNewModel_deliverOwnership( false ); + + return Reference< XOfficeDatabaseDocument >( xModel, UNO_QUERY_THROW ); +} + +Reference< XInterface > ODatabaseSource::getThis() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getThis" ); + return *const_cast< ODatabaseSource* >( this ); +} + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/datasource.hxx b/dbaccess/source/core/dataaccess/datasource.hxx new file mode 100644 index 000000000000..6bc9175101f6 --- /dev/null +++ b/dbaccess/source/core/dataaccess/datasource.hxx @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 _DBA_COREDATAACCESS_DATASOURCE_HXX_ +#define _DBA_COREDATAACCESS_DATASOURCE_HXX_ + +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/container/XContainerListener.hpp> +#include <com/sun/star/sdb/XBookmarksSupplier.hpp> +#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp> +#include <com/sun/star/sdbc/XIsolatedConnection.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/document/XEventListener.hpp> +#include <com/sun/star/util/XFlushable.hpp> +#include <cppuhelper/propshlp.hxx> +#include <comphelper/proparrhlp.hxx> +#include <cppuhelper/weakref.hxx> +#include <cppuhelper/compbase11.hxx> +#include <com/sun/star/embed/XTransactionListener.hpp> +#include "apitools.hxx" +#include "bookmarkcontainer.hxx" +#include <rtl/ref.hxx> +#include <tools/string.hxx> +#include <connectivity/CommonTools.hxx> +#include <comphelper/broadcasthelper.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/sdb/XCompletedConnection.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include "ContentHelper.hxx" +#include <com/sun/star/document/XStorageBasedDocument.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/util/XRefreshable.hpp> +#include <com/sun/star/sdb/XDocumentDataSource.hpp> +#include "ModelImpl.hxx" + +namespace dbaccess +{ + +class OSharedConnectionManager; +class OChildCommitListen_Impl; + +//============================================================ +//= ODatabaseSource +//============================================================ +typedef ::cppu::WeakComponentImplHelper11 < ::com::sun::star::lang::XServiceInfo + , ::com::sun::star::sdbc::XDataSource + , ::com::sun::star::sdb::XBookmarksSupplier + , ::com::sun::star::sdb::XQueryDefinitionsSupplier + , ::com::sun::star::sdb::XCompletedConnection + , ::com::sun::star::container::XContainerListener + , ::com::sun::star::sdbc::XIsolatedConnection + , ::com::sun::star::sdbcx::XTablesSupplier + , ::com::sun::star::util::XFlushable + , ::com::sun::star::util::XFlushListener + , ::com::sun::star::sdb::XDocumentDataSource + > ODatabaseSource_Base; + + +class ODatabaseSource :public ModelDependentComponent // must be first + ,public ODatabaseSource_Base + ,public ::cppu::OPropertySetHelper + ,public ::comphelper::OPropertyArrayUsageHelper < ODatabaseSource > +{ + friend class ODatabaseContext; + friend class OConnection; + friend class OSharedConnectionManager; + +private: + using ODatabaseSource_Base::rBHelper; + OBookmarkContainer m_aBookmarks; + ::cppu::OInterfaceContainerHelper m_aFlushListeners; + +private: + virtual ~ODatabaseSource(); + +public: + ODatabaseSource( const ::rtl::Reference< ODatabaseModelImpl >& _pImpl ); + + struct DBContextAccess { friend class ODatabaseContext; private: DBContextAccess() { } }; + + /** sets a new name for the data source + + The name of a data source (our m_sName member) is the registration name, *if* the + data source actually *is* registered at the database context. + + Normally, this name is passed at time of creation of the ODatabaseModelImpl instance, + but if a newly creaed data source is registered, then it must be possible to propagate + the new trgistration name. + */ + static void setName( + const ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XDocumentDataSource >& _rxDocument, + const ::rtl::OUString& _rNewName, + DBContextAccess + ); + + // XContainerListener + virtual void SAL_CALL elementInserted( const ::com::sun::star::container::ContainerEvent& Event ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL elementRemoved( const ::com::sun::star::container::ContainerEvent& Event ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL elementReplaced( const ::com::sun::star::container::ContainerEvent& Event ) throw (::com::sun::star::uno::RuntimeException); + // ::com::sun::star::sdbcx::XTablesSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getTables( ) throw(::com::sun::star::uno::RuntimeException); + +// com::sun::star::lang::XTypeProvider + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes() throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() throw (::com::sun::star::uno::RuntimeException); + +// com::sun::star::uno::XInterface + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL acquire() throw( ); + virtual void SAL_CALL release() throw( ); + +// ::com::sun::star::lang::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); + +// ::com::sun::star::lang::XServiceInfo - static methods + 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 >&); + +// OComponentHelper + virtual void SAL_CALL disposing(void); + +// com::sun::star::beans::XPropertySet + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw(::com::sun::star::uno::RuntimeException); + // XEventListener + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw(::com::sun::star::uno::RuntimeException); + +// comphelper::OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const; + +// cppu::OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper(); + + 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 void SAL_CALL getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle ) const; + +// ::com::sun::star::sdb::XCompletedConnection + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection > SAL_CALL connectWithCompletion( const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& handler ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + +// ::com::sun::star::sdbc::XDataSource + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection > SAL_CALL getConnection( const ::rtl::OUString& user, const ::rtl::OUString& password ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setLoginTimeout( sal_Int32 seconds ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getLoginTimeout( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + +// :: com::sun::star::sdb::XBookmarksSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getBookmarks( ) throw (::com::sun::star::uno::RuntimeException); + +// :: com::sun::star::sdb::XQueryDefinitionsSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getQueryDefinitions( ) throw(::com::sun::star::uno::RuntimeException); + +// ::com::sun::star::sdbc::XIsolatedConnection + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection > SAL_CALL getIsolatedConnection( const ::rtl::OUString& user, const ::rtl::OUString& password ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection > SAL_CALL getIsolatedConnectionWithCompletion( const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& handler ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + +// XFlushable + virtual void SAL_CALL flush( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addFlushListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XFlushListener >& l ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeFlushListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XFlushListener >& l ) throw (::com::sun::star::uno::RuntimeException); + + // XFlushListener + virtual void SAL_CALL flushed( const ::com::sun::star::lang::EventObject& rEvent ) throw (::com::sun::star::uno::RuntimeException); + + // XDocumentDataSource + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XOfficeDatabaseDocument > SAL_CALL getDatabaseDocument() throw (::com::sun::star::uno::RuntimeException); + +protected: + // ModelDependentComponent overridables + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > getThis() const; + +private: +// helper + /** open a connection for the current settings. this is the simple connection we get from the driver + manager, so it can be used as a master for a "high level" sdb connection. + */ + ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection > buildLowLevelConnection( + const ::rtl::OUString& _rUid, const ::rtl::OUString& _rPwd + ); + + ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection > buildIsolatedConnection( + const rtl::OUString& user, const rtl::OUString& password + ); + + ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection > SAL_CALL getConnection( const ::rtl::OUString& user, const ::rtl::OUString& password , sal_Bool _bIsolated) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection > SAL_CALL connectWithCompletion( const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& handler , sal_Bool _bIsolated) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + + void clearConnections(); + +protected: + using ::cppu::OPropertySetHelper::getFastPropertyValue; +}; + +} // namespace dbaccess + +#endif // _DBA_COREDATAACCESS_DATALINK_HXX_ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/definitioncontainer.cxx b/dbaccess/source/core/dataaccess/definitioncontainer.cxx new file mode 100644 index 000000000000..0efce9c4aa11 --- /dev/null +++ b/dbaccess/source/core/dataaccess/definitioncontainer.cxx @@ -0,0 +1,681 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +#include "definitioncontainer.hxx" +#include "dbastrings.hrc" +#include "apitools.hxx" +#include "core_resource.hxx" +#include "core_resource.hrc" + +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <comphelper/sequence.hxx> +#include <comphelper/enumhelper.hxx> +#include <comphelper/extract.hxx> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/ucb/CommandInfo.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdb/ErrorCondition.hpp> +#include <comphelper/types.hxx> +#include <ucbhelper/contentidentifier.hxx> + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdb; +using namespace ::osl; +using namespace ::comphelper; +using namespace ::cppu; +using namespace ::com::sun::star::ucb; + +namespace dbaccess +{ + +//========================================================================== +//= ODefinitionContainer_Impl +//========================================================================== +void ODefinitionContainer_Impl::erase( TContentPtr _pDefinition ) +{ + NamedDefinitions::iterator aPos = find( _pDefinition ); + if ( aPos != end() ) + m_aDefinitions.erase( aPos ); +} + +ODefinitionContainer_Impl::const_iterator ODefinitionContainer_Impl::find( TContentPtr _pDefinition ) const +{ + return ::std::find_if( + m_aDefinitions.begin(), + m_aDefinitions.end(), + ::std::compose1( + ::std::bind2nd( ::std::equal_to< TContentPtr >(), _pDefinition ), + ::std::select2nd< NamedDefinitions::value_type >() + ) + ); +} + +ODefinitionContainer_Impl::iterator ODefinitionContainer_Impl::find( TContentPtr _pDefinition ) +{ + return ::std::find_if( + m_aDefinitions.begin(), + m_aDefinitions.end(), + ::std::compose1( + ::std::bind2nd( ::std::equal_to< TContentPtr >(), _pDefinition ), + ::std::select2nd< NamedDefinitions::value_type >() + ) + ); +} + +//========================================================================== +//= ODefinitionContainer +//========================================================================== +DBG_NAME(ODefinitionContainer) + +ODefinitionContainer::ODefinitionContainer( const Reference< XMultiServiceFactory >& _xORB + , const Reference< XInterface >& _xParentContainer + , const TContentPtr& _pImpl + , bool _bCheckSlash + ) + :OContentHelper(_xORB,_xParentContainer,_pImpl) + ,m_aApproveListeners(m_aMutex) + ,m_aContainerListeners(m_aMutex) + ,m_bInPropertyChange(sal_False) + ,m_bCheckSlash(_bCheckSlash) +{ + m_pImpl->m_aProps.bIsDocument = sal_False; + m_pImpl->m_aProps.bIsFolder = sal_True; + + const ODefinitionContainer_Impl& rDefinitions( getDefinitions() ); + ODefinitionContainer_Impl::const_iterator aEnd = rDefinitions.end(); + for ( ODefinitionContainer_Impl::const_iterator aDefinition = rDefinitions.begin(); + aDefinition != aEnd; + ++aDefinition + ) + m_aDocuments.push_back( + m_aDocumentMap.insert( + Documents::value_type( aDefinition->first, Documents::mapped_type() ) ).first ); + + DBG_CTOR(ODefinitionContainer, NULL); +} + +void SAL_CALL ODefinitionContainer::disposing() +{ + OContentHelper::disposing(); + + MutexGuard aGuard(m_aMutex); + + // say our listeners goobye + EventObject aEvt(*this); + m_aApproveListeners.disposeAndClear(aEvt); + m_aContainerListeners.disposeAndClear(aEvt); + + // dispose our elements + Documents::iterator aIter = m_aDocumentMap.begin(); + Documents::iterator aEnd = m_aDocumentMap.end(); + + for (; aIter != aEnd; ++aIter) + { + Reference<XContent> xProp = aIter->second; + if ( xProp.is() ) + { + removeObjectListener(xProp); + ::comphelper::disposeComponent(xProp); + } + } + + // remove our elements + m_aDocuments.clear(); + // !!! do this before clearing the map which the vector elements refer to !!! + m_aDocumentMap.clear(); +} + +ODefinitionContainer::~ODefinitionContainer() +{ + DBG_DTOR(ODefinitionContainer, NULL); +} + +IMPLEMENT_FORWARD_XINTERFACE2( ODefinitionContainer,OContentHelper,ODefinitionContainer_Base) +IMPLEMENT_TYPEPROVIDER2(ODefinitionContainer,OContentHelper,ODefinitionContainer_Base); +// XServiceInfo +::rtl::OUString SAL_CALL ODefinitionContainer::getImplementationName( ) throw(RuntimeException) +{ + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sdb.ODefinitionContainer")); +} + +Sequence< ::rtl::OUString > SAL_CALL ODefinitionContainer::getSupportedServiceNames( ) throw(RuntimeException) +{ + Sequence< ::rtl::OUString > aReturn(2); + aReturn.getArray()[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sdb.DefinitionContainer")); + aReturn.getArray()[1] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.Content")); + return aReturn; +} + +// XNameContainer +void SAL_CALL ODefinitionContainer::insertByName( const ::rtl::OUString& _rName, const Any& aElement ) throw(IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException) +{ + ResettableMutexGuard aGuard(m_aMutex); + + // approve the new object + Reference< XContent > xNewElement(aElement,UNO_QUERY); + approveNewObject( _rName, xNewElement ); // will throw if necessary + + notifyByName( aGuard, _rName, xNewElement, NULL, E_INSERTED, ApproveListeners ); + implAppend( _rName, xNewElement ); + notifyByName( aGuard, _rName, xNewElement, NULL, E_INSERTED, ContainerListemers ); +} + +void SAL_CALL ODefinitionContainer::removeByName( const ::rtl::OUString& _rName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException) +{ + ResettableMutexGuard aGuard(m_aMutex); + + // check the arguments + if (!_rName.getLength()) + throw IllegalArgumentException(); + + if (!checkExistence(_rName)) + throw NoSuchElementException(_rName,*this); + + // the old element (for the notifications) + Reference< XContent > xOldElement = implGetByName( _rName, impl_haveAnyListeners_nothrow() ); + + // do the removal + notifyByName( aGuard, _rName, NULL, xOldElement, E_REMOVED, ApproveListeners ); + implRemove( _rName ); + notifyByName( aGuard, _rName, NULL, xOldElement, E_REMOVED, ContainerListemers ); + + removeObjectListener( xOldElement ); + disposeComponent(xOldElement); +} + +// XNameReplace +void SAL_CALL ODefinitionContainer::replaceByName( const ::rtl::OUString& _rName, const Any& aElement ) throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException) +{ + ResettableMutexGuard aGuard(m_aMutex); + + // let derived classes approve the new object + Reference< XContent > xNewElement(aElement,UNO_QUERY); + approveNewObject( _rName, xNewElement ); // will throw if necessary + + // the old element (for the notifications) + Reference< XContent > xOldElement = implGetByName( _rName, impl_haveAnyListeners_nothrow() ); + + notifyByName( aGuard, _rName, xNewElement, xOldElement, E_REPLACED, ApproveListeners ); + implReplace( _rName, xNewElement ); + notifyByName( aGuard, _rName, xNewElement, xOldElement, E_REPLACED, ContainerListemers ); + + // and dispose it + disposeComponent(xOldElement); +} + +namespace +{ + typedef Reference< XVeto > ( SAL_CALL XContainerApproveListener::*ContainerApprovalMethod )( const ContainerEvent& ); + + struct RaiseExceptionFromVeto + { + private: + ContainerApprovalMethod m_pMethod; + const ContainerEvent& m_rEvent; + + public: + RaiseExceptionFromVeto( ContainerApprovalMethod _pMethod, const ContainerEvent& _rEvent ) + :m_pMethod( _pMethod ) + ,m_rEvent( _rEvent ) + { + } + + void operator()( const Reference< XContainerApproveListener >& _Listener ) const + { + Reference< XVeto > xVeto = (_Listener.get()->*m_pMethod)( m_rEvent ); + if ( !xVeto.is() ) + return; + + Any eVetoDetails = xVeto->getDetails(); + + IllegalArgumentException aIllegalArgumentError; + if ( eVetoDetails >>= aIllegalArgumentError ) + throw aIllegalArgumentError; + + WrappedTargetException aWrappedError; + if ( eVetoDetails >>= aWrappedError ) + throw aWrappedError; + + throw WrappedTargetException( xVeto->getReason(), _Listener.get(), eVetoDetails ); + } + }; +} + +void ODefinitionContainer::notifyByName( ResettableMutexGuard& _rGuard, const ::rtl::OUString& _rName, + const Reference< XContent >& _xNewElement, const Reference< XContent >& _xOldElement, + ContainerOperation _eOperation, ListenerType _eType ) +{ + bool bApprove = ( _eType == ApproveListeners ); + + ::cppu::OInterfaceContainerHelper& rContainer( bApprove ? m_aApproveListeners : m_aContainerListeners ); + if ( !rContainer.getLength() ) + return; + + ContainerEvent aEvent( *this, makeAny( _rName ), makeAny( _xNewElement ), makeAny( _xOldElement ) ); + + _rGuard.clear(); + switch ( _eOperation ) + { + case E_INSERTED: + if ( bApprove ) + rContainer.forEach< XContainerApproveListener, RaiseExceptionFromVeto >( + RaiseExceptionFromVeto( &XContainerApproveListener::approveInsertElement, aEvent ) ); + else + rContainer.notifyEach( &XContainerListener::elementInserted, aEvent ); + break; + case E_REPLACED: + if ( bApprove ) + rContainer.forEach< XContainerApproveListener, RaiseExceptionFromVeto >( + RaiseExceptionFromVeto( &XContainerApproveListener::approveReplaceElement, aEvent ) ); + else + rContainer.notifyEach( &XContainerListener::elementReplaced, aEvent ); + break; + case E_REMOVED: + if ( bApprove ) + rContainer.forEach< XContainerApproveListener, RaiseExceptionFromVeto >( + RaiseExceptionFromVeto( &XContainerApproveListener::approveRemoveElement, aEvent ) ); + else + rContainer.notifyEach( &XContainerListener::elementRemoved, aEvent ); + break; + } + + if ( bApprove ) + _rGuard.reset(); +} + +void SAL_CALL ODefinitionContainer::addContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException) +{ + if (_rxListener.is()) + m_aContainerListeners.addInterface(_rxListener); +} + +void SAL_CALL ODefinitionContainer::removeContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException) +{ + if (_rxListener.is()) + m_aContainerListeners.removeInterface(_rxListener); +} + +void SAL_CALL ODefinitionContainer::addContainerApproveListener( const Reference< XContainerApproveListener >& _Listener ) throw (RuntimeException) +{ + if ( _Listener.is() ) + m_aApproveListeners.addInterface( _Listener ); +} + +void SAL_CALL ODefinitionContainer::removeContainerApproveListener( const Reference< XContainerApproveListener >& _Listener ) throw (RuntimeException) +{ + if ( _Listener.is() ) + m_aApproveListeners.removeInterface( _Listener ); +} + +// XElementAccess +Type SAL_CALL ODefinitionContainer::getElementType( ) throw (RuntimeException) +{ + return ::getCppuType( static_cast< Reference< XContent >* >(NULL) ); +} + +sal_Bool SAL_CALL ODefinitionContainer::hasElements( ) throw (RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + return !m_aDocuments.empty(); +} + +// XEnumerationAccess +Reference< XEnumeration > SAL_CALL ODefinitionContainer::createEnumeration( ) throw(RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + return new ::comphelper::OEnumerationByIndex(static_cast<XIndexAccess*>(this)); +} + +// XIndexAccess +sal_Int32 SAL_CALL ODefinitionContainer::getCount( ) throw(RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + return m_aDocuments.size(); +} + +Any SAL_CALL ODefinitionContainer::getByIndex( sal_Int32 _nIndex ) throw(IndexOutOfBoundsException, WrappedTargetException, RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + + if ((_nIndex < 0) || (_nIndex >= (sal_Int32)m_aDocuments.size())) + throw IndexOutOfBoundsException(); + + Documents::iterator aPos = m_aDocuments[_nIndex]; + Reference<XContent> xProp = aPos->second; + if (!xProp.is()) + { // that's the first access to the object + // -> create it + xProp = createObject(aPos->first); + aPos->second = Documents::mapped_type(); + // and update the name-access map + } + + return makeAny(xProp); +} + +Any SAL_CALL ODefinitionContainer::getByName( const ::rtl::OUString& _rName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + + return makeAny( implGetByName( _rName, sal_True ) ); +} + +Reference< XContent > ODefinitionContainer::implGetByName(const ::rtl::OUString& _rName, sal_Bool _bReadIfNeccessary) throw (NoSuchElementException) +{ + Documents::iterator aMapPos = m_aDocumentMap.find(_rName); + if (aMapPos == m_aDocumentMap.end()) + throw NoSuchElementException(_rName,*this); + + Reference< XContent > xProp = aMapPos->second; + + if (_bReadIfNeccessary && !xProp.is()) + { // the object has never been accessed before, so we have to read it now + // (that's the expensive part) + + // create the object and insert it into the map + xProp = createObject(_rName); + aMapPos->second = xProp; + addObjectListener(xProp); + } + + return xProp; +} + +Sequence< ::rtl::OUString > SAL_CALL ODefinitionContainer::getElementNames( ) throw(RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + + Sequence< ::rtl::OUString > aNames(m_aDocumentMap.size()); + ::rtl::OUString* pNames = aNames.getArray(); + Documents::iterator aEnd = m_aDocumentMap.end(); + for ( Documents::iterator aNameIter = m_aDocumentMap.begin(); + aNameIter != aEnd; + ++pNames, ++aNameIter + ) + { + *pNames = aNameIter->first; + } + + return aNames; +} + +sal_Bool SAL_CALL ODefinitionContainer::hasByName( const ::rtl::OUString& _rName ) throw(RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + + return checkExistence(_rName); +} + +void SAL_CALL ODefinitionContainer::disposing( const EventObject& _rSource ) throw(RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + Reference< XContent > xSource(_rSource.Source, UNO_QUERY); + // it's one of our documents .... + Documents::iterator aIter = m_aDocumentMap.begin(); + Documents::iterator aEnd = m_aDocumentMap.end(); + for (;aIter != aEnd;++aIter ) + { + if ( xSource == aIter->second.get() ) + { + removeObjectListener(xSource); + // and clear our document map/vector, so the object will be recreated on next access + aIter->second = Documents::mapped_type(); + } + } +} + +void ODefinitionContainer::implRemove(const ::rtl::OUString& _rName) +{ + // from the object maps + Documents::iterator aFind = m_aDocumentMap.find(_rName); + if ( aFind != m_aDocumentMap.end() ) + { + m_aDocuments.erase( ::std::find(m_aDocuments.begin(),m_aDocuments.end(),aFind)); + m_aDocumentMap.erase(aFind); + + getDefinitions().erase( _rName ); + + notifyDataSourceModified(); + } +} + +namespace +{ + bool lcl_ensureName( const Reference< XContent >& _rxContent, const ::rtl::OUString& _rName ) + { + if ( !_rxContent.is() ) + return true; + + // obtain the current name. If it's the same as the new one, + // don't do anything + try + { + Reference< XPropertySet > xProps( _rxContent, UNO_QUERY ); + if ( xProps.is() ) + { + ::rtl::OUString sCurrentName; + OSL_VERIFY( xProps->getPropertyValue( PROPERTY_NAME ) >>= sCurrentName ); + if ( sCurrentName.equals( _rName ) ) + return true; + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "lcl_ensureName: caught an exception while obtaining the current name!" ); + } + + // set the new name + Reference< XRename > xRename( _rxContent, UNO_QUERY ); + OSL_ENSURE( xRename.is(), "lcl_ensureName: invalid content (not renameable)!" ); + if ( !xRename.is() ) + return false; + try + { + xRename->rename( _rName ); + return true; + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "lcl_ensureName: caught an exception!" ); + } + return false; + } +} + +void ODefinitionContainer::implAppend(const ::rtl::OUString& _rName, const Reference< XContent >& _rxNewObject) +{ + MutexGuard aGuard(m_aMutex); + try + { + Reference<XChild> xChild(_rxNewObject,UNO_QUERY); + if ( xChild.is() ) + xChild->setParent(static_cast<OWeakObject*>(this)); + + ODefinitionContainer_Impl& rDefinitions( getDefinitions() ); + ODefinitionContainer_Impl::const_iterator aFind = rDefinitions.find( _rName ); + if ( aFind == rDefinitions.end() ) + { + // ensure that the new object thas the proper name. + // Somebody could create an object with name "foo", and insert it as "bar" + // into a container. In this case, we need to ensure that the object name + // is also "bar" + // #i44786# / 2005-03-11 / frank.schoenheit@sun.com + lcl_ensureName( _rxNewObject, _rName ); + + ::rtl::Reference< OContentHelper > pContent = OContentHelper::getImplementation( _rxNewObject ); + if ( pContent.is() ) + { + TContentPtr pImpl = pContent->getImpl(); + rDefinitions.erase( pImpl ); + pImpl->m_aProps.aTitle = _rName; + rDefinitions.insert( _rName, pImpl ); + } + } + + + m_aDocuments.push_back(m_aDocumentMap.insert(Documents::value_type(_rName,_rxNewObject)).first); + notifyDataSourceModified(); + // now update our structures + if ( _rxNewObject.is() ) + addObjectListener(_rxNewObject); + } + catch(Exception&) + { + DBG_ERROR("ODefinitionContainer::implAppend: caught something !"); + } +} + +void ODefinitionContainer::implReplace(const ::rtl::OUString& _rName, const Reference< XContent >& _rxNewObject) +{ + DBG_ASSERT(checkExistence(_rName), "ODefinitionContainer::implReplace : invalid name !"); + + Documents::iterator aFind = m_aDocumentMap.find(_rName); + removeObjectListener(aFind->second); + aFind->second = _rxNewObject; + addObjectListener(aFind->second); +} + +void ODefinitionContainer::approveNewObject(const ::rtl::OUString& _sName,const Reference< XContent >& _rxObject) const +{ + // check the arguments + if ( !_sName.getLength() ) + throw IllegalArgumentException( + DBA_RES( RID_STR_NAME_MUST_NOT_BE_EMPTY ), + *this, + 0 ); + + if ( m_bCheckSlash && _sName.indexOf( '/' ) != -1 ) + throw IllegalArgumentException( + m_aErrorHelper.getErrorMessage( ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES ), + *this, + 0 ); + + if ( !_rxObject.is() ) + throw IllegalArgumentException( + DBA_RES( RID_STR_NO_NULL_OBJECTS_IN_CONTAINER ), + *this, + 0 ); + + const ODefinitionContainer_Impl& rDefinitions( getDefinitions() ); + if ( rDefinitions.find( _sName ) != rDefinitions.end() ) + throw ElementExistException( + DBA_RES( RID_STR_NAME_ALREADY_USED ), + *this ); + + ::rtl::Reference< OContentHelper > pContent( OContentHelper::getImplementation( _rxObject ) ); + if ( !pContent.is() ) + throw IllegalArgumentException( + DBA_RES( RID_STR_OBJECT_CONTAINER_MISMATCH ), + *this, + 1 ); + + if ( rDefinitions.find( pContent->getImpl() ) != rDefinitions.end() ) + throw ElementExistException( + DBA_RES( RID_STR_OBJECT_ALREADY_CONTAINED ), + *this ); +} + +// XPropertyChangeListener +void SAL_CALL ODefinitionContainer::propertyChange( const PropertyChangeEvent& evt ) throw (RuntimeException) +{ + ClearableMutexGuard aGuard(m_aMutex); + if(evt.PropertyName == (rtl::OUString) PROPERTY_NAME || evt.PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) )) + { + m_bInPropertyChange = sal_True; + try + { + ::rtl::OUString sNewName,sOldName; + evt.OldValue >>= sOldName; + evt.NewValue >>= sNewName; + Reference<XContent> xContent( evt.Source, UNO_QUERY ); + removeObjectListener( xContent ); + implRemove( sOldName ); + implAppend( sNewName, xContent ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + throw RuntimeException(); + } + m_bInPropertyChange = sal_False; + } +} + +// XVetoableChangeListener +void SAL_CALL ODefinitionContainer::vetoableChange( const PropertyChangeEvent& aEvent ) throw (PropertyVetoException, RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + + if(aEvent.PropertyName == (rtl::OUString) PROPERTY_NAME || aEvent.PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) + { + ::rtl::OUString sNewName; + aEvent.NewValue >>= sNewName; + if(hasByName(sNewName)) + throw PropertyVetoException(); + } +} + +void ODefinitionContainer::addObjectListener(const Reference< XContent >& _xNewObject) +{ + OSL_ENSURE(_xNewObject.is(),"ODefinitionContainer::addObjectListener: Object is null!"); + Reference<XPropertySet> xProp(_xNewObject,UNO_QUERY); + if ( xProp.is() ) + { + xProp->addPropertyChangeListener(PROPERTY_NAME, this); + xProp->addVetoableChangeListener(PROPERTY_NAME, this); + } +} + +void ODefinitionContainer::removeObjectListener(const Reference< XContent >& _xNewObject) +{ + Reference<XPropertySet> xProp(_xNewObject,UNO_QUERY); + if ( xProp.is() ) + { + xProp->removePropertyChangeListener(PROPERTY_NAME, this); + xProp->removeVetoableChangeListener(PROPERTY_NAME, this); + } +} + +sal_Bool ODefinitionContainer::checkExistence(const ::rtl::OUString& _rName) +{ + return m_aDocumentMap.find(_rName) != m_aDocumentMap.end(); +} + +} +// namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documentcontainer.cxx b/dbaccess/source/core/dataaccess/documentcontainer.cxx new file mode 100644 index 000000000000..8c59233ce28c --- /dev/null +++ b/dbaccess/source/core/dataaccess/documentcontainer.cxx @@ -0,0 +1,784 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +#include "documentcontainer.hxx" +#include "dbastrings.hrc" +#include "documentdefinition.hxx" +#include <com/sun/star/ucb/OpenCommandArgument2.hpp> +#include <com/sun/star/ucb/OpenMode.hpp> +#include <tools/debug.hxx> +#include <connectivity/dbtools.hxx> +#include "myucp_resultset.hxx" +#include <ucbhelper/cancelcommandexecution.hxx> +#include <com/sun/star/ucb/UnsupportedOpenModeException.hpp> +#include <com/sun/star/ucb/InsertCommandArgument.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdb/ErrorCondition.hpp> +#include "datasource.hxx" +#include <comphelper/classids.hxx> +#include <comphelper/mimeconfighelper.hxx> +#include <comphelper/string.hxx> +#include <connectivity/sqlerror.hxx> +#include "core_resource.hxx" +#include "core_resource.hrc" +#include <comphelper/namedvaluecollection.hxx> + +#include <vcl/svapp.hxx> +#include <osl/mutex.hxx> +#include <comphelper/namedvaluecollection.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::io; +using namespace ::osl; +using namespace ::comphelper; +using namespace ::cppu; + +namespace dbaccess +{ + +//========================================================================== +//= LocalNameApproval +//========================================================================== +class LocalNameApproval : public IContainerApprove +{ + ::connectivity::SQLError m_aErrors; + +public: + LocalNameApproval( const Reference< XMultiServiceFactory >& _rxFactory ) + :m_aErrors( ::comphelper::ComponentContext( _rxFactory ) ) + { + } + virtual ~LocalNameApproval() + { + } + + void SAL_CALL approveElement( const ::rtl::OUString& _rName, const Reference< XInterface >& _rxElement ); +}; + +void SAL_CALL LocalNameApproval::approveElement( const ::rtl::OUString& _rName, const Reference< XInterface >& /*_rxElement*/ ) +{ + if ( _rName.indexOf( '/' ) != -1 ) + throw IllegalArgumentException( + m_aErrors.getErrorMessage( ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES ), + NULL, + 0 + ); +} + +//========================================================================== +//= ODocumentContainer +//========================================================================== +DBG_NAME(ODocumentContainer) + +ODocumentContainer::ODocumentContainer(const Reference< XMultiServiceFactory >& _xORB + ,const Reference< XInterface >& _xParentContainer + ,const TContentPtr& _pImpl + , sal_Bool _bFormsContainer + ) + :ODefinitionContainer(_xORB,_xParentContainer,_pImpl) + ,OPropertyStateContainer(OContentHelper::rBHelper) + ,m_bFormsContainer(_bFormsContainer) +{ + DBG_CTOR(ODocumentContainer, NULL); + registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::BOUND | PropertyAttribute::READONLY | PropertyAttribute::CONSTRAINED, + &m_pImpl->m_aProps.aTitle, ::getCppuType(&m_pImpl->m_aProps.aTitle)); + + setElementApproval( PContainerApprove( new LocalNameApproval ( _xORB ) ) ); +} + +ODocumentContainer::~ODocumentContainer() +{ + DBG_DTOR(ODocumentContainer, NULL); + + if ( !OContentHelper::rBHelper.bInDispose && !OContentHelper::rBHelper.bDisposed ) + { + acquire(); + dispose(); + } +} + +IMPLEMENT_FORWARD_XINTERFACE3( ODocumentContainer,ODefinitionContainer,ODocumentContainer_Base,OPropertyStateContainer) +IMPLEMENT_TYPEPROVIDER3(ODocumentContainer,ODefinitionContainer,OPropertyStateContainer,ODocumentContainer_Base); +IMPLEMENT_SERVICE_INFO_IMPLNAME(ODocumentContainer, "com.sun.star.comp.dba.ODocumentContainer"); +IMPLEMENT_SERVICE_INFO_SUPPORTS(ODocumentContainer); +IMPLEMENT_PROPERTYCONTAINER_DEFAULTS(ODocumentContainer) + +Sequence< ::rtl::OUString > SAL_CALL ODocumentContainer::getSupportedServiceNames( ) throw(RuntimeException) +{ + Sequence< ::rtl::OUString > aSupported(1); + aSupported[0] = m_bFormsContainer ? SERVICE_NAME_FORM_COLLECTION : SERVICE_NAME_REPORT_COLLECTION; + return aSupported; +} + +::rtl::OUString ODocumentContainer::determineContentType() const +{ + return ::rtl::OUString(); +} + +Reference< XContent > ODocumentContainer::createObject( const ::rtl::OUString& _rName) +{ + const ODefinitionContainer_Impl& rDefinitions( getDefinitions() ); + ODefinitionContainer_Impl::const_iterator aFind = rDefinitions.find( _rName ); + OSL_ENSURE( aFind != rDefinitions.end(), "ODocumentContainer::createObject:Invalid entry in map!" ); + if ( aFind->second->m_aProps.bIsFolder ) + return new ODocumentContainer( m_aContext.getLegacyServiceFactory(), *this, aFind->second, m_bFormsContainer ); + return new ODocumentDefinition( *this, m_aContext.getLegacyServiceFactory(), aFind->second, m_bFormsContainer ); +} + +Reference< XInterface > SAL_CALL ODocumentContainer::createInstance( const ::rtl::OUString& aServiceSpecifier ) throw (Exception, RuntimeException) +{ + return createInstanceWithArguments( aServiceSpecifier, Sequence< Any >() ); +} + +namespace +{ + template< class TYPE > + void lcl_extractAndRemove( ::comphelper::NamedValueCollection& io_rArguments, const ::rtl::OUString& i_rName, TYPE& o_rValue ) + { + if ( io_rArguments.has( i_rName ) ) + { + io_rArguments.get_ensureType( i_rName, o_rValue ); + io_rArguments.remove( i_rName ); + } + } +} + +Reference< XInterface > SAL_CALL ODocumentContainer::createInstanceWithArguments( const ::rtl::OUString& ServiceSpecifier, const Sequence< Any >& _aArguments ) throw (Exception, RuntimeException) +{ + Reference< XInterface > xRet; + Reference< XContent > xContent; + if ( ServiceSpecifier == SERVICE_SDB_DOCUMENTDEFINITION ) + { + MutexGuard aGuard(m_aMutex); + + // extrat known arguments + ::rtl::OUString sName, sPersistentName, sURL, sMediaType, sDocServiceName; + Reference< XCommandProcessor > xCopyFrom; + Reference< XConnection > xConnection; + sal_Bool bAsTemplate( sal_False ); + Sequence< sal_Int8 > aClassID; + + ::comphelper::NamedValueCollection aArgs( _aArguments ); + lcl_extractAndRemove( aArgs, PROPERTY_NAME, sName ); + lcl_extractAndRemove( aArgs, PROPERTY_PERSISTENT_NAME, sPersistentName ); + lcl_extractAndRemove( aArgs, PROPERTY_URL, sURL ); + lcl_extractAndRemove( aArgs, PROPERTY_EMBEDDEDOBJECT, xCopyFrom ); + lcl_extractAndRemove( aArgs, PROPERTY_ACTIVE_CONNECTION, xConnection ); + lcl_extractAndRemove( aArgs, PROPERTY_AS_TEMPLATE, bAsTemplate ); + lcl_extractAndRemove( aArgs, INFO_MEDIATYPE, sMediaType ); + lcl_extractAndRemove( aArgs, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DocumentServiceName" ) ), sDocServiceName ); + + // ClassID has two allowed types, so a special treatment here + Any aClassIDArg = aArgs.get( "ClassID" ); + if ( aClassIDArg.hasValue() ) + { + if ( !( aClassIDArg >>= aClassID ) ) + { + // Extended for usage also with a string + ::rtl::OUString sClassIDString; + if ( !( aClassIDArg >>= sClassIDString ) ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 2 ); + + aClassID = ::comphelper::MimeConfigurationHelper::GetSequenceClassIDRepresentation( sClassIDString ); + } + +#if OSL_DEBUG_LEVEL > 0 + ::rtl::OUString sClassIDString = ::comphelper::MimeConfigurationHelper::GetStringClassIDRepresentation( aClassID ); + (void)sClassIDString; +#endif + aArgs.remove( "ClassID" ); + } + // Everything which now is still present in the arguments is passed to the embedded object + const Sequence< PropertyValue > aCreationArgs( aArgs.getPropertyValues() ); + + const ODefinitionContainer_Impl& rDefinitions( getDefinitions() ); + sal_Bool bNew = ( 0 == sPersistentName.getLength() ); + if ( bNew ) + { + const static ::rtl::OUString sBaseName(RTL_CONSTASCII_USTRINGPARAM("Obj")); + + sPersistentName = sBaseName; + sPersistentName += ::rtl::OUString::valueOf(sal_Int32(rDefinitions.size() + 1)); + Reference<XNameAccess> xElements(getContainerStorage(),UNO_QUERY); + if ( xElements.is() ) + sPersistentName = ::dbtools::createUniqueName(xElements,sPersistentName); + + const bool bNeedClassID = ( aClassID.getLength() == 0 ) && ( 0 == sURL.getLength() ); + if ( xCopyFrom.is() ) + { + Sequence<Any> aIni(2); + aIni[0] <<= getContainerStorage(); + aIni[1] <<= sPersistentName; + Command aCommand; + aCommand.Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("copyTo")); + aCommand.Argument <<= aIni; + + xCopyFrom->execute(aCommand,-1,Reference< XCommandEnvironment >()); + Reference<XPropertySet> xProp(xCopyFrom,UNO_QUERY); + if ( xProp.is() && xProp->getPropertySetInfo().is() && xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_AS_TEMPLATE) ) + xProp->getPropertyValue(PROPERTY_AS_TEMPLATE) >>= bAsTemplate; + + // if we do not have an own class ID, see if we can determine one from the copy we just created + if ( bNeedClassID ) + ODocumentDefinition::GetDocumentServiceFromMediaType( getContainerStorage(), sPersistentName, m_aContext, aClassID ); + } + else + { + if ( bNeedClassID ) + { + if ( sMediaType.getLength() ) + ODocumentDefinition::GetDocumentServiceFromMediaType( sMediaType, m_aContext, aClassID ); + else if ( sDocServiceName.getLength() ) + { + ::comphelper::MimeConfigurationHelper aConfigHelper( m_aContext.getLegacyServiceFactory() ); + const Sequence< NamedValue > aProps( aConfigHelper.GetObjectPropsByDocumentName( sDocServiceName ) ); + const ::comphelper::NamedValueCollection aMediaTypeProps( aProps ); + aClassID = aMediaTypeProps.getOrDefault( "ClassID", Sequence< sal_Int8 >() ); + } + } + } + } + + ODefinitionContainer_Impl::const_iterator aFind = rDefinitions.find( sName ); + TContentPtr pElementImpl; + if ( bNew || ( aFind == rDefinitions.end() ) ) + { + pElementImpl.reset( new OContentHelper_Impl ); + if ( !bNew ) + pElementImpl->m_aProps.aTitle = sName; + + pElementImpl->m_aProps.sPersistentName = sPersistentName; + pElementImpl->m_aProps.bAsTemplate = bAsTemplate; + pElementImpl->m_pDataSource = m_pImpl->m_pDataSource; + } + else + pElementImpl = aFind->second; + + ::rtl::Reference< ODocumentDefinition > pDocDef = new ODocumentDefinition( *this, m_aContext.getLegacyServiceFactory(), pElementImpl, m_bFormsContainer ); + if ( aClassID.getLength() ) + { + pDocDef->initialLoad( aClassID, aCreationArgs, xConnection ); + } + else + { + OSL_ENSURE( aCreationArgs.getLength() == 0, "ODocumentContainer::createInstance: additional creation args are lost, if you do not provide a class ID." ); + } + xContent = pDocDef.get(); + + if ( sURL.getLength() ) + { + Sequence<Any> aIni(2); + aIni[0] <<= sURL; + Command aCommand; + aCommand.Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("insert")); + aCommand.Argument <<= aIni; + Reference< XCommandProcessor > xCommandProcessor(xContent,UNO_QUERY); + if ( xContent.is() ) + { + xCommandProcessor->execute(aCommand,-1,Reference< XCommandEnvironment >()); + } + } + } + else if ( ServiceSpecifier == SERVICE_NAME_FORM_COLLECTION || SERVICE_NAME_REPORT_COLLECTION == ServiceSpecifier ) + { + const Any* pBegin = _aArguments.getConstArray(); + const Any* pEnd = pBegin + _aArguments.getLength(); + PropertyValue aValue; + ::rtl::OUString sName; + Reference<XNameAccess> xCopyFrom; + for(;pBegin != pEnd;++pBegin) + { + *pBegin >>= aValue; + if ( aValue.Name.equalsAscii(PROPERTY_NAME) ) + { + aValue.Value >>= sName; + } + else if ( aValue.Name.equalsAscii(PROPERTY_EMBEDDEDOBJECT) ) + { + xCopyFrom.set(aValue.Value,UNO_QUERY); + } + } + OSL_ENSURE(sName.getLength(),"Invalid name for a document container!"); + const ODefinitionContainer_Impl& rDefinitions( getDefinitions() ); + ODefinitionContainer_Impl::const_iterator aFind = rDefinitions.find( sName ); + TContentPtr pElementImpl; + if ( aFind == rDefinitions.end() ) + { + pElementImpl.reset(new ODefinitionContainer_Impl); + pElementImpl->m_aProps.aTitle = sName; + pElementImpl->m_pDataSource = m_pImpl->m_pDataSource; + } + else + pElementImpl = aFind->second; + OSL_ENSURE( pElementImpl ," Invalid entry in map!"); + xContent = new ODocumentContainer( m_aContext.getLegacyServiceFactory(), *this, pElementImpl, ServiceSpecifier == SERVICE_NAME_FORM_COLLECTION ); + + // copy children + if ( xCopyFrom.is() ) + { + Sequence< ::rtl::OUString> aSeq = xCopyFrom->getElementNames(); + const ::rtl::OUString* elements = aSeq.getConstArray(); + const ::rtl::OUString* elementsEnd = elements + aSeq.getLength(); + Reference<XContent> xObjectToCopy; + + Reference<XMultiServiceFactory> xORB(xContent,UNO_QUERY); + OSL_ENSURE(xORB.is(),"No service factory given"); + if ( xORB.is() ) + { + for(;elements != elementsEnd;++elements) + { + xCopyFrom->getByName(*elements) >>= xObjectToCopy; + Sequence< Any > aArguments(3); + PropertyValue aArgument; + // set as folder + aArgument.Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Name")); + aArgument.Value <<= *elements; + aArguments[0] <<= aArgument; + //parent + aArgument.Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Parent")); + aArgument.Value <<= xContent; + aArguments[1] <<= aArgument; + + aArgument.Name = PROPERTY_EMBEDDEDOBJECT; + aArgument.Value <<= xObjectToCopy; + aArguments[2] <<= aArgument; + + ::rtl::OUString sServiceName; + if ( Reference< XNameAccess >( xObjectToCopy, UNO_QUERY ).is() ) + { + if ( m_bFormsContainer ) + sServiceName = SERVICE_NAME_FORM_COLLECTION; + else + sServiceName = SERVICE_NAME_REPORT_COLLECTION; + } + else + sServiceName = SERVICE_SDB_DOCUMENTDEFINITION; + + Reference<XContent > xNew(xORB->createInstanceWithArguments(sServiceName,aArguments),UNO_QUERY); + Reference<XNameContainer> xNameContainer(xContent,UNO_QUERY); + if ( xNameContainer.is() ) + xNameContainer->insertByName(*elements,makeAny(xNew)); + } + } + } + } + xRet = xContent; + return xRet; +} + +Sequence< ::rtl::OUString > SAL_CALL ODocumentContainer::getAvailableServiceNames( ) throw (RuntimeException) +{ + Sequence< ::rtl::OUString > aSe(3); + aSe[0] = SERVICE_SDB_DOCUMENTDEFINITION; + aSe[1] = SERVICE_NAME_FORM_COLLECTION; + aSe[2] = SERVICE_NAME_REPORT_COLLECTION; + return aSe; +} + +Any SAL_CALL ODocumentContainer::execute( const Command& aCommand, sal_Int32 CommandId, const Reference< XCommandEnvironment >& Environment ) throw (Exception, CommandAbortedException, RuntimeException) +{ + Any aRet; + if ( aCommand.Name.compareToAscii( "open" ) == 0 ) + { + ////////////////////////////////////////////////////////////////// + // open command for a folder content + ////////////////////////////////////////////////////////////////// + OpenCommandArgument2 aOpenCommand; + if ( !( aCommand.Argument >>= aOpenCommand ) ) + { + OSL_ENSURE( sal_False, "Wrong argument type!" ); + ucbhelper::cancelCommandExecution( + makeAny( IllegalArgumentException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + sal_Bool bOpenFolder = + ( ( aOpenCommand.Mode == OpenMode::ALL ) || + ( aOpenCommand.Mode == OpenMode::FOLDERS ) || + ( aOpenCommand.Mode == OpenMode::DOCUMENTS ) ); + + if ( bOpenFolder ) + { + // open as folder - return result set + + Reference< XDynamicResultSet > xSet + = new DynamicResultSet( m_aContext.getLegacyServiceFactory(), + this, + aOpenCommand, + Environment ); + aRet <<= xSet; + } + else + { + // Unsupported. + ucbhelper::cancelCommandExecution( + makeAny( UnsupportedOpenModeException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + sal_Int16( aOpenCommand.Mode ) ) ), + Environment ); + // Unreachable + } + } + else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "insert" ) ) ) + { + ////////////////////////////////////////////////////////////////// + // insert + ////////////////////////////////////////////////////////////////// + + InsertCommandArgument arg; + if ( !( aCommand.Argument >>= arg ) ) + { + OSL_ENSURE( sal_False, "Wrong argument type!" ); + ucbhelper::cancelCommandExecution( + makeAny( IllegalArgumentException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + } + else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "delete" ) ) ) + { + ////////////////////////////////////////////////////////////////// + // delete + ////////////////////////////////////////////////////////////////// + Sequence< ::rtl::OUString> aSeq = getElementNames(); + const ::rtl::OUString* pIter = aSeq.getConstArray(); + const ::rtl::OUString* pEnd = pIter + aSeq.getLength(); + for(;pIter != pEnd;++pIter) + removeByName(*pIter); + + dispose(); + } + else + aRet = OContentHelper::execute(aCommand,CommandId,Environment); + return aRet; +} + +namespace +{ + sal_Bool lcl_queryContent(const ::rtl::OUString& _sName,Reference< XNameContainer >& _xNameContainer,Any& _rRet,::rtl::OUString& _sSimpleName) + { + sal_Bool bRet = sal_False; + sal_Int32 nIndex = 0; + ::rtl::OUString sName = _sName.getToken(0,'/',nIndex); + bRet = _xNameContainer->hasByName(sName); + if ( bRet ) + { + _rRet = _xNameContainer->getByName(_sSimpleName = sName); + while ( nIndex != -1 && bRet ) + { + sName = _sName.getToken(0,'/',nIndex); + _xNameContainer.set(_rRet,UNO_QUERY); + bRet = _xNameContainer.is(); + if ( bRet ) + { + bRet = _xNameContainer->hasByName(sName); + _sSimpleName = sName; + if ( bRet ) + _rRet = _xNameContainer->getByName(sName); + } + } + } + if ( nIndex == -1 ) + _sSimpleName = sName; // a content + else + _xNameContainer.clear(); // a sub folder doesn't exist + return bRet; + } +} + +Reference< XComponent > SAL_CALL ODocumentContainer::loadComponentFromURL( const ::rtl::OUString& _sURL + , const ::rtl::OUString& /*TargetFrameName*/ + , sal_Int32 /*SearchFlags*/ + , const Sequence< PropertyValue >& Arguments ) throw (IOException, IllegalArgumentException, RuntimeException) +{ + ::SolarMutexGuard aSolarGuard; + + MutexGuard aGuard(m_aMutex); + Reference< XComponent > xComp; + try + { + Any aContent; + Reference< XNameContainer > xNameContainer(this); + ::rtl::OUString sName; + if ( !lcl_queryContent(_sURL,xNameContainer,aContent,sName) ) + { + ::rtl::OUString sMessage( DBA_RES( RID_STR_NAME_NOT_FOUND ) ); + ::comphelper::string::searchAndReplaceAsciiI( sMessage, "$name$", _sURL ); + throw IllegalArgumentException( sMessage, *this, 1 ); + } + + Reference< XCommandProcessor > xContent(aContent,UNO_QUERY); + if ( xContent.is() ) + { + Command aCommand; + + ::comphelper::NamedValueCollection aArgs( Arguments ); + aCommand.Name = aArgs.getOrDefault( "OpenMode", ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "open" ) ) ); + aArgs.remove( "OpenMode" ); + + OpenCommandArgument2 aOpenCommand; + aOpenCommand.Mode = OpenMode::DOCUMENT; + aArgs.put( "OpenCommandArgument", aOpenCommand ); + + aCommand.Argument <<= aArgs.getPropertyValues(); + xComp.set(xContent->execute(aCommand,xContent->createCommandIdentifier(),Reference< XCommandEnvironment >()),UNO_QUERY); + } + } + catch(NoSuchElementException) + { + throw IllegalArgumentException(); + } + catch(WrappedTargetException e) + { + // throw IllegalArgumentException(); + throw; + } + return xComp; +} + +Any SAL_CALL ODocumentContainer::getByHierarchicalName( const ::rtl::OUString& _sName ) throw (NoSuchElementException, RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + Any aContent; + Reference< XNameContainer > xNameContainer(this); + ::rtl::OUString sName; + if ( lcl_queryContent(_sName,xNameContainer,aContent,sName) ) + return aContent; + throw NoSuchElementException(_sName,*this); +} + +sal_Bool SAL_CALL ODocumentContainer::hasByHierarchicalName( const ::rtl::OUString& _sName ) throw (RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + Any aContent; + Reference< XNameContainer > xNameContainer(this); + ::rtl::OUString sName; + return lcl_queryContent(_sName,xNameContainer,aContent,sName); +} + +// XHierarchicalNameContainer +void SAL_CALL ODocumentContainer::insertByHierarchicalName( const ::rtl::OUString& _sName, const Any& _aElement ) throw (IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException) +{ + Reference< XContent > xContent(_aElement,UNO_QUERY); + if ( !xContent.is() ) + throw IllegalArgumentException(); + + ClearableMutexGuard aGuard(m_aMutex); + Any aContent; + Reference< XNameContainer > xNameContainer(this); + ::rtl::OUString sName; + if ( lcl_queryContent(_sName,xNameContainer,aContent,sName) ) + throw ElementExistException(_sName,*this); + + if ( !xNameContainer.is() ) + { + ::rtl::OUString sMessage( DBA_RES( RID_STR_NO_SUB_FOLDER ) ); + sal_Int32 index = sName.getLength(); + ::comphelper::string::searchAndReplaceAsciiI( sMessage, "$folder$", _sName.getToken(0,'/',index) ); + throw IllegalArgumentException( sMessage, *this, 1 ); + } + + xNameContainer->insertByName(sName,_aElement); +} + +void SAL_CALL ODocumentContainer::removeByHierarchicalName( const ::rtl::OUString& _sName ) throw (NoSuchElementException, WrappedTargetException, RuntimeException) +{ + if ( !_sName.getLength() ) + throw NoSuchElementException(_sName,*this); + + ClearableMutexGuard aGuard(m_aMutex); + Any aContent; + ::rtl::OUString sName; + Reference< XNameContainer > xNameContainer(this); + if ( !lcl_queryContent(_sName,xNameContainer,aContent,sName) ) + throw NoSuchElementException(_sName,*this); + + xNameContainer->removeByName(sName); +} + +// XHierarchicalNameReplace +void SAL_CALL ODocumentContainer::replaceByHierarchicalName( const ::rtl::OUString& _sName, const Any& _aElement ) throw (IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException) +{ + Reference< XContent > xContent(_aElement,UNO_QUERY); + if ( !xContent.is() ) + throw IllegalArgumentException(); + + ClearableMutexGuard aGuard(m_aMutex); + Any aContent; + ::rtl::OUString sName; + Reference< XNameContainer > xNameContainer(this); + if ( !lcl_queryContent(_sName,xNameContainer,aContent,sName) ) + throw NoSuchElementException(_sName,*this); + + xNameContainer->replaceByName(sName,_aElement); +} + +::rtl::OUString SAL_CALL ODocumentContainer::getHierarchicalName() throw (RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + return impl_getHierarchicalName( false ); +} + +::rtl::OUString SAL_CALL ODocumentContainer::composeHierarchicalName( const ::rtl::OUString& i_rRelativeName ) throw (IllegalArgumentException, NoSupportException, RuntimeException) +{ + ::rtl::OUStringBuffer aBuffer; + aBuffer.append( getHierarchicalName() ); + aBuffer.append( sal_Unicode( '/' ) ); + aBuffer.append( i_rRelativeName ); + return aBuffer.makeStringAndClear(); +} + +::rtl::Reference<OContentHelper> ODocumentContainer::getContent(const ::rtl::OUString& _sName) const +{ + ::rtl::Reference<OContentHelper> pContent = NULL; + try + { + Reference<XUnoTunnel> xUnoTunnel(const_cast<ODocumentContainer*>(this)->implGetByName( _sName, sal_True ), UNO_QUERY ); + if ( xUnoTunnel.is() ) + pContent = reinterpret_cast<OContentHelper*>(xUnoTunnel->getSomething(OContentHelper::getUnoTunnelImplementationId())); + } + catch(Exception) + { + } + return pContent; +} + +void ODocumentContainer::getPropertyDefaultByHandle( sal_Int32 /*_nHandle*/, Any& _rDefault ) const +{ + _rDefault.clear(); +} + +void SAL_CALL ODocumentContainer::commit( ) throw (::com::sun::star::io::IOException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + Documents::iterator aIter = m_aDocumentMap.begin(); + Documents::iterator aEnd = m_aDocumentMap.end(); + for (; aIter != aEnd ; ++aIter) + { + Reference<XTransactedObject> xTrans(aIter->second.get(),UNO_QUERY); + if ( xTrans.is() ) + xTrans->commit(); + } + Reference<XTransactedObject> xTrans(getContainerStorage(),UNO_QUERY); + if ( xTrans.is() ) + xTrans->commit(); +} + +void SAL_CALL ODocumentContainer::revert( ) throw (::com::sun::star::io::IOException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + Documents::iterator aIter = m_aDocumentMap.begin(); + Documents::iterator aEnd = m_aDocumentMap.end(); + for (; aIter != aEnd ; ++aIter) + { + Reference<XTransactedObject> xTrans(aIter->second.get(),UNO_QUERY); + if ( xTrans.is() ) + xTrans->revert(); + } + Reference<XTransactedObject> xTrans(getContainerStorage(),UNO_QUERY); + if ( xTrans.is() ) + xTrans->revert(); +} + +Reference< XStorage> ODocumentContainer::getContainerStorage() const +{ + return m_pImpl->m_pDataSource + ? m_pImpl->m_pDataSource->getStorage( m_bFormsContainer ? ODatabaseModelImpl::E_FORM : ODatabaseModelImpl::E_REPORT ) + : Reference< XStorage>(); +} + +void SAL_CALL ODocumentContainer::removeByName( const ::rtl::OUString& _rName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException) +{ + ResettableMutexGuard aGuard(m_aMutex); + + // check the arguments + if (!_rName.getLength()) + throw IllegalArgumentException(); + + if (!checkExistence(_rName)) + throw NoSuchElementException(_rName,*this); + + Reference< XCommandProcessor > xContent( implGetByName( _rName, sal_True ), UNO_QUERY ); + if ( xContent.is() ) + { + Command aCommand; + + aCommand.Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("delete")); + xContent->execute(aCommand,xContent->createCommandIdentifier(),Reference< XCommandEnvironment >()); + } + + // do the removal + implRemove(_rName); + + // disposeComponent(xContent); // no dispose here, the object may be inserted again under a different name + + notifyByName( aGuard, _rName, NULL, NULL, E_REMOVED, ContainerListemers ); +} + +void SAL_CALL ODocumentContainer::rename( const ::rtl::OUString& newName ) throw (SQLException, ElementExistException, RuntimeException) +{ + try + { + osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex); + if ( newName.equals( m_pImpl->m_aProps.aTitle ) ) + return; + + sal_Int32 nHandle = PROPERTY_ID_NAME; + Any aOld = makeAny(m_pImpl->m_aProps.aTitle); + Any aNew = makeAny(newName); + + aGuard.clear(); + fire(&nHandle, &aNew, &aOld, 1, sal_True ); + m_pImpl->m_aProps.aTitle = newName; + fire(&nHandle, &aNew, &aOld, 1, sal_False ); + } + catch(const PropertyVetoException&) + { + throw ElementExistException(newName,*this); + } +} + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documentcontainer.hxx b/dbaccess/source/core/dataaccess/documentcontainer.hxx new file mode 100644 index 000000000000..ffcdff6c9c19 --- /dev/null +++ b/dbaccess/source/core/dataaccess/documentcontainer.hxx @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 _DBA_COREDATAACCESS_DOCUMENTCONTAINER_HXX_ +#define _DBA_COREDATAACCESS_DOCUMENTCONTAINER_HXX_ + +#include "definitioncontainer.hxx" +#include <cppuhelper/implbase5.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/container/XHierarchicalNameContainer.hpp> +#include <com/sun/star/container/XHierarchicalName.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <comphelper/propertystatecontainer.hxx> +#include <comphelper/proparrhlp.hxx> +#include "apitools.hxx" + +namespace dbaccess +{ +typedef ::cppu::ImplHelper5 < ::com::sun::star::frame::XComponentLoader + , ::com::sun::star::lang::XMultiServiceFactory + , ::com::sun::star::container::XHierarchicalNameContainer + , ::com::sun::star::container::XHierarchicalName + , ::com::sun::star::embed::XTransactedObject + > ODocumentContainer_Base; +//========================================================================== +//= ODocumentContainer - collections of database documents (reports/forms) +//========================================================================== +class ODocumentContainer : public ODefinitionContainer + , public ODocumentContainer_Base + , public ::comphelper::OPropertyStateContainer + , public ::comphelper::OPropertyArrayUsageHelper< ODocumentContainer > +{ + sal_Bool m_bFormsContainer; + +public: + /** constructs the container.<BR> + */ + ODocumentContainer( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _xORB + , const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _xParentContainer + ,const TContentPtr& _pImpl + , sal_Bool _bFormsContainer + ); + + // ::com::sun::star::uno::XInterface + DECLARE_XINTERFACE( ) + // com::sun::star::lang::XTypeProvider + DECLARE_TYPEPROVIDER( ); + // ::com::sun::star::lang::XServiceInfo + DECLARE_SERVICE_INFO(); + + // XComponentLoader + virtual ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > SAL_CALL loadComponentFromURL( const ::rtl::OUString& URL, const ::rtl::OUString& TargetFrameName, sal_Int32 SearchFlags, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& Arguments ) throw (::com::sun::star::io::IOException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + + // ::com::sun::star::lang::XMultiServiceFactory + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstance( const ::rtl::OUString& aServiceSpecifier ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstanceWithArguments( const ::rtl::OUString& ServiceSpecifier, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Arguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getAvailableServiceNames( ) throw (::com::sun::star::uno::RuntimeException); + + // XCommandProcessor + virtual ::com::sun::star::uno::Any SAL_CALL execute( const ::com::sun::star::ucb::Command& aCommand, sal_Int32 CommandId, const ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >& Environment ) throw (::com::sun::star::uno::Exception, ::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::RuntimeException) ; + + // XHierarchicalNameAccess + virtual ::com::sun::star::uno::Any SAL_CALL getByHierarchicalName( const ::rtl::OUString& _sName ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasByHierarchicalName( const ::rtl::OUString& _sName ) throw (::com::sun::star::uno::RuntimeException); + + // XHierarchicalNameContainer + virtual void SAL_CALL insertByHierarchicalName( 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 removeByHierarchicalName( const ::rtl::OUString& Name ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XHierarchicalName + virtual ::rtl::OUString SAL_CALL getHierarchicalName( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL composeHierarchicalName( const ::rtl::OUString& aRelativeName ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + + // XNameContainer + virtual void SAL_CALL removeByName( const ::rtl::OUString& _rName ) throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XHierarchicalNameReplace + virtual void SAL_CALL replaceByHierarchicalName( 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); + + // ::com::sun::star::beans::XPropertySet + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw(::com::sun::star::uno::RuntimeException); + + // XTransactedObject + virtual void SAL_CALL commit( ) throw (::com::sun::star::io::IOException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL revert( ) throw (::com::sun::star::io::IOException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XRename + virtual void SAL_CALL rename( const ::rtl::OUString& newName ) throw (::com::sun::star::sdbc::SQLException, ::com::sun::star::container::ElementExistException, ::com::sun::star::uno::RuntimeException); + + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper(); + + // helper + ::rtl::Reference<OContentHelper> getContent(const ::rtl::OUString& _sName) const; + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > getContainerStorage() const; + +protected: + virtual ~ODocumentContainer(); + + /** OContentHelper + */ + virtual ::rtl::OUString determineContentType() const; + + // ODefinitionContainer + virtual ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContent > createObject( + const ::rtl::OUString& _rName + ); + + virtual void getPropertyDefaultByHandle( sal_Int32 _nHandle, ::com::sun::star::uno::Any& _rDefault ) const; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const; +}; + +} // namespace dbaccess + +#endif // _DBA_COREDATAACCESS_DOCUMENTCONTAINER_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documentdefinition.cxx b/dbaccess/source/core/dataaccess/documentdefinition.cxx new file mode 100644 index 000000000000..4bd8c8edfc72 --- /dev/null +++ b/dbaccess/source/core/dataaccess/documentdefinition.cxx @@ -0,0 +1,2211 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +#include "documentdefinition.hxx" +#include "dbastrings.hrc" +#include "sdbcoretools.hxx" +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <comphelper/property.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/mediadescriptor.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/classids.hxx> +#include <com/sun/star/frame/XUntitledNumbers.hpp> +#include <com/sun/star/awt/XTopWindow.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XTitle.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/task/XJobExecutor.hpp> +#include <com/sun/star/frame/XDispatchProviderInterception.hpp> +#include <com/sun/star/frame/XFramesSupplier.hpp> +#include <com/sun/star/ucb/InsertCommandArgument.hpp> +#include <com/sun/star/report/XReportDefinition.hpp> +#include <com/sun/star/report/XReportEngine.hpp> +#include <com/sun/star/ucb/OpenMode.hpp> +#include <com/sun/star/embed/XEmbedObjectFactory.hpp> +#include <com/sun/star/embed/XEmbedObjectCreator.hpp> +#include <com/sun/star/embed/Aspects.hpp> +#include <ucbhelper/cancelcommandexecution.hxx> +#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp> +#include <com/sun/star/ucb/UnsupportedOpenModeException.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XEmbedPersist.hpp> +#include <com/sun/star/embed/EmbedStates.hpp> +#include <com/sun/star/embed/XComponentSupplier.hpp> +#include <com/sun/star/embed/EntryInitModes.hpp> +#include <com/sun/star/ucb/MissingPropertiesException.hpp> +#include <com/sun/star/ucb/MissingInputStreamException.hpp> +#include <com/sun/star/ucb/OpenCommandArgument2.hpp> +#include <com/sun/star/util/XCloseBroadcaster.hpp> +#include <com/sun/star/frame/XModule.hpp> +#include <com/sun/star/datatransfer/DataFlavor.hpp> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/embed/XCommonEmbedPersist.hpp> +#include "intercept.hxx" +#include <com/sun/star/sdb/ErrorCondition.hpp> +#include <com/sun/star/sdb/XInteractionDocumentSave.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/sdb/DocumentSaveRequest.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/MacroExecMode.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/form/XFormsSupplier.hpp> +#include <com/sun/star/form/XForm.hpp> +#include <comphelper/interaction.hxx> +#include <connectivity/dbtools.hxx> +#include <vcl/svapp.hxx> +#include <osl/mutex.hxx> +#include <sal/macros.h> +#include <com/sun/star/view/XViewSettingsSupplier.hpp> +#include "core_resource.hxx" +#include "core_resource.hrc" +#include "datasource.hxx" +#include <com/sun/star/embed/XStateChangeBroadcaster.hpp> +#include <com/sun/star/task/XInteractionApprove.hpp> +#include <com/sun/star/task/XInteractionDisapprove.hpp> +#include <com/sun/star/frame/XLayoutManager.hpp> +#include <cppuhelper/compbase1.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <comphelper/sequenceashashmap.hxx> +#include <comphelper/mimeconfighelper.hxx> +#include <comphelper/storagehelper.hxx> +#include <com/sun/star/container/XContentEnumerationAccess.hpp> +#include <com/sun/star/io/WrongFormatException.hpp> +#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp> +#include <com/sun/star/sdb/application/DatabaseObject.hpp> +#include <com/sun/star/util/XModifiable2.hpp> + +using namespace ::com::sun::star; +using namespace view; +using namespace uno; +using namespace util; +using namespace ucb; +using namespace beans; +using namespace lang; +using namespace awt; +using namespace embed; +using namespace frame; +using namespace document; +using namespace sdbc; +using namespace sdb; +using namespace io; +using namespace container; +using namespace datatransfer; +using namespace task; +using namespace form; +using namespace drawing; +using namespace ::osl; +using namespace ::comphelper; +using namespace ::cppu; +namespace css = ::com::sun::star; + +using sdb::application::XDatabaseDocumentUI; +namespace DatabaseObject = sdb::application::DatabaseObject; + + +#define DEFAULT_WIDTH 10000 +#define DEFAULT_HEIGHT 7500 + +namespace dbaccess +{ + + typedef ::boost::optional< bool > optional_bool; + + //========================================================================= + //= helper + //========================================================================= + namespace + { + // -------------------------------------------------------------------- + ::rtl::OUString lcl_determineContentType_nothrow( const Reference< XStorage >& _rxContainerStorage, + const ::rtl::OUString& _rEntityName ) + { + ::rtl::OUString sContentType; + try + { + Reference< XStorage > xContainerStorage( _rxContainerStorage, UNO_QUERY_THROW ); + ::utl::SharedUNOComponent< XPropertySet > xStorageProps( + xContainerStorage->openStorageElement( _rEntityName, ElementModes::READ ), UNO_QUERY_THROW ); + OSL_VERIFY( xStorageProps->getPropertyValue( INFO_MEDIATYPE ) >>= sContentType ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return sContentType; + } + } + + //================================================================== + // OEmbedObjectHolder + //================================================================== + typedef ::cppu::WeakComponentImplHelper1< embed::XStateChangeListener > TEmbedObjectHolder; + class OEmbedObjectHolder : public ::comphelper::OBaseMutex + ,public TEmbedObjectHolder + { + Reference< XEmbeddedObject > m_xBroadCaster; + ODocumentDefinition* m_pDefinition; + bool m_bInStateChange; + bool m_bInChangingState; + protected: + virtual void SAL_CALL disposing(); + public: + OEmbedObjectHolder(const Reference< XEmbeddedObject >& _xBroadCaster,ODocumentDefinition* _pDefinition) + : TEmbedObjectHolder(m_aMutex) + ,m_xBroadCaster(_xBroadCaster) + ,m_pDefinition(_pDefinition) + ,m_bInStateChange(false) + ,m_bInChangingState(false) + { + osl_incrementInterlockedCount( &m_refCount ); + { + if ( m_xBroadCaster.is() ) + m_xBroadCaster->addStateChangeListener(this); + } + osl_decrementInterlockedCount( &m_refCount ); + } + + virtual void SAL_CALL changingState( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) throw (embed::WrongStateException, uno::RuntimeException); + virtual void SAL_CALL stateChanged( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) throw (uno::RuntimeException); + virtual void SAL_CALL disposing( const lang::EventObject& Source ) throw (uno::RuntimeException); + }; + + void SAL_CALL OEmbedObjectHolder::disposing() + { + if ( m_xBroadCaster.is() ) + m_xBroadCaster->removeStateChangeListener(this); + m_xBroadCaster = NULL; + m_pDefinition = NULL; + } + + void SAL_CALL OEmbedObjectHolder::changingState( const lang::EventObject& /*aEvent*/, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) throw (embed::WrongStateException, uno::RuntimeException) + { + if ( !m_bInChangingState && nNewState == EmbedStates::RUNNING && nOldState == EmbedStates::ACTIVE && m_pDefinition ) + { + m_bInChangingState = true; + //m_pDefinition->save(sal_False); + m_bInChangingState = false; + } + } + + void SAL_CALL OEmbedObjectHolder::stateChanged( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) throw (uno::RuntimeException) + { + if ( !m_bInStateChange && nNewState == EmbedStates::RUNNING && nOldState == EmbedStates::ACTIVE && m_pDefinition ) + { + m_bInStateChange = true; + Reference<XInterface> xInt(static_cast< ::cppu::OWeakObject* >(m_pDefinition),UNO_QUERY); + { + Reference<XEmbeddedObject> xEmbeddedObject(aEvent.Source,UNO_QUERY); + if ( xEmbeddedObject.is() ) + xEmbeddedObject->changeState(EmbedStates::LOADED); + } + m_bInStateChange = false; + } + } + + void SAL_CALL OEmbedObjectHolder::disposing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException) + { + m_xBroadCaster = NULL; + } + + //================================================================== + // OEmbeddedClientHelper + //================================================================== + typedef ::cppu::WeakImplHelper1 < XEmbeddedClient + > EmbeddedClientHelper_BASE; + class OEmbeddedClientHelper : public EmbeddedClientHelper_BASE + { + ODocumentDefinition* m_pClient; + public: + OEmbeddedClientHelper(ODocumentDefinition* _pClient) :m_pClient(_pClient) {} + + virtual void SAL_CALL saveObject( ) throw (ObjectSaveVetoException, Exception, RuntimeException) + { + } + virtual void SAL_CALL onShowWindow( sal_Bool /*bVisible*/ ) throw (RuntimeException) + { + } + // XComponentSupplier + virtual Reference< util::XCloseable > SAL_CALL getComponent( ) throw (RuntimeException) + { + return Reference< css::util::XCloseable >(); + } + + // XEmbeddedClient + virtual void SAL_CALL visibilityChanged( ::sal_Bool /*bVisible*/ ) throw (WrongStateException, RuntimeException) + { + } + inline void resetClient(ODocumentDefinition* _pClient) { m_pClient = _pClient; } + }; + + //================================================================== + // LockModifiable + //================================================================== + class LockModifiable + { + public: + LockModifiable( const Reference< XInterface >& i_rModifiable ) + :m_xModifiable( i_rModifiable, UNO_QUERY ) + { + OSL_ENSURE( m_xModifiable.is(), "LockModifiable::LockModifiable: invalid component!" ); + if ( m_xModifiable.is() ) + { + if ( !m_xModifiable->isSetModifiedEnabled() ) + { + // somebody already locked that, no need to lock it, again, and no need to unlock it later + m_xModifiable.clear(); + } + else + { + m_xModifiable->disableSetModified(); + } + } + } + + ~LockModifiable() + { + if ( m_xModifiable.is() ) + m_xModifiable->enableSetModified(); + } + + private: + Reference< XModifiable2 > m_xModifiable; + }; + + //================================================================== + // LifetimeCoupler + //================================================================== + typedef ::cppu::WeakImplHelper1 < css::lang::XEventListener + > LifetimeCoupler_Base; + /** helper class which couples the lifetime of a component to the lifetime + of another component + + Instances of this class are constructed with two components. The first is + simply held by reference, and thus kept alive. The second one is observed + for <code>disposing</code> calls - if they occur, i.e. if the component dies, + the reference to the first component is cleared. + + This way, you can ensure that a certain component is kept alive as long + as a second component is not disposed. + */ + class LifetimeCoupler : public LifetimeCoupler_Base + { + private: + Reference< XInterface > m_xClient; + + public: + inline static void couple( const Reference< XInterface >& _rxClient, const Reference< XComponent >& _rxActor ) + { + Reference< css::lang::XEventListener > xEnsureDelete( new LifetimeCoupler( _rxClient, _rxActor ) ); + } + + private: + inline LifetimeCoupler( const Reference< XInterface >& _rxClient, const Reference< XComponent >& _rxActor ) + :m_xClient( _rxClient ) + { + DBG_ASSERT( _rxActor.is(), "LifetimeCoupler::LifetimeCoupler: this will crash!" ); + osl_incrementInterlockedCount( &m_refCount ); + { + _rxActor->addEventListener( this ); + } + osl_decrementInterlockedCount( &m_refCount ); + DBG_ASSERT( m_refCount, "LifetimeCoupler::LifetimeCoupler: the actor is not holding us by hard ref - this won't work!" ); + } + + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) throw (RuntimeException); + protected: + }; + + void SAL_CALL LifetimeCoupler::disposing( const css::lang::EventObject& /*Source*/ ) throw (RuntimeException) + { + m_xClient.clear(); + } + + //================================================================== + // ODocumentSaveContinuation + //================================================================== + class ODocumentSaveContinuation : public OInteraction< XInteractionDocumentSave > + { + ::rtl::OUString m_sName; + Reference<XContent> m_xParentContainer; + + public: + ODocumentSaveContinuation() { } + + inline Reference<XContent> getContent() const { return m_xParentContainer; } + inline ::rtl::OUString getName() const { return m_sName; } + + // XInteractionDocumentSave + virtual void SAL_CALL setName( const ::rtl::OUString& _sName,const Reference<XContent>& _xParent) throw(RuntimeException); + }; + + void SAL_CALL ODocumentSaveContinuation::setName( const ::rtl::OUString& _sName,const Reference<XContent>& _xParent) throw(RuntimeException) + { + m_sName = _sName; + m_xParentContainer = _xParent; + } + +::rtl::OUString ODocumentDefinition::GetDocumentServiceFromMediaType( const Reference< XStorage >& _rxContainerStorage, + const ::rtl::OUString& _rEntityName, const ::comphelper::ComponentContext& _rContext, + Sequence< sal_Int8 >& _rClassId ) +{ + return GetDocumentServiceFromMediaType( + lcl_determineContentType_nothrow( _rxContainerStorage, _rEntityName ), + _rContext, _rClassId ); +} + +::rtl::OUString ODocumentDefinition::GetDocumentServiceFromMediaType( const ::rtl::OUString& _rMediaType, + const ::comphelper::ComponentContext& _rContext, Sequence< sal_Int8 >& _rClassId ) +{ + ::rtl::OUString sResult; + try + { + ::comphelper::MimeConfigurationHelper aConfigHelper( _rContext.getLegacyServiceFactory() ); + sResult = aConfigHelper.GetDocServiceNameFromMediaType( _rMediaType ); + _rClassId = aConfigHelper.GetSequenceClassIDRepresentation(aConfigHelper.GetExplicitlyRegisteredObjClassID( _rMediaType )); + if ( !_rClassId.getLength() && sResult.getLength() ) + { + Reference< XNameAccess > xObjConfig = aConfigHelper.GetObjConfiguration(); + if ( xObjConfig.is() ) + { + Sequence< ::rtl::OUString > aClassIDs = xObjConfig->getElementNames(); + for ( sal_Int32 nInd = 0; nInd < aClassIDs.getLength(); nInd++ ) + { + Reference< XNameAccess > xObjectProps; + ::rtl::OUString aEntryDocName; + + if ( ( xObjConfig->getByName( aClassIDs[nInd] ) >>= xObjectProps ) && xObjectProps.is() + && ( xObjectProps->getByName(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ObjectDocumentServiceName")) + ) >>= aEntryDocName ) + && aEntryDocName.equals( sResult ) ) + { + _rClassId = aConfigHelper.GetSequenceClassIDRepresentation(aClassIDs[nInd]); + break; + } + } + } + } +#if OSL_DEBUG_LEVEL > 0 + // alternative, shorter approach + const Sequence< NamedValue > aProps( aConfigHelper.GetObjectPropsByMediaType( _rMediaType ) ); + const ::comphelper::NamedValueCollection aMediaTypeProps( aProps ); + const ::rtl::OUString sAlternativeResult = aMediaTypeProps.getOrDefault( "ObjectDocumentServiceName", ::rtl::OUString() ); + OSL_ENSURE( sAlternativeResult == sResult, "ODocumentDefinition::GetDocumentServiceFromMediaType: failed, this approach is *not* equivalent (1)!" ); + const Sequence< sal_Int8 > aAlternativeClassID = aMediaTypeProps.getOrDefault( "ClassID", Sequence< sal_Int8 >() ); + OSL_ENSURE( aAlternativeClassID == _rClassId, "ODocumentDefinition::GetDocumentServiceFromMediaType: failed, this approach is *not* equivalent (2)!" ); +#endif + } + catch ( Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return sResult; +} + +//========================================================================== +//= ODocumentDefinition +//========================================================================== +DBG_NAME(ODocumentDefinition) + +ODocumentDefinition::ODocumentDefinition( const Reference< XInterface >& _rxContainer, const Reference< XMultiServiceFactory >& _xORB, + const TContentPtr& _pImpl, sal_Bool _bForm ) + :OContentHelper(_xORB,_rxContainer,_pImpl) + ,OPropertyStateContainer(OContentHelper::rBHelper) + ,m_pInterceptor(NULL) + ,m_bForm(_bForm) + ,m_bOpenInDesign(sal_False) + ,m_bInExecute(sal_False) + ,m_bRemoveListener(sal_False) + ,m_pClientHelper(NULL) +{ + DBG_CTOR(ODocumentDefinition, NULL); + registerProperties(); +} + +void ODocumentDefinition::initialLoad( const Sequence< sal_Int8 >& i_rClassID, const Sequence< PropertyValue >& i_rCreationArgs, + const Reference< XConnection >& i_rConnection ) +{ + OSL_ENSURE( i_rClassID.getLength(), "ODocumentDefinition::initialLoad: illegal class ID!" ); + if ( !i_rClassID.getLength() ) + return; + + loadEmbeddedObject( i_rConnection, i_rClassID, i_rCreationArgs, false, false ); +} + +ODocumentDefinition::~ODocumentDefinition() +{ + DBG_DTOR(ODocumentDefinition, NULL); + if ( !OContentHelper::rBHelper.bInDispose && !OContentHelper::rBHelper.bDisposed ) + { + acquire(); + dispose(); + } + + if ( m_pInterceptor ) + { + m_pInterceptor->dispose(); + m_pInterceptor->release(); + m_pInterceptor = NULL; + } +} + +void ODocumentDefinition::closeObject() +{ + ::osl::MutexGuard aGuard(m_aMutex); + if ( m_xEmbeddedObject.is() ) + { + try + { + Reference< com::sun::star::util::XCloseable> xCloseable(m_xEmbeddedObject,UNO_QUERY); + if ( xCloseable.is() ) + xCloseable->close(sal_True); + } + catch(Exception) + { + } + m_xEmbeddedObject = NULL; + if ( m_pClientHelper ) + { + m_pClientHelper->resetClient(NULL); + m_pClientHelper->release(); + m_pClientHelper = NULL; + } + } +} + +void SAL_CALL ODocumentDefinition::disposing() +{ + OContentHelper::disposing(); + ::osl::MutexGuard aGuard(m_aMutex); + closeObject(); + ::comphelper::disposeComponent(m_xListener); + if ( m_bRemoveListener ) + { + Reference<util::XCloseable> xCloseable(m_pImpl->m_pDataSource->getModel_noCreate(),UNO_QUERY); + if ( xCloseable.is() ) + xCloseable->removeCloseListener(this); + } +} + +IMPLEMENT_TYPEPROVIDER3(ODocumentDefinition,OContentHelper,OPropertyStateContainer,ODocumentDefinition_Base); +IMPLEMENT_FORWARD_XINTERFACE3( ODocumentDefinition,OContentHelper,OPropertyStateContainer,ODocumentDefinition_Base) +IMPLEMENT_SERVICE_INFO1(ODocumentDefinition,"com.sun.star.comp.dba.ODocumentDefinition",SERVICE_SDB_DOCUMENTDEFINITION) + +void ODocumentDefinition::registerProperties() +{ +#define REGISTER_PROPERTY( name, location ) \ + registerProperty( PROPERTY_##name, PROPERTY_ID_##name, PropertyAttribute::READONLY, &location, ::getCppuType( &location ) ); + +#define REGISTER_PROPERTY_BV( name, location ) \ + registerProperty( PROPERTY_##name, PROPERTY_ID_##name, PropertyAttribute::CONSTRAINED | PropertyAttribute::BOUND | PropertyAttribute::READONLY, &location, ::getCppuType( &location ) ); + + REGISTER_PROPERTY_BV( NAME, m_pImpl->m_aProps.aTitle ); + REGISTER_PROPERTY ( AS_TEMPLATE, m_pImpl->m_aProps.bAsTemplate ); + REGISTER_PROPERTY ( PERSISTENT_NAME, m_pImpl->m_aProps.sPersistentName ); + REGISTER_PROPERTY ( IS_FORM, m_bForm ); +} + +void SAL_CALL ODocumentDefinition::getFastPropertyValue( Any& o_rValue, sal_Int32 i_nHandle ) const +{ + if ( i_nHandle == PROPERTY_ID_PERSISTENT_PATH ) + { + ::rtl::OUString sPersistentPath; + if ( m_pImpl->m_aProps.sPersistentName.getLength() ) + { + ::rtl::OUStringBuffer aBuffer; + aBuffer.append( ODatabaseModelImpl::getObjectContainerStorageName( m_bForm ? ODatabaseModelImpl::E_FORM : ODatabaseModelImpl::E_REPORT ) ); + aBuffer.append( sal_Unicode( '/' ) ); + aBuffer.append( m_pImpl->m_aProps.sPersistentName ); + sPersistentPath = aBuffer.makeStringAndClear(); + } + o_rValue <<= sPersistentPath; + return; + } + + OPropertyStateContainer::getFastPropertyValue( o_rValue, i_nHandle ); +} + +Reference< XPropertySetInfo > SAL_CALL ODocumentDefinition::getPropertySetInfo( ) throw(RuntimeException) +{ + Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +IPropertyArrayHelper& ODocumentDefinition::getInfoHelper() +{ + return *getArrayHelper(); +} + +IPropertyArrayHelper* ODocumentDefinition::createArrayHelper( ) const +{ + // properties maintained by our base class (see registerProperties) + Sequence< Property > aProps; + describeProperties( aProps ); + + // properties not maintained by our base class + Sequence< Property > aManualProps( 1 ); + aManualProps[0].Name = PROPERTY_PERSISTENT_PATH; + aManualProps[0].Handle = PROPERTY_ID_PERSISTENT_PATH; + aManualProps[0].Type = ::getCppuType( static_cast< const ::rtl::OUString* >( NULL ) ); + aManualProps[0].Attributes = PropertyAttribute::READONLY; + + return new OPropertyArrayHelper( ::comphelper::concatSequences( aProps, aManualProps ) ); +} + +class OExecuteImpl +{ + sal_Bool& m_rbSet; +public: + OExecuteImpl(sal_Bool& _rbSet) : m_rbSet(_rbSet){ m_rbSet=sal_True; } + ~OExecuteImpl(){ m_rbSet = sal_False; } +}; + +namespace +{ + bool lcl_extractOpenMode( const Any& _rValue, sal_Int32& _out_rMode ) + { + OpenCommandArgument aOpenCommand; + if ( _rValue >>= aOpenCommand ) + _out_rMode = aOpenCommand.Mode; + else + { + OpenCommandArgument2 aOpenCommand2; + if ( _rValue >>= aOpenCommand2 ) + _out_rMode = aOpenCommand2.Mode; + else + return false; + } + return true; + } +} + +void ODocumentDefinition::impl_removeFrameFromDesktop_throw( const ::comphelper::ComponentContext& _rContxt, const Reference< XFrame >& _rxFrame ) +{ + Reference< XFramesSupplier > xDesktop( _rContxt.createComponent( (::rtl::OUString)SERVICE_FRAME_DESKTOP ), UNO_QUERY_THROW ); + Reference< XFrames > xFrames( xDesktop->getFrames(), UNO_QUERY_THROW ); + xFrames->remove( _rxFrame ); +} + +void ODocumentDefinition::impl_onActivateEmbeddedObject_nothrow( const bool i_bReactivated ) +{ + try + { + Reference< XModel > xModel( getComponent(), UNO_QUERY ); + Reference< XController > xController( xModel.is() ? xModel->getCurrentController() : Reference< XController >() ); + if ( !xController.is() ) + return; + + if ( !m_xListener.is() ) + // it's the first time the embedded object has been activated + // create an OEmbedObjectHolder + m_xListener = new OEmbedObjectHolder( m_xEmbeddedObject, this ); + + // raise the window to top (especially necessary if this is not the first activation) + Reference< XFrame > xFrame( xController->getFrame(), UNO_SET_THROW ); + Reference< XTopWindow > xTopWindow( xFrame->getContainerWindow(), UNO_QUERY_THROW ); + xTopWindow->toFront(); + + // remove the frame from the desktop's frame collection because we need full control of it. + impl_removeFrameFromDesktop_throw( m_aContext, xFrame ); + + // ensure that we ourself are kept alive as long as the embedded object's frame is + // opened + LifetimeCoupler::couple( *this, xFrame.get() ); + + // init the edit view + if ( m_bForm && m_bOpenInDesign && !i_bReactivated ) + impl_initFormEditView( xController ); + } + catch( const RuntimeException& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +namespace +{ + // ========================================================================= + // = PreserveVisualAreaSize + // ========================================================================= + /** stack-guard for preserving the size of the VisArea of an XModel + */ + class PreserveVisualAreaSize + { + private: + Reference< XVisualObject > m_xVisObject; + awt::Size m_aOriginalSize; + + public: + inline PreserveVisualAreaSize( const Reference< XModel >& _rxModel ) + :m_xVisObject( _rxModel, UNO_QUERY ) + { + if ( m_xVisObject.is() ) + { + try + { + m_aOriginalSize = m_xVisObject->getVisualAreaSize( Aspects::MSOLE_CONTENT ); + } + catch ( Exception& ) + { + DBG_ERROR( "PreserveVisualAreaSize::PreserveVisualAreaSize: caught an exception!" ); + } + } + } + + inline ~PreserveVisualAreaSize() + { + if ( m_xVisObject.is() && m_aOriginalSize.Width && m_aOriginalSize.Height ) + { + try + { + m_xVisObject->setVisualAreaSize( Aspects::MSOLE_CONTENT, m_aOriginalSize ); + } + catch ( Exception& ) + { + DBG_ERROR( "PreserveVisualAreaSize::~PreserveVisualAreaSize: caught an exception!" ); + } + } + } + }; + + // ========================================================================= + // = LayoutManagerLock + // ========================================================================= + /** helper class for stack-usage which during its lifetime locks a layout manager + */ + class LayoutManagerLock + { + private: + Reference< XLayoutManager > m_xLayoutManager; + + public: + inline LayoutManagerLock( const Reference< XController >& _rxController ) + { + DBG_ASSERT( _rxController.is(), "LayoutManagerLock::LayoutManagerLock: this will crash!" ); + Reference< XFrame > xFrame( _rxController->getFrame() ); + try + { + Reference< XPropertySet > xPropSet( xFrame, UNO_QUERY_THROW ); + m_xLayoutManager.set( + xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LayoutManager" ) ) ), + UNO_QUERY_THROW ); + m_xLayoutManager->lock(); + + } + catch( Exception& ) + { + DBG_ERROR( "LayoutManagerLock::LayoutManagerLock: caught an exception!" ); + } + } + + inline ~LayoutManagerLock() + { + try + { + // unlock the layout manager + if ( m_xLayoutManager.is() ) + m_xLayoutManager->unlock(); + } + catch( Exception& ) + { + DBG_ERROR( "LayoutManagerLock::~LayoutManagerLock: caught an exception!" ); + } + } + }; +} + +void ODocumentDefinition::impl_initFormEditView( const Reference< XController >& _rxController ) +{ + try + { + Reference< XViewSettingsSupplier > xSettingsSupplier( _rxController, UNO_QUERY_THROW ); + Reference< XPropertySet > xViewSettings( xSettingsSupplier->getViewSettings(), UNO_QUERY_THROW ); + + // the below code could indirectly tamper with the "modified" flag of the model, temporarily disable this + LockModifiable aLockModify( _rxController->getModel() ); + + // The visual area size can be changed by the setting of the following properties + // so it should be restored later + PreserveVisualAreaSize aPreserveVisAreaSize( _rxController->getModel() ); + + // Layout manager should not layout while the size is still not restored + // so it will stay locked for this time + LayoutManagerLock aLockLayout( _rxController ); + + // setting of the visual properties + xViewSettings->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ShowRulers")),makeAny(sal_True)); + xViewSettings->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ShowVertRuler")),makeAny(sal_True)); + xViewSettings->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ShowHoriRuler")),makeAny(sal_True)); + xViewSettings->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("IsRasterVisible")),makeAny(sal_True)); + xViewSettings->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("IsSnapToRaster")),makeAny(sal_True)); + xViewSettings->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ShowOnlineLayout")),makeAny(sal_True)); + xViewSettings->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RasterSubdivisionX")),makeAny(sal_Int32(5))); + xViewSettings->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RasterSubdivisionY")),makeAny(sal_Int32(5))); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +void ODocumentDefinition::impl_showOrHideComponent_throw( const bool i_bShow ) +{ + const sal_Int32 nCurrentState = m_xEmbeddedObject.is() ? m_xEmbeddedObject->getCurrentState() : EmbedStates::LOADED; + switch ( nCurrentState ) + { + default: + case EmbedStates::LOADED: + throw embed::WrongStateException( ::rtl::OUString(), *this ); + + case EmbedStates::RUNNING: + if ( !i_bShow ) + // fine, a running (and not yet active) object is never visible + return; + { + LockModifiable aLockModify( impl_getComponent_throw() ); + m_xEmbeddedObject->changeState( EmbedStates::ACTIVE ); + impl_onActivateEmbeddedObject_nothrow( false ); + } + break; + + case EmbedStates::ACTIVE: + { + Reference< XModel > xEmbeddedDoc( impl_getComponent_throw( true ), UNO_QUERY_THROW ); + Reference< XController > xEmbeddedController( xEmbeddedDoc->getCurrentController(), UNO_SET_THROW ); + Reference< XFrame > xEmbeddedFrame( xEmbeddedController->getFrame(), UNO_SET_THROW ); + Reference< XWindow > xEmbeddedWindow( xEmbeddedFrame->getContainerWindow(), UNO_SET_THROW ); + xEmbeddedWindow->setVisible( i_bShow ); + } + break; + } +} + +Any ODocumentDefinition::onCommandOpenSomething( const Any& _rOpenArgument, const bool _bActivate, + const Reference< XCommandEnvironment >& _rxEnvironment ) +{ + OExecuteImpl aExecuteGuard( m_bInExecute ); + + Reference< XConnection > xConnection; + sal_Int32 nOpenMode = OpenMode::DOCUMENT; + + ::comphelper::NamedValueCollection aDocumentArgs; + + // for the document, default to the interaction handler as used for loading the DB doc + // This might be overwritten below, when examining _rOpenArgument. + const ::comphelper::NamedValueCollection& aDBDocArgs( m_pImpl->m_pDataSource->getMediaDescriptor() ); + Reference< XInteractionHandler > xHandler( aDBDocArgs.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() ) ); + if ( xHandler.is() ) + aDocumentArgs.put( "InteractionHandler", xHandler ); + + ::boost::optional< sal_Int16 > aDocumentMacroMode; + + if ( !lcl_extractOpenMode( _rOpenArgument, nOpenMode ) ) + { + Sequence< PropertyValue > aArguments; + if ( _rOpenArgument >>= aArguments ) + { + const PropertyValue* pIter = aArguments.getConstArray(); + const PropertyValue* pEnd = pIter + aArguments.getLength(); + for ( ;pIter != pEnd; ++pIter ) + { + if ( pIter->Name == PROPERTY_ACTIVE_CONNECTION ) + { + xConnection.set( pIter->Value, UNO_QUERY ); + continue; + } + + if ( lcl_extractOpenMode( pIter->Value, nOpenMode ) ) + continue; + + if ( pIter->Name.equalsAscii( "MacroExecutionMode" ) ) + { + sal_Int16 nMacroExecMode( !aDocumentMacroMode ? MacroExecMode::USE_CONFIG : *aDocumentMacroMode ); + OSL_VERIFY( pIter->Value >>= nMacroExecMode ); + aDocumentMacroMode.reset( nMacroExecMode ); + continue; + } + + // unknown argument -> pass to the loaded document + aDocumentArgs.put( pIter->Name, pIter->Value ); + } + } + } + + bool bExecuteDBDocMacros = m_pImpl->m_pDataSource->checkMacrosOnLoading(); + // Note that this call implies the user might be asked for the macro execution mode. + // Normally, this would happen when the database document is loaded, and subsequent calls + // will simply use the user's decision from this point in time. + // However, it is possible to programmatically load forms/reports, without actually + // loading the database document into a frame. In this case, the user will be asked + // here and now. + // #i87741# / 2008-05-05 / frank.schoenheit@sun.com + + // allow the command arguments to downgrade the macro execution mode, but not to upgrade + // it + if ( ( m_pImpl->m_pDataSource->getImposedMacroExecMode() == MacroExecMode::USE_CONFIG ) + && bExecuteDBDocMacros + ) + { + // while loading the whole database document, USE_CONFIG, was passed. + // Additionally, *by now* executing macros from the DB doc is allowed (this is what bExecuteDBDocMacros + // indicates). This means either one of: + // 1. The DB doc or one of the sub docs contained macros and + // 1a. the user explicitly allowed executing them + // 1b. the configuration allows executing them without asking the user + // 2. Neither the DB doc nor the sub docs contained macros, thus macro + // execution was silently enabled, assuming that any macro will be a + // user-created macro + // + // The problem with this: If the to-be-opened sub document has macros embedded in + // the content.xml (which is valid ODF, but normally not produced by OOo itself), + // then this has not been detected while loading the database document - it would + // be too expensive, as it effectively would require loading all forms/reports. + // + // So, in such a case, and with 2. above, we would silently execute those macros, + // regardless of the global security settings - which would be a security issue, of + // course. + if ( m_pImpl->m_pDataSource->determineEmbeddedMacros() == ODatabaseModelImpl::eNoMacros ) + { + // this is case 2. from above + // So, pass a USE_CONFIG to the to-be-loaded document. This means that + // the user will be prompted with a security message upon opening this + // sub document, in case the settings require this, *and* the document + // contains scripts in the content.xml. But this is better than the security + // issue we had before ... + aDocumentMacroMode.reset( MacroExecMode::USE_CONFIG ); + } + } + + if ( !aDocumentMacroMode ) + { + // nobody so far felt responsible for setting it + // => use the DBDoc-wide macro exec mode for the document, too + aDocumentMacroMode.reset( bExecuteDBDocMacros ? MacroExecMode::ALWAYS_EXECUTE_NO_WARN : MacroExecMode::NEVER_EXECUTE ); + } + aDocumentArgs.put( "MacroExecutionMode", *aDocumentMacroMode ); + + if ( ( nOpenMode == OpenMode::ALL ) + || ( nOpenMode == OpenMode::FOLDERS ) + || ( nOpenMode == OpenMode::DOCUMENTS ) + || ( nOpenMode == OpenMode::DOCUMENT_SHARE_DENY_NONE ) + || ( nOpenMode == OpenMode::DOCUMENT_SHARE_DENY_WRITE ) + ) + { + // not supported + ucbhelper::cancelCommandExecution( + makeAny( UnsupportedOpenModeException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + sal_Int16( nOpenMode ) ) ), + _rxEnvironment ); + // Unreachable + DBG_ERROR( "unreachable" ); + } + + OSL_ENSURE( m_pImpl->m_aProps.sPersistentName.getLength(), + "ODocumentDefinition::onCommandOpenSomething: no persistent name - cannot load!" ); + if ( !m_pImpl->m_aProps.sPersistentName.getLength() ) + return Any(); + + // embedded objects themself do not support the hidden flag. We implement support for + // it by changing the STATE to RUNNING only, instead of ACTIVE. + bool bOpenHidden = aDocumentArgs.getOrDefault( "Hidden", false ); + aDocumentArgs.remove( "Hidden" ); + + loadEmbeddedObject( xConnection, Sequence< sal_Int8 >(), aDocumentArgs.getPropertyValues(), false, !m_bOpenInDesign ); + OSL_ENSURE( m_xEmbeddedObject.is(), "ODocumentDefinition::onCommandOpenSomething: what's this?" ); + if ( !m_xEmbeddedObject.is() ) + return Any(); + + Reference< XModel > xModel( getComponent(), UNO_QUERY ); + Reference< report::XReportDefinition > xReportDefinition(xModel,UNO_QUERY); + + Reference< XModule > xModule( xModel, UNO_QUERY ); + if ( xModule.is() ) + { + if ( m_bForm ) + xModule->setIdentifier( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.FormDesign" ) ) ); + else if ( !xReportDefinition.is() ) + xModule->setIdentifier( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.TextReportDesign" ) ) ); + + updateDocumentTitle(); + } + + bool bIsAliveNewStyleReport = ( !m_bOpenInDesign && xReportDefinition.is() ); + if ( bIsAliveNewStyleReport ) + { + // we are in ReadOnly mode + // we would like to open the Writer or Calc with the report direct, without design it. + Reference< report::XReportEngine > xReportEngine( m_aContext.createComponent( "com.sun.star.comp.report.OReportEngineJFree" ), UNO_QUERY_THROW ); + + xReportEngine->setReportDefinition(xReportDefinition); + xReportEngine->setActiveConnection(m_xLastKnownConnection); + if ( bOpenHidden ) + return makeAny( xReportEngine->createDocumentModel() ); + return makeAny( xReportEngine->createDocumentAlive( NULL ) ); + } + + if ( _bActivate && !bOpenHidden ) + { + LockModifiable aLockModify( impl_getComponent_throw() ); + m_xEmbeddedObject->changeState( EmbedStates::ACTIVE ); + impl_onActivateEmbeddedObject_nothrow( false ); + } + else + { + // ensure that we ourself are kept alive as long as the document is open + LifetimeCoupler::couple( *this, xModel.get() ); + } + + if ( !m_bForm && m_pImpl->m_aProps.bAsTemplate && !m_bOpenInDesign ) + ODocumentDefinition::fillReportData( m_aContext, getComponent(), xConnection ); + + return makeAny( xModel ); +} + +Any SAL_CALL ODocumentDefinition::execute( const Command& aCommand, sal_Int32 CommandId, const Reference< XCommandEnvironment >& Environment ) throw (Exception, CommandAbortedException, RuntimeException) +{ + Any aRet; + + sal_Bool bOpen = aCommand.Name.equalsAscii( "open" ); + sal_Bool bOpenInDesign = aCommand.Name.equalsAscii( "openDesign" ); + sal_Bool bOpenForMail = aCommand.Name.equalsAscii( "openForMail" ); + if ( bOpen || bOpenInDesign || bOpenForMail ) + { + // opening the document involves a lot of VCL code, which is not thread-safe, but needs the SolarMutex locked. + // Unfortunately, the DocumentDefinition, as well as the EmbeddedObject implementation, calls into VCL-dependent + // components *without* releasing the own mutex, which is a guaranteed recipe for deadlocks. + // We have control over this implementation here, and in modifying it to release the own mutex before calling into + // the VCL-dependent components is not too difficult (was there, seen it). + // However, we do /not/ have control over the EmbeddedObject implementation, and from a first look, it seems as + // making it release the own mutex before calling SolarMutex-code is ... difficult, at least. + // So, to be on the same side, we lock the SolarMutex here. Yes, it sucks. + ::SolarMutexGuard aSolarGuard; + ::osl::ClearableMutexGuard aGuard(m_aMutex); + if ( m_bInExecute ) + return aRet; + + bool bActivateObject = true; + if ( bOpenForMail ) + { + OSL_ENSURE( false, "ODocumentDefinition::execute: 'openForMail' should not be used anymore - use the 'Hidden' parameter instead!" ); + bActivateObject = false; + } + + // if the object is already opened, do nothing + if ( m_xEmbeddedObject.is() ) + { + sal_Int32 nCurrentState = m_xEmbeddedObject->getCurrentState(); + bool bIsActive = ( nCurrentState == EmbedStates::ACTIVE ); + + if ( bIsActive ) + { + // exception: new-style reports always create a new document when "open" is executed + Reference< report::XReportDefinition > xReportDefinition( impl_getComponent_throw( false ), UNO_QUERY ); + bool bIsAliveNewStyleReport = ( xReportDefinition.is() && ( bOpen || bOpenForMail ) ); + + if ( !bIsAliveNewStyleReport ) + { + impl_onActivateEmbeddedObject_nothrow( true ); + return makeAny( getComponent() ); + } + } + } + + m_bOpenInDesign = bOpenInDesign || bOpenForMail; + return onCommandOpenSomething( aCommand.Argument, bActivateObject, Environment ); + } + + ::osl::ClearableMutexGuard aGuard(m_aMutex); + if ( m_bInExecute ) + return aRet; + + if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "copyTo" ) ) ) + { + Sequence<Any> aIni; + aCommand.Argument >>= aIni; + if ( aIni.getLength() != 2 ) + { + OSL_ENSURE( sal_False, "Wrong argument type!" ); + ucbhelper::cancelCommandExecution( + makeAny( IllegalArgumentException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + Reference< XStorage> xDest(aIni[0],UNO_QUERY); + ::rtl::OUString sPersistentName; + aIni[1] >>= sPersistentName; + Reference< XStorage> xStorage = getContainerStorage(); + + xStorage->copyElementTo(m_pImpl->m_aProps.sPersistentName,xDest,sPersistentName); + } + else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "preview" ) ) ) + { + onCommandPreview(aRet); + } + else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "insert" ) ) ) + { + Sequence<Any> aIni; + aCommand.Argument >>= aIni; + if ( !aIni.getLength() ) + { + OSL_ENSURE( sal_False, "Wrong argument count!" ); + ucbhelper::cancelCommandExecution( + makeAny( IllegalArgumentException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + ::rtl::OUString sURL; + aIni[0] >>= sURL; + onCommandInsert( sURL, Environment ); + } + else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "getdocumentinfo" ) ) // compatibility + || aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "getDocumentInfo" ) ) + ) + { + onCommandGetDocumentProperties( aRet ); + } + else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "delete" ) ) ) + { + ////////////////////////////////////////////////////////////////// + // delete + ////////////////////////////////////////////////////////////////// + closeObject(); + Reference< XStorage> xStorage = getContainerStorage(); + if ( xStorage.is() ) + xStorage->removeElement(m_pImpl->m_aProps.sPersistentName); + + dispose(); + + } + else if ( ( aCommand.Name.compareToAscii( "storeOwn" ) == 0 ) // compatibility + || ( aCommand.Name.compareToAscii( "store" ) == 0 ) + ) + { + impl_store_throw(); + } + else if ( ( aCommand.Name.compareToAscii( "shutdown" ) == 0 ) // compatibility + || ( aCommand.Name.compareToAscii( "close" ) == 0 ) + ) + { + aRet <<= impl_close_throw(); + } + else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "show" ) ) ) + { + impl_showOrHideComponent_throw( true ); + } + else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "hide" ) ) ) + { + impl_showOrHideComponent_throw( false ); + } + else + { + aRet = OContentHelper::execute(aCommand,CommandId,Environment); + } + + return aRet; +} + +namespace +{ + void lcl_resetChildFormsToEmptyDataSource( const Reference< XIndexAccess>& _rxFormsContainer ) + { + OSL_PRECOND( _rxFormsContainer.is(), "lcl_resetChildFormsToEmptyDataSource: illegal call!" ); + sal_Int32 count = _rxFormsContainer->getCount(); + for ( sal_Int32 i = 0; i < count; ++i ) + { + Reference< XForm > xForm( _rxFormsContainer->getByIndex( i ), UNO_QUERY ); + if ( !xForm.is() ) + continue; + + // if the element is a form, reset its DataSourceName property to an empty string + try + { + Reference< XPropertySet > xFormProps( xForm, UNO_QUERY_THROW ); + xFormProps->setPropertyValue( PROPERTY_DATASOURCENAME, makeAny( ::rtl::OUString() ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + // if the element is a container itself, step down the component hierarchy + Reference< XIndexAccess > xContainer( xForm, UNO_QUERY ); + if ( xContainer.is() ) + lcl_resetChildFormsToEmptyDataSource( xContainer ); + } + } + + void lcl_resetFormsToEmptyDataSource( const Reference< XEmbeddedObject>& _rxEmbeddedObject ) + { + try + { + Reference< XComponentSupplier > xCompProv( _rxEmbeddedObject, UNO_QUERY_THROW ); + Reference< XDrawPageSupplier > xSuppPage( xCompProv->getComponent(), UNO_QUERY_THROW ); + // if this interface does not exist, then either getComponent returned NULL, + // or the document is a multi-page document. The latter is allowed, but currently + // simply not handled by this code, as it would not normally happen. + + Reference< XFormsSupplier > xSuppForms( xSuppPage->getDrawPage(), UNO_QUERY_THROW ); + Reference< XIndexAccess > xForms( xSuppForms->getForms(), UNO_QUERY_THROW ); + lcl_resetChildFormsToEmptyDataSource( xForms ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + } +} + +void ODocumentDefinition::onCommandInsert( const ::rtl::OUString& _sURL, const Reference< XCommandEnvironment >& Environment ) + throw( Exception ) +{ + osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); + + // Check, if all required properties were set. + if ( !_sURL.getLength() || m_xEmbeddedObject.is() ) + { + OSL_ENSURE( sal_False, "Content::onCommandInsert - property value missing!" ); + + Sequence< rtl::OUString > aProps( 1 ); + aProps[ 0 ] = PROPERTY_URL; + ucbhelper::cancelCommandExecution( + makeAny( MissingPropertiesException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + aProps ) ), + Environment ); + // Unreachable + } + + if ( !m_xEmbeddedObject.is() ) + { + Reference< XStorage> xStorage = getContainerStorage(); + if ( xStorage.is() ) + { + Reference< XEmbedObjectCreator> xEmbedFactory( m_aContext.createComponent( "com.sun.star.embed.EmbeddedObjectCreator" ), UNO_QUERY ); + if ( xEmbedFactory.is() ) + { + Sequence<PropertyValue> aEmpty,aMediaDesc(1); + aMediaDesc[0].Name = PROPERTY_URL; + aMediaDesc[0].Value <<= _sURL; + m_xEmbeddedObject.set(xEmbedFactory->createInstanceInitFromMediaDescriptor( xStorage + ,m_pImpl->m_aProps.sPersistentName + ,aMediaDesc + ,aEmpty),UNO_QUERY); + + lcl_resetFormsToEmptyDataSource( m_xEmbeddedObject ); + // #i57669# / 2005-12-01 / frank.schoenheit@sun.com + + Reference<XEmbedPersist> xPersist(m_xEmbeddedObject,UNO_QUERY); + if ( xPersist.is() ) + { + xPersist->storeOwn(); + } + try + { + Reference< com::sun::star::util::XCloseable> xCloseable(m_xEmbeddedObject,UNO_QUERY); + if ( xCloseable.is() ) + xCloseable->close(sal_True); + } + catch(Exception) + { + } + m_xEmbeddedObject = NULL; + } + } + } + + aGuard.clear(); +} + +sal_Bool ODocumentDefinition::save(sal_Bool _bApprove) +{ + // default handling: instantiate an interaction handler and let it handle the parameter request + if ( !m_bOpenInDesign ) + return sal_False; + try + { + + { + ::SolarMutexGuard aSolarGuard; + + // the request + Reference<XNameAccess> xName(m_xParentContainer,UNO_QUERY); + DocumentSaveRequest aRequest; + aRequest.Name = m_pImpl->m_aProps.aTitle; + if ( !aRequest.Name.getLength() ) + { + if ( m_bForm ) + aRequest.Name = DBACORE_RESSTRING( RID_STR_FORM ); + else + aRequest.Name = DBACORE_RESSTRING( RID_STR_REPORT ); + aRequest.Name = ::dbtools::createUniqueName(xName,aRequest.Name); + } + + aRequest.Content.set(m_xParentContainer,UNO_QUERY); + OInteractionRequest* pRequest = new OInteractionRequest(makeAny(aRequest)); + Reference< XInteractionRequest > xRequest(pRequest); + // some knittings + // two continuations allowed: OK and Cancel + ODocumentSaveContinuation* pDocuSave = NULL; + + if ( !m_pImpl->m_aProps.aTitle.getLength() ) + { + pDocuSave = new ODocumentSaveContinuation; + pRequest->addContinuation(pDocuSave); + } + OInteraction< XInteractionApprove >* pApprove = NULL; + if ( _bApprove ) + { + pApprove = new OInteraction< XInteractionApprove >; + pRequest->addContinuation(pApprove); + } + + OInteraction< XInteractionDisapprove >* pDisApprove = new OInteraction< XInteractionDisapprove >; + pRequest->addContinuation(pDisApprove); + + OInteractionAbort* pAbort = new OInteractionAbort; + pRequest->addContinuation(pAbort); + + // create the handler, let it handle the request + Reference< XInteractionHandler > xHandler( m_aContext.createComponent( (::rtl::OUString)SERVICE_TASK_INTERACTION_HANDLER ), UNO_QUERY ); + if ( xHandler.is() ) + xHandler->handle(xRequest); + + if ( pAbort->wasSelected() ) + return sal_False; + if ( pDisApprove->wasSelected() ) + return sal_True; + if ( pDocuSave && pDocuSave->wasSelected() ) + { + Reference<XNameContainer> xNC( pDocuSave->getContent(), UNO_QUERY_THROW ); + + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + NameChangeNotifier aNameChangeAndNotify( *this, pDocuSave->getName(), aGuard ); + m_pImpl->m_aProps.aTitle = pDocuSave->getName(); + + Reference< XContent> xContent = this; + xNC->insertByName(pDocuSave->getName(),makeAny(xContent)); + + updateDocumentTitle(); + } + } + + ::osl::MutexGuard aGuard(m_aMutex); + Reference<XEmbedPersist> xPersist(m_xEmbeddedObject,UNO_QUERY); + if ( xPersist.is() ) + { + xPersist->storeOwn(); + notifyDataSourceModified(); + } + } + catch(Exception&) + { + OSL_ENSURE(0,"ODocumentDefinition::save: caught an Exception (tried to let the InteractionHandler handle it)!"); + } + return sal_True; +} + +sal_Bool ODocumentDefinition::saveAs() +{ + // default handling: instantiate an interaction handler and let it handle the parameter request + if ( !m_bOpenInDesign ) + return sal_False; + + { + osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); + if ( !m_pImpl->m_aProps.aTitle.getLength() ) + { + aGuard.clear(); + return save(sal_False); // (sal_False) : we don't want an approve dialog + } + } + try + { + { + ::SolarMutexGuard aSolarGuard; + + // the request + Reference<XNameAccess> xName(m_xParentContainer,UNO_QUERY); + DocumentSaveRequest aRequest; + aRequest.Name = m_pImpl->m_aProps.aTitle; + + aRequest.Content.set(m_xParentContainer,UNO_QUERY); + OInteractionRequest* pRequest = new OInteractionRequest(makeAny(aRequest)); + Reference< XInteractionRequest > xRequest(pRequest); + // some knittings + // two continuations allowed: OK and Cancel + ODocumentSaveContinuation* pDocuSave = new ODocumentSaveContinuation; + pRequest->addContinuation(pDocuSave); + OInteraction< XInteractionDisapprove >* pDisApprove = new OInteraction< XInteractionDisapprove >; + pRequest->addContinuation(pDisApprove); + OInteractionAbort* pAbort = new OInteractionAbort; + pRequest->addContinuation(pAbort); + + // create the handler, let it handle the request + Reference< XInteractionHandler > xHandler(m_aContext.createComponent(::rtl::OUString(SERVICE_TASK_INTERACTION_HANDLER)), UNO_QUERY); + if ( xHandler.is() ) + xHandler->handle(xRequest); + + if ( pAbort->wasSelected() ) + return sal_False; + if ( pDisApprove->wasSelected() ) + return sal_True; + if ( pDocuSave->wasSelected() ) + { + ::osl::MutexGuard aGuard(m_aMutex); + Reference<XNameContainer> xNC(pDocuSave->getContent(),UNO_QUERY); + if ( xNC.is() ) + { + if ( m_pImpl->m_aProps.aTitle != pDocuSave->getName() ) + { + try + { + Reference< XStorage> xStorage = getContainerStorage(); + const static ::rtl::OUString sBaseName(RTL_CONSTASCII_USTRINGPARAM("Obj")); + + Reference<XNameAccess> xElements(xStorage,UNO_QUERY_THROW); + ::rtl::OUString sPersistentName = ::dbtools::createUniqueName(xElements,sBaseName); + xStorage->copyElementTo(m_pImpl->m_aProps.sPersistentName,xStorage,sPersistentName); + + ::rtl::OUString sOldName = m_pImpl->m_aProps.aTitle; + rename(pDocuSave->getName()); + updateDocumentTitle(); + + Sequence< Any > aArguments(3); + PropertyValue aValue; + // set as folder + aValue.Name = PROPERTY_NAME; + aValue.Value <<= sOldName; + aArguments[0] <<= aValue; + + aValue.Name = PROPERTY_PERSISTENT_NAME; + aValue.Value <<= sPersistentName; + aArguments[1] <<= aValue; + + aValue.Name = PROPERTY_AS_TEMPLATE; + aValue.Value <<= m_pImpl->m_aProps.bAsTemplate; + aArguments[2] <<= aValue; + + Reference< XMultiServiceFactory > xORB( m_xParentContainer, UNO_QUERY_THROW ); + Reference< XInterface > xComponent( xORB->createInstanceWithArguments( SERVICE_SDB_DOCUMENTDEFINITION, aArguments ) ); + Reference< XNameContainer > xNameContainer( m_xParentContainer, UNO_QUERY_THROW ); + xNameContainer->insertByName( sOldName, makeAny( xComponent ) ); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + Reference<XEmbedPersist> xPersist(m_xEmbeddedObject,UNO_QUERY); + if ( xPersist.is() ) + { + xPersist->storeOwn(); + notifyDataSourceModified(); + } + } + } + } + + } + catch(Exception&) + { + OSL_ENSURE(0,"ODocumentDefinition::save: caught an Exception (tried to let the InteractionHandler handle it)!"); + } + return sal_True; +} + +namespace +{ + // ......................................................................... + void lcl_putLoadArgs( ::comphelper::NamedValueCollection& _io_rArgs, const optional_bool _bSuppressMacros, const optional_bool _bReadOnly ) + { + if ( !!_bSuppressMacros ) + { + if ( *_bSuppressMacros ) + { + // if we're to suppress macros, do exactly this + _io_rArgs.put( "MacroExecutionMode", MacroExecMode::NEVER_EXECUTE ); + } + else + { + // otherwise, put the setting only if not already present + if ( !_io_rArgs.has( "MacroExecutionMode" ) ) + { + _io_rArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG ); + } + } + } + + if ( !!_bReadOnly ) + _io_rArgs.put( "ReadOnly", *_bReadOnly ); + } +} + +namespace +{ + Reference< XFrame > lcl_getDatabaseDocumentFrame( ODatabaseModelImpl& _rImpl ) + { + Reference< XModel > xDatabaseDocumentModel( _rImpl.getModel_noCreate() ); + + Reference< XController > xDatabaseDocumentController; + if ( xDatabaseDocumentModel.is() ) + xDatabaseDocumentController = xDatabaseDocumentModel->getCurrentController(); + + Reference< XFrame > xFrame; + if ( xDatabaseDocumentController.is() ) + xFrame = xDatabaseDocumentController->getFrame(); + + return xFrame; + } +} + +sal_Bool ODocumentDefinition::objectSupportsEmbeddedScripts() const +{ + bool bAllowDocumentMacros = !m_pImpl->m_pDataSource + || ( m_pImpl->m_pDataSource->determineEmbeddedMacros() == ODatabaseModelImpl::eSubDocumentMacros ); + + // if *any* of the objects of the database document already has macros, we continue to allow it + // to have them, until the user did a migration. + // If there are no macros, yet, we don't allow to create them + + return bAllowDocumentMacros; +} + +::rtl::OUString ODocumentDefinition::determineContentType() const +{ + return lcl_determineContentType_nothrow( getContainerStorage(), m_pImpl->m_aProps.sPersistentName ); +} + +void ODocumentDefinition::separateOpenCommandArguments( const Sequence< PropertyValue >& i_rOpenCommandArguments, + ::comphelper::NamedValueCollection& o_rDocumentLoadArgs, ::comphelper::NamedValueCollection& o_rEmbeddedObjectDescriptor ) +{ + ::comphelper::NamedValueCollection aOpenCommandArguments( i_rOpenCommandArguments ); + + const sal_Char* pObjectDescriptorArgs[] = + { + "RecoveryStorage" + }; + for ( size_t i=0; i < SAL_N_ELEMENTS( pObjectDescriptorArgs ); ++i ) + { + if ( aOpenCommandArguments.has( pObjectDescriptorArgs[i] ) ) + { + o_rEmbeddedObjectDescriptor.put( pObjectDescriptorArgs[i], aOpenCommandArguments.get( pObjectDescriptorArgs[i] ) ); + aOpenCommandArguments.remove( pObjectDescriptorArgs[i] ); + } + } + + o_rDocumentLoadArgs.merge( aOpenCommandArguments, false ); +} + +Sequence< PropertyValue > ODocumentDefinition::fillLoadArgs( const Reference< XConnection>& _xConnection, const bool _bSuppressMacros, const bool _bReadOnly, + const Sequence< PropertyValue >& i_rOpenCommandArguments, Sequence< PropertyValue >& _out_rEmbeddedObjectDescriptor ) +{ + // ......................................................................... + // (re-)create interceptor, and put it into the descriptor of the embedded object + if ( m_pInterceptor ) + { + m_pInterceptor->dispose(); + m_pInterceptor->release(); + m_pInterceptor = NULL; + } + + m_pInterceptor = new OInterceptor( this ,_bReadOnly); + m_pInterceptor->acquire(); + Reference<XDispatchProviderInterceptor> xInterceptor = m_pInterceptor; + + ::comphelper::NamedValueCollection aEmbeddedDescriptor; + aEmbeddedDescriptor.put( "OutplaceDispatchInterceptor", xInterceptor ); + + // ......................................................................... + ::comphelper::NamedValueCollection aMediaDesc; + separateOpenCommandArguments( i_rOpenCommandArguments, aMediaDesc, aEmbeddedDescriptor ); + + // ......................................................................... + // create the OutplaceFrameProperties, and put them into the descriptor of the embedded object + ::comphelper::NamedValueCollection OutplaceFrameProperties; + OutplaceFrameProperties.put( "TopWindow", (sal_Bool)sal_True ); + + Reference< XFrame > xParentFrame; + if ( m_pImpl->m_pDataSource ) + xParentFrame = lcl_getDatabaseDocumentFrame( *m_pImpl->m_pDataSource ); + if ( !xParentFrame.is() ) + { // i87957 we need a parent frame + Reference< XComponentLoader > xDesktop( m_aContext.createComponent( (::rtl::OUString)SERVICE_FRAME_DESKTOP ), UNO_QUERY_THROW ); + xParentFrame.set( xDesktop, UNO_QUERY ); + if ( xParentFrame.is() ) + { + Reference<util::XCloseable> xCloseable(m_pImpl->m_pDataSource->getModel_noCreate(),UNO_QUERY); + if ( xCloseable.is() ) + { + xCloseable->addCloseListener(this); + m_bRemoveListener = sal_True; + } + } + } + OSL_ENSURE( xParentFrame.is(), "ODocumentDefinition::fillLoadArgs: no parent frame!" ); + if ( xParentFrame.is() ) + OutplaceFrameProperties.put( "ParentFrame", xParentFrame ); + + aEmbeddedDescriptor.put( "OutplaceFrameProperties", OutplaceFrameProperties.getNamedValues() ); + + // ......................................................................... + // tell the embedded object to have (or not have) script support + aEmbeddedDescriptor.put( "EmbeddedScriptSupport", (sal_Bool)objectSupportsEmbeddedScripts() ); + + // ......................................................................... + // tell the embedded object to not participate in the document recovery game - the DB doc will handle it + aEmbeddedDescriptor.put( "DocumentRecoverySupport", (sal_Bool)sal_False ); + + // ......................................................................... + // pass the descriptor of the embedded object to the caller + aEmbeddedDescriptor >>= _out_rEmbeddedObjectDescriptor; + + // ......................................................................... + // create the ComponentData, and put it into the document's media descriptor + { + ::comphelper::NamedValueCollection aComponentData; + aComponentData.put( "ActiveConnection", _xConnection ); + aComponentData.put( "ApplyFormDesignMode", !_bReadOnly ); + aMediaDesc.put( "ComponentData", aComponentData.getPropertyValues() ); + } + + if ( m_pImpl->m_aProps.aTitle.getLength() ) + aMediaDesc.put( "DocumentTitle", m_pImpl->m_aProps.aTitle ); + + aMediaDesc.put( "DocumentBaseURL", m_pImpl->m_pDataSource->getURL() ); + + // ......................................................................... + // put the common load arguments into the document's media descriptor + lcl_putLoadArgs( aMediaDesc, optional_bool( _bSuppressMacros ), optional_bool( _bReadOnly ) ); + + return aMediaDesc.getPropertyValues(); +} + +void ODocumentDefinition::loadEmbeddedObject( const Reference< XConnection >& i_rConnection, const Sequence< sal_Int8 >& _aClassID, + const Sequence< PropertyValue >& i_rOpenCommandArguments, const bool _bSuppressMacros, const bool _bReadOnly ) +{ + if ( !m_xEmbeddedObject.is() ) + { + Reference< XStorage> xStorage = getContainerStorage(); + if ( xStorage.is() ) + { + Reference< XEmbedObjectFactory> xEmbedFactory( m_aContext.createComponent( "com.sun.star.embed.OOoEmbeddedObjectFactory" ), UNO_QUERY ); + if ( xEmbedFactory.is() ) + { + ::rtl::OUString sDocumentService; + sal_Bool bSetSize = sal_False; + sal_Int32 nEntryConnectionMode = EntryInitModes::DEFAULT_INIT; + Sequence< sal_Int8 > aClassID = _aClassID; + if ( aClassID.getLength() ) + { + nEntryConnectionMode = EntryInitModes::TRUNCATE_INIT; + bSetSize = sal_True; + } + else + { + sDocumentService = GetDocumentServiceFromMediaType( getContentType(), m_aContext, aClassID ); + // check if we are not a form and + // the com.sun.star.report.pentaho.SOReportJobFactory is not present. + if ( !m_bForm && !sDocumentService.equalsAscii("com.sun.star.text.TextDocument")) + { + // we seem to be a "new style" report, check if report extension is present. + Reference< XContentEnumerationAccess > xEnumAccess( m_aContext.getLegacyServiceFactory(), UNO_QUERY ); + const ::rtl::OUString sReportEngineServiceName = ::dbtools::getDefaultReportEngineServiceName(m_aContext.getLegacyServiceFactory()); + Reference< XEnumeration > xEnumDrivers = xEnumAccess->createContentEnumeration(sReportEngineServiceName); + if ( !xEnumDrivers.is() || !xEnumDrivers->hasMoreElements() ) + { + com::sun::star::io::WrongFormatException aWFE; + aWFE.Message = DBACORE_RESSTRING( RID_STR_MISSING_EXTENSION ); + throw aWFE; + } + } + if ( !aClassID.getLength() ) + { + if ( m_bForm ) + aClassID = MimeConfigurationHelper::GetSequenceClassID(SO3_SW_CLASSID); + else + { + aClassID = MimeConfigurationHelper::GetSequenceClassID(SO3_RPT_CLASSID_90); + } + } + } + + OSL_ENSURE( aClassID.getLength(),"No Class ID" ); + + Sequence< PropertyValue > aEmbeddedObjectDescriptor; + Sequence< PropertyValue > aLoadArgs( fillLoadArgs( + i_rConnection, _bSuppressMacros, _bReadOnly, i_rOpenCommandArguments, aEmbeddedObjectDescriptor ) ); + + m_xEmbeddedObject.set(xEmbedFactory->createInstanceUserInit(aClassID + ,sDocumentService + ,xStorage + ,m_pImpl->m_aProps.sPersistentName + ,nEntryConnectionMode + ,aLoadArgs + ,aEmbeddedObjectDescriptor + ),UNO_QUERY); + if ( m_xEmbeddedObject.is() ) + { + if ( !m_pClientHelper ) + { + m_pClientHelper = new OEmbeddedClientHelper(this); + m_pClientHelper->acquire(); + } + Reference<XEmbeddedClient> xClient = m_pClientHelper; + m_xEmbeddedObject->setClientSite(xClient); + m_xEmbeddedObject->changeState(EmbedStates::RUNNING); + if ( bSetSize ) + { + LockModifiable aLockModify( impl_getComponent_throw( false ) ); + + awt::Size aSize( DEFAULT_WIDTH, DEFAULT_HEIGHT ); + m_xEmbeddedObject->setVisualAreaSize(Aspects::MSOLE_CONTENT,aSize); + } + } + } + } + } + else + { + sal_Int32 nCurrentState = m_xEmbeddedObject->getCurrentState(); + if ( nCurrentState == EmbedStates::LOADED ) + { + if ( !m_pClientHelper ) + { + m_pClientHelper = new OEmbeddedClientHelper(this); + m_pClientHelper->acquire(); + } + Reference<XEmbeddedClient> xClient = m_pClientHelper; + m_xEmbeddedObject->setClientSite(xClient); + + Sequence< PropertyValue > aEmbeddedObjectDescriptor; + Sequence< PropertyValue > aLoadArgs( fillLoadArgs( + i_rConnection, _bSuppressMacros, _bReadOnly, i_rOpenCommandArguments, aEmbeddedObjectDescriptor ) ); + + Reference<XCommonEmbedPersist> xCommon(m_xEmbeddedObject,UNO_QUERY); + OSL_ENSURE(xCommon.is(),"unsupported interface!"); + if ( xCommon.is() ) + xCommon->reload( aLoadArgs, aEmbeddedObjectDescriptor ); + m_xEmbeddedObject->changeState(EmbedStates::RUNNING); + } + else + { + OSL_ENSURE( ( nCurrentState == EmbedStates::RUNNING ) || ( nCurrentState == EmbedStates::ACTIVE ), + "ODocumentDefinition::loadEmbeddedObject: unexpected state!" ); + + // if the document was already loaded (which means the embedded object is in state RUNNING or ACTIVE), + // then just re-set some model parameters + try + { + // ensure the media descriptor doesn't contain any values which are intended for the + // EmbeddedObjectDescriptor only + ::comphelper::NamedValueCollection aEmbeddedObjectDescriptor; + ::comphelper::NamedValueCollection aNewMediaDesc; + separateOpenCommandArguments( i_rOpenCommandArguments, aNewMediaDesc, aEmbeddedObjectDescriptor ); + + // merge the new media descriptor into the existing media descriptor + const Reference< XModel > xModel( getComponent(), UNO_QUERY_THROW ); + const Sequence< PropertyValue > aArgs = xModel->getArgs(); + ::comphelper::NamedValueCollection aExistentMediaDesc( aArgs ); + aExistentMediaDesc.merge( aNewMediaDesc, sal_False ); + + lcl_putLoadArgs( aExistentMediaDesc, optional_bool(), optional_bool() ); + // don't put _bSuppressMacros and _bReadOnly here - if the document was already + // loaded, we should not tamper with its settings. + // #i88977# / 2008-05-05 / frank.schoenheit@sun.com + // #i86872# / 2008-03-13 / frank.schoenheit@sun.com + + xModel->attachResource( xModel->getURL(), aExistentMediaDesc.getPropertyValues() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + + // set the OfficeDatabaseDocument instance as parent of the embedded document + // #i40358# / 2005-01-19 / frank.schoenheit@sun.com + Reference< XChild > xDepdendDocAsChild( getComponent(), UNO_QUERY ); + if ( xDepdendDocAsChild.is() ) + { + try + { + if ( !xDepdendDocAsChild->getParent().is() ) + { // first encounter + xDepdendDocAsChild->setParent( getDataSource( m_xParentContainer ) ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + if ( i_rConnection.is() ) + m_xLastKnownConnection = i_rConnection; +} + +void ODocumentDefinition::onCommandPreview(Any& _rImage) +{ + loadEmbeddedObjectForPreview(); + if ( m_xEmbeddedObject.is() ) + { + try + { + Reference<XTransferable> xTransfer(getComponent(),UNO_QUERY); + if ( xTransfer.is() ) + { + DataFlavor aFlavor; + aFlavor.MimeType = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("image/png")); + aFlavor.HumanPresentableName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Portable Network Graphics")); + aFlavor.DataType = ::getCppuType(static_cast< const Sequence < sal_Int8 >* >(NULL)); + + _rImage = xTransfer->getTransferData( aFlavor ); + } + } + catch( Exception ) + { + } + } +} + +void ODocumentDefinition::getPropertyDefaultByHandle( sal_Int32 /*_nHandle*/, Any& _rDefault ) const +{ + _rDefault.clear(); +} + +void ODocumentDefinition::onCommandGetDocumentProperties( Any& _rProps ) +{ + loadEmbeddedObjectForPreview(); + if ( m_xEmbeddedObject.is() ) + { + try + { + Reference<XDocumentPropertiesSupplier> xDocSup( + getComponent(), UNO_QUERY ); + if ( xDocSup.is() ) + _rProps <<= xDocSup->getDocumentProperties(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } +} + +Reference< util::XCloseable > ODocumentDefinition::impl_getComponent_throw( const bool i_ForceCreate ) +{ + OSL_ENSURE(m_xEmbeddedObject.is(),"Illegal call for embeddedObject"); + Reference< util::XCloseable > xComp; + if ( m_xEmbeddedObject.is() ) + { + int nState = m_xEmbeddedObject->getCurrentState(); + if ( ( nState == EmbedStates::LOADED ) && i_ForceCreate ) + { + m_xEmbeddedObject->changeState( EmbedStates::RUNNING ); + nState = m_xEmbeddedObject->getCurrentState(); + OSL_ENSURE( nState == EmbedStates::RUNNING, "ODocumentDefinition::impl_getComponent_throw: could not switch to RUNNING!" ); + } + + if ( nState == EmbedStates::ACTIVE || nState == EmbedStates::RUNNING ) + { + Reference<XComponentSupplier> xCompProv(m_xEmbeddedObject,UNO_QUERY); + if ( xCompProv.is() ) + { + xComp = xCompProv->getComponent(); + OSL_ENSURE(xComp.is(),"No valid component"); + } + } + } + return xComp; +} + +Reference< util::XCloseable > ODocumentDefinition::getComponent() throw (RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + return impl_getComponent_throw( true ); +} + +namespace +{ + Reference< XDatabaseDocumentUI > lcl_getDatabaseDocumentUI( ODatabaseModelImpl& _rModelImpl ) + { + Reference< XDatabaseDocumentUI > xUI; + + Reference< XModel > xModel( _rModelImpl.getModel_noCreate() ); + if ( xModel.is() ) + xUI.set( xModel->getCurrentController(), UNO_QUERY ); + return xUI; + } +} + +Reference< XComponent > ODocumentDefinition::impl_openUI_nolck_throw( bool _bForEditing ) +{ + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + if ( !m_pImpl || !m_pImpl->m_pDataSource ) + throw DisposedException(); + + Reference< XDatabaseDocumentUI > xUI( lcl_getDatabaseDocumentUI( *m_pImpl->m_pDataSource ) ); + if ( !xUI.is() ) + { + // no XDatabaseDocumentUI -> just execute the respective command + m_bOpenInDesign = _bForEditing; + Reference< XComponent > xComponent( onCommandOpenSomething( Any(), true, NULL ), UNO_QUERY ); + OSL_ENSURE( xComponent.is(), "ODocumentDefinition::impl_openUI_nolck_throw: opening the thingie failed." ); + return xComponent; + } + + Reference< XComponent > xComponent; + try + { + ::rtl::OUString sName( impl_getHierarchicalName( false ) ); + sal_Int32 nObjectType = m_bForm ? DatabaseObject::FORM : DatabaseObject::REPORT; + aGuard.clear(); + + xComponent = xUI->loadComponent( + nObjectType, sName, _bForEditing + ); + } + catch( RuntimeException& ) { throw; } + catch( const Exception& ) + { + throw WrappedTargetException( + ::rtl::OUString(), *this, ::cppu::getCaughtException() ); + } + return xComponent; +} + +void ODocumentDefinition::impl_store_throw() +{ + Reference<XEmbedPersist> xPersist( m_xEmbeddedObject, UNO_QUERY ); + if ( xPersist.is() ) + { + xPersist->storeOwn(); + notifyDataSourceModified(); + } +} + +bool ODocumentDefinition::impl_close_throw() +{ + bool bSuccess = prepareClose(); + if ( bSuccess && m_xEmbeddedObject.is() ) + { + m_xEmbeddedObject->changeState( EmbedStates::LOADED ); + bSuccess = m_xEmbeddedObject->getCurrentState() == EmbedStates::LOADED; + } + return bSuccess; +} + +Reference< XComponent > SAL_CALL ODocumentDefinition::open( ) throw (WrappedTargetException, RuntimeException) +{ + return impl_openUI_nolck_throw( false ); +} + +Reference< XComponent > SAL_CALL ODocumentDefinition::openDesign( ) throw (WrappedTargetException, RuntimeException) +{ + return impl_openUI_nolck_throw( true ); +} + +void SAL_CALL ODocumentDefinition::store( ) throw (WrappedTargetException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + try + { + impl_store_throw(); + } + catch( RuntimeException& ) { throw; } + catch( const Exception& ) + { + throw WrappedTargetException( + ::rtl::OUString(), *this, ::cppu::getCaughtException() ); + } +} + +::sal_Bool SAL_CALL ODocumentDefinition::close( ) throw (WrappedTargetException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + sal_Bool bSuccess = sal_False; + try + { + bSuccess = impl_close_throw(); + } + catch( RuntimeException& ) { throw; } + catch( const Exception& ) + { + throw WrappedTargetException( + ::rtl::OUString(), *this, ::cppu::getCaughtException() ); + } + return bSuccess; +} + +::rtl::OUString SAL_CALL ODocumentDefinition::getHierarchicalName() throw (RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + return impl_getHierarchicalName( false ); +} + +::rtl::OUString SAL_CALL ODocumentDefinition::composeHierarchicalName( const ::rtl::OUString& i_rRelativeName ) throw (IllegalArgumentException, NoSupportException, RuntimeException) +{ + ::rtl::OUStringBuffer aBuffer; + aBuffer.append( getHierarchicalName() ); + aBuffer.append( sal_Unicode( '/' ) ); + aBuffer.append( i_rRelativeName ); + return aBuffer.makeStringAndClear(); +} + +void SAL_CALL ODocumentDefinition::rename( const ::rtl::OUString& _rNewName ) throw (SQLException, ElementExistException, RuntimeException) +{ + try + { + ::osl::ResettableMutexGuard aGuard(m_aMutex); + if ( _rNewName.equals( m_pImpl->m_aProps.aTitle ) ) + return; + + // document definitions are organized in a hierarchical way, so reject names + // which contain a /, as this is reserved for hierarchy level separation + if ( _rNewName.indexOf( '/' ) != -1 ) + m_aErrorHelper.raiseException( ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES, *this ); + + NameChangeNotifier aNameChangeAndNotify( *this, _rNewName, aGuard ); + m_pImpl->m_aProps.aTitle = _rNewName; + + if ( m_xEmbeddedObject.is() && m_xEmbeddedObject->getCurrentState() == EmbedStates::ACTIVE ) + updateDocumentTitle(); + } + catch(const PropertyVetoException&) + { + throw ElementExistException(_rNewName,*this); + } +} + +Reference< XStorage> ODocumentDefinition::getContainerStorage() const +{ + return m_pImpl->m_pDataSource + ? m_pImpl->m_pDataSource->getStorage( m_bForm ? ODatabaseModelImpl::E_FORM : ODatabaseModelImpl::E_REPORT ) + : Reference< XStorage>(); +} + +sal_Bool ODocumentDefinition::isModified() +{ + osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex); + sal_Bool bRet = sal_False; + if ( m_xEmbeddedObject.is() ) + { + Reference<XModifiable> xModel(getComponent(),UNO_QUERY); + bRet = xModel.is() && xModel->isModified(); + } + return bRet; +} + +bool ODocumentDefinition::prepareClose() +{ + if ( !m_xEmbeddedObject.is() ) + return true; + + try + { + // suspend the controller. Embedded objects are not allowed to raise + // own UI at their own discretion, instead, this has always to be triggered + // by the embedding component. Thus, we do the suspend call here. + // #i49370# / 2005-06-09 / frank.schoenheit@sun.com + + Reference< util::XCloseable > xComponent( impl_getComponent_throw( false ) ); + if ( !xComponent.is() ) + return true; + + Reference< XModel > xModel( xComponent, UNO_QUERY ); + Reference< XController > xController; + if ( xModel.is() ) + xController = xModel->getCurrentController(); + + OSL_ENSURE( xController.is() || ( m_xEmbeddedObject->getCurrentState() < EmbedStates::ACTIVE ), + "ODocumentDefinition::prepareClose: no controller!" ); + if ( !xController.is() ) + // document has not yet been activated, i.e. has no UI, yet + return true; + + sal_Bool bCouldSuspend = xController->suspend( sal_True ); + if ( !bCouldSuspend ) + // controller vetoed the closing + return false; + + if ( isModified() ) + { + Reference< XFrame > xFrame( xController->getFrame() ); + if ( xFrame.is() ) + { + Reference< XTopWindow > xTopWindow( xFrame->getContainerWindow(), UNO_QUERY_THROW ); + xTopWindow->toFront(); + } + if ( !save( sal_True ) ) + { + if ( bCouldSuspend ) + // revert suspension + xController->suspend( sal_False ); + // saving failed or was cancelled + return false; + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return true; +} + +void ODocumentDefinition::fillReportData( const ::comphelper::ComponentContext& _rContext, + const Reference< util::XCloseable >& _rxComponent, + const Reference< XConnection >& _rxActiveConnection ) +{ + Sequence< Any > aArgs(2); + PropertyValue aValue; + aValue.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TextDocument" ) ); + aValue.Value <<= _rxComponent; + aArgs[0] <<= aValue; + aValue.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ActiveConnection" ) ); + aValue.Value <<= _rxActiveConnection; + aArgs[1] <<= aValue; + + try + { + Reference< XJobExecutor > xExecuteable( + _rContext.createComponentWithArguments( "com.sun.star.wizards.report.CallReportWizard", aArgs ), UNO_QUERY_THROW ); + xExecuteable->trigger( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "fill" ) ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +void ODocumentDefinition::updateDocumentTitle() +{ + ::rtl::OUString sName = m_pImpl->m_aProps.aTitle; + if ( m_pImpl->m_pDataSource ) + { + if ( !sName.getLength() ) + { + if ( m_bForm ) + sName = DBACORE_RESSTRING( RID_STR_FORM ); + else + sName = DBACORE_RESSTRING( RID_STR_REPORT ); + Reference< XUntitledNumbers > xUntitledProvider(m_pImpl->m_pDataSource->getModel_noCreate(), UNO_QUERY ); + if ( xUntitledProvider.is() ) + sName += ::rtl::OUString::valueOf( xUntitledProvider->leaseNumber(getComponent()) ); + } + + Reference< XTitle > xDatabaseDocumentModel(m_pImpl->m_pDataSource->getModel_noCreate(),uno::UNO_QUERY); + if ( xDatabaseDocumentModel.is() ) + sName = xDatabaseDocumentModel->getTitle() + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" : ")) + sName; + } + Reference< XTitle> xTitle(getComponent(),UNO_QUERY); + if ( xTitle.is() ) + xTitle->setTitle(sName); +} + +void SAL_CALL ODocumentDefinition::queryClosing( const lang::EventObject& Source, ::sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException) +{ + (void) Source; + (void) GetsOwnership; + try + { + if ( !close() ) + throw util::CloseVetoException(); + } + catch(const lang::WrappedTargetException&) + { + throw util::CloseVetoException(); + } +} + +void SAL_CALL ODocumentDefinition::notifyClosing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException) +{ +} + +void SAL_CALL ODocumentDefinition::disposing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException) +{ +} + +void ODocumentDefinition::firePropertyChange( sal_Int32 i_nHandle, const Any& i_rNewValue, const Any& i_rOldValue, + sal_Bool i_bVetoable, const NotifierAccess ) +{ + fire( &i_nHandle, &i_rNewValue, &i_rOldValue, 1, i_bVetoable ); +} + +// ============================================================================= +// NameChangeNotifier +// ============================================================================= +NameChangeNotifier::NameChangeNotifier( ODocumentDefinition& i_rDocumentDefinition, const ::rtl::OUString& i_rNewName, + ::osl::ResettableMutexGuard& i_rClearForNotify ) + :m_rDocumentDefinition( i_rDocumentDefinition ) + ,m_aOldValue( makeAny( i_rDocumentDefinition.getCurrentName() ) ) + ,m_aNewValue( makeAny( i_rNewName ) ) + ,m_rClearForNotify( i_rClearForNotify ) +{ + impl_fireEvent_throw( sal_True ); +} + +NameChangeNotifier::~NameChangeNotifier() +{ + impl_fireEvent_throw( sal_False ); +} + +void NameChangeNotifier::impl_fireEvent_throw( const sal_Bool i_bVetoable ) +{ + m_rClearForNotify.clear(); + m_rDocumentDefinition.firePropertyChange( + PROPERTY_ID_NAME, m_aNewValue, m_aOldValue, i_bVetoable, ODocumentDefinition::NotifierAccess() ); + m_rClearForNotify.reset(); +} + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documentdefinition.hxx b/dbaccess/source/core/dataaccess/documentdefinition.hxx new file mode 100644 index 000000000000..f74b6acf6815 --- /dev/null +++ b/dbaccess/source/core/dataaccess/documentdefinition.hxx @@ -0,0 +1,386 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 _DBA_COREDATAACCESS_DOCUMENTDEFINITION_HXX_ +#define _DBA_COREDATAACCESS_DOCUMENTDEFINITION_HXX_ + +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/implbase4.hxx> +#include "ContentHelper.hxx" +#include <comphelper/propertystatecontainer.hxx> +#include <comphelper/proparrhlp.hxx> +#include "apitools.hxx" +#include <comphelper/uno3.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/embed/XStateChangeListener.hpp> +#include <com/sun/star/sdb/XSubDocument.hpp> +#include <com/sun/star/util/XCloseListener.hpp> +#include <com/sun/star/container/XHierarchicalName.hpp> + +namespace comphelper +{ + class NamedValueCollection; +} + +//........................................................................ +namespace dbaccess +{ +//........................................................................ + + class OInterceptor; + class OEmbeddedClientHelper; +//========================================================================== +//= ODocumentDefinition - a database "document" which is simply a link to a real +//= document +//========================================================================== + +typedef ::cppu::ImplHelper4 < ::com::sun::star::embed::XComponentSupplier + , ::com::sun::star::sdb::XSubDocument + , ::com::sun::star::util::XCloseListener + , ::com::sun::star::container::XHierarchicalName + > ODocumentDefinition_Base; + +class ODocumentDefinition + :public OContentHelper + ,public ::comphelper::OPropertyStateContainer + ,public ::comphelper::OPropertyArrayUsageHelper< ODocumentDefinition > + ,public ODocumentDefinition_Base +{ + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XEmbeddedObject> m_xEmbeddedObject; + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStateChangeListener > m_xListener; + ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection > m_xLastKnownConnection; + + OInterceptor* m_pInterceptor; + sal_Bool m_bForm; // <TRUE/> if it is a form + sal_Bool m_bOpenInDesign; + sal_Bool m_bInExecute; + sal_Bool m_bRemoveListener; + OEmbeddedClientHelper* m_pClientHelper; + +protected: + virtual ~ODocumentDefinition(); + +public: + + ODocumentDefinition( + const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxContainer, + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >&, + const TContentPtr& _pImpl, + sal_Bool _bForm + ); + + void initialLoad( + const ::com::sun::star::uno::Sequence< sal_Int8 >& i_rClassID, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& i_rCreationArgs, + const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& i_rConnection + ); + +// com::sun::star::lang::XTypeProvider + DECLARE_TYPEPROVIDER( ); + +// ::com::sun::star::uno::XInterface + DECLARE_XINTERFACE( ) + +// ::com::sun::star::lang::XServiceInfo + DECLARE_SERVICE_INFO_STATIC(); + +// ::com::sun::star::beans::XPropertySet + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw(::com::sun::star::uno::RuntimeException); + + // OPropertySetHelper + virtual void SAL_CALL getFastPropertyValue( + ::com::sun::star::uno::Any& o_rValue, + sal_Int32 i_nHandle + ) const; + + // XComponentSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloseable > SAL_CALL getComponent( ) throw (::com::sun::star::uno::RuntimeException); + + // XSubDocument + virtual ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > SAL_CALL open( ) throw (::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > SAL_CALL openDesign( ) throw (::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL store( ) throw (::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL close( ) throw (::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XHierarchicalName + virtual ::rtl::OUString SAL_CALL getHierarchicalName( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL composeHierarchicalName( const ::rtl::OUString& aRelativeName ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + +// OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper(); + + // XCommandProcessor + virtual ::com::sun::star::uno::Any SAL_CALL execute( const ::com::sun::star::ucb::Command& aCommand, sal_Int32 CommandId, const ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >& Environment ) throw (::com::sun::star::uno::Exception, ::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::RuntimeException) ; + + // XRename + virtual void SAL_CALL rename( const ::rtl::OUString& newName ) throw (::com::sun::star::sdbc::SQLException, ::com::sun::star::container::ElementExistException, ::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); + + // XEventListener + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); + + /** returns the forms/reports container storage, depending on m_bForm. Our own storage + inside this container storage is the one with the name as indicated by m_pImpl->m_aProps.sPersistentName. + */ + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > + getContainerStorage() const; + + sal_Bool save(sal_Bool _bApprove); + sal_Bool saveAs(); + void closeObject(); + sal_Bool isModified(); + inline sal_Bool isNewReport() const { return !m_bForm && !m_pImpl->m_aProps.bAsTemplate; } + + static void fillReportData( + const ::comphelper::ComponentContext& _rContext, + const ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloseable >& _rxComponent, + const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxActiveConnection + ); + + const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& + getConnection() const { return m_xLastKnownConnection; } + + /** prepares closing the document component + + The method suspends the controller associated with the document, and saves the document + if necessary. + + @return + <TRUE/> if and only if the document component can be closed + */ + bool prepareClose(); + + static ::com::sun::star::uno::Sequence< sal_Int8 > getDefaultDocumentTypeClassId(); + + static ::rtl::OUString GetDocumentServiceFromMediaType( + const ::rtl::OUString& _rMediaType, + const ::comphelper::ComponentContext& _rContext, + ::com::sun::star::uno::Sequence< sal_Int8 >& _rClassId + ); + static ::rtl::OUString GetDocumentServiceFromMediaType( + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& _rxContainerStorage, + const ::rtl::OUString& _rEntityName, + const ::comphelper::ComponentContext& _rContext, + ::com::sun::star::uno::Sequence< sal_Int8 >& _rClassId + ); + + struct NotifierAccess { friend class NameChangeNotifier; private: NotifierAccess() { } }; + const ::rtl::OUString& getCurrentName() const { return m_pImpl->m_aProps.aTitle; } + void firePropertyChange( + sal_Int32 i_nHandle, + const ::com::sun::star::uno::Any& i_rNewValue, + const ::com::sun::star::uno::Any& i_rOldValue, + sal_Bool i_bVetoable, + const NotifierAccess + ); + +private: + /** does necessary initializations after our embedded object has been switched to ACTIVE + */ + void impl_onActivateEmbeddedObject_nothrow( const bool i_bReactivated ); + + /** initializes a newly created view/controller of a form which is displaying our embedded object + + Has only to be called if the respective embedded object has been loaded for design (and + not for data entry) + + @param _rxController + the controller which belongs to the XModel of our (active) embedded object + */ + static void impl_initFormEditView( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController >& _rxController ); + + /** removes the given frame from the desktop's frame collection + @raises ::com::sun::star::uno::RuntimeException + */ + static void impl_removeFrameFromDesktop_throw( + const ::comphelper::ComponentContext& _rContxt, + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& _rxFrame + ); + + /** opens the UI for this sub document + */ + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > + impl_openUI_nolck_throw( bool _bForEditing ); + + /** stores our document, if it's already loaded + */ + void impl_store_throw(); + + /** closes our document, if it's open + */ + bool impl_close_throw(); + + /** returns our component, creates it if necessary + */ + ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloseable > + impl_getComponent_throw( const bool i_ForceCreate = true ); + + /** shows or hides our component + + The embedded object must exist, and be in state LOADED, at least. + */ + void impl_showOrHideComponent_throw( const bool i_bShow ); + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const; + + virtual void getPropertyDefaultByHandle( sal_Int32 _nHandle, ::com::sun::star::uno::Any& _rDefault ) const; + + // helper + virtual void SAL_CALL disposing(); + + // OContentHelper overridables + virtual ::rtl::OUString determineContentType() const; + + /** fills the load arguments + */ + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > + fillLoadArgs( + const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection>& _xConnection, + const bool _bSuppressMacros, + const bool _bReadOnly, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& i_rOpenCommandArguments, + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& _out_rEmbeddedObjectDescriptor + ); + + /** splits the given arguments to an "open*" command into arguments for loading the document, and arguments to be + put into the EmbeddedObjectDescriptor + + Any values already present in <code>o_rDocumentLoadArgs</code> and <code>o_rEmbeddedObjectDescriptor</code> + will be overwritten by values from <code>i_rOpenCommandArguments</code>, if applicable, otherwise they will + be preserved. + + @param i_rOpenCommandArguments + the arguments passed to the "open*" command at the content + @param o_rDocumentLoadArgs + the arguments to be passed when actually loading the embedded document. + @param o_rEmbeddedObjectDescriptor + the EmbeddedObjectDescriptor to be passed when initializing the embedded object + */ + void separateOpenCommandArguments( + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& i_rOpenCommandArguments, + ::comphelper::NamedValueCollection& o_rDocumentLoadArgs, + ::comphelper::NamedValueCollection& o_rEmbeddedObjectDescriptor + ); + + /** loads the EmbeddedObject if not already loaded + @param _aClassID + If set, it will be used to create the embedded object. + */ + void loadEmbeddedObject( + const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection>& _xConnection, + const ::com::sun::star::uno::Sequence< sal_Int8 >& _aClassID, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& _rAdditionalArgs, + const bool _bSuppressMacros, + const bool _bReadOnly + ); + + /** loads the embedded object, if not already loaded. No new object can be created with this method. + */ + void loadEmbeddedObject( bool _bSuppressMacros = false ) + { + loadEmbeddedObject( + NULL, + ::com::sun::star::uno::Sequence< sal_Int8 >(), + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >(), + _bSuppressMacros, + false + ); + } + + /** loads the embedded object for preview. Macros will be suppressed, and the document will + be read-only. + */ + void loadEmbeddedObjectForPreview() + { + loadEmbeddedObject( + NULL, + ::com::sun::star::uno::Sequence< sal_Int8 >(), + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >(), + true, + true + ); + } + + /** searches for read-only flag in the args of the model and sets it to the given value, + if the value was not found, it will be appended. + @param _bReadOnly + If <TRUE/> the document will be switched to readonly mode + */ + void updateDocumentTitle(); + + void registerProperties(); + + /** determines whether the document we represent supports embedded scripts and macros + */ + sal_Bool objectSupportsEmbeddedScripts() const; + + //- commands + + void onCommandGetDocumentProperties( ::com::sun::star::uno::Any& _rProps ); + void onCommandInsert( const ::rtl::OUString& _sURL, const ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >& Environment ) throw( ::com::sun::star::uno::Exception ); + void onCommandPreview( ::com::sun::star::uno::Any& _rImage ); + ::com::sun::star::uno::Any + onCommandOpenSomething( + const ::com::sun::star::uno::Any& _rArgument, + const bool _bActivate, + const ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >& _rxEnvironment + ); +private: + using ::cppu::OPropertySetHelper::getFastPropertyValue; +}; + +class NameChangeNotifier +{ +public: + NameChangeNotifier( + ODocumentDefinition& i_rDocumentDefinition, + const ::rtl::OUString& i_rNewName, + ::osl::ResettableMutexGuard& i_rClearForNotify + ); + ~NameChangeNotifier(); + +private: + ODocumentDefinition& m_rDocumentDefinition; + const ::com::sun::star::uno::Any m_aOldValue; + const ::com::sun::star::uno::Any m_aNewValue; + mutable ::osl::ResettableMutexGuard& m_rClearForNotify; + + void impl_fireEvent_throw( const sal_Bool i_bVetoable ); +}; + +} // namespace dbaccess + +#endif // _DBA_COREDATAACCESS_DOCUMENTDEFINITION_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documenteventexecutor.cxx b/dbaccess/source/core/dataaccess/documenteventexecutor.cxx new file mode 100644 index 000000000000..35262dd70038 --- /dev/null +++ b/dbaccess/source/core/dataaccess/documenteventexecutor.cxx @@ -0,0 +1,222 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * 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_dbaccess.hxx" + +#include "documenteventexecutor.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/document/XDocumentEventBroadcaster.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +/** === end UNO includes === **/ + +#include <comphelper/componentcontext.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <cppuhelper/weakref.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> +#include <osl/mutex.hxx> + +namespace dbaccess +{ + + /** === 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::uno::WeakReference; + using ::com::sun::star::document::XDocumentEventBroadcaster; + using ::com::sun::star::document::XEventsSupplier; + using ::com::sun::star::container::XNameAccess; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::util::XURLTransformer; + using ::com::sun::star::frame::XDispatchProvider; + using ::com::sun::star::frame::XDispatch; + using ::com::sun::star::util::URL; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::frame::XController; + using ::com::sun::star::document::DocumentEvent; + /** === end UNO using === **/ + using namespace ::com::sun::star; + + //==================================================================== + //= DocumentEventExecutor_Data + //==================================================================== + struct DocumentEventExecutor_Data + { + WeakReference< XEventsSupplier > xDocument; + Reference< XURLTransformer > xURLTransformer; + + DocumentEventExecutor_Data( const Reference< XEventsSupplier >& _rxDocument ) + :xDocument( _rxDocument ) + { + } + }; + + namespace + { + static void lcl_dispatchScriptURL_throw( DocumentEventExecutor_Data& _rDocExecData, + const ::rtl::OUString& _rScriptURL, const DocumentEvent& _rTrigger ) + { + Reference< XModel > xDocument( _rDocExecData.xDocument.get(), UNO_QUERY_THROW ); + + Reference< XController > xController( xDocument->getCurrentController() ); + Reference< XDispatchProvider > xDispProv; + if ( xController.is() ) + xDispProv.set( xController->getFrame(), UNO_QUERY ); + if ( !xDispProv.is() ) + { + OSL_ENSURE( false, "lcl_dispatchScriptURL_throw: no controller/frame? How should I dispatch?" ); + return; + } + + URL aScriptURL; + aScriptURL.Complete = _rScriptURL; + if ( _rDocExecData.xURLTransformer.is() ) + _rDocExecData.xURLTransformer->parseStrict( aScriptURL ); + + // unfortunately, executing a script can trigger all kind of complex stuff, and unfortunately, not + // every component involved into this properly cares for thread safety. To be on the safe side, + // we lock the solar mutex here. + SolarMutexGuard aSolarGuard; + + Reference< XDispatch > xDispatch( xDispProv->queryDispatch( aScriptURL, ::rtl::OUString(), 0 ) ); + if ( !xDispatch.is() ) + { + OSL_ENSURE( false, "lcl_dispatchScriptURL_throw: no dispatcher for the script URL!" ); + return; + } + + PropertyValue aEventParam; + aEventParam.Value <<= _rTrigger; + Sequence< PropertyValue > aDispatchArgs( &aEventParam, 1 ); + xDispatch->dispatch( aScriptURL, aDispatchArgs ); + } + } + + //==================================================================== + //= DocumentEventExecutor + //==================================================================== + DocumentEventExecutor::DocumentEventExecutor( const ::comphelper::ComponentContext& _rContext, + const Reference< XEventsSupplier >& _rxDocument ) + :m_pData( new DocumentEventExecutor_Data( _rxDocument ) ) + { + Reference< XDocumentEventBroadcaster > xBroadcaster( _rxDocument, UNO_QUERY_THROW ); + + osl_incrementInterlockedCount( &m_refCount ); + { + xBroadcaster->addDocumentEventListener( this ); + } + osl_decrementInterlockedCount( &m_refCount ); + + try + { + _rContext.createComponent( "com.sun.star.util.URLTransformer", m_pData->xURLTransformer ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + DocumentEventExecutor::~DocumentEventExecutor() + { + } + + void SAL_CALL DocumentEventExecutor::documentEventOccured( const DocumentEvent& _Event ) throw (RuntimeException) + { + Reference< XEventsSupplier > xEventsSupplier( m_pData->xDocument.get(), UNO_QUERY ); + if ( !xEventsSupplier.is() ) + { + OSL_ENSURE( false, "DocumentEventExecutor::documentEventOccured: no document anymore, but still being notified?" ); + return; + } + + Reference< XModel > xDocument( xEventsSupplier, UNO_QUERY_THROW ); + + try + { + Reference< XNameAccess > xDocEvents( xEventsSupplier->getEvents().get(), UNO_SET_THROW ); + if ( !xDocEvents->hasByName( _Event.EventName ) ) + { + // this is worth an assertion: We are listener at the very same document which we just asked + // for its events. So when EventName is fired, why isn't it supported by xDocEvents? + OSL_ENSURE( false, "DocumentEventExecutor::documentEventOccured: an unsupported event is notified!" ); + return; + } + + const ::comphelper::NamedValueCollection aScriptDescriptor( xDocEvents->getByName( _Event.EventName ) ); + + ::rtl::OUString sEventType; + bool bScriptAssigned = aScriptDescriptor.get_ensureType( "EventType", sEventType ); + + ::rtl::OUString sScript; + bScriptAssigned = bScriptAssigned && aScriptDescriptor.get_ensureType( "Script", sScript ); + + if ( !bScriptAssigned ) + // no script is assigned to this event + return; + + bool bDispatchScriptURL = + ( sEventType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Script" ) ) + || sEventType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Service" ) ) + ); + bool bNonEmptyScript = sScript.getLength() != 0; + + OSL_ENSURE( bDispatchScriptURL && bNonEmptyScript, + "DocumentEventExecutor::documentEventOccured: invalid/unsupported script descriptor" ); + + if ( bDispatchScriptURL && bNonEmptyScript ) + { + lcl_dispatchScriptURL_throw( *m_pData, sScript, _Event ); + } + } + catch( const RuntimeException& ) { throw; } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + void SAL_CALL DocumentEventExecutor::disposing( const lang::EventObject& /*_Source*/ ) throw (RuntimeException) + { + // not interested in + } + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documenteventexecutor.hxx b/dbaccess/source/core/dataaccess/documenteventexecutor.hxx new file mode 100644 index 000000000000..c83a3e2886fd --- /dev/null +++ b/dbaccess/source/core/dataaccess/documenteventexecutor.hxx @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * 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 DBACCESS_DOCUMENTEVENTEXECUTOR_HXX +#define DBACCESS_DOCUMENTEVENTEXECUTOR_HXX + +/** === begin UNO includes === **/ +#include <com/sun/star/document/XDocumentEventListener.hpp> +#include <com/sun/star/document/XEventsSupplier.hpp> +/** === end UNO includes === **/ + +#include <cppuhelper/implbase1.hxx> + +#include <memory> + +namespace comphelper +{ + class ComponentContext; +} + +namespace dbaccess +{ + + struct DocumentEventExecutor_Data; + //==================================================================== + //= DocumentEventExecutor + //==================================================================== + typedef ::cppu::WeakImplHelper1 < ::com::sun::star::document::XDocumentEventListener + > DocumentEventExecutor_Base; + class DocumentEventExecutor : public DocumentEventExecutor_Base + { + public: + DocumentEventExecutor( + const ::comphelper::ComponentContext& _rContext, + const ::com::sun::star::uno::Reference< ::com::sun::star::document::XEventsSupplier >& _rxDocument ); + + protected: + virtual ~DocumentEventExecutor(); + + // css.document.XDocumentEventListener + virtual void SAL_CALL documentEventOccured( const ::com::sun::star::document::DocumentEvent& Event ) throw (::com::sun::star::uno::RuntimeException); + // css.lang.XEventListener + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); + + private: + ::std::auto_ptr< DocumentEventExecutor_Data > m_pData; + }; + +} // namespace dbaccess + +#endif // DBACCESS_DOCUMENTEVENTEXECUTOR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documenteventnotifier.cxx b/dbaccess/source/core/dataaccess/documenteventnotifier.cxx new file mode 100644 index 000000000000..dabd16a934fb --- /dev/null +++ b/dbaccess/source/core/dataaccess/documenteventnotifier.cxx @@ -0,0 +1,300 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * 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_dbaccess.hxx" + +#include "documenteventnotifier.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/frame/DoubleInitializationException.hpp> +/** === end UNO includes === **/ + +#include <comphelper/asyncnotification.hxx> +#include <cppuhelper/interfacecontainer.hxx> +#include <cppuhelper/weak.hxx> +#include <tools/diagnose_ex.h> + +namespace dbaccess +{ + + /** === 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::frame::DoubleInitializationException; + using ::com::sun::star::document::XDocumentEventListener; + using ::com::sun::star::document::DocumentEvent; + using ::com::sun::star::frame::XController2; + /** === end UNO using === **/ + using namespace ::com::sun::star; + + //================================================================== + //= DocumentEventHolder + //================================================================== + typedef ::comphelper::EventHolder< DocumentEvent > DocumentEventHolder; + + //==================================================================== + //= DocumentEventNotifier_Impl + //==================================================================== + class DocumentEventNotifier_Impl : public ::comphelper::IEventProcessor + { + oslInterlockedCount m_refCount; + ::cppu::OWeakObject& m_rDocument; + ::osl::Mutex& m_rMutex; + bool m_bInitialized; + bool m_bDisposed; + ::rtl::Reference< ::comphelper::AsyncEventNotifier > m_pEventBroadcaster; + ::cppu::OInterfaceContainerHelper m_aLegacyEventListeners; + ::cppu::OInterfaceContainerHelper m_aDocumentEventListeners; + + public: + DocumentEventNotifier_Impl( ::cppu::OWeakObject& _rBroadcasterDocument, ::osl::Mutex& _rMutex ) + :m_refCount( 0 ) + ,m_rDocument( _rBroadcasterDocument ) + ,m_rMutex( _rMutex ) + ,m_bInitialized( false ) + ,m_bDisposed( false ) + ,m_aLegacyEventListeners( _rMutex ) + ,m_aDocumentEventListeners( _rMutex ) + { + } + + // IReference + virtual void SAL_CALL acquire(); + virtual void SAL_CALL release(); + + void addLegacyEventListener( const Reference< document::XEventListener >& _Listener ) + { + m_aLegacyEventListeners.addInterface( _Listener ); + } + + void removeLegacyEventListener( const Reference< document::XEventListener >& _Listener ) + { + m_aLegacyEventListeners.removeInterface( _Listener ); + } + + void addDocumentEventListener( const Reference< XDocumentEventListener >& _Listener ) + { + m_aDocumentEventListeners.addInterface( _Listener ); + } + + void removeDocumentEventListener( const Reference< XDocumentEventListener >& _Listener ) + { + m_aDocumentEventListeners.removeInterface( _Listener ); + } + + void disposing(); + + void onDocumentInitialized(); + + void notifyDocumentEvent( const ::rtl::OUString& _EventName, const Reference< XController2 >& _ViewController, + const Any& _Supplement ) + { + impl_notifyEvent_nothrow( DocumentEvent( + m_rDocument, _EventName, _ViewController, _Supplement ) ); + } + + void notifyDocumentEventAsync( const ::rtl::OUString& _EventName, const Reference< XController2 >& _ViewController, + const Any& _Supplement ) + { + impl_notifyEventAsync_nothrow( DocumentEvent( + m_rDocument, _EventName, _ViewController, _Supplement ) ); + } + + protected: + virtual ~DocumentEventNotifier_Impl() + { + } + + // IEventProcessor + virtual void processEvent( const ::comphelper::AnyEvent& _rEvent ); + + private: + void impl_notifyEvent_nothrow( const DocumentEvent& _rEvent ); + void impl_notifyEventAsync_nothrow( const DocumentEvent& _rEvent ); + }; + + void SAL_CALL DocumentEventNotifier_Impl::acquire() + { + osl_incrementInterlockedCount( &m_refCount ); + } + + void SAL_CALL DocumentEventNotifier_Impl::release() + { + if ( 0 == osl_decrementInterlockedCount( &m_refCount ) ) + delete this; + } + + void DocumentEventNotifier_Impl::disposing() + { + // SYNCHRONIZED -> + // cancel any pending asynchronous events + ::osl::ResettableMutexGuard aGuard( m_rMutex ); + if ( m_pEventBroadcaster.is() ) + { + m_pEventBroadcaster->removeEventsForProcessor( this ); + m_pEventBroadcaster->terminate(); + m_pEventBroadcaster = NULL; + } + + lang::EventObject aEvent( m_rDocument ); + aGuard.clear(); + // <-- SYNCHRONIZED + + m_aLegacyEventListeners.disposeAndClear( aEvent ); + m_aDocumentEventListeners.disposeAndClear( aEvent ); + + // SYNCHRONIZED -> + aGuard.reset(); + m_bDisposed = true; + // <-- SYNCHRONIZED + } + + void DocumentEventNotifier_Impl::onDocumentInitialized() + { + if ( m_bInitialized ) + throw DoubleInitializationException(); + + m_bInitialized = true; + if ( m_pEventBroadcaster.is() ) + // there are already pending asynchronous events + m_pEventBroadcaster->create(); + } + + void DocumentEventNotifier_Impl::impl_notifyEvent_nothrow( const DocumentEvent& _rEvent ) + { + OSL_PRECOND( m_bInitialized, + "DocumentEventNotifier_Impl::impl_notifyEvent_nothrow: only to be called when the document is already initialized!" ); + try + { + document::EventObject aLegacyEvent( _rEvent.Source, _rEvent.EventName ); + m_aLegacyEventListeners.notifyEach( &document::XEventListener::notifyEvent, aLegacyEvent ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + try + { + m_aDocumentEventListeners.notifyEach( &XDocumentEventListener::documentEventOccured, _rEvent ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + void DocumentEventNotifier_Impl::impl_notifyEventAsync_nothrow( const DocumentEvent& _rEvent ) + { + if ( !m_pEventBroadcaster.is() ) + { + m_pEventBroadcaster.set( new ::comphelper::AsyncEventNotifier ); + if ( m_bInitialized ) + // start processing the events if and only if we (our document, respectively) are + // already initialized + m_pEventBroadcaster->create(); + } + m_pEventBroadcaster->addEvent( new DocumentEventHolder( _rEvent ), this ); + } + + void DocumentEventNotifier_Impl::processEvent( const ::comphelper::AnyEvent& _rEvent ) + { + // beware, this is called from the notification thread + { + ::osl::MutexGuard aGuard( m_rMutex ); + if ( m_bDisposed ) + return; + } + const DocumentEventHolder& rEventHolder = dynamic_cast< const DocumentEventHolder& >( _rEvent ); + impl_notifyEvent_nothrow( rEventHolder.getEventObject() ); + } + + //==================================================================== + //= DocumentEventNotifier + //==================================================================== + DocumentEventNotifier::DocumentEventNotifier( ::cppu::OWeakObject& _rBroadcasterDocument, ::osl::Mutex& _rMutex ) + :m_pImpl( new DocumentEventNotifier_Impl( _rBroadcasterDocument, _rMutex ) ) + { + } + + DocumentEventNotifier::~DocumentEventNotifier() + { + } + + void DocumentEventNotifier::disposing() + { + m_pImpl->disposing(); + } + + void DocumentEventNotifier::onDocumentInitialized() + { + m_pImpl->onDocumentInitialized(); + } + + void DocumentEventNotifier::addLegacyEventListener( const Reference< document::XEventListener >& _Listener ) + { + m_pImpl->addLegacyEventListener( _Listener ); + } + + void DocumentEventNotifier::removeLegacyEventListener( const Reference< document::XEventListener >& _Listener ) + { + m_pImpl->removeLegacyEventListener( _Listener ); + } + + void DocumentEventNotifier::addDocumentEventListener( const Reference< XDocumentEventListener >& _Listener ) + { + m_pImpl->addDocumentEventListener( _Listener ); + } + + void DocumentEventNotifier::removeDocumentEventListener( const Reference< XDocumentEventListener >& _Listener ) + { + m_pImpl->removeDocumentEventListener( _Listener ); + } + + void DocumentEventNotifier::notifyDocumentEvent( const ::rtl::OUString& _EventName, + const Reference< XController2 >& _ViewController, const Any& _Supplement ) + { + m_pImpl->notifyDocumentEvent( _EventName, _ViewController, _Supplement ); + } + + void DocumentEventNotifier::notifyDocumentEventAsync( const ::rtl::OUString& _EventName, + const Reference< XController2 >& _ViewController, const Any& _Supplement ) + { + m_pImpl->notifyDocumentEventAsync( _EventName, _ViewController, _Supplement ); + } + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documenteventnotifier.hxx b/dbaccess/source/core/dataaccess/documenteventnotifier.hxx new file mode 100644 index 000000000000..c92064aabbc7 --- /dev/null +++ b/dbaccess/source/core/dataaccess/documenteventnotifier.hxx @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/************************************************************************* + * 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 DBACCESS_DOCUMENTEVENTNOTIFIER_HXX +#define DBACCESS_DOCUMENTEVENTNOTIFIER_HXX + +/** === begin UNO includes === **/ +#include <com/sun/star/document/XEventListener.hpp> +#include <com/sun/star/document/XDocumentEventListener.hpp> +/** === end UNO includes === **/ + +#include <rtl/ref.hxx> + +namespace cppu +{ + class OWeakObject; +} + +namespace dbaccess +{ + + class DocumentEventNotifier_Impl; + //==================================================================== + //= DocumentEventNotifier + //==================================================================== + class DocumentEventNotifier + { + public: + DocumentEventNotifier( ::cppu::OWeakObject& _rBroadcasterDocument, ::osl::Mutex& _rMutex ); + ~DocumentEventNotifier(); + + void addLegacyEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::document::XEventListener >& _Listener ); + void removeLegacyEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::document::XEventListener >& _Listener ); + void addDocumentEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::document::XDocumentEventListener >& _Listener ); + void removeDocumentEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::document::XDocumentEventListener >& _Listener ); + + /** disposes the instance + @precond + the mutex is not locked + */ + void disposing(); + + /** tells the instance that its document is completely initialized now. + + Before you call this method, no notification will actually happen + + @precond + the mutex is locked + */ + void onDocumentInitialized(); + + /** notifies a document event described by the given parameters + + @precond + the mutex is not locked + @precond + ->onDocumentInitialized has been called + */ + void notifyDocumentEvent( + const ::rtl::OUString& _EventName, + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController2 >& _rxViewController = NULL, + const ::com::sun::star::uno::Any& _Supplement = ::com::sun::star::uno::Any() + ); + + /** notifies a document event, described by the given parameters, asynchronously + + Note that no event is actually notified before you called ->onDocumentInitialized. + + @precond + the mutex is locked + */ + void notifyDocumentEventAsync( + const ::rtl::OUString& _EventName, + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController2 >& _ViewController = NULL, + const ::com::sun::star::uno::Any& _Supplement = ::com::sun::star::uno::Any() + ); + + /** notifies a document event to all registered listeners + + @precond + the mutex is not locked + @precond + ->onDocumentInitialized has been called + */ + void notifyDocumentEvent( + const sal_Char* _pAsciiEventName, + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController2 >& _rxViewController = NULL, + const ::com::sun::star::uno::Any& _rSupplement = ::com::sun::star::uno::Any() + ) + { + notifyDocumentEvent( ::rtl::OUString::createFromAscii( _pAsciiEventName ), _rxViewController, _rSupplement ); + } + + /** notifies a document event to all registered listeners, asynchronously + + Note that no event is actually notified before you called ->onDocumentInitialized. + + @precond + the mutex is locked + */ + void notifyDocumentEventAsync( + const sal_Char* _pAsciiEventName, + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController2 >& _rxViewController = NULL, + const ::com::sun::star::uno::Any& _rSupplement = ::com::sun::star::uno::Any() + ) + { + notifyDocumentEventAsync( ::rtl::OUString::createFromAscii( _pAsciiEventName ), _rxViewController, _rSupplement ); + } + + private: + ::rtl::Reference< DocumentEventNotifier_Impl > m_pImpl; + }; + +} // namespace dbaccess + +#endif // DBACCESS_DOCUMENTEVENTNOTIFIER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documentevents.cxx b/dbaccess/source/core/dataaccess/documentevents.cxx new file mode 100644 index 000000000000..208b2486c459 --- /dev/null +++ b/dbaccess/source/core/dataaccess/documentevents.cxx @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * 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_dbaccess.hxx" + +#include "documentevents.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/beans/PropertyValue.hpp> +/** === end UNO includes === **/ + +#include <comphelper/namedvaluecollection.hxx> + +#include <algorithm> +#include <functional> + +namespace dbaccess +{ + + /** === 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::beans::PropertyValue; + using ::com::sun::star::container::NoSuchElementException; + using ::com::sun::star::lang::WrappedTargetException; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Type; + /** === end UNO using === **/ + + //==================================================================== + //= DocumentEvents_Data + //==================================================================== + struct DocumentEvents_Data : public ::boost::noncopyable + { + ::cppu::OWeakObject& rParent; + ::osl::Mutex& rMutex; + DocumentEventsData& rEventsData; + + DocumentEvents_Data( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, DocumentEventsData& _rEventsData ) + :rParent( _rParent ) + ,rMutex( _rMutex ) + ,rEventsData( _rEventsData ) + { + } + }; + + //==================================================================== + //= helper + //==================================================================== + struct DocumentEventData + { + const sal_Char* pAsciiEventName; + bool bNeedsSyncNotify; + }; + + namespace + { + static const DocumentEventData* lcl_getDocumentEventData() + { + static const DocumentEventData s_aData[] = { + { "OnCreate", true }, + { "OnLoadFinished", true }, + { "OnNew", false }, // compatibility, see http://www.openoffice.org/issues/show_bug.cgi?id=46484 + { "OnLoad", false }, // compatibility, see http://www.openoffice.org/issues/show_bug.cgi?id=46484 + { "OnSaveAs", true }, + { "OnSaveAsDone", false }, + { "OnSaveAsFailed", false }, + { "OnSave", true }, + { "OnSaveDone", false }, + { "OnSaveFailed", false }, + { "OnSaveTo", true }, + { "OnSaveToDone", false }, + { "OnSaveToFailed", false }, + { "OnPrepareUnload", true }, + { "OnUnload", true }, + { "OnFocus", false }, + { "OnUnfocus", false }, + { "OnModifyChanged", false }, + { "OnViewCreated", false }, + { "OnPrepareViewClosing", true }, + { "OnViewClosed", false }, + { "OnTitleChanged", false }, + { "OnSubComponentOpened", false }, + { "OnSubComponentClosed", false }, + { NULL, false } + }; + return s_aData; + } + } + + //==================================================================== + //= DocumentEvents + //==================================================================== + DocumentEvents::DocumentEvents( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, DocumentEventsData& _rEventsData ) + :m_pData( new DocumentEvents_Data( _rParent, _rMutex, _rEventsData ) ) + { + const DocumentEventData* pEventData = lcl_getDocumentEventData(); + while ( pEventData->pAsciiEventName ) + { + ::rtl::OUString sEventName = ::rtl::OUString::createFromAscii( pEventData->pAsciiEventName ); + DocumentEventsData::iterator existingPos = m_pData->rEventsData.find( sEventName ); + if ( existingPos == m_pData->rEventsData.end() ) + m_pData->rEventsData[ sEventName ] = Sequence< PropertyValue >(); + ++pEventData; + } + } + + DocumentEvents::~DocumentEvents() + { + } + + void SAL_CALL DocumentEvents::acquire() throw() + { + m_pData->rParent.acquire(); + } + + void SAL_CALL DocumentEvents::release() throw() + { + m_pData->rParent.release(); + } + + bool DocumentEvents::needsSynchronousNotification( const ::rtl::OUString& _rEventName ) + { + const DocumentEventData* pEventData = lcl_getDocumentEventData(); + while ( pEventData->pAsciiEventName ) + { + if ( _rEventName.compareToAscii( pEventData->pAsciiEventName ) == 0 ) + return pEventData->bNeedsSyncNotify; + ++pEventData; + } + + // this is an unknown event ... assume async notification + return false; + } + + void SAL_CALL DocumentEvents::replaceByName( const ::rtl::OUString& _Name, const Any& _Element ) throw (IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException) + { + ::osl::MutexGuard aGuard( m_pData->rMutex ); + + DocumentEventsData::iterator elementPos = m_pData->rEventsData.find( _Name ); + if ( elementPos == m_pData->rEventsData.end() ) + throw NoSuchElementException( _Name, *this ); + + Sequence< PropertyValue > aEventDescriptor; + if ( _Element.hasValue() && !( _Element >>= aEventDescriptor ) ) + throw IllegalArgumentException( _Element.getValueTypeName(), *this, 2 ); + + // Weird enough, the event assignment UI has (well: had) the idea of using an empty "EventType"/"Script" + // to indicate the event descriptor should be reset, instead of just passing an empty event descriptor. + ::comphelper::NamedValueCollection aCheck( aEventDescriptor ); + if ( aCheck.has( "EventType" ) ) + { + ::rtl::OUString sEventType = aCheck.getOrDefault( "EventType", ::rtl::OUString() ); + OSL_ENSURE( sEventType.getLength(), "DocumentEvents::replaceByName: doing a reset via an empty EventType is weird!" ); + if ( !sEventType.getLength() ) + aEventDescriptor.realloc( 0 ); + } + if ( aCheck.has( "Script" ) ) + { + ::rtl::OUString sScript = aCheck.getOrDefault( "Script", ::rtl::OUString() ); + OSL_ENSURE( sScript.getLength(), "DocumentEvents::replaceByName: doing a reset via an empty Script is weird!" ); + if ( !sScript.getLength() ) + aEventDescriptor.realloc( 0 ); + } + + elementPos->second = aEventDescriptor; + } + + Any SAL_CALL DocumentEvents::getByName( const ::rtl::OUString& _Name ) throw (NoSuchElementException, WrappedTargetException, RuntimeException) + { + ::osl::MutexGuard aGuard( m_pData->rMutex ); + + DocumentEventsData::const_iterator elementPos = m_pData->rEventsData.find( _Name ); + if ( elementPos == m_pData->rEventsData.end() ) + throw NoSuchElementException( _Name, *this ); + + Any aReturn; + const Sequence< PropertyValue >& rEventDesc( elementPos->second ); + if ( rEventDesc.getLength() > 0 ) + aReturn <<= rEventDesc; + return aReturn; + } + + Sequence< ::rtl::OUString > SAL_CALL DocumentEvents::getElementNames( ) throw (RuntimeException) + { + ::osl::MutexGuard aGuard( m_pData->rMutex ); + + Sequence< ::rtl::OUString > aNames( m_pData->rEventsData.size() ); + ::std::transform( + m_pData->rEventsData.begin(), + m_pData->rEventsData.end(), + aNames.getArray(), + ::std::select1st< DocumentEventsData::value_type >() + ); + return aNames; + } + + ::sal_Bool SAL_CALL DocumentEvents::hasByName( const ::rtl::OUString& _Name ) throw (RuntimeException) + { + ::osl::MutexGuard aGuard( m_pData->rMutex ); + + return m_pData->rEventsData.find( _Name ) != m_pData->rEventsData.end(); + } + + Type SAL_CALL DocumentEvents::getElementType( ) throw (RuntimeException) + { + return ::cppu::UnoType< Sequence< PropertyValue > >::get(); + } + + ::sal_Bool SAL_CALL DocumentEvents::hasElements( ) throw (RuntimeException) + { + ::osl::MutexGuard aGuard( m_pData->rMutex ); + return !m_pData->rEventsData.empty(); + } + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documentevents.hxx b/dbaccess/source/core/dataaccess/documentevents.hxx new file mode 100644 index 000000000000..16cb0c86875e --- /dev/null +++ b/dbaccess/source/core/dataaccess/documentevents.hxx @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * 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 DBACCESS_DOCUMENTEVENTS_HXX +#define DBACCESS_DOCUMENTEVENTS_HXX + +/** === begin UNO includes === **/ +#include <com/sun/star/container/XNameReplace.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +/** === end UNO includes === **/ + +#include <cppuhelper/implbase1.hxx> + +#include <memory> +#include <map> +#include <boost/noncopyable.hpp> + +namespace dbaccess +{ + + typedef ::std::map< ::rtl::OUString, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > > + DocumentEventsData; + + //==================================================================== + //= DocumentEvents + //==================================================================== + struct DocumentEvents_Data; + + typedef ::cppu::WeakImplHelper1 < ::com::sun::star::container::XNameReplace + > DocumentEvents_Base; + + class DocumentEvents :public DocumentEvents_Base + ,public ::boost::noncopyable + { + public: + DocumentEvents( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, DocumentEventsData& _rEventsData ); + ~DocumentEvents(); + + static bool needsSynchronousNotification( const ::rtl::OUString& _rEventName ); + + // XInterface + virtual void SAL_CALL acquire() throw(); + virtual void SAL_CALL release() throw(); + + // 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); + + private: + ::std::auto_ptr< DocumentEvents_Data > m_pData; + }; + +} // namespace dbaccess + +#endif // DBACCESS_DOCUMENTEVENTS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/intercept.cxx b/dbaccess/source/core/dataaccess/intercept.cxx new file mode 100644 index 000000000000..1b950f2851be --- /dev/null +++ b/dbaccess/source/core/dataaccess/intercept.cxx @@ -0,0 +1,446 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +#include "intercept.hxx" +#include "dbastrings.hrc" + +#include <com/sun/star/embed/EmbedStates.hpp> +#include <com/sun/star/document/XEventBroadcaster.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <cppuhelper/weak.hxx> + +#include <comphelper/types.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> + + +namespace dbaccess +{ +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::container; +using namespace ::comphelper; +using namespace ::cppu; + +#define DISPATCH_SAVEAS 0 +#define DISPATCH_SAVE 1 +#define DISPATCH_CLOSEDOC 2 +#define DISPATCH_CLOSEWIN 3 +#define DISPATCH_CLOSEFRAME 4 +#define DISPATCH_RELOAD 5 +// the OSL_ENSURE in CTOR has to be changed too, when adding new defines + +void SAL_CALL OInterceptor::dispose() + throw( RuntimeException ) +{ + EventObject aEvt( *this ); + + osl::MutexGuard aGuard(m_aMutex); + + if ( m_pDisposeEventListeners && m_pDisposeEventListeners->getLength() ) + m_pDisposeEventListeners->disposeAndClear( aEvt ); + + if ( m_pStatCL ) + m_pStatCL->disposeAndClear( aEvt ); + + m_xSlaveDispatchProvider.clear(); + m_xMasterDispatchProvider.clear(); + + m_pContentHolder = NULL; +} + + +DBG_NAME(OInterceptor) + +OInterceptor::OInterceptor( ODocumentDefinition* _pContentHolder,sal_Bool _bAllowEditDoc ) + :m_pContentHolder( _pContentHolder ) + ,m_aInterceptedURL(7) + ,m_pDisposeEventListeners(0) + ,m_pStatCL(0) + ,m_bAllowEditDoc(_bAllowEditDoc) +{ + DBG_CTOR(OInterceptor,NULL); + + OSL_ENSURE(DISPATCH_RELOAD < m_aInterceptedURL.getLength(),"Illegal size."); + + m_aInterceptedURL[DISPATCH_SAVEAS] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".uno:SaveAs")); + m_aInterceptedURL[DISPATCH_SAVE] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".uno:Save")); + m_aInterceptedURL[DISPATCH_CLOSEDOC] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".uno:CloseDoc")); + m_aInterceptedURL[DISPATCH_CLOSEWIN] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".uno:CloseWin")); + m_aInterceptedURL[DISPATCH_CLOSEFRAME] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".uno:CloseFrame")); + m_aInterceptedURL[DISPATCH_RELOAD] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".uno:Reload")); +} + + +OInterceptor::~OInterceptor() +{ + if( m_pDisposeEventListeners ) + delete m_pDisposeEventListeners; + + if(m_pStatCL) + delete m_pStatCL; + + DBG_DTOR(OInterceptor,NULL); +} + +struct DispatchHelper +{ + URL aURL; + Sequence<PropertyValue > aArguments; +}; + +//XDispatch +void SAL_CALL OInterceptor::dispatch( const URL& _URL,const Sequence<PropertyValue >& Arguments ) throw (RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_pContentHolder ) + return; + + if ( _URL.Complete == m_aInterceptedURL[ DISPATCH_SAVE ] ) + { + m_pContentHolder->save( sal_False ); + return; + } + + if ( _URL.Complete == m_aInterceptedURL[ DISPATCH_RELOAD ] ) + { + ODocumentDefinition::fillReportData( + m_pContentHolder->getContext(), + m_pContentHolder->getComponent(), + m_pContentHolder->getConnection() + ); + return; + } + + if( _URL.Complete == m_aInterceptedURL[ DISPATCH_SAVEAS ] ) + { + if ( m_pContentHolder->isNewReport() ) + { + m_pContentHolder->saveAs(); + } + else if ( m_xSlaveDispatchProvider.is() ) + { + Sequence< PropertyValue > aNewArgs = Arguments; + sal_Int32 nInd = 0; + + while( nInd < aNewArgs.getLength() ) + { + if ( aNewArgs[nInd].Name.equalsAscii( "SaveTo" ) ) + { + aNewArgs[nInd].Value <<= sal_True; + break; + } + nInd++; + } + + if ( nInd == aNewArgs.getLength() ) + { + aNewArgs.realloc( nInd + 1 ); + aNewArgs[nInd].Name = ::rtl::OUString::createFromAscii( "SaveTo" ); + aNewArgs[nInd].Value <<= sal_True; + } + + Reference< XDispatch > xDispatch = m_xSlaveDispatchProvider->queryDispatch( + _URL, ::rtl::OUString::createFromAscii( "_self" ), 0 ); + if ( xDispatch.is() ) + xDispatch->dispatch( _URL, aNewArgs ); + } + return; + } + + if ( _URL.Complete == m_aInterceptedURL[ DISPATCH_CLOSEDOC ] + || _URL.Complete == m_aInterceptedURL[ DISPATCH_CLOSEWIN ] + || _URL.Complete == m_aInterceptedURL[ DISPATCH_CLOSEFRAME ] + ) + { + DispatchHelper* pHelper = new DispatchHelper; + pHelper->aArguments = Arguments; + pHelper->aURL = _URL; + Application::PostUserEvent( LINK( this, OInterceptor, OnDispatch ), reinterpret_cast< void* >( pHelper ) ); + return; + } +} + +IMPL_LINK( OInterceptor, OnDispatch, void*, _pDispatcher ) +{ + ::std::auto_ptr<DispatchHelper> pHelper( reinterpret_cast< DispatchHelper* >( _pDispatcher ) ); + try + { + if ( m_pContentHolder && m_pContentHolder->prepareClose() && m_xSlaveDispatchProvider.is() ) + { + Reference< XDispatch > xDispatch = m_xSlaveDispatchProvider->queryDispatch( + pHelper->aURL, ::rtl::OUString::createFromAscii( "_self" ), 0 ); + if ( xDispatch.is() ) + { + Reference< ::com::sun::star::document::XEventBroadcaster> xEvtB(m_pContentHolder->getComponent(),UNO_QUERY); + if ( xEvtB.is() ) + xEvtB->removeEventListener(this); + + Reference< XInterface > xKeepContentHolderAlive( *m_pContentHolder ); + xDispatch->dispatch( pHelper->aURL,pHelper->aArguments); + } + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return 0L; +} + +void SAL_CALL OInterceptor::addStatusListener( + const Reference< + XStatusListener >& Control, + const URL& _URL ) + throw ( + RuntimeException + ) +{ + if(!Control.is()) + return; + + if ( m_pContentHolder && _URL.Complete == m_aInterceptedURL[DISPATCH_SAVEAS] ) + { // SaveAs + + if ( !m_pContentHolder->isNewReport() ) + { + FeatureStateEvent aStateEvent; + aStateEvent.FeatureURL.Complete = m_aInterceptedURL[DISPATCH_SAVEAS]; + aStateEvent.FeatureDescriptor = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SaveCopyTo")); + aStateEvent.IsEnabled = sal_True; + aStateEvent.Requery = sal_False; + aStateEvent.State <<= (rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("($3)"))); + Control->statusChanged(aStateEvent); + } + + { + osl::MutexGuard aGuard(m_aMutex); + if(!m_pStatCL) + m_pStatCL = new PropertyChangeListenerContainer(m_aMutex); + } + + m_pStatCL->addInterface(_URL.Complete,Control); + } + else if ( m_pContentHolder && _URL.Complete == m_aInterceptedURL[DISPATCH_SAVE] ) + { // Save + FeatureStateEvent aStateEvent; + aStateEvent.FeatureURL.Complete = m_aInterceptedURL[DISPATCH_SAVE]; + aStateEvent.FeatureDescriptor = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Update")); + aStateEvent.IsEnabled = m_pContentHolder != NULL && m_pContentHolder->isModified(); + aStateEvent.Requery = sal_False; + + Control->statusChanged(aStateEvent); + { + osl::MutexGuard aGuard(m_aMutex); + if(!m_pStatCL) + m_pStatCL = new PropertyChangeListenerContainer(m_aMutex); + } + + m_pStatCL->addInterface(_URL.Complete,Control); + Reference< ::com::sun::star::document::XEventBroadcaster> xEvtB(m_pContentHolder->getComponent(),UNO_QUERY); + if ( xEvtB.is() ) + xEvtB->addEventListener(this); + } + else + { + sal_Int32 i = 2; + if(_URL.Complete == m_aInterceptedURL[i] || + _URL.Complete == m_aInterceptedURL[++i] || + _URL.Complete == m_aInterceptedURL[++i] || + _URL.Complete == m_aInterceptedURL[i = DISPATCH_RELOAD] ) + { // Close and return + FeatureStateEvent aStateEvent; + aStateEvent.FeatureURL.Complete = m_aInterceptedURL[i]; + aStateEvent.FeatureDescriptor = rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("Close and Return")); + aStateEvent.IsEnabled = sal_True; + aStateEvent.Requery = sal_False; + Control->statusChanged(aStateEvent); + + + { + osl::MutexGuard aGuard(m_aMutex); + if(!m_pStatCL) + m_pStatCL = new PropertyChangeListenerContainer(m_aMutex); + } + + m_pStatCL->addInterface(_URL.Complete,Control); + return; + } + } +} + + +void SAL_CALL OInterceptor::removeStatusListener( + const Reference< + XStatusListener >& Control, + const URL& _URL ) + throw ( + RuntimeException + ) +{ + if(!(Control.is() && m_pStatCL)) + return; + else + { + m_pStatCL->removeInterface(_URL.Complete,Control); + return; + } +} + + +//XInterceptorInfo +Sequence< ::rtl::OUString > SAL_CALL OInterceptor::getInterceptedURLs( ) throw ( RuntimeException ) +{ + // now implemented as update + return m_aInterceptedURL; +} + + +// XDispatchProvider + +Reference< XDispatch > SAL_CALL OInterceptor::queryDispatch( const URL& _URL,const ::rtl::OUString& TargetFrameName,sal_Int32 SearchFlags ) + throw (RuntimeException) +{ + osl::MutexGuard aGuard(m_aMutex); + const ::rtl::OUString* pIter = m_aInterceptedURL.getConstArray(); + const ::rtl::OUString* pEnd = pIter + m_aInterceptedURL.getLength(); + for(;pIter != pEnd;++pIter) + { + if ( _URL.Complete == *pIter ) + return (XDispatch*)this; + } + + if(m_xSlaveDispatchProvider.is()) + return m_xSlaveDispatchProvider->queryDispatch(_URL,TargetFrameName,SearchFlags); + else + return Reference<XDispatch>(); +} + +Sequence< Reference< XDispatch > > SAL_CALL OInterceptor::queryDispatches( const Sequence<DispatchDescriptor >& Requests ) throw ( RuntimeException ) +{ + Sequence< Reference< XDispatch > > aRet; + osl::MutexGuard aGuard(m_aMutex); + if(m_xSlaveDispatchProvider.is()) + aRet = m_xSlaveDispatchProvider->queryDispatches(Requests); + else + aRet.realloc(Requests.getLength()); + + for(sal_Int32 i = 0; i < Requests.getLength(); ++i) + { + const ::rtl::OUString* pIter = m_aInterceptedURL.getConstArray(); + const ::rtl::OUString* pEnd = pIter + m_aInterceptedURL.getLength(); + for(;pIter != pEnd;++pIter) + { + if ( Requests[i].FeatureURL.Complete == *pIter ) + { + aRet[i] = (XDispatch*) this; + break; + } + } + } + + return aRet; +} + + + +//XDispatchProviderInterceptor + +Reference< XDispatchProvider > SAL_CALL OInterceptor::getSlaveDispatchProvider( ) throw ( RuntimeException ) +{ + osl::MutexGuard aGuard(m_aMutex); + return m_xSlaveDispatchProvider; +} + +void SAL_CALL +OInterceptor::setSlaveDispatchProvider( const Reference< XDispatchProvider >& NewDispatchProvider ) + throw ( RuntimeException ) +{ + osl::MutexGuard aGuard(m_aMutex); + m_xSlaveDispatchProvider = NewDispatchProvider; +} + + +Reference< XDispatchProvider > SAL_CALL OInterceptor::getMasterDispatchProvider( ) + throw ( + RuntimeException + ) +{ + osl::MutexGuard aGuard(m_aMutex); + return m_xMasterDispatchProvider; +} + + +void SAL_CALL OInterceptor::setMasterDispatchProvider( + const Reference< XDispatchProvider >& NewSupplier ) + throw ( + RuntimeException + ) +{ + osl::MutexGuard aGuard(m_aMutex); + m_xMasterDispatchProvider = NewSupplier; +} + +void SAL_CALL OInterceptor::notifyEvent( const ::com::sun::star::document::EventObject& Event ) throw (::com::sun::star::uno::RuntimeException) +{ + osl::ResettableMutexGuard _rGuard(m_aMutex); + if ( m_pStatCL && Event.EventName == ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("OnModifyChanged")) ) + { + OInterfaceContainerHelper* pListener = m_pStatCL->getContainer(m_aInterceptedURL[DISPATCH_SAVE]); + if ( pListener ) + { + FeatureStateEvent aEvt; + aEvt.FeatureURL.Complete = m_aInterceptedURL[DISPATCH_SAVE]; + aEvt.FeatureDescriptor = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Update")); + Reference<XModifiable> xModel(Event.Source,UNO_QUERY); + aEvt.IsEnabled = xModel.is() && xModel->isModified(); + aEvt.Requery = sal_False; + + NOTIFY_LISTERNERS((*pListener),XStatusListener,statusChanged) + } + } +} + +void SAL_CALL OInterceptor::disposing( const ::com::sun::star::lang::EventObject& /*Source*/ ) throw (::com::sun::star::uno::RuntimeException) +{ +} + +} // namespace dbaccess +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/intercept.hxx b/dbaccess/source/core/dataaccess/intercept.hxx new file mode 100644 index 000000000000..cb2cadc77c07 --- /dev/null +++ b/dbaccess/source/core/dataaccess/intercept.hxx @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 DBA_INTERCEPT_HXX +#define DBA_INTERCEPT_HXX + +#include <osl/mutex.hxx> +#include <cppuhelper/implbase4.hxx> +#include <cppuhelper/interfacecontainer.hxx> +#include <com/sun/star/frame/XDispatchProviderInterceptor.hpp> +#include <com/sun/star/frame/XInterceptorInfo.hpp> +#include <com/sun/star/document/XEventListener.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include "documentdefinition.hxx" +#include <vcl/svapp.hxx> + +namespace dbaccess +{ + + +class OInterceptor : public ::cppu::WeakImplHelper4< ::com::sun::star::frame::XDispatchProviderInterceptor, + ::com::sun::star::frame::XInterceptorInfo, + ::com::sun::star::frame::XDispatch, + ::com::sun::star::document::XEventListener> +{ + DECL_LINK( OnDispatch, void* _aURL ); +protected: + virtual ~OInterceptor(); +public: + + OInterceptor( ODocumentDefinition* _pContentHolder,sal_Bool _bAllowEditDoc ); + + void SAL_CALL dispose() throw(::com::sun::star::uno::RuntimeException); + + //XDispatch + virtual void SAL_CALL + dispatch( + const ::com::sun::star::util::URL& URL, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::beans::PropertyValue >& Arguments ) + throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL + addStatusListener( + const ::com::sun::star::uno::Reference< + ::com::sun::star::frame::XStatusListener >& Control, + const ::com::sun::star::util::URL& URL ) + throw ( + ::com::sun::star::uno::RuntimeException + ); + + virtual void SAL_CALL + removeStatusListener( + const ::com::sun::star::uno::Reference< + ::com::sun::star::frame::XStatusListener >& Control, + const ::com::sun::star::util::URL& URL ) + throw ( + ::com::sun::star::uno::RuntimeException + ); + + //XInterceptorInfo + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > + SAL_CALL getInterceptedURLs( ) + throw ( + ::com::sun::star::uno::RuntimeException + ); + + //XDispatchProvider ( inherited by XDispatchProviderInterceptor ) + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::frame::XDispatch > SAL_CALL + queryDispatch( + const ::com::sun::star::util::URL& URL, + const ::rtl::OUString& TargetFrameName, + sal_Int32 SearchFlags ) + throw ( + ::com::sun::star::uno::RuntimeException + ); + + virtual ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::frame::XDispatch > > SAL_CALL + queryDispatches( + const ::com::sun::star::uno::Sequence< + ::com::sun::star::frame::DispatchDescriptor >& Requests ) + throw ( + ::com::sun::star::uno::RuntimeException + ); + + //XDispatchProviderInterceptor + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::frame::XDispatchProvider > SAL_CALL + getSlaveDispatchProvider( ) + throw ( + ::com::sun::star::uno::RuntimeException + ); + + virtual void SAL_CALL + setSlaveDispatchProvider( + const ::com::sun::star::uno::Reference< + ::com::sun::star::frame::XDispatchProvider >& NewDispatchProvider ) + throw ( + ::com::sun::star::uno::RuntimeException + ); + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::frame::XDispatchProvider > SAL_CALL + getMasterDispatchProvider( ) + throw ( + ::com::sun::star::uno::RuntimeException + ); + + virtual void SAL_CALL + setMasterDispatchProvider( + const ::com::sun::star::uno::Reference< + ::com::sun::star::frame::XDispatchProvider >& NewSupplier ) + throw ( + ::com::sun::star::uno::RuntimeException + ); + + // XEventListener + virtual void SAL_CALL notifyEvent( const ::com::sun::star::document::EventObject& Event ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); + +private: + + osl::Mutex m_aMutex; + + ODocumentDefinition* m_pContentHolder; + + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > m_xSlaveDispatchProvider; + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > m_xMasterDispatchProvider; + + ::com::sun::star::uno::Sequence< ::rtl::OUString > m_aInterceptedURL; + + cppu::OInterfaceContainerHelper* m_pDisposeEventListeners; + PropertyChangeListenerContainer* m_pStatCL; + sal_Bool m_bAllowEditDoc; +}; + +} // namespace dbaccess + +#endif //DBA_INTERCEPT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/makefile.mk b/dbaccess/source/core/dataaccess/makefile.mk new file mode 100644 index 000000000000..e37544b70bf7 --- /dev/null +++ b/dbaccess/source/core/dataaccess/makefile.mk @@ -0,0 +1,69 @@ +#************************************************************************* +# +# 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=$(PRJ)$/source +PRJNAME=dbaccess +TARGET=dataaccess + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/dba.pmk + +# --- Files ------------------------------------- + +SLOFILES= \ + $(SLO)$/SharedConnection.obj \ + $(SLO)$/ContentHelper.obj \ + $(SLO)$/bookmarkcontainer.obj \ + $(SLO)$/definitioncontainer.obj \ + $(SLO)$/commanddefinition.obj \ + $(SLO)$/documentcontainer.obj \ + $(SLO)$/commandcontainer.obj \ + $(SLO)$/documentdefinition.obj \ + $(SLO)$/ComponentDefinition.obj \ + $(SLO)$/databasecontext.obj \ + $(SLO)$/connection.obj \ + $(SLO)$/datasource.obj \ + $(SLO)$/databaseregistrations.obj \ + $(SLO)$/intercept.obj \ + $(SLO)$/myucp_datasupplier.obj \ + $(SLO)$/myucp_resultset.obj \ + $(SLO)$/databasedocument.obj \ + $(SLO)$/dataaccessdescriptor.obj\ + $(SLO)$/ModelImpl.obj \ + $(SLO)$/documentevents.obj \ + $(SLO)$/documenteventexecutor.obj \ + $(SLO)$/documenteventnotifier.obj \ + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/dbaccess/source/core/dataaccess/myucp_datasupplier.cxx b/dbaccess/source/core/dataaccess/myucp_datasupplier.cxx new file mode 100644 index 000000000000..93177d05b5fd --- /dev/null +++ b/dbaccess/source/core/dataaccess/myucp_datasupplier.cxx @@ -0,0 +1,393 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +/************************************************************************** + TODO + ************************************************************************** + + *************************************************************************/ + +#include <vector> + +#include <ucbhelper/contentidentifier.hxx> +#include <ucbhelper/providerhelper.hxx> + +#include "myucp_datasupplier.hxx" +#include "ContentHelper.hxx" +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <tools/debug.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::container; + +// @@@ Adjust namespace name. +using namespace dbaccess; + +// @@@ Adjust namespace name. +namespace dbaccess +{ + +//========================================================================= +// +// struct ResultListEntry. +// +//========================================================================= + +struct ResultListEntry +{ + rtl::OUString aId; + Reference< XContentIdentifier > xId; + ::rtl::Reference< OContentHelper > xContent; + Reference< XRow > xRow; + const ContentProperties& rData; + + ResultListEntry( const ContentProperties& rEntry ) : rData( rEntry ) {} +}; + +//========================================================================= +// +// ResultList. +// +//========================================================================= + +typedef std::vector< ResultListEntry* > ResultList; + +//========================================================================= +// +// struct DataSupplier_Impl. +// +//========================================================================= + +struct DataSupplier_Impl +{ + osl::Mutex m_aMutex; + ResultList m_aResults; + rtl::Reference< ODocumentContainer > m_xContent; + Reference< XMultiServiceFactory > m_xSMgr; + sal_Int32 m_nOpenMode; + sal_Bool m_bCountFinal; + + DataSupplier_Impl( const Reference< XMultiServiceFactory >& rxSMgr, + const rtl::Reference< ODocumentContainer >& rContent, + sal_Int32 nOpenMode ) + : m_xContent(rContent) + , m_xSMgr( rxSMgr ) + , m_nOpenMode( nOpenMode ) + , m_bCountFinal( sal_False ) {} + ~DataSupplier_Impl(); +}; + +//========================================================================= +DataSupplier_Impl::~DataSupplier_Impl() +{ + ResultList::const_iterator it = m_aResults.begin(); + ResultList::const_iterator end = m_aResults.end(); + + while ( it != end ) + { + delete (*it); + it++; + } +} + +} + +//========================================================================= +// +// DataSupplier Implementation. +// +//========================================================================= +DBG_NAME(DataSupplier) + +DataSupplier::DataSupplier( const Reference< XMultiServiceFactory >& rxSMgr, + const rtl::Reference< ODocumentContainer >& rContent, + sal_Int32 nOpenMode ) +: m_pImpl( new DataSupplier_Impl( rxSMgr, rContent,nOpenMode ) ) +{ + DBG_CTOR(DataSupplier,NULL); + +} + +DataSupplier::~DataSupplier() +{ + + DBG_DTOR(DataSupplier,NULL); +} + +rtl::OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( (size_t)nIndex < m_pImpl->m_aResults.size() ) + { + rtl::OUString aId = m_pImpl->m_aResults[ nIndex ]->aId; + if ( aId.getLength() ) + { + // Already cached. + return aId; + } + } + + if ( getResult( nIndex ) ) + { + rtl::OUString aId + = m_pImpl->m_xContent->getIdentifier()->getContentIdentifier(); + + if ( aId.getLength() ) + aId += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")); + + aId += m_pImpl->m_aResults[ nIndex ]->rData.aTitle; + + m_pImpl->m_aResults[ nIndex ]->aId = aId; + return aId; + } + return rtl::OUString(); +} + +Reference< XContentIdentifier > +DataSupplier::queryContentIdentifier( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( (size_t)nIndex < m_pImpl->m_aResults.size() ) + { + Reference< XContentIdentifier > xId = m_pImpl->m_aResults[ nIndex ]->xId; + if ( xId.is() ) + { + // Already cached. + return xId; + } + } + + rtl::OUString aId = queryContentIdentifierString( nIndex ); + if ( aId.getLength() ) + { + Reference< XContentIdentifier > xId = new ::ucbhelper::ContentIdentifier( aId ); + m_pImpl->m_aResults[ nIndex ]->xId = xId; + return xId; + } + return Reference< XContentIdentifier >(); +} + +Reference< XContent > +DataSupplier::queryContent( sal_uInt32 _nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( (size_t)_nIndex < m_pImpl->m_aResults.size() ) + { + Reference< XContent > xContent = m_pImpl->m_aResults[ _nIndex ]->xContent.get(); + if ( xContent.is() ) + { + // Already cached. + return xContent; + } + } + + Reference< XContentIdentifier > xId = queryContentIdentifier( _nIndex ); + if ( xId.is() ) + { + try + { + Reference< XContent > xContent; + ::rtl::OUString sName = xId->getContentIdentifier(); + sal_Int32 nIndex = sName.lastIndexOf('/') + 1; + sName = sName.getToken(0,'/',nIndex); + + m_pImpl->m_aResults[ _nIndex ]->xContent = m_pImpl->m_xContent->getContent(sName); + + xContent = m_pImpl->m_aResults[ _nIndex ]->xContent.get(); + return xContent; + + } + catch ( IllegalIdentifierException& ) + { + } + } + return Reference< XContent >(); +} + +sal_Bool DataSupplier::getResult( sal_uInt32 nIndex ) +{ + osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( (size_t)nIndex < m_pImpl->m_aResults.size() ) + { + // Result already present. + return sal_True; + } + + // Result not (yet) present. + + if ( m_pImpl->m_bCountFinal ) + return sal_False; + + // Try to obtain result... + + sal_uInt32 nOldCount = m_pImpl->m_aResults.size(); + sal_Bool bFound = sal_False; + sal_uInt32 nPos = nOldCount; + + // @@@ Obtain data and put it into result list... + Sequence< ::rtl::OUString> aSeq = m_pImpl->m_xContent->getElementNames(); + if ( nIndex < sal::static_int_cast< sal_uInt32 >( aSeq.getLength() ) ) + { + const ::rtl::OUString* pIter = aSeq.getConstArray(); + const ::rtl::OUString* pEnd = pIter + aSeq.getLength(); + for(pIter = pIter + nPos;pIter != pEnd;++pIter,++nPos) + { + m_pImpl->m_aResults.push_back( + new ResultListEntry( m_pImpl->m_xContent->getContent(*pIter)->getContentProperties() ) ); + + if ( nPos == nIndex ) + { + // Result obtained. + bFound = sal_True; + break; + } + } + } + + if ( !bFound ) + m_pImpl->m_bCountFinal = sal_True; + + rtl::Reference< ::ucbhelper::ResultSet > xResultSet = getResultSet().get(); + if ( xResultSet.is() ) + { + // Callbacks follow! + aGuard.clear(); + + if ( (size_t)nOldCount < m_pImpl->m_aResults.size() ) + xResultSet->rowCountChanged( + nOldCount, m_pImpl->m_aResults.size() ); + + if ( m_pImpl->m_bCountFinal ) + xResultSet->rowCountFinal(); + } + + return bFound; +} + +sal_uInt32 DataSupplier::totalCount() +{ + osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( m_pImpl->m_bCountFinal ) + return m_pImpl->m_aResults.size(); + + sal_uInt32 nOldCount = m_pImpl->m_aResults.size(); + + // @@@ Obtain data and put it into result list... + Sequence< ::rtl::OUString> aSeq = m_pImpl->m_xContent->getElementNames(); + const ::rtl::OUString* pIter = aSeq.getConstArray(); + const ::rtl::OUString* pEnd = pIter + aSeq.getLength(); + for(;pIter != pEnd;++pIter) + m_pImpl->m_aResults.push_back( + new ResultListEntry( m_pImpl->m_xContent->getContent(*pIter)->getContentProperties() ) ); + + m_pImpl->m_bCountFinal = sal_True; + + rtl::Reference< ::ucbhelper::ResultSet > xResultSet = getResultSet().get(); + if ( xResultSet.is() ) + { + // Callbacks follow! + aGuard.clear(); + + if ( (size_t)nOldCount < m_pImpl->m_aResults.size() ) + xResultSet->rowCountChanged( + nOldCount, m_pImpl->m_aResults.size() ); + + xResultSet->rowCountFinal(); + } + + return m_pImpl->m_aResults.size(); +} + +sal_uInt32 DataSupplier::currentCount() +{ + return m_pImpl->m_aResults.size(); +} + +sal_Bool DataSupplier::isCountFinal() +{ + return m_pImpl->m_bCountFinal; +} + +Reference< XRow > +DataSupplier::queryPropertyValues( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( (size_t)nIndex < m_pImpl->m_aResults.size() ) + { + Reference< XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xRow; + if ( xRow.is() ) + { + // Already cached. + return xRow; + } + } + + if ( getResult( nIndex ) ) + { + if ( !m_pImpl->m_aResults[ nIndex ]->xContent.is() ) + queryContent(nIndex); + + Reference< XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xContent->getPropertyValues(getResultSet()->getProperties()); + m_pImpl->m_aResults[ nIndex ]->xRow = xRow; + return xRow; + } + + return Reference< XRow >(); +} + +void DataSupplier::releasePropertyValues( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( (size_t)nIndex < m_pImpl->m_aResults.size() ) + m_pImpl->m_aResults[ nIndex ]->xRow = Reference< XRow >(); +} + +void DataSupplier::close() +{ +} + +void DataSupplier::validate() + throw( ResultSetException ) +{ +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/myucp_datasupplier.hxx b/dbaccess/source/core/dataaccess/myucp_datasupplier.hxx new file mode 100644 index 000000000000..77dcbf2e9659 --- /dev/null +++ b/dbaccess/source/core/dataaccess/myucp_datasupplier.hxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 DBA_DATASUPPLIER_HXX +#define DBA_DATASUPPLIER_HXX + +#include <rtl/ref.hxx> +#include <ucbhelper/resultset.hxx> +#include "documentcontainer.hxx" +#include <memory> + +namespace dbaccess { + +struct DataSupplier_Impl; +class OContentHelper; + +class DataSupplier : public ucbhelper::ResultSetDataSupplier +{ + ::std::auto_ptr<DataSupplier_Impl> m_pImpl; + +public: + DataSupplier( const com::sun::star::uno::Reference< + com::sun::star::lang::XMultiServiceFactory >& rxSMgr, + const rtl::Reference< ODocumentContainer >& rxContent, + sal_Int32 nOpenMode ); + virtual ~DataSupplier(); + + virtual rtl::OUString queryContentIdentifierString( sal_uInt32 nIndex ); + virtual com::sun::star::uno::Reference< + com::sun::star::ucb::XContentIdentifier > + queryContentIdentifier( sal_uInt32 nIndex ); + virtual com::sun::star::uno::Reference< com::sun::star::ucb::XContent > + queryContent( sal_uInt32 nIndex ); + + virtual sal_Bool getResult( sal_uInt32 nIndex ); + + virtual sal_uInt32 totalCount(); + virtual sal_uInt32 currentCount(); + virtual sal_Bool isCountFinal(); + + virtual com::sun::star::uno::Reference< com::sun::star::sdbc::XRow > + queryPropertyValues( sal_uInt32 nIndex ); + virtual void releasePropertyValues( sal_uInt32 nIndex ); + + virtual void close(); + + virtual void validate() + throw( com::sun::star::ucb::ResultSetException ); +}; + +} + +#endif // DBA_DATASUPPLIER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/myucp_resultset.cxx b/dbaccess/source/core/dataaccess/myucp_resultset.cxx new file mode 100644 index 000000000000..d59336d87527 --- /dev/null +++ b/dbaccess/source/core/dataaccess/myucp_resultset.cxx @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_dbaccess.hxx" + +/************************************************************************** + TODO + ************************************************************************** + + - This implementation is not a dynamic result set!!! It only implements + the necessary interfaces, but never recognizes/notifies changes!!! + + *************************************************************************/ + +#include "myucp_datasupplier.hxx" +#include "myucp_resultset.hxx" + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::container; + +using namespace dbaccess; + +//========================================================================= +// +// DynamicResultSet Implementation. +// +//========================================================================= + +DynamicResultSet::DynamicResultSet( + const Reference< XMultiServiceFactory >& rxSMgr, + const rtl::Reference< ODocumentContainer >& rxContent, + const OpenCommandArgument2& rCommand, + const Reference< XCommandEnvironment >& rxEnv ) + :ResultSetImplHelper( rxSMgr, rCommand ) + ,m_xContent(rxContent) + ,m_xEnv( rxEnv ) +{ +} + +//========================================================================= +// +// Non-interface methods. +// +//========================================================================= +void DynamicResultSet::initStatic() +{ + m_xResultSet1 + = new ::ucbhelper::ResultSet( m_xSMgr, + m_aCommand.Properties, + new DataSupplier( m_xSMgr, + m_xContent, + m_aCommand.Mode ), + m_xEnv ); +} + +void DynamicResultSet::initDynamic() +{ + m_xResultSet1 + = new ::ucbhelper::ResultSet( m_xSMgr, + m_aCommand.Properties, + new DataSupplier( m_xSMgr, + m_xContent, + m_aCommand.Mode ), + m_xEnv ); + m_xResultSet2 = m_xResultSet1; +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/myucp_resultset.hxx b/dbaccess/source/core/dataaccess/myucp_resultset.hxx new file mode 100644 index 000000000000..b74be38df9d6 --- /dev/null +++ b/dbaccess/source/core/dataaccess/myucp_resultset.hxx @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 DBA_UCPRESULTSET_HXX +#define DBA_UCPRESULTSET_HXX + +#include <rtl/ref.hxx> +#include <ucbhelper/resultsethelper.hxx> +#include "documentcontainer.hxx" + + +// @@@ Adjust namespace name. +namespace dbaccess { + +class DynamicResultSet : public ::ucbhelper::ResultSetImplHelper +{ + rtl::Reference< ODocumentContainer > m_xContent; + com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > m_xEnv; + +private: + virtual void initStatic(); + virtual void initDynamic(); + +public: + DynamicResultSet( + const com::sun::star::uno::Reference< + com::sun::star::lang::XMultiServiceFactory >& rxSMgr, + const rtl::Reference< ODocumentContainer >& rxContent, + const com::sun::star::ucb::OpenCommandArgument2& rCommand, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment >& rxEnv ); +}; + +} + +#endif // DBA_UCPRESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |