diff options
Diffstat (limited to 'dbaccess/source/core/dataaccess')
-rw-r--r-- | dbaccess/source/core/dataaccess/ModelImpl.cxx | 172 | ||||
-rw-r--r-- | dbaccess/source/core/dataaccess/ModelImpl.hxx | 48 | ||||
-rw-r--r-- | dbaccess/source/core/dataaccess/connection.cxx | 30 | ||||
-rw-r--r-- | dbaccess/source/core/dataaccess/connection.hxx | 50 | ||||
-rw-r--r-- | dbaccess/source/core/dataaccess/databasecontext.cxx | 2 | ||||
-rw-r--r-- | dbaccess/source/core/dataaccess/databasedocument.cxx | 355 | ||||
-rw-r--r-- | dbaccess/source/core/dataaccess/databasedocument.hxx | 49 | ||||
-rw-r--r-- | dbaccess/source/core/dataaccess/datasource.cxx | 22 | ||||
-rw-r--r-- | dbaccess/source/core/dataaccess/documentcontainer.cxx | 132 | ||||
-rw-r--r-- | dbaccess/source/core/dataaccess/documentcontainer.hxx | 14 | ||||
-rw-r--r-- | dbaccess/source/core/dataaccess/documentdefinition.cxx | 405 | ||||
-rw-r--r-- | dbaccess/source/core/dataaccess/documentdefinition.hxx | 115 | ||||
-rw-r--r-- | dbaccess/source/core/dataaccess/makefile.mk | 2 |
13 files changed, 1009 insertions, 387 deletions
diff --git a/dbaccess/source/core/dataaccess/ModelImpl.cxx b/dbaccess/source/core/dataaccess/ModelImpl.cxx index b77d53eb7783..516b035eb23e 100644 --- a/dbaccess/source/core/dataaccess/ModelImpl.cxx +++ b/dbaccess/source/core/dataaccess/ModelImpl.cxx @@ -38,6 +38,7 @@ #include "dbastrings.hrc" #include "ModelImpl.hxx" #include "userinformation.hxx" +#include "sdbcoretools.hxx" /** === begin UNO includes === **/ #include <com/sun/star/container/XSet.hpp> @@ -53,7 +54,6 @@ #include <comphelper/interaction.hxx> #include <comphelper/mediadescriptor.hxx> -#include <comphelper/namedvaluecollection.hxx> #include <comphelper/seqstream.hxx> #include <comphelper/sequence.hxx> #include <connectivity/dbexception.hxx> @@ -296,7 +296,7 @@ void DocumentStorageAccess::commitStorages() SAL_THROW(( IOException, RuntimeExc ++aIter ) { - m_pModelImplementation->commitStorageIfWriteable( aIter->second ); + tools::stor::commitStorageIfWriteable( aIter->second ); } } catch(const WrappedTargetException&) @@ -317,7 +317,7 @@ bool DocumentStorageAccess::commitEmbeddedStorage( bool _bPreventRootCommits ) { NamedStorages::const_iterator pos = m_aExposedStorages.find( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "database" ) ) ); if ( pos != m_aExposedStorages.end() ) - bSuccess = m_pModelImplementation->commitStorageIfWriteable( pos->second ); + bSuccess = tools::stor::commitStorageIfWriteable( pos->second ); } catch( Exception& ) { @@ -808,27 +808,41 @@ const Reference< XNumberFormatsSupplier > & ODatabaseModelImpl::getNumberFormats } return m_xNumberFormatsSupplier; } + // ----------------------------------------------------------------------------- -void ODatabaseModelImpl::attachResource( const ::rtl::OUString& _rURL, const Sequence< PropertyValue >& _rArgs ) +void ODatabaseModelImpl::setDocFileLocation( const ::rtl::OUString& i_rLoadedFrom ) { - ::comphelper::NamedValueCollection aMediaDescriptor( _rArgs ); + ENSURE_OR_THROW( i_rLoadedFrom.getLength(), "invalid URL" ); + m_sDocFileLocation = i_rLoadedFrom; +} - ::rtl::OUString sDocumentLocation( aMediaDescriptor.getOrDefault( "SalvagedFile", _rURL ) ); - if ( !sDocumentLocation.getLength() ) - // this indicates "the document is being recovered, but _rURL already is the real document URL, - // not the temporary document location" - sDocumentLocation = _rURL; +// ----------------------------------------------------------------------------- +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" ) ) - aMediaDescriptor.remove( "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_aArgs = stripLoadArguments( aMediaDescriptor ); + m_aMediaDescriptor = stripLoadArguments( aMediaDescriptor ); - switchToURL( sDocumentLocation, _rURL ); + impl_switchToLogicalURL( i_rDocumentURL ); } // ----------------------------------------------------------------------------- -Sequence< PropertyValue > ODatabaseModelImpl::stripLoadArguments( const ::comphelper::NamedValueCollection& _rArguments ) +::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)!" ); @@ -836,7 +850,7 @@ Sequence< PropertyValue > ODatabaseModelImpl::stripLoadArguments( const ::comphe ::comphelper::NamedValueCollection aMutableArgs( _rArguments ); aMutableArgs.remove( "Model" ); aMutableArgs.remove( "ViewName" ); - return aMutableArgs.getPropertyValues(); + return aMutableArgs; } // ----------------------------------------------------------------------------- @@ -870,11 +884,9 @@ Reference< XStorage > ODatabaseModelImpl::getOrCreateRootStorage() if ( xStorageFactory.is() ) { Any aSource; - ::comphelper::NamedValueCollection aArgs( m_aArgs ); - - aSource = aArgs.get( "Stream" ); + aSource = m_aMediaDescriptor.get( "Stream" ); if ( !aSource.hasValue() ) - aSource = aArgs.get( "InputStream" ); + aSource = m_aMediaDescriptor.get( "InputStream" ); if ( !aSource.hasValue() && m_sDocFileLocation.getLength() ) aSource <<= m_sDocFileLocation; // TODO: shouldn't we also check URL? @@ -950,48 +962,12 @@ bool ODatabaseModelImpl::commitEmbeddedStorage( bool _bPreventRootCommits ) } // ----------------------------------------------------------------------------- -namespace -{ - bool lcl_storageIsWritable_nothrow( const Reference< XStorage >& _rxStorage ) - { - if ( !_rxStorage.is() ) - return false; - - sal_Int32 nMode = ElementModes::READ; - try - { - Reference< XPropertySet > xStorageProps( _rxStorage, UNO_QUERY_THROW ); - xStorageProps->getPropertyValue( - ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OpenMode" ) ) ) >>= nMode; - } - catch( const Exception& ) - { - DBG_UNHANDLED_EXCEPTION(); - } - return ( nMode & ElementModes::WRITE ) != 0; - } -} - -// ----------------------------------------------------------------------------- -bool ODatabaseModelImpl::commitStorageIfWriteable( const Reference< XStorage >& _rxStorage ) SAL_THROW(( IOException, WrappedTargetException, RuntimeException )) -{ - bool bSuccess = false; - Reference<XTransactedObject> xTrans( _rxStorage, UNO_QUERY ); - if ( xTrans.is() ) - { - if ( lcl_storageIsWritable_nothrow( _rxStorage ) ) - xTrans->commit(); - bSuccess = true; - } - return bSuccess; -} -// ----------------------------------------------------------------------------- bool ODatabaseModelImpl::commitStorageIfWriteable_ignoreErrors( const Reference< XStorage >& _rxStorage ) SAL_THROW(()) { bool bSuccess = false; try { - bSuccess = commitStorageIfWriteable( _rxStorage ); + bSuccess = tools::stor::commitStorageIfWriteable( _rxStorage ); } catch( const Exception& ) { @@ -1066,7 +1042,7 @@ Reference< XModel > ODatabaseModelImpl::createNewModel_deliverOwnership( bool _b // 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_aArgs ); + xModel->attachResource( xModel->getURL(), m_aMediaDescriptor.getPropertyValues() ); } if ( _bInitialize ) @@ -1180,6 +1156,17 @@ const AsciiPropertyValue* ODatabaseModelImpl::getDefaultDataSourceSettings() 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; @@ -1216,9 +1203,8 @@ bool ODatabaseModelImpl::adjustMacroMode_AutoReject() // ----------------------------------------------------------------------------- bool ODatabaseModelImpl::checkMacrosOnLoading() { - ::comphelper::NamedValueCollection aArgs( m_aArgs ); Reference< XInteractionHandler > xInteraction; - xInteraction = aArgs.getOrDefault( "InteractionHandler", xInteraction ); + xInteraction = m_aMediaDescriptor.getOrDefault( "InteractionHandler", xInteraction ); return m_aMacroMode.checkMacrosOnLoading( xInteraction ); } @@ -1344,38 +1330,41 @@ Reference< XStorage > ODatabaseModelImpl::impl_switchToStorage_throw( const Refe lcl_rebaseScriptStorage_throw( m_xBasicLibraries, m_xDocumentStorage.getTyped() ); lcl_rebaseScriptStorage_throw( m_xDialogLibraries, m_xDocumentStorage.getTyped() ); - m_bReadOnly = !lcl_storageIsWritable_nothrow( 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::switchToURL( const ::rtl::OUString& _rDocumentLocation, const ::rtl::OUString& _rDocumentURL ) +void ODatabaseModelImpl::impl_switchToLogicalURL( const ::rtl::OUString& i_rDocumentURL ) { - // register at the database context, or change registration - const bool bURLChanged = ( _rDocumentURL != m_sDocumentURL ); + if ( i_rDocumentURL == m_sDocumentURL ) + return; + const ::rtl::OUString sOldURL( m_sDocumentURL ); - if ( bURLChanged ) + // 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) + ) { - 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 ) { - INetURLObject aURL( _rDocumentURL ); - if ( aURL.GetProtocol() != INET_PROT_NOT_VALID ) - { - m_sName = _rDocumentURL; - // TODO: our data source must broadcast the change of the Name property - } + m_sName = i_rDocumentURL; + // TODO: our data source must broadcast the change of the Name property } } - // remember both - m_sDocFileLocation = _rDocumentLocation.getLength() ? _rDocumentLocation : _rDocumentURL; - m_sDocumentURL = _rDocumentURL; + // remember URL + m_sDocumentURL = i_rDocumentURL; - if ( bURLChanged && m_pDBContext ) + // 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 ); @@ -1396,8 +1385,7 @@ sal_Int16 ODatabaseModelImpl::getCurrentMacroExecMode() const sal_Int16 nCurrentMode = MacroExecMode::NEVER_EXECUTE; try { - ::comphelper::NamedValueCollection aArgs( m_aArgs ); - nCurrentMode = aArgs.getOrDefault( "MacroExecutionMode", nCurrentMode ); + nCurrentMode = m_aMediaDescriptor.getOrDefault( "MacroExecutionMode", nCurrentMode ); } catch( const Exception& ) { @@ -1409,28 +1397,20 @@ sal_Int16 ODatabaseModelImpl::getCurrentMacroExecMode() const // ----------------------------------------------------------------------------- sal_Bool ODatabaseModelImpl::setCurrentMacroExecMode( sal_uInt16 nMacroMode ) { - try - { - ::comphelper::NamedValueCollection aArgs( m_aArgs ); - aArgs.put( "MacroExecutionMode", nMacroMode ); - aArgs >>= m_aArgs; - return sal_True; - } - catch( const Exception& ) - { - DBG_UNHANDLED_EXCEPTION(); - } - - return sal_False; + m_aMediaDescriptor.put( "MacroExecutionMode", nMacroMode ); + return sal_True; } // ----------------------------------------------------------------------------- ::rtl::OUString ODatabaseModelImpl::getDocumentLocation() const { - // don't return getURL() (or m_sDocumentURL, which is the same). In case we were recovered - // after a previous crash of OOo, m_sDocFileLocation points to the file which were loaded from, - // and this is the one we need for security checks. - return getDocFileLocation(); + 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. } // ----------------------------------------------------------------------------- diff --git a/dbaccess/source/core/dataaccess/ModelImpl.hxx b/dbaccess/source/core/dataaccess/ModelImpl.hxx index 3b51e85d1c1c..f83b2230c2b4 100644 --- a/dbaccess/source/core/dataaccess/ModelImpl.hxx +++ b/dbaccess/source/core/dataaccess/ModelImpl.hxx @@ -70,6 +70,7 @@ /** === end UNO includes === **/ #include <comphelper/broadcasthelper.hxx> +#include <comphelper/namedvaluecollection.hxx> #include <comphelper/proparrhlp.hxx> #include <comphelper/sharedmutex.hxx> #include <connectivity/CommonTools.hxx> @@ -207,7 +208,7 @@ private: ODatabaseContext* m_pDBContext; DocumentEventsData m_aDocumentEvents; - ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > m_aArgs; + ::comphelper::NamedValueCollection m_aMediaDescriptor; /// the URL the document was loaded from ::rtl::OUString m_sDocFileLocation; @@ -318,14 +319,18 @@ public: DocumentEventsData& getDocumentEvents() { return m_aDocumentEvents; } - const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& - getResource() const { return m_aArgs; } + const ::comphelper::NamedValueCollection& + getMediaDescriptor() const { return m_aMediaDescriptor; } - void attachResource( + void setResource( const ::rtl::OUString& _rURL, - const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& _rArgs ); + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& _rArgs + ); + void setDocFileLocation( + const ::rtl::OUString& i_rLoadedFrom + ); - static ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > + static ::comphelper::NamedValueCollection stripLoadArguments( const ::comphelper::NamedValueCollection& _rArguments ); // other stuff @@ -341,16 +346,6 @@ public: /// commits our storage void commitRootStorage(); - /// commits a given storage if it's not readonly - static bool commitStorageIfWriteable( - const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& _rxStorage - ) - SAL_THROW(( - ::com::sun::star::io::IOException, - ::com::sun::star::lang::WrappedTargetException, - ::com::sun::star::uno::RuntimeException - )); - /// 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 @@ -488,19 +483,6 @@ public: const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& _rxNewRootStorage ); - /** switches to the given document location/URL - - The document location is the URL of the file from which the document has been loaded. - The document URL is the "intended location" of the document. It differs from the location - if and only if the document was loaded as part of a document recovery process. In this case, - the location points to some temporary file, but the URL is the URL of the file which has been - just recovered. The next store operation would operate on the URL, not the location. - */ - void switchToURL( - const ::rtl::OUString& _rDocumentLocation, - const ::rtl::OUString& _rDocumentURL - ); - /** returns the macro mode imposed by an external instance, which passed it to attachResource */ sal_Int16 getImposedMacroExecMode() const @@ -536,6 +518,14 @@ 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 diff --git a/dbaccess/source/core/dataaccess/connection.cxx b/dbaccess/source/core/dataaccess/connection.cxx index 257f8fc6477d..f543e2665a7e 100644 --- a/dbaccess/source/core/dataaccess/connection.cxx +++ b/dbaccess/source/core/dataaccess/connection.cxx @@ -39,6 +39,7 @@ #include "ContainerMediator.hxx" #include "SingleSelectQueryComposer.hxx" #include "querycomposer.hxx" +#include "sdbcoretools.hxx" /** === begin UNO includes === **/ #include <com/sun/star/sdb/CommandType.hpp> @@ -74,6 +75,10 @@ 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 { @@ -614,7 +619,7 @@ 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->isInitialized()) + if (m_pTables && !m_pTables->isInitialized()) { impl_fillTableFilter(); // check if our "master connection" can supply tables @@ -632,7 +637,7 @@ void OConnection::refresh(const Reference< XNameAccess >& _rToBeRefreshed) } else if ( _rToBeRefreshed == Reference< XNameAccess >(m_pViews) ) { - if (!m_pViews->isInitialized()) + if (m_pViews && !m_pViews->isInitialized()) { impl_fillTableFilter(); // check if our "master connection" can supply tables @@ -726,6 +731,21 @@ Reference< XInterface > SAL_CALL OConnection::createInstance( const ::rtl::OUStr 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); } // ----------------------------------------------------------------------------- @@ -795,7 +815,7 @@ void OConnection::impl_loadConnectionTools_throw() } // ----------------------------------------------------------------------------- -Reference< tools::XTableName > SAL_CALL OConnection::createTableName( ) throw (RuntimeException) +Reference< XTableName > SAL_CALL OConnection::createTableName( ) throw (RuntimeException) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::createTableName" ); MutexGuard aGuard(m_aMutex); @@ -806,7 +826,7 @@ Reference< tools::XTableName > SAL_CALL OConnection::createTableName( ) throw ( } // ----------------------------------------------------------------------------- -Reference< tools::XObjectNames > SAL_CALL OConnection::getObjectNames( ) throw (RuntimeException) +Reference< XObjectNames > SAL_CALL OConnection::getObjectNames( ) throw (RuntimeException) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getObjectNames" ); MutexGuard aGuard(m_aMutex); @@ -817,7 +837,7 @@ Reference< tools::XObjectNames > SAL_CALL OConnection::getObjectNames( ) throw } // ----------------------------------------------------------------------------- -Reference< tools::XDataSourceMetaData > SAL_CALL OConnection::getDataSourceMetaData( ) throw (RuntimeException) +Reference< XDataSourceMetaData > SAL_CALL OConnection::getDataSourceMetaData( ) throw (RuntimeException) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "OConnection::getDataSourceMetaData" ); MutexGuard aGuard(m_aMutex); diff --git a/dbaccess/source/core/dataaccess/connection.hxx b/dbaccess/source/core/dataaccess/connection.hxx index e4eace3db14c..eb80cc2fc7db 100644 --- a/dbaccess/source/core/dataaccess/connection.hxx +++ b/dbaccess/source/core/dataaccess/connection.hxx @@ -27,62 +27,25 @@ #ifndef _DBA_CORE_CONNECTION_HXX_ #define _DBA_CORE_CONNECTION_HXX_ -#ifndef _DBASHARED_APITOOLS_HXX_ #include "apitools.hxx" -#endif -#ifndef _DBA_CORE_QUERYCONTAINER_HXX_ #include "querycontainer.hxx" -#endif -#ifndef _DBA_CORE_TABLECONTAINER_HXX_ #include "tablecontainer.hxx" -#endif -#ifndef _DBA_CORE_VIEWCONTAINER_HXX_ #include "viewcontainer.hxx" -#endif -#ifndef DBA_CORE_REFRESHLISTENER_HXX #include "RefreshListener.hxx" -#endif -#ifndef DBTOOLS_WARNINGSCONTAINER_HXX -#include <connectivity/warningscontainer.hxx> -#endif /** === begin UNO includes === **/ -#ifndef _COM_SUN_STAR_CONTAINER_XCHILD_HPP_ #include <com/sun/star/container/XChild.hpp> -#endif -#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_ #include <com/sun/star/lang/DisposedException.hpp> -#endif -#ifndef _COM_SUN_STAR_SDB_XSQLQUERYCOMPOSERFACTORY_HPP_ #include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp> -#endif -#ifndef _COM_SUN_STAR_SDB_XCOMMANDPREPARATION_HPP_ #include <com/sun/star/sdb/XCommandPreparation.hpp> -#endif -#ifndef _COM_SUN_STAR_SDBCX_XTABLESSUPPLIER_HPP_ #include <com/sun/star/sdbcx/XTablesSupplier.hpp> -#endif -#ifndef _COM_SUN_STAR_SDBCX_XVIEWSSUPPLIER_HPP_ #include <com/sun/star/sdbcx/XViewsSupplier.hpp> -#endif -#ifndef _COM_SUN_STAR_SDBCX_XUSERSSUPPLIER_HPP_ #include <com/sun/star/sdbcx/XUsersSupplier.hpp> -#endif -#ifndef _COM_SUN_STAR_SDBCX_XGROUPSSUPPLIER_HPP_ #include <com/sun/star/sdbcx/XGroupsSupplier.hpp> -#endif -#ifndef _COM_SUN_STAR_SDB_XQUERIESSUPPLIER_HPP_ #include <com/sun/star/sdb/XQueriesSupplier.hpp> -#endif -#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_ #include <com/sun/star/lang/XMultiServiceFactory.hpp> -#endif -#ifndef _COM_SUN_STAR_SDB_TOOLS_XCONNECTIONTOOLS_HPP_ #include <com/sun/star/sdb/tools/XConnectionTools.hpp> -#endif -#ifndef _COM_SUN_STAR_SDB_APPLICATION_XTABLEUIPROVIDER_HPP_ #include <com/sun/star/sdb/application/XTableUIProvider.hpp> -#endif /** === end UNO includes === **/ #if ! defined(INCLUDED_COMPHELPER_IMPLBASE_VAR_HXX_14) @@ -90,14 +53,10 @@ #define COMPHELPER_IMPLBASE_INTERFACE_NUMBER 14 #include <comphelper/implbase_var.hxx> #endif - -#ifndef COMPHELPER_COMPONENTCONTEXT_HXX #include <comphelper/componentcontext.hxx> -#endif - -#ifndef _CONNECTIVITY_CONNECTIONWRAPPER_HXX_ +#include <comphelper/stl_types.hxx> #include <connectivity/ConnectionWrapper.hxx> -#endif +#include <connectivity/warningscontainer.hxx> //........................................................................ namespace dbaccess @@ -148,6 +107,11 @@ protected: ::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; diff --git a/dbaccess/source/core/dataaccess/databasecontext.cxx b/dbaccess/source/core/dataaccess/databasecontext.cxx index 4d0fbd7ff480..8ee57b538365 100644 --- a/dbaccess/source/core/dataaccess/databasecontext.cxx +++ b/dbaccess/source/core/dataaccess/databasecontext.cxx @@ -385,7 +385,7 @@ Reference< XInterface > ODatabaseContext::loadObjectFromURL(const ::rtl::OUStrin ::comphelper::NamedValueCollection aArgs; aArgs.put( "URL", _sURL ); aArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG ); - aArgs.put( "InteractionHandler", m_aContext.createComponent( "com.sun.star.sdb.InteractionHandler" ) ); + aArgs.put( "InteractionHandler", m_aContext.createComponent( "com.sun.star.task.InteractionHandler" ) ); Sequence< PropertyValue > aResource( aArgs.getPropertyValues() ); xLoad->load( aResource ); diff --git a/dbaccess/source/core/dataaccess/databasedocument.cxx b/dbaccess/source/core/dataaccess/databasedocument.cxx index c04097254886..125c54121628 100644 --- a/dbaccess/source/core/dataaccess/databasedocument.cxx +++ b/dbaccess/source/core/dataaccess/databasedocument.cxx @@ -38,6 +38,7 @@ #include "databasecontext.hxx" #include "documentcontainer.hxx" #include "sdbcoretools.hxx" +#include "recovery/dbdocrecovery.hxx" /** === begin UNO includes === **/ #include <com/sun/star/beans/Optional.hpp> @@ -60,6 +61,8 @@ #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> @@ -71,6 +74,11 @@ #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> @@ -110,6 +118,8 @@ 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 @@ -132,7 +142,7 @@ bool ViewMonitor::onControllerConnected( const Reference< XController >& _rxCont } //-------------------------------------------------------------------------- -void ViewMonitor::onSetCurrentController( const Reference< XController >& _rxController ) +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 @@ -142,6 +152,8 @@ void ViewMonitor::onSetCurrentController( const Reference< XController >& _rxCon // notify the respective events if ( bLoadFinished ) m_rEventNotifier.notifyDocumentEventAsync( m_bIsNewDocument ? "OnNew" : "OnLoad" ); + + return bLoadFinished; } //============================================================ @@ -168,6 +180,7 @@ ODatabaseDocument::ODatabaseDocument(const ::rtl::Reference<ODatabaseModelImpl>& ,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() ); @@ -372,15 +385,15 @@ namespace } // ----------------------------------------------------------------------------- - static Sequence< PropertyValue > lcl_appendFileNameToDescriptor( const Sequence< PropertyValue >& _rDescriptor, const ::rtl::OUString _rURL ) + static Sequence< PropertyValue > lcl_appendFileNameToDescriptor( const ::comphelper::NamedValueCollection& _rDescriptor, const ::rtl::OUString _rURL ) { - ::comphelper::NamedValueCollection aMediaDescriptor( _rDescriptor ); + ::comphelper::NamedValueCollection aMutableDescriptor( _rDescriptor ); if ( _rURL.getLength() ) { - aMediaDescriptor.put( "FileName", _rURL ); - aMediaDescriptor.put( "URL", _rURL ); + aMutableDescriptor.put( "FileName", _rURL ); + aMutableDescriptor.put( "URL", _rURL ); } - return aMediaDescriptor.getPropertyValues(); + return aMutableDescriptor.getPropertyValues(); } } @@ -422,9 +435,9 @@ void ODatabaseDocument::impl_reset_nothrow() void ODatabaseDocument::impl_import_nolck_throw( const ::comphelper::ComponentContext _rContext, const Reference< XInterface >& _rxTargetComponent, const ::comphelper::NamedValueCollection& _rResource ) { - Sequence< Any > aFilterArgs; + Sequence< Any > aFilterCreationArgs; Reference< XStatusIndicator > xStatusIndicator; - lcl_extractAndStartStatusIndicator( _rResource, xStatusIndicator, aFilterArgs ); + lcl_extractAndStartStatusIndicator( _rResource, xStatusIndicator, aFilterCreationArgs ); /** property map for import info set */ comphelper::PropertyMapEntry aExportInfoMap[] = @@ -437,19 +450,20 @@ void ODatabaseDocument::impl_import_nolck_throw( const ::comphelper::ComponentCo 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 = aFilterArgs.getLength(); - aFilterArgs.realloc(nCount + 1); - aFilterArgs[nCount] <<= xInfoSet; + const sal_Int32 nCount = aFilterCreationArgs.getLength(); + aFilterCreationArgs.realloc(nCount + 1); + aFilterCreationArgs[nCount] <<= xInfoSet; Reference< XImporter > xImporter( - _rContext.createComponentWithArguments( "com.sun.star.comp.sdb.DBFilter", aFilterArgs ), + _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 ); - xFilter->filter( ODatabaseModelImpl::stripLoadArguments( _rResource ) ); + Sequence< PropertyValue > aFilterArgs( ODatabaseModelImpl::stripLoadArguments( _rResource ).getPropertyValues() ); + xFilter->filter( aFilterArgs ); if ( xStatusIndicator.is() ) xStatusIndicator->end(); @@ -537,14 +551,176 @@ void SAL_CALL ODatabaseDocument::load( const Sequence< PropertyValue >& _Argumen } // ----------------------------------------------------------------------------- +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 ); +} - if ( ( _rURL == getURL() ) - && ( _rArguments.getLength() == 1 ) - && ( _rArguments[0].Name.compareToAscii( "BreakMacroSignature" ) == 0 ) +// ----------------------------------------------------------------------------- +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, @@ -553,7 +729,14 @@ sal_Bool SAL_CALL ODatabaseDocument::attachResource( const ::rtl::OUString& _rUR // (we do not support macro signatures, so we can ignore this call) } - m_pImpl->attachResource( _rURL, _rArguments ); + // 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 @@ -565,7 +748,7 @@ sal_Bool SAL_CALL ODatabaseDocument::attachResource( const ::rtl::OUString& _rUR // should know this before anybody actually uses the object. m_bAllowDocumentScripting = ( m_pImpl->determineEmbeddedMacros() != ODatabaseModelImpl::eSubDocumentMacros ); - aGuard.clear(); + _rDocGuard.clear(); // <- SYNCHRONIZED m_aEventNotifier.notifyDocumentEvent( "OnLoadFinished" ); } @@ -584,7 +767,7 @@ sal_Bool SAL_CALL ODatabaseDocument::attachResource( const ::rtl::OUString& _rUR Sequence< PropertyValue > SAL_CALL ODatabaseDocument::getArgs( ) throw (RuntimeException) { DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit ); - return m_pImpl->getResource(); + return m_pImpl->getMediaDescriptor().getPropertyValues(); } // ----------------------------------------------------------------------------- @@ -592,6 +775,16 @@ void SAL_CALL ODatabaseDocument::connectController( const Reference< XController { 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 ) ); @@ -688,8 +881,29 @@ void SAL_CALL ODatabaseDocument::setCurrentController( const Reference< XControl m_xCurrentController = _xController; - m_aViewMonitor.onSetCurrentController( _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) { @@ -714,6 +928,8 @@ sal_Bool SAL_CALL ODatabaseDocument::hasLocation( ) 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) @@ -726,15 +942,53 @@ void SAL_CALL ODatabaseDocument::store( ) throw (IOException, RuntimeException) { DocumentGuard aGuard( *this ); - if ( m_pImpl->getDocFileLocation() == m_pImpl->getURL() ) - if ( m_pImpl->m_bDocumentReadOnly ) - throw IOException(); + ::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!" ); - impl_storeAs_throw( m_pImpl->getURL(), m_pImpl->getResource(), SAVE, aGuard ); + 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_storeAs_throw( const ::rtl::OUString& _rURL, const Sequence< PropertyValue>& _rArguments, +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 ), @@ -780,6 +1034,12 @@ void ODatabaseDocument::impl_storeAs_throw( const ::rtl::OUString& _rURL, const 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; @@ -791,7 +1051,8 @@ void ODatabaseDocument::impl_storeAs_throw( const ::rtl::OUString& _rURL, const impl_storeToStorage_throw( xCurrentStorage, aMediaDescriptor, _rGuard ); // success - tell our impl - m_pImpl->attachResource( _rURL, aMediaDescriptor ); + 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 ) @@ -813,13 +1074,7 @@ void ODatabaseDocument::impl_storeAs_throw( const ::rtl::OUString& _rURL, const throw; } - ::rtl::OUString sErrorMessage = extractExceptionMessage( m_pImpl->m_aContext, aError ); - sErrorMessage = ResourceManager::loadString( - RID_STR_ERROR_WHILE_SAVING, - "$location$", _rURL, - "$message$", sErrorMessage - ); - throw IOException( sErrorMessage, *this ); + impl_throwIOExceptionCausedBySave_throw( aError, _rURL ); } // notify the document event @@ -934,7 +1189,7 @@ void ODatabaseDocument::impl_storeToStorage_throw( const Reference< XStorage >& lcl_triggerStatusIndicator_throw( aWriteArgs, _rDocGuard, false ); // commit target storage - OSL_VERIFY( ODatabaseModelImpl::commitStorageIfWriteable( _rxTargetStorage ) ); + OSL_VERIFY( tools::stor::commitStorageIfWriteable( _rxTargetStorage ) ); } catch( const IOException& ) { throw; } catch( const RuntimeException& ) { throw; } @@ -980,16 +1235,7 @@ void SAL_CALL ODatabaseDocument::storeToURL( const ::rtl::OUString& _rURL, const throw; } - Exception aExcept; - aError >>= aExcept; - - ::rtl::OUString sErrorMessage = extractExceptionMessage( m_pImpl->m_aContext, aError ); - sErrorMessage = ResourceManager::loadString( - RID_STR_ERROR_WHILE_SAVING, - "$location$", _rURL, - "$message$", sErrorMessage - ); - throw IOException( sErrorMessage, *this ); + impl_throwIOExceptionCausedBySave_throw( aError, _rURL ); } m_aEventNotifier.notifyDocumentEventAsync( "OnSaveToDone", NULL, makeAny( _rURL ) ); @@ -1145,8 +1391,25 @@ Reference< XNameAccess > ODatabaseDocument::impl_getDocumentContainer_throw( ODa Reference< XNameAccess > xContainer = rContainerRef; if ( !xContainer.is() ) { - TContentPtr& rContainerData( m_pImpl->getObjectContainer( _eType ) ); - rContainerRef = xContainer = new ODocumentContainer( m_pImpl->m_aContext.getLegacyServiceFactory(), *this, rContainerData, bFormsContainer ); + 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; diff --git a/dbaccess/source/core/dataaccess/databasedocument.hxx b/dbaccess/source/core/dataaccess/databasedocument.hxx index d90310015f70..d2aa57130d18 100644 --- a/dbaccess/source/core/dataaccess/databasedocument.hxx +++ b/dbaccess/source/core/dataaccess/databasedocument.hxx @@ -57,11 +57,12 @@ #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_16) -#define INCLUDED_COMPHELPER_IMPLBASE_VAR_HXX_16 -#define COMPHELPER_IMPLBASE_INTERFACE_NUMBER 16 +#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 @@ -121,8 +122,12 @@ public: ); /** 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. */ - void onSetCurrentController( + bool onSetCurrentController( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController >& _rxController ); @@ -140,7 +145,7 @@ private: //============================================================ //= ODatabaseDocument //============================================================ -typedef ::comphelper::WeakComponentImplHelper16 < ::com::sun::star::frame::XModel2 +typedef ::comphelper::WeakComponentImplHelper17 < ::com::sun::star::frame::XModel2 , ::com::sun::star::util::XModifiable , ::com::sun::star::frame::XStorable , ::com::sun::star::document::XEventBroadcaster @@ -156,6 +161,7 @@ typedef ::comphelper::WeakComponentImplHelper16 < ::com::sun::star::frame::XMo , ::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 @@ -204,6 +210,7 @@ class ODatabaseDocument :public ModelDependentComponent // ModelDepe 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 @@ -221,7 +228,7 @@ class ODatabaseDocument :public ModelDependentComponent // ModelDepe */ void impl_storeAs_throw( const ::rtl::OUString& _rURL, - const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue>& _rArguments, + const ::comphelper::NamedValueCollection& _rArguments, const StoreType _eType, DocumentGuard& _rGuard ) @@ -422,6 +429,11 @@ public: 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); @@ -598,6 +610,31 @@ private: 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 diff --git a/dbaccess/source/core/dataaccess/datasource.cxx b/dbaccess/source/core/dataaccess/datasource.cxx index 286ef1887710..b5cf356c2115 100644 --- a/dbaccess/source/core/dataaccess/datasource.cxx +++ b/dbaccess/source/core/dataaccess/datasource.cxx @@ -39,6 +39,7 @@ #include "SharedConnection.hxx" #include "databasedocument.hxx" + /** === begin UNO includes === **/ #include <com/sun/star/beans/NamedValue.hpp> #include <com/sun/star/beans/PropertyAttribute.hpp> @@ -67,6 +68,7 @@ #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> @@ -1337,8 +1339,24 @@ Reference< XNameAccess > SAL_CALL ODatabaseSource::getQueryDefinitions( ) throw( Reference< XNameAccess > xContainer = m_pImpl->m_xCommandDefinitions; if ( !xContainer.is() ) { - TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_QUERY ) ); - xContainer = new OCommandContainer( m_pImpl->m_aContext.getLegacyServiceFactory(), *this, rContainerData, sal_False ); + 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; diff --git a/dbaccess/source/core/dataaccess/documentcontainer.cxx b/dbaccess/source/core/dataaccess/documentcontainer.cxx index 4f5277f5ed8b..d9427eff0463 100644 --- a/dbaccess/source/core/dataaccess/documentcontainer.cxx +++ b/dbaccess/source/core/dataaccess/documentcontainer.cxx @@ -82,6 +82,7 @@ #endif #include "core_resource.hxx" #include "core_resource.hrc" +#include <comphelper/namedvaluecollection.hxx> #include <vcl/svapp.hxx> #include <vos/mutex.hxx> @@ -202,6 +203,20 @@ Reference< XInterface > SAL_CALL ODocumentContainer::createInstance( const ::rtl { 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) { @@ -211,36 +226,47 @@ Reference< XInterface > SAL_CALL ODocumentContainer::createInstanceWithArguments { MutexGuard aGuard(m_aMutex); - ::rtl::OUString sName, sPersistentName, sURL, sMediaType; + // 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; - sal_Bool bAsTemplate = sal_False; ::comphelper::NamedValueCollection aArgs( _aArguments ); - sName = aArgs.getOrDefault( (::rtl::OUString)PROPERTY_NAME, sName ); - sPersistentName = aArgs.getOrDefault( (::rtl::OUString)PROPERTY_PERSISTENT_NAME, sPersistentName ); - xCopyFrom = aArgs.getOrDefault( (::rtl::OUString)PROPERTY_EMBEDDEDOBJECT, xCopyFrom ); - sURL = aArgs.getOrDefault( (::rtl::OUString)PROPERTY_URL, sURL ); - xConnection = aArgs.getOrDefault( (::rtl::OUString)PROPERTY_ACTIVE_CONNECTION, xConnection ); - bAsTemplate = aArgs.getOrDefault( (::rtl::OUString)PROPERTY_AS_TEMPLATE, bAsTemplate ); - sMediaType = aArgs.getOrDefault( (::rtl::OUString)INFO_MEDIATYPE, sMediaType ); - - if ( aArgs.has( "ClassID" ) ) + 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() ) { - Any aClassIDValue = aArgs.get( "ClassID" ); - // class IDs might be passed as byte sequence ... - if ( !( aClassIDValue >>= aClassID ) ) + if ( !( aClassIDArg >>= aClassID ) ) { - // ... or as string - ::rtl::OUString sClassID; - aClassIDValue >>= sClassID; - aClassID = ::comphelper::MimeConfigurationHelper::GetSequenceClassIDRepresentation( sClassID ); + // 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 ) { @@ -273,8 +299,18 @@ Reference< XInterface > SAL_CALL ODocumentContainer::createInstanceWithArguments } else { - if ( bNeedClassID && sMediaType.getLength() ) - ODocumentDefinition::GetDocumentServiceFromMediaType( sMediaType, m_aContext, aClassID ); + 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 >() ); + } + } } } @@ -293,7 +329,16 @@ Reference< XInterface > SAL_CALL ODocumentContainer::createInstanceWithArguments else pElementImpl = aFind->second; - xContent = new ODocumentDefinition( *this, m_aContext.getLegacyServiceFactory(), pElementImpl, m_bFormsContainer, aClassID, xConnection ); + ::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() ) { @@ -551,28 +596,15 @@ Reference< XComponent > SAL_CALL ODocumentContainer::loadComponentFromURL( const { Command aCommand; - static const ::rtl::OUString s_sOpenMode = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("OpenMode")); - const PropertyValue* pIter = Arguments.getConstArray(); - const PropertyValue* pEnd = pIter + Arguments.getLength(); - for( ; pIter != pEnd ; ++pIter) - { - if ( pIter->Name == s_sOpenMode ) - { - pIter->Value >>= aCommand.Name; - break; - } - } - if ( !aCommand.Name.getLength() ) // default mode - aCommand.Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("open")); + ::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 ); - Sequence< PropertyValue > aArguments(Arguments); - sal_Int32 nLen = aArguments.getLength(); - aArguments.realloc(nLen + 1); - - aArguments[nLen].Value <<= aOpenCommand; - aCommand.Argument <<= aArguments; + aCommand.Argument <<= aArgs.getPropertyValues(); xComp.set(xContent->execute(aCommand,xContent->createCommandIdentifier(),Reference< XCommandEnvironment >()),UNO_QUERY); } } @@ -664,6 +696,24 @@ void SAL_CALL ODocumentContainer::replaceByHierarchicalName( const ::rtl::OUStri 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 { diff --git a/dbaccess/source/core/dataaccess/documentcontainer.hxx b/dbaccess/source/core/dataaccess/documentcontainer.hxx index 9e26ea62d4b5..c1a9c424d7d3 100644 --- a/dbaccess/source/core/dataaccess/documentcontainer.hxx +++ b/dbaccess/source/core/dataaccess/documentcontainer.hxx @@ -31,8 +31,8 @@ #ifndef _DBA_CORE_DEFINITIONCONTAINER_HXX_ #include "definitioncontainer.hxx" #endif -#ifndef _CPPUHELPER_IMPLBASE4_HXX_ -#include <cppuhelper/implbase4.hxx> +#ifndef _CPPUHELPER_IMPLBASE5_HXX_ +#include <cppuhelper/implbase5.hxx> #endif #ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_ #include <com/sun/star/lang/XMultiServiceFactory.hpp> @@ -43,6 +43,9 @@ #ifndef _COM_SUN_STAR_CONTAINER_XHIERARCHICALNAMECONTAINER_HPP_ #include <com/sun/star/container/XHierarchicalNameContainer.hpp> #endif +#ifndef _COM_SUN_STAR_CONTAINER_XHIERARCHICALNAME_HPP_ +#include <com/sun/star/container/XHierarchicalName.hpp> +#endif #ifndef _COM_SUN_STAR_EMBED_XTRANSACTEDOBJECT_HPP_ #include <com/sun/star/embed/XTransactedObject.hpp> #endif @@ -60,9 +63,10 @@ namespace dbaccess { //........................................................................ -typedef ::cppu::ImplHelper4 < ::com::sun::star::frame::XComponentLoader +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; //========================================================================== @@ -111,6 +115,10 @@ public: 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); diff --git a/dbaccess/source/core/dataaccess/documentdefinition.cxx b/dbaccess/source/core/dataaccess/documentdefinition.cxx index 70c59c0eca98..ffc1ea3db6eb 100644 --- a/dbaccess/source/core/dataaccess/documentdefinition.cxx +++ b/dbaccess/source/core/dataaccess/documentdefinition.cxx @@ -249,6 +249,7 @@ #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; @@ -415,6 +416,40 @@ namespace dbaccess }; //================================================================== + // 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 @@ -531,6 +566,15 @@ namespace dbaccess } } } +#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& ) { @@ -545,14 +589,9 @@ namespace dbaccess DBG_NAME(ODocumentDefinition) //-------------------------------------------------------------------------- -ODocumentDefinition::ODocumentDefinition(const Reference< XInterface >& _rxContainer - , const Reference< XMultiServiceFactory >& _xORB - ,const TContentPtr& _pImpl - , sal_Bool _bForm - , const Sequence< sal_Int8 >& _aClassID - ,const Reference<XConnection>& _xConnection - ) - :OContentHelper(_xORB,_rxContainer,_pImpl) +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) @@ -563,9 +602,19 @@ ODocumentDefinition::ODocumentDefinition(const Reference< XInterface >& _rxConta { DBG_CTOR(ODocumentDefinition, NULL); registerProperties(); - if ( _aClassID.getLength() ) - loadEmbeddedObject( _xConnection, _aClassID, Sequence< PropertyValue >(), false, false ); } + +//-------------------------------------------------------------------------- +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() { @@ -628,15 +677,39 @@ IMPLEMENT_SERVICE_INFO1(ODocumentDefinition,"com.sun.star.comp.dba.ODocumentDefi //-------------------------------------------------------------------------- void ODocumentDefinition::registerProperties() { - registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::BOUND | PropertyAttribute::READONLY | PropertyAttribute::CONSTRAINED, - &m_pImpl->m_aProps.aTitle, ::getCppuType(&m_pImpl->m_aProps.aTitle)); - registerProperty(PROPERTY_AS_TEMPLATE, PROPERTY_ID_AS_TEMPLATE, PropertyAttribute::BOUND | PropertyAttribute::READONLY | PropertyAttribute::CONSTRAINED, - &m_pImpl->m_aProps.bAsTemplate, ::getCppuType(&m_pImpl->m_aProps.bAsTemplate)); - registerProperty(PROPERTY_PERSISTENT_NAME, PROPERTY_ID_PERSISTENT_NAME, PropertyAttribute::BOUND | PropertyAttribute::READONLY | PropertyAttribute::CONSTRAINED, - &m_pImpl->m_aProps.sPersistentName, ::getCppuType(&m_pImpl->m_aProps.sPersistentName)); - registerProperty(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("IsForm")), PROPERTY_ID_IS_FORM, PropertyAttribute::BOUND | PropertyAttribute::READONLY | PropertyAttribute::CONSTRAINED, - &m_bForm, ::getCppuType(&m_bForm)); +#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) { @@ -654,10 +727,21 @@ IPropertyArrayHelper& ODocumentDefinition::getInfoHelper() //-------------------------------------------------------------------------- IPropertyArrayHelper* ODocumentDefinition::createArrayHelper( ) const { + // properties maintained by our base class (see registerProperties) Sequence< Property > aProps; - describeProperties(aProps); - return new OPropertyArrayHelper(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; @@ -665,6 +749,7 @@ public: OExecuteImpl(sal_Bool& _rbSet) : m_rbSet(_rbSet){ m_rbSet=sal_True; } ~OExecuteImpl(){ m_rbSet = sal_False; } }; + // ----------------------------------------------------------------------------- namespace { @@ -694,7 +779,7 @@ void ODocumentDefinition::impl_removeFrameFromDesktop_throw( const ::comphelper: } // ----------------------------------------------------------------------------- -void ODocumentDefinition::impl_onActivateEmbeddedObject_nothrow() +void ODocumentDefinition::impl_onActivateEmbeddedObject_nothrow( const bool i_bReactivated ) { try { @@ -718,10 +803,10 @@ void ODocumentDefinition::impl_onActivateEmbeddedObject_nothrow() // ensure that we ourself are kept alive as long as the embedded object's frame is // opened - LifetimeCoupler::couple( *this, Reference< XComponent >( xFrame, UNO_QUERY_THROW ) ); + LifetimeCoupler::couple( *this, xFrame.get() ); // init the edit view - if ( m_bForm && m_bOpenInDesign ) + if ( m_bForm && m_bOpenInDesign && !i_bReactivated ) impl_initFormEditView( xController ); } catch( const RuntimeException& ) @@ -831,6 +916,9 @@ void ODocumentDefinition::impl_initFormEditView( const Reference< XController >& 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() ); @@ -848,9 +936,6 @@ void ODocumentDefinition::impl_initFormEditView( const Reference< XController >& 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))); - - Reference< XModifiable > xModifiable( _rxController->getModel(), UNO_QUERY_THROW ); - xModifiable->setModified( sal_False ); } catch( const Exception& ) { @@ -859,6 +944,39 @@ void ODocumentDefinition::impl_initFormEditView( const Reference< XController >& } // ----------------------------------------------------------------------------- +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 ) { @@ -871,7 +989,7 @@ Any ODocumentDefinition::onCommandOpenSomething( const Any& _rOpenArgument, cons // for the document, default to the interaction handler as used for loading the DB doc // This might be overwritten below, when examining _rOpenArgument. - ::comphelper::NamedValueCollection aDBDocArgs( m_pImpl->m_pDataSource->getResource() ); + const ::comphelper::NamedValueCollection& aDBDocArgs( m_pImpl->m_pDataSource->getMediaDescriptor() ); Reference< XInteractionHandler > xHandler( aDBDocArgs.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() ) ); if ( xHandler.is() ) aDocumentArgs.put( "InteractionHandler", xHandler ); @@ -963,10 +1081,6 @@ Any ODocumentDefinition::onCommandOpenSomething( const Any& _rOpenArgument, cons } aDocumentArgs.put( "MacroExecutionMode", *aDocumentMacroMode ); - - if ( xConnection.is() ) - m_xLastKnownConnection = xConnection; - if ( ( nOpenMode == OpenMode::ALL ) || ( nOpenMode == OpenMode::FOLDERS ) || ( nOpenMode == OpenMode::DOCUMENTS ) @@ -1030,8 +1144,14 @@ Any ODocumentDefinition::onCommandOpenSomething( const Any& _rOpenArgument, cons if ( _bActivate && !bOpenHidden ) { + LockModifiable aLockModify( impl_getComponent_throw() ); m_xEmbeddedObject->changeState( EmbedStates::ACTIVE ); - ODocumentDefinition::impl_onActivateEmbeddedObject_nothrow(); + 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 ) @@ -1077,14 +1197,17 @@ Any SAL_CALL ODocumentDefinition::execute( const Command& aCommand, sal_Int32 Co sal_Int32 nCurrentState = m_xEmbeddedObject->getCurrentState(); bool bIsActive = ( nCurrentState == EmbedStates::ACTIVE ); - // exception: new-style reports always create a new document when "open" is executed - Reference< report::XReportDefinition > xReportDefinition( getComponent(), UNO_QUERY ); - bool bIsAliveNewStyleReport = ( xReportDefinition.is() && ( bOpen || bOpenForMail ) ); - - if ( bIsActive && !bIsAliveNewStyleReport ) + if ( bIsActive ) { - ODocumentDefinition::impl_onActivateEmbeddedObject_nothrow(); - return makeAny( getComponent() ); + // 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() ); + } } } @@ -1117,16 +1240,6 @@ Any SAL_CALL ODocumentDefinition::execute( const Command& aCommand, sal_Int32 Co Reference< XStorage> xStorage = getContainerStorage(); // ----------------------------------------------------------------------------- xStorage->copyElementTo(m_pImpl->m_aProps.sPersistentName,xDest,sPersistentName); - /*loadEmbeddedObject( true ); - Reference<XEmbedPersist> xPersist(m_xEmbeddedObject,UNO_QUERY); - if ( xPersist.is() ) - { - xPersist->storeToEntry(xStorage,sPersistentName,Sequence<PropertyValue>(),Sequence<PropertyValue>()); - xPersist->storeOwn(); - m_xEmbeddedObject->changeState(EmbedStates::LOADED); - } - else - throw CommandAbortedException();*/ } else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "preview" ) ) ) { @@ -1182,6 +1295,14 @@ Any SAL_CALL ODocumentDefinition::execute( const Command& aCommand, sal_Int32 Co { 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); @@ -1361,7 +1482,7 @@ sal_Bool ODocumentDefinition::save(sal_Bool _bApprove) pRequest->addContinuation(pAbort); // create the handler, let it handle the request - Reference< XInteractionHandler > xHandler( m_aContext.createComponent( (::rtl::OUString)SERVICE_SDB_INTERACTION_HANDLER ), UNO_QUERY ); + Reference< XInteractionHandler > xHandler( m_aContext.createComponent( (::rtl::OUString)SERVICE_TASK_INTERACTION_HANDLER ), UNO_QUERY ); if ( xHandler.is() ) xHandler->handle(xRequest); @@ -1371,16 +1492,16 @@ sal_Bool ODocumentDefinition::save(sal_Bool _bApprove) return sal_True; if ( pDocuSave && pDocuSave->wasSelected() ) { - ::osl::MutexGuard aGuard(m_aMutex); - Reference<XNameContainer> xNC(pDocuSave->getContent(),UNO_QUERY); - if ( xNC.is() ) - { - m_pImpl->m_aProps.aTitle = pDocuSave->getName(); - Reference< XContent> xContent = this; - xNC->insertByName(pDocuSave->getName(),makeAny(xContent)); + Reference<XNameContainer> xNC( pDocuSave->getContent(), UNO_QUERY_THROW ); - updateDocumentTitle(); - } + ::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(); } } @@ -1436,7 +1557,7 @@ sal_Bool ODocumentDefinition::saveAs() pRequest->addContinuation(pAbort); // create the handler, let it handle the request - Reference< XInteractionHandler > xHandler(m_aContext.createComponent(::rtl::OUString(SERVICE_SDB_INTERACTION_HANDLER)), UNO_QUERY); + Reference< XInteractionHandler > xHandler(m_aContext.createComponent(::rtl::OUString(SERVICE_TASK_INTERACTION_HANDLER)), UNO_QUERY); if ( xHandler.is() ) xHandler->handle(xRequest); @@ -1578,8 +1699,30 @@ sal_Bool ODocumentDefinition::objectSupportsEmbeddedScripts() const } // ----------------------------------------------------------------------------- +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 < sizeof( pObjectDescriptorArgs ) / sizeof( pObjectDescriptorArgs[0] ); ++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 >& _rAdditionalArgs, Sequence< PropertyValue >& _out_rEmbeddedObjectDescriptor ) + const Sequence< PropertyValue >& i_rOpenCommandArguments, Sequence< PropertyValue >& _out_rEmbeddedObjectDescriptor ) { // ......................................................................... // (re-)create interceptor, and put it into the descriptor of the embedded object @@ -1598,6 +1741,10 @@ Sequence< PropertyValue > ODocumentDefinition::fillLoadArgs( const Reference< XC 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 ); @@ -1630,11 +1777,12 @@ Sequence< PropertyValue > ODocumentDefinition::fillLoadArgs( const Reference< XC aEmbeddedDescriptor.put( "EmbeddedScriptSupport", (sal_Bool)objectSupportsEmbeddedScripts() ); // ......................................................................... - // pass the descriptor of the embedded object to the caller - aEmbeddedDescriptor >>= _out_rEmbeddedObjectDescriptor; + // 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 ); // ......................................................................... - ::comphelper::NamedValueCollection aMediaDesc( _rAdditionalArgs ); + // 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 @@ -1657,8 +1805,8 @@ Sequence< PropertyValue > ODocumentDefinition::fillLoadArgs( const Reference< XC return aMediaDesc.getPropertyValues(); } // ----------------------------------------------------------------------------- -void ODocumentDefinition::loadEmbeddedObject( const Reference< XConnection >& _xConnection, const Sequence< sal_Int8 >& _aClassID, - const Sequence< PropertyValue >& _rAdditionalArgs, const bool _bSuppressMacros, const bool _bReadOnly ) +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() ) { @@ -1684,7 +1832,7 @@ void ODocumentDefinition::loadEmbeddedObject( const Reference< XConnection >& _x // the com.sun.star.report.pentaho.SOReportJobFactory is not present. if ( !m_bForm && !sDocumentService.equalsAscii("com.sun.star.text.TextDocument")) { - // we seems to be a new report, check if report extension is present. + // 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); @@ -1710,7 +1858,7 @@ void ODocumentDefinition::loadEmbeddedObject( const Reference< XConnection >& _x Sequence< PropertyValue > aEmbeddedObjectDescriptor; Sequence< PropertyValue > aLoadArgs( fillLoadArgs( - _xConnection, _bSuppressMacros, _bReadOnly, _rAdditionalArgs, aEmbeddedObjectDescriptor ) ); + i_rConnection, _bSuppressMacros, _bReadOnly, i_rOpenCommandArguments, aEmbeddedObjectDescriptor ) ); m_xEmbeddedObject.set(xEmbedFactory->createInstanceUserInit(aClassID ,sDocumentService @@ -1732,8 +1880,9 @@ void ODocumentDefinition::loadEmbeddedObject( const Reference< XConnection >& _x m_xEmbeddedObject->changeState(EmbedStates::RUNNING); if ( bSetSize ) { - awt::Size aSize( DEFAULT_WIDTH, DEFAULT_HEIGHT ); + LockModifiable aLockModify( impl_getComponent_throw( false ) ); + awt::Size aSize( DEFAULT_WIDTH, DEFAULT_HEIGHT ); m_xEmbeddedObject->setVisualAreaSize(Aspects::MSOLE_CONTENT,aSize); } } @@ -1755,7 +1904,7 @@ void ODocumentDefinition::loadEmbeddedObject( const Reference< XConnection >& _x Sequence< PropertyValue > aEmbeddedObjectDescriptor; Sequence< PropertyValue > aLoadArgs( fillLoadArgs( - _xConnection, _bSuppressMacros, _bReadOnly, _rAdditionalArgs, aEmbeddedObjectDescriptor ) ); + i_rConnection, _bSuppressMacros, _bReadOnly, i_rOpenCommandArguments, aEmbeddedObjectDescriptor ) ); Reference<XCommonEmbedPersist> xCommon(m_xEmbeddedObject,UNO_QUERY); OSL_ENSURE(xCommon.is(),"unsupported interface!"); @@ -1772,21 +1921,25 @@ void ODocumentDefinition::loadEmbeddedObject( const Reference< XConnection >& _x // then just re-set some model parameters try { - Reference< XModel > xModel( getComponent(), UNO_QUERY_THROW ); - Sequence< PropertyValue > aArgs = xModel->getArgs(); - - ::comphelper::NamedValueCollection aMediaDesc( aArgs ); - ::comphelper::NamedValueCollection aArguments( _rAdditionalArgs ); - aMediaDesc.merge( aArguments, sal_False ); - - lcl_putLoadArgs( aMediaDesc, optional_bool(), optional_bool() ); + // 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 - aMediaDesc >>= aArgs; - xModel->attachResource( xModel->getURL(), aArgs ); + xModel->attachResource( xModel->getURL(), aExistentMediaDesc.getPropertyValues() ); } catch( const Exception& ) { @@ -1812,6 +1965,9 @@ void ODocumentDefinition::loadEmbeddedObject( const Reference< XConnection >& _x DBG_UNHANDLED_EXCEPTION(); } } + + if ( i_rConnection.is() ) + m_xLastKnownConnection = i_rConnection; } // ----------------------------------------------------------------------------- @@ -1863,18 +2019,18 @@ void ODocumentDefinition::onCommandGetDocumentProperties( Any& _rProps ) } } // ----------------------------------------------------------------------------- -Reference< util::XCloseable> ODocumentDefinition::getComponent() throw (RuntimeException) +Reference< util::XCloseable > ODocumentDefinition::impl_getComponent_throw( const bool i_ForceCreate ) { OSL_ENSURE(m_xEmbeddedObject.is(),"Illegal call for embeddedObject"); - Reference< util::XCloseable> xComp; + Reference< util::XCloseable > xComp; if ( m_xEmbeddedObject.is() ) { - int nOldState = m_xEmbeddedObject->getCurrentState(); - int nState = nOldState; - if ( nOldState == EmbedStates::LOADED ) + int nState = m_xEmbeddedObject->getCurrentState(); + if ( ( nState == EmbedStates::LOADED ) && i_ForceCreate ) { m_xEmbeddedObject->changeState( EmbedStates::RUNNING ); - nState = 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 ) @@ -1891,6 +2047,13 @@ Reference< util::XCloseable> ODocumentDefinition::getComponent() throw (RuntimeE } // ----------------------------------------------------------------------------- +Reference< util::XCloseable > ODocumentDefinition::getComponent() throw (RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + return impl_getComponent_throw( true ); +} + +// ----------------------------------------------------------------------------- namespace { Reference< XDatabaseDocumentUI > lcl_getDatabaseDocumentUI( ODatabaseModelImpl& _rModelImpl ) @@ -2011,13 +2174,29 @@ void SAL_CALL ODocumentDefinition::store( ) throw (WrappedTargetException, Runt 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::ClearableGuard< osl::Mutex > aGuard(m_aMutex); + ::osl::ResettableMutexGuard aGuard(m_aMutex); if ( _rNewName.equals( m_pImpl->m_aProps.aTitle ) ) return; @@ -2026,16 +2205,9 @@ void SAL_CALL ODocumentDefinition::rename( const ::rtl::OUString& _rNewName ) th if ( _rNewName.indexOf( '/' ) != -1 ) m_aErrorHelper.raiseException( ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES, *this ); - sal_Int32 nHandle = PROPERTY_ID_NAME; - Any aOld = makeAny( m_pImpl->m_aProps.aTitle ); - Any aNew = makeAny( _rNewName ); - - aGuard.clear(); - fire(&nHandle, &aNew, &aOld, 1, sal_True ); + NameChangeNotifier aNameChangeAndNotify( *this, _rNewName, aGuard ); m_pImpl->m_aProps.aTitle = _rNewName; - fire(&nHandle, &aNew, &aOld, 1, sal_False ); - ::osl::ClearableGuard< ::osl::Mutex > aGuard2( m_aMutex ); if ( m_xEmbeddedObject.is() && m_xEmbeddedObject->getCurrentState() == EmbedStates::ACTIVE ) updateDocumentTitle(); } @@ -2076,7 +2248,11 @@ bool ODocumentDefinition::prepareClose() // by the embedding component. Thus, we do the suspend call here. // #i49370# / 2005-06-09 / frank.schoenheit@sun.com - Reference< XModel > xModel( getComponent(), UNO_QUERY ); + 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(); @@ -2190,6 +2366,43 @@ void SAL_CALL ODocumentDefinition::notifyClosing( const lang::EventObject& /*Sou 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 //........................................................................ diff --git a/dbaccess/source/core/dataaccess/documentdefinition.hxx b/dbaccess/source/core/dataaccess/documentdefinition.hxx index b2ca8f49f7bb..76427ea78baf 100644 --- a/dbaccess/source/core/dataaccess/documentdefinition.hxx +++ b/dbaccess/source/core/dataaccess/documentdefinition.hxx @@ -31,8 +31,8 @@ #ifndef _CPPUHELPER_PROPSHLP_HXX #include <cppuhelper/propshlp.hxx> #endif -#ifndef _CPPUHELPER_IMPLBASE3_HXX_ -#include <cppuhelper/implbase3.hxx> +#ifndef _CPPUHELPER_IMPLBASE4_HXX_ +#include <cppuhelper/implbase4.hxx> #endif #ifndef DBA_CONTENTHELPER_HXX #include "ContentHelper.hxx" @@ -63,6 +63,12 @@ #endif #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 @@ -76,9 +82,10 @@ namespace dbaccess //= document //========================================================================== -typedef ::cppu::ImplHelper3 < ::com::sun::star::embed::XComponentSupplier +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 @@ -104,14 +111,18 @@ protected: 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 - ,const ::com::sun::star::uno::Sequence< sal_Int8 >& _aClassID = ::com::sun::star::uno::Sequence< sal_Int8 >() - ,const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection>& _xConnection = ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection>() + 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( ); @@ -124,6 +135,12 @@ public: // ::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); @@ -133,6 +150,10 @@ public: 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(); @@ -194,10 +215,20 @@ public: ::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(); + void impl_onActivateEmbeddedObject_nothrow( const bool i_bReactivated ); /** initializes a newly created view/controller of a form which is displaying our embedded object @@ -220,19 +251,27 @@ private: /** opens the UI for this sub document */ ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > - impl_openUI_nolck_throw( bool _bForEditing ); + impl_openUI_nolck_throw( bool _bForEditing ); /** stores our document, if it's already loaded */ - void - impl_store_throw(); + void impl_store_throw(); /** closes our document, if it's open */ - bool - impl_close_throw(); + 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 ); -private: // OPropertyArrayUsageHelper virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const; @@ -244,7 +283,6 @@ private: // OContentHelper overridables virtual ::rtl::OUString determineContentType() const; -private: /** fills the load arguments */ ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > @@ -252,10 +290,30 @@ private: 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 >& _rAdditionalArgs, + 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. @@ -321,6 +379,27 @@ private: 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 ); }; //........................................................................ diff --git a/dbaccess/source/core/dataaccess/makefile.mk b/dbaccess/source/core/dataaccess/makefile.mk index 5d804e911ae7..831eae349858 100644 --- a/dbaccess/source/core/dataaccess/makefile.mk +++ b/dbaccess/source/core/dataaccess/makefile.mk @@ -61,7 +61,7 @@ SLOFILES= \ $(SLO)$/ModelImpl.obj \ $(SLO)$/documentevents.obj \ $(SLO)$/documenteventexecutor.obj \ - $(SLO)$/documenteventnotifier.obj + $(SLO)$/documenteventnotifier.obj \ # --- Targets ---------------------------------- |