/************************************************************************* * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: migrationengine.cxx,v $ * * $Revision: 1.3 $ * * last change: $Author: obo $ $Date: 2008-03-10 11:40:00 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. * * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2005 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * ************************************************************************/ // 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 "docerrorhandling.hxx" #include "migrationengine.hxx" #include "migrationprogress.hxx" #include "migrationlog.hxx" #include "progresscapture.hxx" /** === begin UNO includes === **/ #include #include #include #include #include #include #include /** === end UNO includes === **/ #include #include #include #include #include #include #include #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::Command; using ::com::sun::star::embed::XComponentSupplier; using ::com::sun::star::task::XStatusIndicator; /** === end UNO using === **/ //==================================================================== //= SubDocument //==================================================================== struct SubDocument { Reference< XCommandProcessor > xCommandProcessor; ::rtl::OUString sHierarchicalName; SubDocumentType eType; SubDocument( const Reference< XCommandProcessor >& _rxCommandProcessor, const ::rtl::OUString& _rName, const SubDocumentType _eType ) :xCommandProcessor( _rxCommandProcessor ) ,sHierarchicalName( _rName ) ,eType( _eType ) { } }; typedef ::std::vector< SubDocument > SubDocuments; //==================================================================== //= MigrationEngine_Impl - declaration //==================================================================== class MigrationEngine_Impl { public: MigrationEngine_Impl( const ::comphelper::ComponentContext& _rContext, const Reference< XOfficeDatabaseDocument >& _rxDocument, IMigrationProgress& _rProgress, MigrationLog& _rLogger ); ~MigrationEngine_Impl(); inline sal_Int32 getFormCount() const { return m_nFormCount; } inline sal_Int32 getReportCount()const { return m_nReportCount; } bool migrateAll(); private: ::comphelper::ComponentContext m_aContext; const Reference< XOfficeDatabaseDocument > m_xDocument; IMigrationProgress& m_rProgress; MigrationLog& m_rLogger; SubDocuments m_aSubDocs; size_t m_nFormCount; size_t m_nReportCount; private: /** collects a description of all sub documents of our database document @return if and only if collecting the documents was successful */ bool impl_collectSubDocuments_nothrow(); /** reports the given error (usually an exception caught on the caller's side) to the user, using the document's interaction handler, if any. */ void impl_reportError_nothrow( const Any& _rError ) const; /** migrates the macros/scripts of the given sub document */ bool impl_handleDocument_nothrow( const SubDocument& _rDocument ) 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_rProgress( _rProgress ) ,m_rLogger( _rLogger ) ,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 ); } return true; } //-------------------------------------------------------------------- namespace { size_t lcl_collectHierarchicalElementNames_throw( const Reference< XNameAccess >& _rxContainer, const ::rtl::OUString& _rContainerLoc, SubDocuments& _out_rDocs, const SubDocumentType _eType ) { size_t nAddedElements = 0; 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() ) { nAddedElements += lcl_collectHierarchicalElementNames_throw( xSubContainer, sElementName, _out_rDocs, _eType ); } 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 ) ); ++nAddedElements; } } } return nAddedElements; } } //-------------------------------------------------------------------- bool MigrationEngine_Impl::impl_collectSubDocuments_nothrow() { try { ::rtl::OUString sRootLocation; Reference< XFormDocumentsSupplier > xSuppForms( m_xDocument, UNO_QUERY_THROW ); Reference< XNameAccess > xDocContainer( xSuppForms->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 ); m_nReportCount = lcl_collectHierarchicalElementNames_throw( xDocContainer, sRootLocation, m_aSubDocs, eReport ); } catch( const Exception& ) { // TODO: check whether we can handle this error DBG_UNHANDLED_EXCEPTION(); return false; } return true; } //-------------------------------------------------------------------- namespace { //................................................................ static void lcl_disposeComponent_nothrow( const Reference< XCommandProcessor >& _rxCommandProc ) { OSL_PRECOND( _rxCommandProc.is(), "lcl_disposeComponent_nothrow: illegal object!" ); if ( !_rxCommandProc.is() ) return; 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 ) { ; // 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 MigrationEngine_Impl::impl_handleDocument_nothrow( const SubDocument& _rDocument ) const { DocumentID nDocID = m_rLogger.startedDocument( _rDocument.eType, _rDocument.sHierarchicalName ); // 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 ); // load the document ::rtl::Reference< ProgressCapture > pStatusIndicator( new ProgressCapture( aProgress, m_rProgress ) ); Reference< XModel > xDocument( lcl_loadSubDocument_nothrow( _rDocument, pStatusIndicator.get() ) ); if ( !xDocument.is() ) { pStatusIndicator->dispose(); m_rProgress.endObject(); m_rLogger.finishedDocument( nDocID, false ); // TODO: log the *reason* for the failure return false; } // TODO // clean up lcl_disposeComponent_nothrow( _rDocument.xCommandProcessor ); pStatusIndicator->dispose(); // end the progress, just in case the ProgressCapture didn't receive the XStatusIndicator::end event m_rProgress.endObject(); m_rLogger.finishedDocument( nDocID, true ); return true; } //-------------------------------------------------------------------- void MigrationEngine_Impl::impl_reportError_nothrow( const Any& _rError ) const { DocumentErrorHandling::reportError( m_aContext, m_xDocument, _rError ); } //==================================================================== //= 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 //........................................................................