| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_dbaccess.hxx" |
| |
| #include "dbmm_global.hrc" |
| #include "dbmm_module.hxx" |
| #include "dbmm_types.hxx" |
| #include "docinteraction.hxx" |
| #include "migrationengine.hxx" |
| #include "migrationerror.hxx" |
| #include "migrationprogress.hxx" |
| #include "migrationlog.hxx" |
| #include "progresscapture.hxx" |
| #include "progressmixer.hxx" |
| |
| /** === begin UNO includes === **/ |
| #include <com/sun/star/sdb/XFormDocumentsSupplier.hpp> |
| #include <com/sun/star/sdb/XReportDocumentsSupplier.hpp> |
| #include <com/sun/star/util/XCloseable.hpp> |
| #include <com/sun/star/frame/XModel.hpp> |
| #include <com/sun/star/frame/XComponentLoader.hpp> |
| #include <com/sun/star/ucb/XCommandProcessor.hpp> |
| #include <com/sun/star/ucb/XContent.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> |
| #include <com/sun/star/script/DocumentScriptLibraryContainer.hpp> |
| #include <com/sun/star/script/DocumentDialogLibraryContainer.hpp> |
| #include <com/sun/star/document/XEmbeddedScripts.hpp> |
| #include <com/sun/star/document/XEventsSupplier.hpp> |
| #include <com/sun/star/uri/UriReferenceFactory.hpp> |
| #include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp> |
| #include <com/sun/star/form/XFormsSupplier.hpp> |
| #include <com/sun/star/drawing/XDrawPageSupplier.hpp> |
| #include <com/sun/star/drawing/XDrawPagesSupplier.hpp> |
| #include <com/sun/star/script/XEventAttacherManager.hpp> |
| #include <com/sun/star/script/XLibraryContainerPassword.hpp> |
| #include <com/sun/star/io/WrongFormatException.hpp> |
| #include <com/sun/star/script/XScriptEventsSupplier.hpp> |
| #include <com/sun/star/io/XInputStreamProvider.hpp> |
| /** === end UNO includes === **/ |
| |
| #include <comphelper/documentinfo.hxx> |
| #include <comphelper/interaction.hxx> |
| #include <comphelper/namedvaluecollection.hxx> |
| #include <comphelper/storagehelper.hxx> |
| #include <comphelper/string.hxx> |
| #include <comphelper/types.hxx> |
| #include <cppuhelper/exc_hlp.hxx> |
| #include <tools/string.hxx> |
| #include <tools/diagnose_ex.h> |
| #include <rtl/ustrbuf.hxx> |
| #include <rtl/ref.hxx> |
| #include <unotools/sharedunocomponent.hxx> |
| #include <xmlscript/xmldlg_imexp.hxx> |
| |
| #include <vector> |
| #include <set> |
| |
| #define DEFAULT_DOC_PROGRESS_RANGE 100000 |
| |
| //........................................................................ |
| namespace dbmm |
| { |
| //........................................................................ |
| |
| /** === begin UNO using === **/ |
| using ::com::sun::star::uno::Reference; |
| using ::com::sun::star::uno::XInterface; |
| using ::com::sun::star::uno::UNO_QUERY; |
| using ::com::sun::star::uno::UNO_QUERY_THROW; |
| using ::com::sun::star::uno::UNO_SET_THROW; |
| using ::com::sun::star::uno::Exception; |
| using ::com::sun::star::uno::RuntimeException; |
| using ::com::sun::star::uno::Any; |
| using ::com::sun::star::uno::makeAny; |
| using ::com::sun::star::sdb::XOfficeDatabaseDocument; |
| using ::com::sun::star::sdb::XFormDocumentsSupplier; |
| using ::com::sun::star::sdb::XReportDocumentsSupplier; |
| using ::com::sun::star::container::XNameAccess; |
| using ::com::sun::star::uno::Sequence; |
| using ::com::sun::star::util::XCloseable; |
| using ::com::sun::star::util::CloseVetoException; |
| using ::com::sun::star::lang::XComponent; |
| using ::com::sun::star::frame::XModel; |
| using ::com::sun::star::frame::XComponentLoader; |
| using ::com::sun::star::ucb::XCommandProcessor; |
| using ::com::sun::star::ucb::XContent; |
| 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; |
| using ::com::sun::star::script::DocumentDialogLibraryContainer; |
| using ::com::sun::star::script::DocumentScriptLibraryContainer; |
| using ::com::sun::star::script::XStorageBasedLibraryContainer; |
| using ::com::sun::star::document::XEmbeddedScripts; |
| using ::com::sun::star::container::XNameContainer; |
| using ::com::sun::star::document::XEventsSupplier; |
| using ::com::sun::star::container::XNameReplace; |
| using com::sun::star::uri::UriReferenceFactory; |
| using com::sun::star::uri::XUriReferenceFactory; |
| using com::sun::star::uri::XVndSunStarScriptUrlReference; |
| using ::com::sun::star::form::XFormsSupplier; |
| using ::com::sun::star::drawing::XDrawPageSupplier; |
| using ::com::sun::star::drawing::XDrawPagesSupplier; |
| using ::com::sun::star::drawing::XDrawPage; |
| using ::com::sun::star::drawing::XDrawPages; |
| using ::com::sun::star::container::XIndexAccess; |
| using ::com::sun::star::script::XEventAttacherManager; |
| using ::com::sun::star::script::ScriptEventDescriptor; |
| using ::com::sun::star::script::XLibraryContainerPassword; |
| using ::com::sun::star::io::WrongFormatException; |
| using ::com::sun::star::script::XScriptEventsSupplier; |
| using ::com::sun::star::io::XInputStreamProvider; |
| using ::com::sun::star::io::XInputStream; |
| /** === 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 |
| #define PHASE_BASIC 5 |
| #define PHASE_DIALOGS 6 |
| |
| //==================================================================== |
| //= SubDocument |
| //==================================================================== |
| struct SubDocument |
| { |
| Reference< XCommandProcessor > xCommandProcessor; |
| Reference< XModel > xDocument; // valid only temporarily |
| ::rtl::OUString sHierarchicalName; |
| SubDocumentType eType; |
| size_t nNumber; |
| |
| SubDocument( const Reference< XCommandProcessor >& _rxCommandProcessor, const ::rtl::OUString& _rName, |
| const SubDocumentType _eType, const size_t _nNumber ) |
| :xCommandProcessor( _rxCommandProcessor ) |
| ,xDocument() |
| ,sHierarchicalName( _rName ) |
| ,eType( _eType ) |
| ,nNumber( _nNumber ) |
| { |
| } |
| }; |
| |
| 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" ) ); |
| 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" ) ); |
| |
| 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 bool lcl_getScriptTypeFromLanguage( const ::rtl::OUString& _rLanguage, ScriptType& _out_rScriptType ) |
| { |
| struct LanguageMapping |
| { |
| const sal_Char* pAsciiLanguage; |
| const ScriptType eScriptType; |
| |
| LanguageMapping( const sal_Char* _pAsciiLanguage, const ScriptType _eScriptType ) |
| :pAsciiLanguage( _pAsciiLanguage ) |
| ,eScriptType( _eScriptType ) |
| { |
| } |
| } |
| aLanguageMapping[] = |
| { |
| LanguageMapping( "JavaScript", eJavaScript ), |
| LanguageMapping( "BeanShell", eBeanShell ), |
| LanguageMapping( "Java", eJava ), |
| LanguageMapping( "Python", ePython ), // TODO: is this correct? |
| LanguageMapping( "Basic", eBasic ) |
| }; |
| for ( size_t i=0; i < sizeof( aLanguageMapping ) / sizeof( aLanguageMapping[0] ); ++i ) |
| { |
| if ( _rLanguage.equalsAscii( aLanguageMapping[i].pAsciiLanguage ) ) |
| { |
| _out_rScriptType = aLanguageMapping[i].eScriptType; |
| return true; |
| } |
| } |
| OSL_ENSURE( false, "lcl_getScriptTypeFromLanguage: unknown language!" ); |
| return false; |
| } |
| |
| //---------------------------------------------------------------- |
| ::rtl::OUString lcl_getSubDocumentDescription( const SubDocument& _rDocument ) |
| { |
| ::rtl::OUString sObjectName = String( MacroMigrationResId( _rDocument.eType == eForm ? STR_FORM : STR_REPORT ) ); |
| ::comphelper::string::searchAndReplaceAsciiI( sObjectName, "$name$", _rDocument.sHierarchicalName ); |
| return sObjectName; |
| } |
| |
| //---------------------------------------------------------------- |
| 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 ); |
| } |
| |
| //---------------------------------------------------------------- |
| ::rtl::OUString lcl_getMimeType_nothrow( const Reference< XCommandProcessor >& _rxContent ) |
| { |
| ::rtl::OUString sMimeType; |
| try |
| { |
| Reference< XContent > xContent( _rxContent, UNO_QUERY_THROW ); |
| sMimeType = xContent->getContentType(); |
| } |
| catch( const Exception& ) |
| { |
| DBG_UNHANDLED_EXCEPTION(); |
| } |
| return sMimeType; |
| } |
| |
| //---------------------------------------------------------------- |
| enum OpenDocResult |
| { |
| eOpenedDoc, |
| eIgnoreDoc, |
| eFailure |
| }; |
| |
| //---------------------------------------------------------------- |
| static OpenDocResult lcl_loadSubDocument_nothrow( SubDocument& _rDocument, |
| const Reference< XStatusIndicator >& _rxProgress, MigrationLog& _rLogger ) |
| { |
| OSL_PRECOND( !_rDocument.xDocument.is(), "lcl_loadSubDocument_nothrow: already loaded!" ); |
| |
| 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!" ); |
| |
| _rDocument.xDocument.set( xDocComponent, UNO_QUERY_THROW ); |
| } |
| catch( const Exception& ) |
| { |
| Any aError( ::cppu::getCaughtException() ); |
| |
| bool bCausedByNewStyleReport = |
| ( _rDocument.eType == eReport ) |
| && ( aError.isExtractableTo( ::cppu::UnoType< WrongFormatException >::get() ) ) |
| && ( lcl_getMimeType_nothrow( _rDocument.xCommandProcessor ).equalsAscii( "application/vnd.sun.xml.report" ) ); |
| |
| if ( bCausedByNewStyleReport ) |
| { |
| _rLogger.logRecoverable( MigrationError( |
| ERR_NEW_STYLE_REPORT, |
| lcl_getSubDocumentDescription( _rDocument ) |
| ) ); |
| return eIgnoreDoc; |
| } |
| else |
| { |
| _rLogger.logFailure( MigrationError( |
| ERR_OPENING_SUB_DOCUMENT_FAILED, |
| lcl_getSubDocumentDescription( _rDocument ), |
| aError |
| ) ); |
| } |
| } |
| return _rDocument.xDocument.is() ? eOpenedDoc : eFailure; |
| } |
| |
| //---------------------------------------------------------------- |
| static bool lcl_unloadSubDocument_nothrow( SubDocument& _rDocument, MigrationLog& _rLogger ) |
| { |
| bool bSuccess = false; |
| Any aException; |
| try |
| { |
| OSL_VERIFY( lcl_executeCommand_throw( _rDocument.xCommandProcessor, "close" ) >>= bSuccess ); |
| } |
| catch( const Exception& ) |
| { |
| aException = ::cppu::getCaughtException(); |
| } |
| |
| // log the failure, if any |
| if ( !bSuccess ) |
| { |
| _rLogger.logFailure( MigrationError( |
| ERR_CLOSING_SUB_DOCUMENT_FAILED, |
| lcl_getSubDocumentDescription( _rDocument ), |
| aException |
| ) ); |
| } |
| |
| _rDocument.xDocument.clear(); |
| return bSuccess; |
| } |
| |
| //---------------------------------------------------------------- |
| 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, MigrationLog& _rLogger ) |
| { |
| bool bSuccess = false; |
| Any aException; |
| try |
| { |
| Reference< XStorageBasedDocument > xStorageDoc( _rxDocument, UNO_QUERY_THROW ); |
| Reference< XStorage > xDocStorage( xStorageDoc->getDocumentStorage(), UNO_QUERY_THROW ); |
| bSuccess = lcl_commitStorage_nothrow( xDocStorage ); |
| } |
| catch( const Exception& ) |
| { |
| aException = ::cppu::getCaughtException(); |
| } |
| |
| // log the failure, if any |
| if ( !bSuccess ) |
| { |
| _rLogger.logFailure( MigrationError( |
| ERR_STORAGE_COMMIT_FAILED, |
| ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument ), |
| aException |
| ) ); |
| } |
| return bSuccess; |
| } |
| |
| //---------------------------------------------------------------- |
| bool lcl_storeDocument_nothrow( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger ) |
| { |
| bool bSuccess = false; |
| Any aException; |
| try |
| { |
| Reference< XStorable > xStorable( _rxDocument, UNO_QUERY_THROW ); |
| xStorable->store(); |
| bSuccess = true; |
| } |
| catch( const Exception& ) |
| { |
| aException = ::cppu::getCaughtException(); |
| } |
| |
| // log the failure, if any |
| if ( !bSuccess ) |
| { |
| _rLogger.logFailure( MigrationError( |
| ERR_STORING_DATABASEDOC_FAILED, |
| aException |
| ) ); |
| } |
| return bSuccess; |
| } |
| |
| //---------------------------------------------------------------- |
| bool lcl_storeEmbeddedDocument_nothrow( const SubDocument& _rDocument ) |
| { |
| try |
| { |
| lcl_executeCommand_throw( _rDocument.xCommandProcessor, "store" ); |
| } |
| catch( const Exception& ) |
| { |
| DBG_UNHANDLED_EXCEPTION(); |
| return false; |
| } |
| return true; |
| } |
| } |
| |
| //==================================================================== |
| //= DrawPageIterator |
| //==================================================================== |
| class DrawPageIterator |
| { |
| public: |
| DrawPageIterator( const Reference< XModel >& _rxDocument ) |
| :m_xDocument( _rxDocument ) |
| ,m_nPageCount( 0 ) |
| ,m_nCurrentPage( 0 ) |
| { |
| Reference< XDrawPageSupplier > xSingle( _rxDocument, UNO_QUERY ); |
| Reference< XDrawPagesSupplier > xMulti( _rxDocument, UNO_QUERY ); |
| if ( xSingle.is() ) |
| { |
| m_xSinglePage.set( xSingle->getDrawPage(), UNO_SET_THROW ); |
| m_nPageCount = 1; |
| } |
| else if ( xMulti.is() ) |
| { |
| m_xMultiPages.set( xMulti->getDrawPages(), UNO_SET_THROW ); |
| m_nPageCount = m_xMultiPages->getCount(); |
| } |
| } |
| |
| bool hasMore() const |
| { |
| return m_nCurrentPage < m_nPageCount; |
| } |
| |
| Reference< XDrawPage > next() |
| { |
| Reference< XDrawPage > xNextPage; |
| |
| if ( m_xSinglePage.is() ) |
| { |
| xNextPage = m_xSinglePage; |
| } |
| else if ( m_xMultiPages.is() ) |
| { |
| xNextPage.set( m_xMultiPages->getByIndex( m_nCurrentPage ), UNO_QUERY_THROW ); |
| } |
| ++m_nCurrentPage; |
| return xNextPage; |
| } |
| |
| private: |
| const Reference< XModel > m_xDocument; |
| Reference< XDrawPage > m_xSinglePage; |
| Reference< XDrawPages > m_xMultiPages; |
| sal_Int32 m_nPageCount; |
| sal_Int32 m_nCurrentPage; |
| }; |
| |
| //==================================================================== |
| //= FormComponentScripts |
| //==================================================================== |
| class FormComponentScripts |
| { |
| public: |
| FormComponentScripts( |
| const Reference< XInterface >& _rxComponent, |
| const Reference< XEventAttacherManager >& _rxManager, |
| const sal_Int32 _nIndex |
| ) |
| :m_xComponent( _rxComponent, UNO_SET_THROW ) |
| ,m_xManager( _rxManager, UNO_SET_THROW ) |
| ,m_nIndex( _nIndex ) |
| { |
| } |
| |
| Sequence< ScriptEventDescriptor > getEvents() const |
| { |
| return m_xManager->getScriptEvents( m_nIndex ); |
| } |
| |
| void setEvents( const Sequence< ScriptEventDescriptor >& _rEvents ) const |
| { |
| m_xManager->registerScriptEvents( m_nIndex, _rEvents ); |
| } |
| |
| const Reference< XInterface >& getComponent() const |
| { |
| return m_xComponent; |
| } |
| |
| private: |
| const Reference< XInterface > m_xComponent; |
| const Reference< XEventAttacherManager > m_xManager; |
| const sal_Int32 m_nIndex; |
| }; |
| |
| //==================================================================== |
| //= FormComponentIterator |
| //==================================================================== |
| class FormComponentIterator |
| { |
| public: |
| FormComponentIterator( const Reference< XIndexAccess >& _rxContainer ) |
| :m_xContainer( _rxContainer, UNO_SET_THROW ) |
| ,m_xEventManager( _rxContainer, UNO_QUERY_THROW ) |
| ,m_nElementCount( _rxContainer->getCount() ) |
| ,m_nCurrentElement( 0 ) |
| { |
| } |
| |
| bool hasMore() const |
| { |
| return m_nCurrentElement < m_nElementCount; |
| } |
| |
| FormComponentScripts next() |
| { |
| FormComponentScripts aComponent( |
| Reference< XInterface >( m_xContainer->getByIndex( m_nCurrentElement ), UNO_QUERY_THROW ), |
| m_xEventManager, |
| m_nCurrentElement |
| ); |
| ++m_nCurrentElement; |
| return aComponent; |
| } |
| |
| private: |
| const Reference< XIndexAccess > m_xContainer; |
| const Reference< XEventAttacherManager > m_xEventManager; |
| const sal_Int32 m_nElementCount; |
| sal_Int32 m_nCurrentElement; |
| |
| }; |
| |
| //==================================================================== |
| //= 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: |
| ScriptsStorage( MigrationLog& _rLogger ); |
| ScriptsStorage( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger ); |
| ~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(); } |
| |
| /** 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 ); |
| |
| /// 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; |
| |
| /** returns the names of the elements in the "Scripts" storage |
| */ |
| ::std::set< ::rtl::OUString > |
| getElementNames() 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; |
| |
| /** commits the changes at our XStorage object |
| */ |
| bool commit(); |
| |
| /** 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, MigrationLog& _rLogger ); |
| |
| private: |
| MigrationLog& m_rLogger; |
| SharedStorage m_xScriptsStorage; |
| }; |
| |
| //==================================================================== |
| //= ScriptsStorage - implementation |
| //==================================================================== |
| //-------------------------------------------------------------------- |
| ScriptsStorage::ScriptsStorage( MigrationLog& _rLogger ) |
| :m_rLogger( _rLogger ) |
| ,m_xScriptsStorage() |
| { |
| } |
| |
| //-------------------------------------------------------------------- |
| ScriptsStorage::ScriptsStorage( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger ) |
| :m_rLogger( _rLogger ) |
| ,m_xScriptsStorage() |
| { |
| bind( _rxDocument ); |
| } |
| |
| //-------------------------------------------------------------------- |
| ScriptsStorage::~ScriptsStorage() |
| { |
| } |
| |
| //-------------------------------------------------------------------- |
| bool ScriptsStorage::commit() |
| { |
| return lcl_commitStorage_nothrow( m_xScriptsStorage ); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ScriptsStorage::bind( const Reference< XModel >& _rxDocument ) |
| { |
| 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 ); |
| |
| // 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() ) |
| ) |
| { |
| m_xScriptsStorage.set( |
| xDocStorage->openStorageElement( |
| lcl_getScriptsStorageName(), ElementModes::READWRITE |
| ), |
| UNO_QUERY_THROW |
| ); |
| } |
| } |
| catch( const Exception& ) |
| { |
| m_rLogger.logFailure( MigrationError( |
| ERR_BIND_SCRIPT_STORAGE_FAILED, |
| ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument ), |
| ::cppu::getCaughtException() |
| ) ); |
| } |
| } |
| |
| //-------------------------------------------------------------------- |
| 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 ), ElementModes::READWRITE |
| ) ); |
| } |
| return xStorage; |
| } |
| |
| //-------------------------------------------------------------------- |
| ::std::set< ::rtl::OUString > ScriptsStorage::getElementNames() const |
| { |
| Sequence< ::rtl::OUString > aElementNames; |
| if ( isValid() ) |
| aElementNames = m_xScriptsStorage->getElementNames(); |
| |
| ::std::set< ::rtl::OUString > aNames; |
| ::std::copy( |
| aElementNames.getConstArray(), |
| aElementNames.getConstArray() + aElementNames.getLength(), |
| ::std::insert_iterator< ::std::set< ::rtl::OUString > >( aNames, aNames.end() ) |
| ); |
| return aNames; |
| } |
| |
| //-------------------------------------------------------------------- |
| void ScriptsStorage::removeScriptTypeStorage( const ScriptType _eType ) const |
| { |
| ::rtl::OUString sSubStorageName( lcl_getScriptsSubStorageName( _eType ) ); |
| if ( m_xScriptsStorage->hasByName( sSubStorageName ) ) |
| m_xScriptsStorage->removeElement( sSubStorageName ); |
| } |
| |
| //-------------------------------------------------------------------- |
| bool ScriptsStorage::removeFromDocument( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger ) |
| { |
| try |
| { |
| Reference< XStorageBasedDocument > xStorageDoc( _rxDocument, UNO_QUERY_THROW ); |
| Reference< XStorage > xDocStorage( xStorageDoc->getDocumentStorage(), UNO_QUERY_THROW ); |
| xDocStorage->removeElement( lcl_getScriptsStorageName() ); |
| } |
| catch( const Exception& ) |
| { |
| _rLogger.logFailure( MigrationError( |
| ERR_REMOVE_SCRIPTS_STORAGE_FAILED, |
| ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument ), |
| ::cppu::getCaughtException() |
| ) ) ; |
| 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; |
| }; |
| |
| //==================================================================== |
| //= PhaseGuard |
| //==================================================================== |
| class PhaseGuard |
| { |
| public: |
| PhaseGuard( ProgressMixer& _rMixer ) |
| :m_rMixer( _rMixer ) |
| { |
| } |
| |
| PhaseGuard( ProgressMixer& _rMixer, const PhaseID _nID, const sal_uInt32 _nPhaseRange ) |
| :m_rMixer( _rMixer ) |
| { |
| start( _nID, _nPhaseRange ); |
| } |
| |
| ~PhaseGuard() |
| { |
| m_rMixer.endPhase(); |
| } |
| |
| void start( const PhaseID _nID, const sal_uInt32 _nPhaseRange ) |
| { |
| m_rMixer.startPhase( _nID, _nPhaseRange ); |
| } |
| |
| private: |
| ProgressMixer& m_rMixer; |
| }; |
| |
| //==================================================================== |
| //= MigrationEngine_Impl - declaration |
| //==================================================================== |
| class MigrationEngine_Impl |
| { |
| public: |
| MigrationEngine_Impl( |
| const ::comphelper::ComponentContext& _rContext, |
| const Reference< XOfficeDatabaseDocument >& _rxDocument, |
| IMigrationProgress& _rProgress, |
| MigrationLog& _rLogger |
| ); |
| ~MigrationEngine_Impl(); |
| |
| inline size_t getFormCount() const { return m_nFormCount; } |
| inline size_t getReportCount()const { return m_nReportCount; } |
| bool migrateAll(); |
| |
| private: |
| ::comphelper::ComponentContext m_aContext; |
| const Reference< XOfficeDatabaseDocument > m_xDocument; |
| const Reference< XModel > m_xDocumentModel; |
| IMigrationProgress& m_rProgress; |
| MigrationLog& m_rLogger; |
| mutable DocumentID m_nCurrentDocumentID; |
| SubDocuments m_aSubDocs; |
| size_t m_nFormCount; |
| size_t m_nReportCount; |
| |
| private: |
| /** collects a description of all sub documents of our database document |
| |
| @return |
| <TRUE/> if and only if collecting the documents was successful |
| */ |
| bool impl_collectSubDocuments_nothrow(); |
| |
| /** migrates the macros/scripts of the given sub document |
| */ |
| bool impl_handleDocument_nothrow( const SubDocument& _rDocument ) const; |
| |
| /** checks the structure of the 'Scripts' folder of a sub document |
| for unknown elements |
| |
| @return |
| <TRUE/> if and only if the 'Scripts' folder contains known elements only. |
| */ |
| bool impl_checkScriptStorageStructure_nothrow( const SubDocument& _rDocument ) const; |
| |
| /** migrates the scripts of the given "storage-based" script type |
| */ |
| bool impl_migrateScriptStorage_nothrow( |
| const SubDocument& _rDocument, |
| const ScriptType _eScriptType, |
| ProgressMixer& _rProgress, |
| const PhaseID _nPhaseID |
| ) const; |
| |
| /** migrates the content of the given "container based" libraries (Basic/Dialogs) |
| */ |
| bool impl_migrateContainerLibraries_nothrow( |
| const SubDocument& _rDocument, |
| const ScriptType _eScriptType, |
| ProgressMixer& _rProgress, |
| const PhaseID _nPhaseID |
| ) const; |
| |
| /** adjusts the events for the given dialog/element, taking into account the new names |
| of the moved libraries |
| */ |
| void impl_adjustDialogElementEvents_throw( |
| const Reference< XInterface >& _rxElement |
| ) const; |
| |
| /** adjusts the events in the given dialog, and its controls, taking into account the new names |
| of the moved libraries |
| */ |
| bool impl_adjustDialogEvents_nothrow( |
| Any& _inout_rDialogLibraryElement, |
| const ::rtl::OUString& _rDocName, |
| const ::rtl::OUString& _rDialogLibName, |
| const ::rtl::OUString& _rDialogName |
| ) const; |
| |
| /** adjust the document-events which refer to macros/scripts in the document, taking into |
| account the new names of the moved libraries |
| */ |
| bool impl_adjustDocumentEvents_nothrow( |
| const SubDocument& _rDocument |
| ) const; |
| |
| /** adjusts the script references bound to form component events |
| */ |
| bool impl_adjustFormComponentEvents_nothrow( |
| const SubDocument& _rDocument |
| ) const; |
| |
| /** adjusts the script references for the elements of the given form component container |
| */ |
| void impl_adjustFormComponentEvents_throw( |
| const Reference< XIndexAccess >& _rxComponentContainer |
| ) const; |
| |
| /** adjusts the library name in the given script URL, so that it reflects |
| the new name of the library |
| |
| @return <TRUE/> |
| if and only if adjustments to the script code have been made |
| */ |
| bool impl_adjustScriptLibrary_nothrow( |
| const ::rtl::OUString& _rScriptType, |
| ::rtl::OUString& _inout_rScriptCode |
| ) const; |
| |
| bool impl_adjustScriptLibrary_nothrow( Any& _inout_rScriptDescriptor ) const; |
| bool impl_adjustScriptLibrary_nothrow( ScriptEventDescriptor& _inout_rScriptEvent ) const; |
| |
| /** asks the user for a password for the given library, and unprotects the library |
| |
| @return <TRUE/> |
| if and only if the library could be successfully unprotected |
| */ |
| bool impl_unprotectPasswordLibrary_throw( |
| const Reference< XLibraryContainerPassword >& _rxPasswordManager, |
| const ScriptType _eScriptType, |
| const ::rtl::OUString& _rLibraryName |
| ) const; |
| }; |
| |
| //==================================================================== |
| //= MigrationEngine_Impl - implementation |
| //==================================================================== |
| //-------------------------------------------------------------------- |
| MigrationEngine_Impl::MigrationEngine_Impl( const ::comphelper::ComponentContext& _rContext, |
| 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_nCurrentDocumentID( - 1 ) |
| ,m_aSubDocs() |
| ,m_nFormCount( 0 ) |
| ,m_nReportCount( 0 ) |
| { |
| OSL_VERIFY( impl_collectSubDocuments_nothrow() ); |
| } |
| |
| //-------------------------------------------------------------------- |
| MigrationEngine_Impl::~MigrationEngine_Impl() |
| { |
| } |
| |
| //-------------------------------------------------------------------- |
| bool MigrationEngine_Impl::migrateAll() |
| { |
| if ( m_aSubDocs.empty() ) |
| { |
| OSL_ENSURE( false, "MigrationEngine_Impl::migrateAll: no forms/reports found!" ); |
| // The whole migration wizard is not expected to be called when there are no forms/reports |
| // with macros, not to mention when there are no forms/reports at all. |
| return false; |
| } |
| |
| // initialize global progress |
| sal_Int32 nOverallRange( m_aSubDocs.size() ); |
| String sProgressSkeleton = String( MacroMigrationResId( STR_OVERALL_PROGRESS ) ); |
| sProgressSkeleton.SearchAndReplaceAscii( "$overall$", String::CreateFromInt32( nOverallRange ) ); |
| |
| m_rProgress.start( nOverallRange ); |
| |
| for ( SubDocuments::const_iterator doc = m_aSubDocs.begin(); |
| doc != m_aSubDocs.end(); |
| ++doc |
| ) |
| { |
| sal_Int32 nOverallProgressValue( doc - m_aSubDocs.begin() + 1 ); |
| // update overall progress text |
| ::rtl::OUString sOverallProgress( sProgressSkeleton ); |
| ::comphelper::string::searchAndReplaceAsciiI( sOverallProgress, "$current$", ::rtl::OUString::valueOf( nOverallProgressValue ) ); |
| m_rProgress.setOverallProgressText( sOverallProgress ); |
| |
| // migrate document |
| if ( !impl_handleDocument_nothrow( *doc ) ) |
| return false; |
| |
| // update overall progress vallue |
| 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, m_rLogger ) ) |
| return false; |
| |
| // save the document |
| if ( !lcl_storeDocument_nothrow( m_xDocumentModel, m_rLogger ) ) |
| return false; |
| |
| return true; |
| } |
| |
| //-------------------------------------------------------------------- |
| namespace |
| { |
| void lcl_collectHierarchicalElementNames_throw( |
| const Reference< XNameAccess >& _rxContainer, const ::rtl::OUString& _rContainerLoc, |
| SubDocuments& _out_rDocs, const SubDocumentType _eType, size_t& _io_counter ) |
| { |
| const ::rtl::OUString sHierarhicalBase( |
| _rContainerLoc.getLength() ? ::rtl::OUStringBuffer( _rContainerLoc ).appendAscii( "/" ).makeStringAndClear() |
| : ::rtl::OUString() ); |
| |
| Sequence< ::rtl::OUString > aElementNames( _rxContainer->getElementNames() ); |
| for ( const ::rtl::OUString* elementName = aElementNames.getConstArray(); |
| elementName != aElementNames.getConstArray() + aElementNames.getLength(); |
| ++elementName |
| ) |
| { |
| Any aElement( _rxContainer->getByName( *elementName ) ); |
| ::rtl::OUString sElementName( ::rtl::OUStringBuffer( sHierarhicalBase ).append( *elementName ) ); |
| |
| Reference< XNameAccess > xSubContainer( aElement, UNO_QUERY ); |
| if ( xSubContainer.is() ) |
| { |
| lcl_collectHierarchicalElementNames_throw( xSubContainer, sElementName, _out_rDocs, _eType, _io_counter ); |
| } |
| else |
| { |
| Reference< XCommandProcessor > xCommandProcessor( aElement, UNO_QUERY ); |
| OSL_ENSURE( xCommandProcessor.is(), "lcl_collectHierarchicalElementNames_throw: no container, and no comand processor? What *is* it, then?!" ); |
| if ( xCommandProcessor.is() ) |
| { |
| _out_rDocs.push_back( SubDocument( xCommandProcessor, sElementName, _eType, ++_io_counter ) ); |
| } |
| } |
| } |
| } |
| } |
| |
| //-------------------------------------------------------------------- |
| 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 |
| { |
| Reference< XNameAccess > xDocContainer( m_xDocument->getFormDocuments(), UNO_SET_THROW ); |
| m_nFormCount = 0; |
| lcl_collectHierarchicalElementNames_throw( xDocContainer, ::rtl::OUString(), m_aSubDocs, eForm, m_nFormCount ); |
| |
| xDocContainer.set( m_xDocument->getReportDocuments(), UNO_SET_THROW ); |
| m_nReportCount = 0; |
| lcl_collectHierarchicalElementNames_throw( xDocContainer, ::rtl::OUString(), m_aSubDocs, eReport, m_nReportCount ); |
| } |
| catch( const Exception& ) |
| { |
| m_rLogger.logFailure( MigrationError( |
| ERR_COLLECTING_DOCUMENTS_FAILED, |
| ::cppu::getCaughtException() |
| ) ); |
| return false; |
| } |
| return true; |
| } |
| |
| //-------------------------------------------------------------------- |
| bool MigrationEngine_Impl::impl_handleDocument_nothrow( const SubDocument& _rDocument ) const |
| { |
| OSL_ENSURE( m_nCurrentDocumentID == -1, |
| "MigrationEngine_Impl::impl_handleDocument_nothrow: there already is a current document!"); |
| m_nCurrentDocumentID = m_rLogger.startedDocument( _rDocument.eType, _rDocument.sHierarchicalName ); |
| |
| // start the progress |
| ::rtl::OUString sObjectName( lcl_getSubDocumentDescription( _rDocument ) ); |
| m_rProgress.startObject( sObjectName, ::rtl::OUString(), DEFAULT_DOC_PROGRESS_RANGE ); |
| |
| // ----------------- |
| // load the document |
| ::rtl::Reference< ProgressCapture > pStatusIndicator( new ProgressCapture( sObjectName, m_rProgress ) ); |
| SubDocument aSubDocument( _rDocument ); |
| OpenDocResult eResult = lcl_loadSubDocument_nothrow( aSubDocument, pStatusIndicator.get(), m_rLogger ); |
| if ( eResult != eOpenedDoc ) |
| { |
| pStatusIndicator->dispose(); |
| m_rProgress.endObject(); |
| m_rLogger.finishedDocument( m_nCurrentDocumentID ); |
| m_nCurrentDocumentID = -1; |
| return ( eResult == eIgnoreDoc ); |
| } |
| |
| // ----------------- |
| // 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 ); |
| aProgressMixer.registerPhase( PHASE_BASIC, 5 ); |
| // more weight than then others, assuming that usually, there are much more Basic macros than any other scripts |
| aProgressMixer.registerPhase( PHASE_DIALOGS, 1 ); |
| |
| bool bSuccess = impl_checkScriptStorageStructure_nothrow( aSubDocument ); |
| |
| // migrate storage-based script libraries (which can be handled by mere storage operations) |
| bSuccess = bSuccess |
| && impl_migrateScriptStorage_nothrow( aSubDocument, eJavaScript, aProgressMixer, PHASE_JAVASCRIPT ) |
| && impl_migrateScriptStorage_nothrow( aSubDocument, eBeanShell, aProgressMixer, PHASE_BEANSHELL ) |
| && impl_migrateScriptStorage_nothrow( aSubDocument, ePython, aProgressMixer, PHASE_PYTHON ) |
| && impl_migrateScriptStorage_nothrow( aSubDocument, eJava, aProgressMixer, PHASE_JAVA ); |
| |
| // migrate Basic and dialog libraries |
| bSuccess = bSuccess |
| && impl_migrateContainerLibraries_nothrow( aSubDocument, eBasic, aProgressMixer, PHASE_BASIC ) |
| && impl_migrateContainerLibraries_nothrow( aSubDocument, eDialog, aProgressMixer, PHASE_DIALOGS ); |
| // order matters: First Basic scripts, then dialogs. So we can adjust references from the latter |
| // to the former |
| |
| // adjust the events in the document |
| // (note that errors are ignored here - failure to convert a script reference |
| // is not considered a critical error) |
| if ( bSuccess ) |
| { |
| impl_adjustDocumentEvents_nothrow( aSubDocument ); |
| impl_adjustFormComponentEvents_nothrow( aSubDocument ); |
| } |
| |
| // ----------------- |
| // clean up |
| // store the sub document, including removal of the (now obsolete) "Scripts" sub folder |
| if ( m_rLogger.movedAnyLibrary( m_nCurrentDocumentID ) ) |
| { |
| bSuccess = bSuccess |
| && ScriptsStorage::removeFromDocument( aSubDocument.xDocument, m_rLogger ) |
| && lcl_commitDocumentStorage_nothrow( aSubDocument.xDocument, m_rLogger ) |
| && lcl_storeEmbeddedDocument_nothrow( aSubDocument ); |
| } |
| |
| // unload in any case, even if we were not successful |
| bSuccess = lcl_unloadSubDocument_nothrow( aSubDocument, m_rLogger ) |
| && bSuccess; |
| |
| pStatusIndicator->dispose(); |
| |
| // end the progress, just in case the ProgressCapture didn't receive the XStatusIndicator::end event |
| m_rProgress.endObject(); |
| |
| m_rLogger.finishedDocument( m_nCurrentDocumentID ); |
| m_nCurrentDocumentID = -1; |
| return bSuccess; |
| } |
| |
| //-------------------------------------------------------------------- |
| namespace |
| { |
| static ::rtl::OUString lcl_createTargetLibName( const SubDocument& _rDocument, |
| const ::rtl::OUString& _rSourceLibName, const Reference< XNameAccess >& _rxTargetContainer ) |
| { |
| // The new library name is composed from the prefix, the base name, and the old library name. |
| const ::rtl::OUString sPrefix( ::rtl::OUString::createFromAscii( _rDocument.eType == eForm ? "Form_" : "Report_" ) ); |
| |
| ::rtl::OUString sBaseName( _rDocument.sHierarchicalName.copy( |
| _rDocument.sHierarchicalName.lastIndexOf( '/' ) + 1 ) ); |
| // Normalize this name. In our current storage implementation (and script containers in a document |
| // are finally mapped to sub storages of the document storage), not all characters are allowed. |
| // The bug requesting to change this is #i95409#. |
| // Unfortunately, the storage implementation does not complain if you use invalid characters/names, but instead |
| // it silently accepts them, and produces garbage in the file (#i95408). |
| // So, until especially the former is fixed, we need to strip the name from all invalid characters. |
| // #i95865# / 2008-11-06 / frank.schoenheit@sun.com |
| |
| // The general idea is to replace invalid characters with '_'. However, since "valid" essentially means |
| // ASCII only, this implies that for a lot of languages, we would simply replace everything with '_', |
| // which of course is not desired. |
| // So, we use a heuristics: If the name contains at most 3 invalid characters, and as many valid as invalid |
| // characters, then we use the replacement. Otherwise, we just use a unambiguous number for the sub document. |
| sal_Int32 nValid=0, nInvalid=0; |
| const sal_Unicode* pBaseName = sBaseName.getStr(); |
| const sal_Int32 nBaseNameLen = sBaseName.getLength(); |
| for ( sal_Int32 i=0; i<nBaseNameLen; ++i ) |
| { |
| if ( ::comphelper::OStorageHelper::IsValidZipEntryFileName( pBaseName + i, 1, sal_False ) ) |
| ++nValid; |
| else |
| ++nInvalid; |
| } |
| if ( ( nInvalid <= 3 ) && ( nInvalid * 2 <= nValid ) ) |
| { // not "too many" invalid => replace them |
| ::rtl::OUStringBuffer aReplacement; |
| aReplacement.ensureCapacity( nBaseNameLen ); |
| aReplacement.append( sBaseName ); |
| const sal_Unicode* pReplacement = aReplacement.getStr(); |
| for ( sal_Int32 i=0; i<nBaseNameLen; ++i ) |
| { |
| if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( pReplacement + i, 1, sal_False ) ) |
| aReplacement.setCharAt( i, '_' ); |
| } |
| sBaseName = aReplacement.makeStringAndClear(); |
| |
| ::rtl::OUStringBuffer aNewLibNameAttempt; |
| aNewLibNameAttempt.append( sPrefix ); |
| aNewLibNameAttempt.append( sBaseName ); |
| aNewLibNameAttempt.appendAscii( "_" ); |
| aNewLibNameAttempt.append( _rSourceLibName ); |
| ::rtl::OUString sTargetName( aNewLibNameAttempt.makeStringAndClear() ); |
| if ( !_rxTargetContainer->hasByName( sTargetName ) ) |
| return sTargetName; |
| } |
| |
| // "too many" invalid characters, or the name composed with the base name was already used. |
| // (The latter is valid, since there can be multiple sub documents with the same base name, |
| // in different levels in the hierarchy.) |
| // In this case, just use the umambiguous sub document number. |
| ::rtl::OUStringBuffer aNewLibName; |
| aNewLibName.append( sPrefix ); |
| aNewLibName.append( ::rtl::OUString::valueOf( sal_Int64( _rDocument.nNumber ) ) ); |
| aNewLibName.appendAscii( "_" ); |
| aNewLibName.append( _rSourceLibName ); |
| return aNewLibName.makeStringAndClear(); |
| } |
| } |
| |
| //-------------------------------------------------------------------- |
| bool MigrationEngine_Impl::impl_checkScriptStorageStructure_nothrow( const SubDocument& _rDocument ) const |
| { |
| OSL_PRECOND( _rDocument.xDocument.is(), "MigrationEngine_Impl::impl_checkScriptStorageStructure_nothrow: invalid document!" ); |
| if ( !_rDocument.xDocument.is() ) |
| return false; |
| |
| try |
| { |
| // the root storage of the document whose scripts are to be migrated |
| ScriptsStorage aDocStorage( _rDocument.xDocument, m_rLogger ); |
| if ( !aDocStorage.isValid() ) |
| { // no scripts at all, or no scripts of the given type |
| return !m_rLogger.hadFailure(); |
| } |
| ::std::set< ::rtl::OUString > aElementNames( aDocStorage.getElementNames() ); |
| |
| ScriptType aKnownStorageBasedTypes[] = { |
| eBeanShell, eJavaScript, ePython, eJava |
| }; |
| for ( size_t i=0; i<sizeof( aKnownStorageBasedTypes ) / sizeof( aKnownStorageBasedTypes[0] ); ++i ) |
| aElementNames.erase( lcl_getScriptsSubStorageName( aKnownStorageBasedTypes[i] ) ); |
| |
| if ( !aElementNames.empty() ) |
| { |
| m_rLogger.logFailure( MigrationError( |
| ERR_UNKNOWN_SCRIPT_FOLDER, |
| lcl_getSubDocumentDescription( _rDocument ), |
| *aElementNames.begin() |
| ) ); |
| return false; |
| } |
| } |
| catch( const Exception& ) |
| { |
| m_rLogger.logFailure( MigrationError( |
| ERR_EXAMINING_SCRIPTS_FOLDER_FAILED, |
| lcl_getSubDocumentDescription( _rDocument ), |
| ::cppu::getCaughtException() |
| ) ); |
| return false; |
| } |
| return true; |
| } |
| |
| //-------------------------------------------------------------------- |
| bool MigrationEngine_Impl::impl_migrateScriptStorage_nothrow( const SubDocument& _rDocument, |
| const ScriptType _eScriptType, ProgressMixer& _rProgress, const PhaseID _nPhaseID ) const |
| { |
| OSL_PRECOND( _rDocument.xDocument.is(), "MigrationEngine_Impl::impl_migrateScriptStorage_nothrow: invalid document!" ); |
| if ( !_rDocument.xDocument.is() ) |
| return false; |
| |
| ScriptsStorage aDatabaseScripts( m_rLogger ); |
| // the scripts of our complete database document - created on demand only |
| SharedStorage xTargetStorage; |
| // the target for moving the scripts storages - created on demand only |
| |
| PhaseGuard aPhase( _rProgress ); |
| bool bSuccess = false; |
| Any aException; |
| try |
| { |
| // the root storage of the document whose scripts are to be migrated |
| ScriptsStorage aDocStorage( _rDocument.xDocument, m_rLogger ); |
| if ( !aDocStorage.isValid() |
| || !aDocStorage.hasScripts( _eScriptType ) |
| ) |
| { |
| // no scripts at all, or no scripts of the given type |
| _rProgress.startPhase( _nPhaseID, 1 ); |
| _rProgress.endPhase(); |
| return !m_rLogger.hadFailure(); |
| } |
| |
| 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() ); |
| aPhase.start( _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 ) |
| { |
| m_rLogger.logFailure( MigrationError( |
| ERR_UNEXPECTED_LIBSTORAGE_ELEMENT, |
| lcl_getSubDocumentDescription( _rDocument ), |
| getScriptTypeDisplayName( _eScriptType ), |
| *element |
| ) ); |
| return false; |
| } |
| |
| // ensure we have access to the DBDoc's scripts storage |
| if ( !aDatabaseScripts.isValid() ) |
| { // not needed 'til now |
| aDatabaseScripts.bind( m_xDocumentModel ); |
| if ( aDatabaseScripts.isValid() ) |
| xTargetStorage = aDatabaseScripts.getScriptsRoot( _eScriptType ); |
| |
| if ( !xTargetStorage.is() ) |
| { |
| m_rLogger.logFailure( MigrationError( |
| ERR_CREATING_DBDOC_SCRIPT_STORAGE_FAILED, |
| getScriptTypeDisplayName( _eScriptType ) |
| ) ); |
| return false; |
| } |
| } |
| |
| // move the library to the DBDoc's scripts library, under the new name |
| ::rtl::OUString sNewLibName( lcl_createTargetLibName( _rDocument, *element, xTargetStorage.getTyped().get() ) ); |
| xScriptsRoot->moveElementTo( *element, xTargetStorage, sNewLibName ); |
| |
| // log the fact that we moved the library |
| m_rLogger.movedLibrary( m_nCurrentDocumentID, _eScriptType, *element, sNewLibName ); |
| |
| // progress |
| _rProgress.advancePhase( element - aStorageElements.getConstArray() ); |
| } |
| |
| // commit the storages, so the changes we made persist |
| if ( !lcl_commitStorage_nothrow( xScriptsRoot ) |
| || ( xTargetStorage.is() && !lcl_commitStorage_nothrow( xTargetStorage ) ) |
| ) |
| { |
| m_rLogger.logFailure( MigrationError( |
| ERR_COMMITTING_SCRIPT_STORAGES_FAILED, |
| getScriptTypeDisplayName( _eScriptType ), |
| lcl_getSubDocumentDescription( _rDocument ) |
| ) ); |
| 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 ); |
| |
| // done so far |
| bSuccess = aDocStorage.commit() |
| && aDatabaseScripts.commit(); |
| } |
| catch( const Exception& ) |
| { |
| aException = ::cppu::getCaughtException(); |
| bSuccess = false; |
| } |
| |
| // log the error, if any |
| if ( !bSuccess ) |
| { |
| m_rLogger.logFailure( MigrationError( |
| ERR_GENERAL_SCRIPT_MIGRATION_FAILURE, |
| getScriptTypeDisplayName( _eScriptType ), |
| lcl_getSubDocumentDescription( _rDocument ), |
| aException |
| ) ); |
| } |
| |
| return bSuccess; |
| } |
| |
| //-------------------------------------------------------------------- |
| bool MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow( const SubDocument& _rDocument, |
| const ScriptType _eScriptType, ProgressMixer& _rProgress, const PhaseID _nPhaseID ) const |
| { |
| OSL_PRECOND( ( _eScriptType == eBasic ) || ( _eScriptType == eDialog ), |
| "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: illegal script type!" ); |
| |
| bool bSuccess = false; |
| PhaseGuard aPhase( _rProgress ); |
| Any aException; |
| do // artificial loop for flow control only |
| { |
| try |
| { |
| // access library container of the sub document |
| Reference< XEmbeddedScripts > xSubDocScripts( _rDocument.xDocument, UNO_QUERY ); |
| if ( !xSubDocScripts.is() ) |
| { // no script support in the sub document -> nothing to migrate |
| // (though ... this is suspicious, at least ...) |
| bSuccess = true; |
| break; |
| } |
| |
| Reference< XStorageBasedLibraryContainer > xSourceLibraries( |
| _eScriptType == eBasic ? xSubDocScripts->getBasicLibraries() : xSubDocScripts->getDialogLibraries(), |
| UNO_QUERY_THROW |
| ); |
| Reference< XLibraryContainerPassword > xSourcePasswords( xSourceLibraries, UNO_QUERY ); |
| OSL_ENSURE( xSourcePasswords.is(), |
| "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: suspicious: no password management for the source libraries!" ); |
| |
| Sequence< ::rtl::OUString > aSourceLibNames( xSourceLibraries->getElementNames() ); |
| aPhase.start( _nPhaseID, aSourceLibNames.getLength() ); |
| |
| if ( !xSourceLibraries->hasElements() ) |
| { |
| bSuccess = true; |
| break; |
| } |
| |
| // create library containers for the document - those will be the target for the migration |
| Reference< XStorageBasedDocument > xStorageDoc( m_xDocument, UNO_QUERY_THROW ); |
| Reference< XStorageBasedLibraryContainer > xTargetLibraries; |
| if ( _eScriptType == eBasic ) |
| { |
| xTargetLibraries.set( DocumentScriptLibraryContainer::create( |
| m_aContext.getUNOContext(), xStorageDoc ), UNO_QUERY_THROW ); |
| } |
| else |
| { |
| xTargetLibraries.set( DocumentDialogLibraryContainer::create( |
| m_aContext.getUNOContext(), xStorageDoc ), UNO_QUERY_THROW ); |
| } |
| |
| // copy all libs to the target, with potentially renaming them |
| const ::rtl::OUString* pSourceLibBegin = aSourceLibNames.getConstArray(); |
| const ::rtl::OUString* pSourceLibEnd = pSourceLibBegin + aSourceLibNames.getLength(); |
| for ( const ::rtl::OUString* pSourceLibName = pSourceLibBegin; |
| pSourceLibName != pSourceLibEnd; |
| ++pSourceLibName |
| ) |
| { |
| // if the library is password-protected, ask the user to unprotect it |
| if ( xSourcePasswords.is() |
| && xSourcePasswords->isLibraryPasswordProtected( *pSourceLibName ) |
| && !xSourcePasswords->isLibraryPasswordVerified( *pSourceLibName ) |
| ) |
| { |
| if ( !impl_unprotectPasswordLibrary_throw( xSourcePasswords, _eScriptType, *pSourceLibName ) ) |
| { |
| m_rLogger.logFailure( MigrationError( |
| ERR_PASSWORD_VERIFICATION_FAILED, |
| _rDocument.sHierarchicalName, |
| getScriptTypeDisplayName( _eScriptType ), |
| *pSourceLibName |
| ) ); |
| return false; |
| } |
| } |
| |
| ::rtl::OUString sNewLibName( lcl_createTargetLibName( _rDocument, *pSourceLibName, xTargetLibraries.get() ) ); |
| |
| if ( xSourceLibraries->isLibraryLink( *pSourceLibName ) ) |
| { |
| // just re-create the link in the target library |
| xTargetLibraries->createLibraryLink( |
| sNewLibName, |
| xSourceLibraries->getLibraryLinkURL( *pSourceLibName ), |
| xSourceLibraries->isLibraryReadOnly( *pSourceLibName ) |
| ); |
| } |
| else |
| { |
| if ( !xSourceLibraries->isLibraryLoaded( *pSourceLibName ) ) |
| xSourceLibraries->loadLibrary( *pSourceLibName ); |
| |
| // copy the content of this particular libary |
| Reference< XNameAccess > xSourceLib( xSourceLibraries->getByName( *pSourceLibName ), UNO_QUERY_THROW ); |
| Reference< XNameContainer > xTargetLib( xTargetLibraries->createLibrary( sNewLibName ), UNO_QUERY_THROW ); |
| |
| Sequence< ::rtl::OUString > aLibElementNames( xSourceLib->getElementNames() ); |
| for ( const ::rtl::OUString* pSourceElementName = aLibElementNames.getConstArray(); |
| pSourceElementName != aLibElementNames.getConstArray() + aLibElementNames.getLength(); |
| ++pSourceElementName |
| ) |
| { |
| Any aElement = xSourceLib->getByName( *pSourceElementName ); |
| OSL_ENSURE( aElement.hasValue(), |
| "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: invalid (empty) lib element!" ); |
| |
| // if this is a dialog, adjust the references to scripts |
| if ( _eScriptType == eDialog ) |
| { |
| impl_adjustDialogEvents_nothrow( aElement, lcl_getSubDocumentDescription( _rDocument ), |
| *pSourceLibName, *pSourceElementName ); |
| } |
| |
| xTargetLib->insertByName( *pSourceElementName, aElement ); |
| } |
| |
| // transfer the read-only flag |
| xTargetLibraries->setLibraryReadOnly( |
| sNewLibName, xSourceLibraries->isLibraryReadOnly( *pSourceLibName ) ); |
| } |
| |
| // remove the source lib |
| xSourceLibraries->removeLibrary( *pSourceLibName ); |
| |
| // tell the logger |
| m_rLogger.movedLibrary( m_nCurrentDocumentID, _eScriptType, *pSourceLibName, sNewLibName ); |
| |
| // tell the progress |
| _rProgress.advancePhase( pSourceLibName - pSourceLibBegin ); |
| } |
| |
| // clean up |
| xSourceLibraries->storeLibraries(); |
| |
| xTargetLibraries->storeLibraries(); |
| Reference< XStorage > xTargetRoot( xTargetLibraries->getRootLocation(), UNO_QUERY_THROW ); |
| bSuccess = lcl_commitStorage_nothrow( xTargetRoot ); |
| } |
| catch( const Exception& ) |
| { |
| aException = ::cppu::getCaughtException(); |
| bSuccess = false; |
| } |
| } while ( false ); |
| |
| // log the error, if any |
| if ( !bSuccess ) |
| { |
| m_rLogger.logFailure( MigrationError( |
| ERR_GENERAL_MACRO_MIGRATION_FAILURE, |
| lcl_getSubDocumentDescription( _rDocument ), |
| aException |
| ) ); |
| } |
| |
| return bSuccess; |
| } |
| |
| //-------------------------------------------------------------------- |
| bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( const ::rtl::OUString& _rScriptType, |
| ::rtl::OUString& _inout_rScriptCode ) const |
| { |
| OSL_PRECOND( _inout_rScriptCode.getLength(), "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: invalid script!" ); |
| if ( !_inout_rScriptCode.getLength() ) |
| return false; |
| |
| bool bSuccess = false; |
| Any aException; |
| try |
| { |
| if ( !_rScriptType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Script" ) ) |
| || !_rScriptType.getLength() |
| ) |
| { |
| OSL_ENSURE( false, |
| "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: no or unknown script type!" ); |
| m_rLogger.logRecoverable( MigrationError( |
| ERR_UNKNOWN_SCRIPT_TYPE, |
| _rScriptType |
| ) ); |
| return false; |
| } |
| |
| // analyze the script URI |
| Reference< XUriReferenceFactory > xUriRefFac = UriReferenceFactory::create( m_aContext.getUNOContext() ); |
| Reference< XVndSunStarScriptUrlReference > xUri( xUriRefFac->parse( _inout_rScriptCode ), UNO_QUERY_THROW ); |
| |
| ::rtl::OUString sScriptLanguage = xUri->getParameter( |
| ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "language" ) ) ); |
| ScriptType eScriptType = eBasic; |
| if ( !lcl_getScriptTypeFromLanguage( sScriptLanguage, eScriptType ) ) |
| { |
| OSL_ENSURE( false, |
| "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: unknown script language!" ); |
| m_rLogger.logRecoverable( MigrationError( |
| ERR_UNKNOWN_SCRIPT_LANGUAGE, |
| sScriptLanguage |
| ) ); |
| return false; |
| } |
| |
| ::rtl::OUString sLocation = xUri->getParameter( |
| ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "location" ) ) ); |
| if ( !sLocation.equalsAscii( "document" ) ) |
| { |
| // only document libraries must be migrated, of course |
| return false; |
| } |
| |
| ::rtl::OUString sScriptName = xUri->getName(); |
| sal_Int32 nLibModuleSeparator = sScriptName.indexOf( '.' ); |
| if ( nLibModuleSeparator < 0 ) |
| { |
| OSL_ENSURE( false, |
| "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: invalid/unknown location format!" ); |
| m_rLogger.logRecoverable( MigrationError( |
| ERR_UNKNOWN_SCRIPT_NAME_FORMAT, |
| sScriptName |
| ) ); |
| return false; |
| } |
| |
| // replace the library name |
| ::rtl::OUString sLibrary = sScriptName.copy( 0, nLibModuleSeparator ); |
| ::rtl::OUString sNewLibName = m_rLogger.getNewLibraryName( |
| m_nCurrentDocumentID, eScriptType, sLibrary ); |
| OSL_ENSURE( sLibrary != sNewLibName, |
| "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: a library which has not been migrated?" ); |
| |
| ::rtl::OUStringBuffer aNewLocation; |
| aNewLocation.append( sNewLibName ); |
| aNewLocation.append( sScriptName.copy( nLibModuleSeparator ) ); |
| xUri->setName( aNewLocation.makeStringAndClear() ); |
| |
| // update the new script URL |
| _inout_rScriptCode = xUri->getUriReference(); |
| bSuccess = true; |
| } |
| catch( const Exception& ) |
| { |
| aException = ::cppu::getCaughtException(); |
| bSuccess = false; |
| } |
| |
| // log the failure, if any |
| if ( !bSuccess ) |
| { |
| m_rLogger.logRecoverable( MigrationError( |
| ERR_SCRIPT_TRANSLATION_FAILURE, |
| _rScriptType, |
| _inout_rScriptCode, |
| aException |
| ) ); |
| } |
| |
| return bSuccess; |
| } |
| |
| //-------------------------------------------------------------------- |
| bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( ScriptEventDescriptor& _inout_rScriptEvent ) const |
| { |
| if ( _inout_rScriptEvent.ScriptType.getLength() && _inout_rScriptEvent.ScriptCode.getLength() ) |
| return impl_adjustScriptLibrary_nothrow( _inout_rScriptEvent.ScriptType, _inout_rScriptEvent.ScriptCode ); |
| return false; |
| } |
| |
| //-------------------------------------------------------------------- |
| bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( Any& _inout_rScriptDescriptor ) const |
| { |
| ::comphelper::NamedValueCollection aScriptDesc( _inout_rScriptDescriptor ); |
| |
| ::rtl::OUString sScriptType; |
| ::rtl::OUString sScript; |
| try |
| { |
| OSL_VERIFY( aScriptDesc.get_ensureType( "EventType", sScriptType ) ); |
| OSL_VERIFY( aScriptDesc.get_ensureType( "Script", sScript ) ); |
| } |
| catch( const Exception& ) |
| { |
| m_rLogger.logRecoverable( MigrationError( |
| ERR_INVALID_SCRIPT_DESCRIPTOR_FORMAT, |
| ::cppu::getCaughtException() |
| ) ); |
| } |
| |
| if ( sScriptType.getLength() && sScript.getLength() ) |
| if ( !impl_adjustScriptLibrary_nothrow( sScriptType, sScript ) ) |
| return false; |
| |
| aScriptDesc.put( "Script", sScript ); |
| _inout_rScriptDescriptor <<= aScriptDesc.getPropertyValues(); |
| return true; |
| } |
| |
| //-------------------------------------------------------------------- |
| bool MigrationEngine_Impl::impl_adjustDocumentEvents_nothrow( const SubDocument& _rDocument ) const |
| { |
| try |
| { |
| Reference< XEventsSupplier > xSuppEvents( _rDocument.xDocument, UNO_QUERY ); |
| if ( !xSuppEvents.is() ) |
| // this is allowed. E.g. new-style reports currently do not support this |
| return true; |
| |
| Reference< XNameReplace > xEvents( xSuppEvents->getEvents(), UNO_SET_THROW ); |
| Sequence< ::rtl::OUString > aEventNames = xEvents->getElementNames(); |
| |
| Any aEvent; |
| for ( const ::rtl::OUString* eventName = aEventNames.getConstArray(); |
| eventName != aEventNames.getConstArray() + aEventNames.getLength(); |
| ++eventName |
| ) |
| { |
| aEvent = xEvents->getByName( *eventName ); |
| if ( !aEvent.hasValue() ) |
| continue; |
| |
| // translate |
| if ( !impl_adjustScriptLibrary_nothrow( aEvent ) ) |
| continue; |
| |
| // put back |
| xEvents->replaceByName( *eventName, aEvent ); |
| } |
| } |
| catch( const Exception& ) |
| { |
| m_rLogger.logRecoverable( MigrationError( |
| ERR_ADJUSTING_DOCUMENT_EVENTS_FAILED, |
| lcl_getSubDocumentDescription( _rDocument ), |
| ::cppu::getCaughtException() |
| ) ); |
| return false; |
| } |
| return true; |
| } |
| |
| //-------------------------------------------------------------------- |
| void MigrationEngine_Impl::impl_adjustDialogElementEvents_throw( const Reference< XInterface >& _rxElement ) const |
| { |
| Reference< XScriptEventsSupplier > xEventsSupplier( _rxElement, UNO_QUERY_THROW ); |
| Reference< XNameReplace > xEvents( xEventsSupplier->getEvents(), UNO_QUERY_THROW ); |
| Sequence< ::rtl::OUString > aEventNames( xEvents->getElementNames() ); |
| |
| const ::rtl::OUString* eventName = aEventNames.getArray(); |
| const ::rtl::OUString* eventNamesEnd = eventName + aEventNames.getLength(); |
| |
| ScriptEventDescriptor aScriptEvent; |
| for ( ; eventName != eventNamesEnd; ++eventName ) |
| { |
| OSL_VERIFY( xEvents->getByName( *eventName ) >>= aScriptEvent ); |
| |
| if ( !impl_adjustScriptLibrary_nothrow( aScriptEvent ) ) |
| continue; |
| |
| xEvents->replaceByName( *eventName, makeAny( aScriptEvent ) ); |
| } |
| } |
| |
| //-------------------------------------------------------------------- |
| bool MigrationEngine_Impl::impl_adjustDialogEvents_nothrow( Any& _inout_rDialogLibraryElement, |
| const ::rtl::OUString& _rDocName, const ::rtl::OUString& _rDialogLibName, const ::rtl::OUString& _rDialogName ) const |
| { |
| try |
| { |
| // load a dialog model from the stream describing it |
| Reference< XInputStreamProvider > xISP( _inout_rDialogLibraryElement, UNO_QUERY_THROW ); |
| Reference< XInputStream > xInput( xISP->createInputStream(), UNO_QUERY_THROW ); |
| |
| Reference< XNameContainer > xDialogModel( m_aContext.createComponent( "com.sun.star.awt.UnoControlDialogModel" ), UNO_QUERY_THROW ); |
| ::xmlscript::importDialogModel( xInput, xDialogModel, m_aContext.getUNOContext() ); |
| |
| // adjust the events of the dialog |
| impl_adjustDialogElementEvents_throw( xDialogModel ); |
| |
| // adjust the events of the controls |
| Sequence< ::rtl::OUString > aControlNames( xDialogModel->getElementNames() ); |
| const ::rtl::OUString* controlName = aControlNames.getConstArray(); |
| const ::rtl::OUString* controlNamesEnd = controlName + aControlNames.getLength(); |
| for ( ; controlName != controlNamesEnd; ++controlName ) |
| { |
| impl_adjustDialogElementEvents_throw( Reference< XInterface >( xDialogModel->getByName( *controlName ), UNO_QUERY ) ); |
| } |
| |
| // export dialog model |
| xISP = ::xmlscript::exportDialogModel( xDialogModel, m_aContext.getUNOContext() ); |
| _inout_rDialogLibraryElement <<= xISP; |
| } |
| catch( const Exception& ) |
| { |
| m_rLogger.logRecoverable( MigrationError( |
| ERR_ADJUSTING_DIALOG_EVENTS_FAILED, |
| _rDocName, |
| _rDialogLibName, |
| _rDialogName, |
| ::cppu::getCaughtException() |
| ) ); |
| return false; |
| } |
| return true; |
| } |
| |
| //-------------------------------------------------------------------- |
| void MigrationEngine_Impl::impl_adjustFormComponentEvents_throw( const Reference< XIndexAccess >& _rxComponentContainer ) const |
| { |
| FormComponentIterator aCompIter( _rxComponentContainer ); |
| while ( aCompIter.hasMore() ) |
| { |
| // 1. adjust the component's scripts of the current component |
| FormComponentScripts aComponent( aCompIter.next() ); |
| Sequence< ScriptEventDescriptor > aEvents( aComponent.getEvents() ); |
| |
| bool bChangedComponentEvents = false; |
| for ( ScriptEventDescriptor* scriptEvent = aEvents.getArray(); |
| scriptEvent != aEvents.getArray() + aEvents.getLength(); |
| ++scriptEvent |
| ) |
| { |
| if ( !impl_adjustScriptLibrary_nothrow( *scriptEvent ) ) |
| continue; |
| |
| bChangedComponentEvents = true; |
| } |
| |
| if ( bChangedComponentEvents ) |
| aComponent.setEvents( aEvents ); |
| |
| // 2. step down if the component is a container itself |
| Reference< XIndexAccess > xContainer( aComponent.getComponent(), UNO_QUERY ); |
| if ( xContainer.is() ) |
| impl_adjustFormComponentEvents_throw( xContainer ); |
| } |
| } |
| |
| //-------------------------------------------------------------------- |
| bool MigrationEngine_Impl::impl_adjustFormComponentEvents_nothrow( const SubDocument& _rDocument ) const |
| { |
| try |
| { |
| DrawPageIterator aPageIter( _rDocument.xDocument ); |
| while ( aPageIter.hasMore() ) |
| { |
| Reference< XFormsSupplier > xSuppForms( aPageIter.next(), UNO_QUERY_THROW ); |
| Reference< XIndexAccess > xForms( xSuppForms->getForms(), UNO_QUERY_THROW ); |
| impl_adjustFormComponentEvents_throw( xForms ); |
| } |
| } |
| catch( const Exception& ) |
| { |
| m_rLogger.logRecoverable( MigrationError( |
| ERR_ADJUSTING_FORMCOMP_EVENTS_FAILED, |
| lcl_getSubDocumentDescription( _rDocument ), |
| ::cppu::getCaughtException() |
| ) ); |
| return false; |
| } |
| return true; |
| } |
| |
| //-------------------------------------------------------------------- |
| bool MigrationEngine_Impl::impl_unprotectPasswordLibrary_throw( const Reference< XLibraryContainerPassword >& _rxPasswordManager, |
| const ScriptType _eScriptType, const ::rtl::OUString& _rLibraryName ) const |
| { |
| // a human-readable description of the affected library |
| ::rtl::OUString sLibraryDescription( String( |
| MacroMigrationResId( STR_LIBRARY_TYPE_AND_NAME ) ) ); |
| ::comphelper::string::searchAndReplaceAsciiI( sLibraryDescription, "$type$", |
| getScriptTypeDisplayName( _eScriptType ) ); |
| ::comphelper::string::searchAndReplaceAsciiI( sLibraryDescription, "$library$", |
| _rLibraryName ); |
| |
| InteractionHandler aHandler( m_aContext, m_xDocumentModel ); |
| ::rtl::OUString sPassword; |
| while ( true ) |
| { |
| if ( !aHandler.requestDocumentPassword( sLibraryDescription, sPassword ) ) |
| // aborted by the user |
| return false; |
| |
| bool bSuccessVerification = _rxPasswordManager->verifyLibraryPassword( _rLibraryName, sPassword ); |
| if ( bSuccessVerification ) |
| return true; |
| } |
| |
| } |
| |
| //==================================================================== |
| //= MigrationEngine |
| //==================================================================== |
| //-------------------------------------------------------------------- |
| MigrationEngine::MigrationEngine( const ::comphelper::ComponentContext& _rContext, |
| const Reference< XOfficeDatabaseDocument >& _rxDocument, IMigrationProgress& _rProgress, |
| MigrationLog& _rLogger ) |
| :m_pImpl( new MigrationEngine_Impl( _rContext, _rxDocument, _rProgress, _rLogger ) ) |
| { |
| } |
| |
| //-------------------------------------------------------------------- |
| MigrationEngine::~MigrationEngine() |
| { |
| } |
| |
| //-------------------------------------------------------------------- |
| sal_Int32 MigrationEngine::getFormCount() const |
| { |
| return m_pImpl->getFormCount(); |
| } |
| |
| //-------------------------------------------------------------------- |
| sal_Int32 MigrationEngine::getReportCount() const |
| { |
| return m_pImpl->getReportCount(); |
| } |
| |
| //-------------------------------------------------------------------- |
| bool MigrationEngine::migrateAll() |
| { |
| return m_pImpl->migrateAll(); |
| } |
| |
| //........................................................................ |
| } // namespace dbmm |
| //........................................................................ |