Tag: cws_dev300_odbmacros3 User: fs Date: 2008-04-21 10:29:09+0000 Modified: dba/dbaccess/source/ext/macromigration/migrationengine.cxx
Log: #i49133# support for migrating the script (not Macro/Dialog) libraries, by simply moving the respective storages File Changes: Directory: /dba/dbaccess/source/ext/macromigration/ =================================================== File [changed]: migrationengine.cxx Url: http://dba.openoffice.org/source/browse/dba/dbaccess/source/ext/macromigration/migrationengine.cxx?r1=1.4&r2=1.4.2.1 Delta lines: +607 -85 ---------------------- --- migrationengine.cxx 2008-04-10 13:15:44+0000 1.4 +++ migrationengine.cxx 2008-04-21 10:29:06+0000 1.4.2.1 @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: migrationengine.cxx,v $ - * $Revision: 1.4 $ + * $Revision: 1.4.2.1 $ * * This file is part of OpenOffice.org. * @@ -39,6 +39,7 @@ #include "migrationprogress.hxx" #include "migrationlog.hxx" #include "progresscapture.hxx" +#include "progressmixer.hxx" /** === begin UNO includes === **/ #include <com/sun/star/sdb/XFormDocumentsSupplier.hpp> @@ -48,6 +49,11 @@ #include <com/sun/star/frame/XComponentLoader.hpp> #include <com/sun/star/ucb/XCommandProcessor.hpp> #include <com/sun/star/embed/XComponentSupplier.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/document/XStorageBasedDocument.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/embed/XEmbedPersist.hpp> /** === end UNO includes === **/ #include <comphelper/string.hxx> @@ -56,8 +62,10 @@ #include <tools/diagnose_ex.h> #include <rtl/ustrbuf.hxx> #include <rtl/ref.hxx> +#include <unotools/sharedunocomponent.hxx> #include <vector> +#include <set> #define DEFAULT_DOC_PROGRESS_RANGE 100000 @@ -90,7 +98,19 @@ using ::com::sun::star::ucb::Command; using ::com::sun::star::embed::XComponentSupplier; using ::com::sun::star::task::XStatusIndicator; + using ::com::sun::star::embed::XStorage; + using ::com::sun::star::document::XStorageBasedDocument; + using ::com::sun::star::embed::XTransactedObject; + using ::com::sun::star::frame::XStorable; + using ::com::sun::star::embed::XEmbedPersist; /** === end UNO using === **/ + namespace ElementModes = ::com::sun::star::embed::ElementModes; + +// migration phases whose progresses are to be mixed into one progress +#define PHASE_JAVASCRIPT 1 +#define PHASE_BEANSHELL 2 +#define PHASE_PYTHON 3 +#define PHASE_JAVA 4 //==================================================================== //= SubDocument @@ -112,6 +132,393 @@ typedef ::std::vector< SubDocument > SubDocuments; //==================================================================== + //= helper + //==================================================================== + //-------------------------------------------------------------------- + typedef ::utl::SharedUNOComponent< XStorage > SharedStorage; + + namespace + { + //---------------------------------------------------------------- + static const ::rtl::OUString& lcl_getScriptsStorageName() + { + static const ::rtl::OUString s_sScriptsStorageName( RTL_CONSTASCII_USTRINGPARAM( "Scripts" ) ); + return s_sScriptsStorageName; + } + + //---------------------------------------------------------------- + static const ::rtl::OUString& lcl_getScriptsSubStorageName( const ScriptType _eType ) + { + static const ::rtl::OUString s_sBeanShell ( RTL_CONSTASCII_USTRINGPARAM( "beanshell" ) ); // TODO: is this correct? + static const ::rtl::OUString s_sJavaScript( RTL_CONSTASCII_USTRINGPARAM( "javascript" ) ); + static const ::rtl::OUString s_sPython ( RTL_CONSTASCII_USTRINGPARAM( "python" ) ); // TODO: is this correct? + static const ::rtl::OUString s_sJava ( RTL_CONSTASCII_USTRINGPARAM( "java" ) ); // TODO: is this correct? + + switch ( _eType ) + { + case eBeanShell: return s_sBeanShell; + case eJavaScript: return s_sJavaScript; + case ePython: return s_sPython; + case eJava: return s_sJava; + default: + break; + } + + OSL_ENSURE( false, "lcl_getScriptsSubStorageName: illegal type!" ); + static ::rtl::OUString s_sEmpty; + return s_sEmpty; + } + + //---------------------------------------------------------------- + static Any lcl_executeCommand_throw( const Reference< XCommandProcessor >& _rxCommandProc, + const sal_Char* _pAsciiCommand ) + { + OSL_PRECOND( _rxCommandProc.is(), "lcl_executeCommand_throw: illegal object!" ); + if ( !_rxCommandProc.is() ) + return Any(); + + Command aCommand; + aCommand.Name = ::rtl::OUString::createFromAscii( _pAsciiCommand ); + return _rxCommandProc->execute( + aCommand, _rxCommandProc->createCommandIdentifier(), NULL ); + } + + //---------------------------------------------------------------- + static void lcl_disposeComponent_nothrow( const Reference< XCommandProcessor >& _rxCommandProc ) + { + bool bCouldClose = false; + try + { + OSL_VERIFY( lcl_executeCommand_throw( _rxCommandProc, "shutdown" ) >>= bCouldClose ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + if ( !bCouldClose ) + { + ; + // TODO: can we handle this somehow? + } + } + + //---------------------------------------------------------------- + static Reference< XModel > lcl_loadSubDocument_nothrow( const SubDocument& _rDocument, + const Reference< XStatusIndicator >& _rxProgress ) + { + Reference< XModel > xDocument; + + try + { + ::comphelper::NamedValueCollection aLoadArgs; + aLoadArgs.put( "Hidden", (sal_Bool)sal_True ); + aLoadArgs.put( "StatusIndicator", _rxProgress ); + + Reference< XCommandProcessor > xCommandProcessor( _rDocument.xCommandProcessor, UNO_SET_THROW ); + Command aCommand; + aCommand.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "openDesign" ) ); + aCommand.Argument <<= aLoadArgs.getPropertyValues(); + Reference< XComponent > xDocComponent( + xCommandProcessor->execute( + aCommand, xCommandProcessor->createCommandIdentifier(), NULL + ), + UNO_QUERY + ); + OSL_ENSURE( xDocComponent.is(), "lcl_loadSubDocument_nothrow: no component loaded!" ); + + xDocument.set( xDocComponent, UNO_QUERY_THROW ); + } + catch( const Exception& ) + { + // TODO: how to proceed? + DBG_UNHANDLED_EXCEPTION(); + } + + return xDocument; + } + + //---------------------------------------------------------------- + bool lcl_commitStorage_nothrow( const Reference< XStorage >& _rxStorage ) + { + try + { + Reference< XTransactedObject > xTrans( _rxStorage, UNO_QUERY_THROW ); + xTrans->commit(); + } + catch( const Exception& ) + { + return false; + } + return true; + } + + //---------------------------------------------------------------- + bool lcl_commitDocumentStorage_nothrow( const Reference< XModel >& _rxDocument ) + { + bool bSuccess = false; + try + { + Reference< XStorageBasedDocument > xStorageDoc( _rxDocument, UNO_QUERY_THROW ); + Reference< XStorage > xDocStorage( xStorageDoc->getDocumentStorage(), UNO_QUERY_THROW ); + bSuccess = lcl_commitStorage_nothrow( xDocStorage ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return bSuccess; + } + + //---------------------------------------------------------------- + bool lcl_storeDocument_nothrow( const Reference< XModel >& _rxDocument ) + { + try + { + Reference< XStorable > xStorable( _rxDocument, UNO_QUERY_THROW ); + xStorable->store(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + return false; + } + return true; + } + + //---------------------------------------------------------------- + bool lcl_storeEmbeddedDocument_nothrow( const SubDocument& _rDocument ) + { + try + { + lcl_executeCommand_throw( _rDocument.xCommandProcessor, "store" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + return false; + } + return true; + } + } + + //==================================================================== + //= ScriptsStorage - declaration + //==================================================================== + /** a helper class which encapsulates access to the storages for Java/Script, BeanShell, and Python scripts, + i.e. all script types which can be manipulated on storage level. + */ + class ScriptsStorage + { + public: + enum AccessMode + { + READ, + WRITE + }; + + public: + ScriptsStorage(); + ScriptsStorage( const Reference< XModel >& _rxDocument, const AccessMode _eMode ); + ~ScriptsStorage(); + + /** determines whether the instance is valid, i.e. refers to a valid root storage + for reading/storing scripts + */ + inline bool isValid() const { return m_xScriptsStorage.is(); } + + /** determines whether the storage is writeable + */ + inline bool isWriteable() const { return isValid() && ( m_nStorageOpenMode != ElementModes::READ ); } + + /** binds the instance to a new document. Only to be called when the instance is not yet + bound (i.e. isValid returns <FALSE/>). + */ + void bind( const Reference< XModel >& _rxDocument, const AccessMode _eMode ); + + /// determines whether scripts of the given type are present + bool hasScripts( const ScriptType _eType ) const; + + /// returns the root storage for the scripts of the given type + SharedStorage + getScriptsRoot( const ScriptType _eType ) const; + + /** removes the sub storage for a given script type + @precond + the respective storage is empty + @precond + the ScriptsStorage instance was opened for writing + */ + void removeScriptTypeStorage( const ScriptType _eType ) const; + + /** removes the "Scripts" sub storage from the given document's root storage + @precond + the "Scripts" storage is empty + */ + static bool + removeFromDocument( const Reference< XModel >& _rxDocument ); + + private: + SharedStorage m_xScriptsStorage; + sal_Int32 m_nStorageOpenMode; + }; + + //==================================================================== + //= ScriptsStorage - implementation + //==================================================================== + //-------------------------------------------------------------------- + ScriptsStorage::ScriptsStorage() + :m_xScriptsStorage() + ,m_nStorageOpenMode( ElementModes::READ ) + { + } + + //-------------------------------------------------------------------- + ScriptsStorage::ScriptsStorage( const Reference< XModel >& _rxDocument, const AccessMode _eMode ) + :m_xScriptsStorage() + ,m_nStorageOpenMode( ElementModes::READ ) + { + bind( _rxDocument, _eMode ); + } + + //-------------------------------------------------------------------- + ScriptsStorage::~ScriptsStorage() + { + if ( isWriteable() ) + { + OSL_VERIFY( lcl_commitStorage_nothrow( m_xScriptsStorage ) ); + } + } + + //-------------------------------------------------------------------- + void ScriptsStorage::bind( const Reference< XModel >& _rxDocument, const AccessMode _eMode ) + { + OSL_PRECOND( !isValid(), "ScriptsStorage:bind: did not bother, yet, to check whether this is allowed!" ); + try + { + Reference< XStorageBasedDocument > xStorageDoc( _rxDocument, UNO_QUERY_THROW ); + Reference< XStorage > xDocStorage( xStorageDoc->getDocumentStorage(), UNO_QUERY_THROW ); + + const bool bForWrite = ( _eMode == WRITE ); + m_nStorageOpenMode = bForWrite ? ElementModes::READWRITE : ElementModes::READ; + + // the the "Scripts" storage exist, or if it does not (yet) exist and we are in write mode + // => open the storage + if ( ( xDocStorage->hasByName( lcl_getScriptsStorageName() ) + && xDocStorage->isStorageElement( lcl_getScriptsStorageName() ) + ) + || ( !xDocStorage->hasByName( lcl_getScriptsStorageName() ) + && bForWrite + ) + ) + { + m_xScriptsStorage.set( + xDocStorage->openStorageElement( + lcl_getScriptsStorageName(), m_nStorageOpenMode + ), + UNO_QUERY_THROW + ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + //-------------------------------------------------------------------- + bool ScriptsStorage::hasScripts( const ScriptType _eType ) const + { + OSL_PRECOND( isValid(), "ScriptsStorage::hasScripts: illegal call!" ); + if ( !isValid() ) + return false; + + const ::rtl::OUString& rSubStorageName( lcl_getScriptsSubStorageName( _eType ) ); + return m_xScriptsStorage->hasByName( rSubStorageName ) + && m_xScriptsStorage->isStorageElement( rSubStorageName ); + } + + //-------------------------------------------------------------------- + SharedStorage ScriptsStorage::getScriptsRoot( const ScriptType _eType ) const + { + SharedStorage xStorage; + if ( isValid() ) + { + xStorage.reset( m_xScriptsStorage->openStorageElement( + lcl_getScriptsSubStorageName( _eType ), m_nStorageOpenMode + ) ); + } + return xStorage; + } + + //-------------------------------------------------------------------- + void ScriptsStorage::removeScriptTypeStorage( const ScriptType _eType ) const + { + OSL_PRECOND( isWriteable(), "ScriptsStorage::removeScriptTypeStorage: not writeable!" ); + if ( isWriteable() ) + { + ::rtl::OUString sSubStorageName( lcl_getScriptsSubStorageName( _eType ) ); + if ( m_xScriptsStorage->hasByName( sSubStorageName ) ) + m_xScriptsStorage->removeElement( sSubStorageName ); + } + } + + //-------------------------------------------------------------------- + bool ScriptsStorage::removeFromDocument( const Reference< XModel >& _rxDocument ) + { + try + { + Reference< XStorageBasedDocument > xStorageDoc( _rxDocument, UNO_QUERY_THROW ); + Reference< XStorage > xDocStorage( xStorageDoc->getDocumentStorage(), UNO_QUERY_THROW ); + xDocStorage->removeElement( lcl_getScriptsStorageName() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + return false; + } + return true; + } + + //==================================================================== + //= ProgressDelegator + //==================================================================== + class ProgressDelegator : public IProgressConsumer + { + public: + ProgressDelegator( IMigrationProgress& _rDelegator, + const ::rtl::OUString& _rObjectName, + const ::rtl::OUString& _rAction + ) + :m_rDelegator( _rDelegator ) + ,m_sObjectName( _rObjectName ) + ,m_sAction( _rAction ) + { + } + virtual ~ProgressDelegator() + { + } + + // IProgressConsumer + virtual void start( sal_uInt32 _nRange ) + { + m_rDelegator.startObject( m_sObjectName, m_sAction, _nRange ); + } + virtual void advance( sal_uInt32 _nValue ) + { + m_rDelegator.setObjectProgressValue( _nValue ); + } + virtual void end() + { + m_rDelegator.endObject(); + } + + private: + IMigrationProgress& m_rDelegator; + ::rtl::OUString m_sObjectName; + ::rtl::OUString m_sAction; + }; + + //==================================================================== //= MigrationEngine_Impl - declaration //==================================================================== class MigrationEngine_Impl @@ -132,6 +539,7 @@ private: ::comphelper::ComponentContext m_aContext; const Reference< XOfficeDatabaseDocument > m_xDocument; + const Reference< XModel > m_xDocumentModel; IMigrationProgress& m_rProgress; MigrationLog& m_rLogger; SubDocuments m_aSubDocs; @@ -154,6 +562,17 @@ /** migrates the macros/scripts of the given sub document */ bool impl_handleDocument_nothrow( const SubDocument& _rDocument ) const; + + /** migrates the storage-based + */ + bool impl_migrateScriptStorage_nothrow( + const SubDocument& _rDocument, + const Reference< XModel >& _rxDocument, + const DocumentID _nDocID, + const ScriptType _eType, + ProgressMixer& _rProgress, + const PhaseID _nPhaseID + ) const; }; //==================================================================== @@ -164,6 +583,7 @@ const Reference< XOfficeDatabaseDocument >& _rxDocument, IMigrationProgress& _rProgress, MigrationLog& _rLogger ) :m_aContext( _rContext ) ,m_xDocument( _rxDocument ) + ,m_xDocumentModel( _rxDocument, UNO_QUERY_THROW ) ,m_rProgress( _rProgress ) ,m_rLogger( _rLogger ) ,m_aSubDocs() @@ -215,6 +635,16 @@ m_rProgress.setOverallProgressValue( nOverallProgressValue ); } + // commit the root storage of the database document, for all changes made so far to take effect + if ( !lcl_commitDocumentStorage_nothrow( m_xDocumentModel ) ) + // TODO: can we propagate the error? + return false; + + // save the document + if ( !lcl_storeDocument_nothrow( m_xDocumentModel ) ) + // TODO: is this a critical error? Do we need to report it? + return false; + return true; } @@ -263,16 +693,18 @@ //-------------------------------------------------------------------- bool MigrationEngine_Impl::impl_collectSubDocuments_nothrow() { + OSL_PRECOND( m_xDocument.is(), "MigrationEngine_Impl::impl_collectSubDocuments_nothrow: invalid document!" ); + if ( !m_xDocument.is() ) + return false; + try { ::rtl::OUString sRootLocation; - Reference< XFormDocumentsSupplier > xSuppForms( m_xDocument, UNO_QUERY_THROW ); - Reference< XNameAccess > xDocContainer( xSuppForms->getFormDocuments(), UNO_SET_THROW ); + Reference< XNameAccess > xDocContainer( m_xDocument->getFormDocuments(), UNO_SET_THROW ); m_nFormCount = lcl_collectHierarchicalElementNames_throw( xDocContainer, sRootLocation, m_aSubDocs, eForm ); - Reference< XReportDocumentsSupplier > xSuppReports( m_xDocument, UNO_QUERY_THROW ); - xDocContainer.set( xSuppReports->getReportDocuments(), UNO_SET_THROW ); + xDocContainer.set( m_xDocument->getReportDocuments(), UNO_SET_THROW ); m_nReportCount = lcl_collectHierarchicalElementNames_throw( xDocContainer, sRootLocation, m_aSubDocs, eReport ); } catch( const Exception& ) @@ -286,103 +718,192 @@ } //-------------------------------------------------------------------- - namespace - { - //................................................................ - static void lcl_disposeComponent_nothrow( const Reference< XCommandProcessor >& _rxCommandProc ) + bool MigrationEngine_Impl::impl_handleDocument_nothrow( const SubDocument& _rDocument ) const { - OSL_PRECOND( _rxCommandProc.is(), "lcl_disposeComponent_nothrow: illegal object!" ); - if ( !_rxCommandProc.is() ) - return; + DocumentID nDocID = m_rLogger.startedDocument( _rDocument.eType, _rDocument.sHierarchicalName ); - bool bCouldClose = false; - try - { - Command aCommand; - aCommand.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "shutdown" ) ); - OSL_VERIFY( _rxCommandProc->execute( - aCommand, _rxCommandProc->createCommandIdentifier(), NULL ) >>= bCouldClose ); - } - catch( const Exception& ) - { - DBG_UNHANDLED_EXCEPTION(); - } - if ( !bCouldClose ) + // start the progress + ::rtl::OUString sObjectName; + sObjectName = String( MacroMigrationResId( _rDocument.eType == eForm ? STR_FORM : STR_REPORT ) ); + ::comphelper::string::searchAndReplaceAsciiI( sObjectName, "$name$", _rDocument.sHierarchicalName ); + m_rProgress.startObject( sObjectName, ::rtl::OUString(), DEFAULT_DOC_PROGRESS_RANGE ); + + // ----------------- + // load the document + ::rtl::Reference< ProgressCapture > pStatusIndicator( new ProgressCapture( sObjectName, m_rProgress ) ); + Reference< XModel > xSubDocument( lcl_loadSubDocument_nothrow( _rDocument, pStatusIndicator.get() ) ); + if ( !xSubDocument.is() ) { - ; - // TODO: can we handle this somehow? - } + pStatusIndicator->dispose(); + m_rProgress.endObject(); + m_rLogger.finishedDocument( nDocID, false ); + // TODO: log the *reason* for the failure + return false; } - //................................................................ - static Reference< XModel > lcl_loadSubDocument_nothrow( const SubDocument& _rDocument, - const Reference< XStatusIndicator >& _rxProgress ) - { - Reference< XModel > xDocument; + // ----------------- + // migrate the libraries + ProgressDelegator aDelegator( m_rProgress, sObjectName, String( MacroMigrationResId( STR_MIGRATING_LIBS ) ) ); + ProgressMixer aProgressMixer( aDelegator ); + aProgressMixer.registerPhase( PHASE_JAVASCRIPT, 1 ); + aProgressMixer.registerPhase( PHASE_BEANSHELL, 1 ); + aProgressMixer.registerPhase( PHASE_PYTHON, 1 ); + aProgressMixer.registerPhase( PHASE_JAVA, 1 ); + + // migrate storage-based script libraries (which can be handled by mere storage operations) + bool bSuccess = + impl_migrateScriptStorage_nothrow( _rDocument, xSubDocument, nDocID, eJavaScript, aProgressMixer, PHASE_JAVASCRIPT ) + && impl_migrateScriptStorage_nothrow( _rDocument, xSubDocument, nDocID, eBeanShell, aProgressMixer, PHASE_BEANSHELL ) + && impl_migrateScriptStorage_nothrow( _rDocument, xSubDocument, nDocID, ePython, aProgressMixer, PHASE_PYTHON ) + && impl_migrateScriptStorage_nothrow( _rDocument, xSubDocument, nDocID, eJava, aProgressMixer, PHASE_JAVA ); - try - { - ::comphelper::NamedValueCollection aLoadArgs; - aLoadArgs.put( "Hidden", (sal_Bool)sal_True ); - aLoadArgs.put( "StatusIndicator", _rxProgress ); + // TODO: more to come - Reference< XCommandProcessor > xCommandProcessor( _rDocument.xCommandProcessor, UNO_SET_THROW ); - Command aCommand; - aCommand.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "openDesign" ) ); - aCommand.Argument <<= aLoadArgs.getPropertyValues(); - Reference< XComponent > xDocComponent( - xCommandProcessor->execute( - aCommand, xCommandProcessor->createCommandIdentifier(), NULL - ), - UNO_QUERY - ); - OSL_ENSURE( xDocComponent.is(), "lcl_loadSubDocument_nothrow: no component loaded!" ); + // ----------------- + // clean up + if ( bSuccess ) + bSuccess = /*lcl_commitDocumentStorage_nothrow( xSubDocument ) + && */lcl_storeEmbeddedDocument_nothrow( _rDocument ) + && ScriptsStorage::removeFromDocument( xSubDocument ) + && lcl_commitDocumentStorage_nothrow( xSubDocument ); + lcl_disposeComponent_nothrow( _rDocument.xCommandProcessor ); + pStatusIndicator->dispose(); - xDocument.set( xDocComponent, UNO_QUERY_THROW ); + // end the progress, just in case the ProgressCapture didn't receive the XStatusIndicator::end event + m_rProgress.endObject(); + + m_rLogger.finishedDocument( nDocID, bSuccess ); + return bSuccess; } - catch( const Exception& ) + + //-------------------------------------------------------------------- + namespace { - // TODO: how to proceed? - DBG_UNHANDLED_EXCEPTION(); - } + static ::rtl::OUString lcl_createTargetLibName( const SubDocument& _rDocument, + const ::rtl::OUString& _rSourceLibName, const Reference< XStorage >& _rxTargetStorage ) + { + // a prefix denoting the type + const ::rtl::OUString sPrefix( ::rtl::OUString::createFromAscii( _rDocument.eType == eForm ? "Form_" : "Report_" ) ); + + ::rtl::OUStringBuffer aBuffer; + aBuffer.append( sPrefix ); + + // first try with the base name of the sub document + aBuffer.append( _rDocument.sHierarchicalName.copy( + _rDocument.sHierarchicalName.lastIndexOf( '/' ) + 1 ) ); + ::rtl::OUString sTargetName( aBuffer.makeStringAndClear() ); + if ( !_rxTargetStorage->hasByName( sTargetName ) ) + return sTargetName; + + // if this name is already used (which is valid, since documents with the same base + // name can exist in different logical folders), then use the complete name + aBuffer.append( sPrefix ); + aBuffer.append( ::comphelper::string::searchAndReplaceAllAsciiWithAscii( + _rDocument.sHierarchicalName, "/", "_" ) ); + aBuffer.appendAscii( "_" ); + aBuffer.append( _rSourceLibName ); + return aBuffer.makeStringAndClear(); - return xDocument; } } //-------------------------------------------------------------------- - bool MigrationEngine_Impl::impl_handleDocument_nothrow( const SubDocument& _rDocument ) const + bool MigrationEngine_Impl::impl_migrateScriptStorage_nothrow( const SubDocument& _rDocument, const Reference< XModel >& _rxDocument, + const DocumentID _nDocID, const ScriptType _eScriptType, ProgressMixer& _rProgress, const PhaseID _nPhaseID ) const { - DocumentID nDocID = m_rLogger.startedDocument( _rDocument.eType, _rDocument.sHierarchicalName ); + OSL_PRECOND( _rxDocument.is(), "MigrationEngine_Impl::impl_migrateScriptStorage_nothrow: invalid document!" ); + if ( !_rxDocument.is() ) + return false; - // start the progress - ::rtl::OUString aProgress; - aProgress = String( MacroMigrationResId( _rDocument.eType == eForm ? STR_FORM : STR_REPORT ) ); - ::comphelper::string::searchAndReplaceAsciiI( aProgress, "$name$", _rDocument.sHierarchicalName ); - m_rProgress.startObject( aProgress, ::rtl::OUString(), DEFAULT_DOC_PROGRESS_RANGE ); + ScriptsStorage aDatabaseScripts; + // the scripts of our complete database document - created on demand only + SharedStorage xTargetStorage; + // the target for moving the scripts storages - created on demand only - // load the document - ::rtl::Reference< ProgressCapture > pStatusIndicator( new ProgressCapture( aProgress, m_rProgress ) ); - Reference< XModel > xDocument( lcl_loadSubDocument_nothrow( _rDocument, pStatusIndicator.get() ) ); - if ( !xDocument.is() ) + try { - pStatusIndicator->dispose(); - m_rProgress.endObject(); - m_rLogger.finishedDocument( nDocID, false ); - // TODO: log the *reason* for the failure + // the root storage of the document whose scripts are to be migrated + ScriptsStorage aDocStorage( _rxDocument, ScriptsStorage::WRITE ); + if ( !aDocStorage.isValid() + || !aDocStorage.hasScripts( _eScriptType ) + ) + { + // no scripts at all, or no scripts of the given type + _rProgress.startPhase( _nPhaseID, 1 ); + _rProgress.endPhase(); + return true; + } + + SharedStorage xScriptsRoot( aDocStorage.getScriptsRoot( _eScriptType ) ); + if ( !xScriptsRoot.is() ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "internal error" ) ), NULL ); + + // loop through the script libraries + Sequence< ::rtl::OUString > aStorageElements( xScriptsRoot->getElementNames() ); + _rProgress.startPhase( _nPhaseID, aStorageElements.getLength() ); + + for ( const ::rtl::OUString* element = aStorageElements.getConstArray(); + element != aStorageElements.getConstArray() + aStorageElements.getLength(); + ++element + ) + { + bool bIsScriptLibrary = xScriptsRoot->isStorageElement( *element ); + OSL_ENSURE( bIsScriptLibrary, + "MigrationEngine_Impl::impl_migrateScriptStorage_nothrow: warning: unknown scripts storage structure!" ); + // we cannot handle this. We would need to copy this stream to the respective scripts storage + // of the database document, but we cannot guarantee that the name is not used, yet, and we cannot + // simply rename the thing. + if ( !bIsScriptLibrary ) + // TODO: propagate the type of the error + return false; + + // ensure we have access to the DBDoc's scripts storage + if ( !aDatabaseScripts.isValid() ) + { // not needed 'til now + aDatabaseScripts.bind( m_xDocumentModel, ScriptsStorage::WRITE ); + if ( !aDatabaseScripts.isValid() ) + // TODO: propagate the type of the error + return false; + xTargetStorage = aDatabaseScripts.getScriptsRoot( _eScriptType ); + if ( !xTargetStorage.is() ) + // TODO: propagate the type of the error return false; } - // TODO + // move the library to the DBDoc's scripts library, under the new name + ::rtl::OUString sNewLibName( lcl_createTargetLibName( _rDocument, *element, xTargetStorage ) ); + xScriptsRoot->moveElementTo( *element, xTargetStorage, sNewLibName ); - // clean up - lcl_disposeComponent_nothrow( _rDocument.xCommandProcessor ); - pStatusIndicator->dispose(); + // log the fact that we moved the library + m_rLogger.movedLibrary( _nDocID, _eScriptType, *element, sNewLibName ); - // end the progress, just in case the ProgressCapture didn't receive the XStatusIndicator::end event - m_rProgress.endObject(); + // progress + _rProgress.advancePhase( element - aStorageElements.getConstArray() ); + } + + // commit the storages, so the changes we made persist + if ( !lcl_commitStorage_nothrow( xScriptsRoot ) ) + // TODO: propagate the type of the error + return false; + if ( xTargetStorage.is() && !lcl_commitStorage_nothrow( xTargetStorage ) ) + // TODO: propagate the type of the error + return false; + + // now that the concrete scripts storage does not have any elements anymore, + // remove it + xScriptsRoot.reset( NULL ); // need to reset the storage to be allowed to remove it + aDocStorage.removeScriptTypeStorage( _eScriptType ); + + // progress - we're done with this phase + _rProgress.endPhase(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + // TODO: propagate the error to the user. + return false; + } - m_rLogger.finishedDocument( nDocID, true ); return true; } @@ -396,8 +917,9 @@ //= MigrationEngine //==================================================================== //-------------------------------------------------------------------- - MigrationEngine::MigrationEngine( const ::comphelper::ComponentContext& _rContext, const Reference< XOfficeDatabaseDocument >& _rxDocument, - IMigrationProgress& _rProgress, MigrationLog& _rLogger ) + MigrationEngine::MigrationEngine( const ::comphelper::ComponentContext& _rContext, + const Reference< XOfficeDatabaseDocument >& _rxDocument, IMigrationProgress& _rProgress, + MigrationLog& _rLogger ) :m_pImpl( new MigrationEngine_Impl( _rContext, _rxDocument, _rProgress, _rLogger ) ) { } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
