1990 lines
82 KiB
C++
1990 lines
82 KiB
C++
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
#include "precompiled_dbaccess.hxx"
|
|
|
|
#include "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
|
|
//........................................................................
|