1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "dbmm_global.hrc"
21 #include "dbmm_module.hxx"
22 #include "dbmm_types.hxx"
23 #include "docinteraction.hxx"
24 #include "migrationengine.hxx"
25 #include "migrationerror.hxx"
26 #include "migrationprogress.hxx"
27 #include "migrationlog.hxx"
28 #include "progresscapture.hxx"
29 #include "progressmixer.hxx"
31 #include <com/sun/star/sdb/XFormDocumentsSupplier.hpp>
32 #include <com/sun/star/sdb/XReportDocumentsSupplier.hpp>
33 #include <com/sun/star/util/XCloseable.hpp>
34 #include <com/sun/star/frame/XModel.hpp>
35 #include <com/sun/star/frame/XComponentLoader.hpp>
36 #include <com/sun/star/ucb/XCommandProcessor.hpp>
37 #include <com/sun/star/ucb/XContent.hpp>
38 #include <com/sun/star/embed/XComponentSupplier.hpp>
39 #include <com/sun/star/embed/ElementModes.hpp>
40 #include <com/sun/star/document/XStorageBasedDocument.hpp>
41 #include <com/sun/star/embed/XTransactedObject.hpp>
42 #include <com/sun/star/frame/XStorable.hpp>
43 #include <com/sun/star/embed/XEmbedPersist.hpp>
44 #include <com/sun/star/script/DocumentScriptLibraryContainer.hpp>
45 #include <com/sun/star/script/DocumentDialogLibraryContainer.hpp>
46 #include <com/sun/star/document/XEmbeddedScripts.hpp>
47 #include <com/sun/star/document/XEventsSupplier.hpp>
48 #include <com/sun/star/uri/UriReferenceFactory.hpp>
49 #include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp>
50 #include <com/sun/star/form/XFormsSupplier.hpp>
51 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
52 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
53 #include <com/sun/star/script/XEventAttacherManager.hpp>
54 #include <com/sun/star/script/XLibraryContainerPassword.hpp>
55 #include <com/sun/star/io/WrongFormatException.hpp>
56 #include <com/sun/star/script/XScriptEventsSupplier.hpp>
57 #include <com/sun/star/io/XInputStreamProvider.hpp>
59 #include <comphelper/documentinfo.hxx>
60 #include <comphelper/interaction.hxx>
61 #include <comphelper/namedvaluecollection.hxx>
62 #include <comphelper/storagehelper.hxx>
63 #include <comphelper/types.hxx>
64 #include <cppuhelper/exc_hlp.hxx>
65 #include <tools/diagnose_ex.h>
66 #include <rtl/ustrbuf.hxx>
67 #include <rtl/ref.hxx>
68 #include <unotools/sharedunocomponent.hxx>
69 #include <xmlscript/xmldlg_imexp.hxx>
75 #define DEFAULT_DOC_PROGRESS_RANGE 100000
80 using ::com::sun::star::uno::Reference
;
81 using ::com::sun::star::uno::XInterface
;
82 using ::com::sun::star::uno::UNO_QUERY
;
83 using ::com::sun::star::uno::UNO_QUERY_THROW
;
84 using ::com::sun::star::uno::UNO_SET_THROW
;
85 using ::com::sun::star::uno::Exception
;
86 using ::com::sun::star::uno::RuntimeException
;
87 using ::com::sun::star::uno::Any
;
88 using ::com::sun::star::uno::makeAny
;
89 using ::com::sun::star::uno::XComponentContext
;
90 using ::com::sun::star::sdb::XOfficeDatabaseDocument
;
91 using ::com::sun::star::sdb::XFormDocumentsSupplier
;
92 using ::com::sun::star::sdb::XReportDocumentsSupplier
;
93 using ::com::sun::star::container::XNameAccess
;
94 using ::com::sun::star::uno::Sequence
;
95 using ::com::sun::star::util::XCloseable
;
96 using ::com::sun::star::util::CloseVetoException
;
97 using ::com::sun::star::lang::XComponent
;
98 using ::com::sun::star::frame::XModel
;
99 using ::com::sun::star::frame::XComponentLoader
;
100 using ::com::sun::star::ucb::XCommandProcessor
;
101 using ::com::sun::star::ucb::XContent
;
102 using ::com::sun::star::ucb::Command
;
103 using ::com::sun::star::embed::XComponentSupplier
;
104 using ::com::sun::star::task::XStatusIndicator
;
105 using ::com::sun::star::embed::XStorage
;
106 using ::com::sun::star::document::XStorageBasedDocument
;
107 using ::com::sun::star::embed::XTransactedObject
;
108 using ::com::sun::star::frame::XStorable
;
109 using ::com::sun::star::embed::XEmbedPersist
;
110 using ::com::sun::star::script::DocumentDialogLibraryContainer
;
111 using ::com::sun::star::script::DocumentScriptLibraryContainer
;
112 using ::com::sun::star::script::XStorageBasedLibraryContainer
;
113 using ::com::sun::star::document::XEmbeddedScripts
;
114 using ::com::sun::star::container::XNameContainer
;
115 using ::com::sun::star::document::XEventsSupplier
;
116 using ::com::sun::star::container::XNameReplace
;
117 using com::sun::star::uri::UriReferenceFactory
;
118 using com::sun::star::uri::XUriReferenceFactory
;
119 using com::sun::star::uri::XVndSunStarScriptUrlReference
;
120 using ::com::sun::star::form::XFormsSupplier
;
121 using ::com::sun::star::drawing::XDrawPageSupplier
;
122 using ::com::sun::star::drawing::XDrawPagesSupplier
;
123 using ::com::sun::star::drawing::XDrawPage
;
124 using ::com::sun::star::drawing::XDrawPages
;
125 using ::com::sun::star::container::XIndexAccess
;
126 using ::com::sun::star::script::XEventAttacherManager
;
127 using ::com::sun::star::script::ScriptEventDescriptor
;
128 using ::com::sun::star::script::XLibraryContainerPassword
;
129 using ::com::sun::star::io::WrongFormatException
;
130 using ::com::sun::star::script::XScriptEventsSupplier
;
131 using ::com::sun::star::io::XInputStreamProvider
;
132 using ::com::sun::star::io::XInputStream
;
134 namespace ElementModes
= ::com::sun::star::embed::ElementModes
;
136 // migration phases whose progresses are to be mixed into one progress
137 #define PHASE_JAVASCRIPT 1
138 #define PHASE_BEANSHELL 2
139 #define PHASE_PYTHON 3
141 #define PHASE_BASIC 5
142 #define PHASE_DIALOGS 6
147 Reference
< XCommandProcessor
> xCommandProcessor
;
148 Reference
< XModel
> xDocument
; // valid only temporarily
149 OUString sHierarchicalName
;
150 SubDocumentType eType
;
153 SubDocument( const Reference
< XCommandProcessor
>& _rxCommandProcessor
, const OUString
& _rName
,
154 const SubDocumentType _eType
, const size_t _nNumber
)
155 :xCommandProcessor( _rxCommandProcessor
)
157 ,sHierarchicalName( _rName
)
164 typedef ::std::vector
< SubDocument
> SubDocuments
;
167 typedef ::utl::SharedUNOComponent
< XStorage
> SharedStorage
;
171 static const char sScriptsStorageName
[] = "Scripts";
173 static OUString
lcl_getScriptsSubStorageName( const ScriptType _eType
)
177 case eBeanShell
: return OUString("beanshell");
178 case eJavaScript
: return OUString("javascript");
179 case ePython
: return OUString("python"); // TODO: is this correct?
180 case eJava
: return OUString("java");
185 OSL_FAIL( "lcl_getScriptsSubStorageName: illegal type!" );
189 static bool lcl_getScriptTypeFromLanguage( const OUString
& _rLanguage
, ScriptType
& _out_rScriptType
)
191 struct LanguageMapping
193 const sal_Char
* pAsciiLanguage
;
194 const ScriptType eScriptType
;
196 LanguageMapping( const sal_Char
* _pAsciiLanguage
, const ScriptType _eScriptType
)
197 :pAsciiLanguage( _pAsciiLanguage
)
198 ,eScriptType( _eScriptType
)
204 LanguageMapping( "JavaScript", eJavaScript
),
205 LanguageMapping( "BeanShell", eBeanShell
),
206 LanguageMapping( "Java", eJava
),
207 LanguageMapping( "Python", ePython
), // TODO: is this correct?
208 LanguageMapping( "Basic", eBasic
)
210 for ( size_t i
=0; i
< sizeof( aLanguageMapping
) / sizeof( aLanguageMapping
[0] ); ++i
)
212 if ( _rLanguage
.equalsAscii( aLanguageMapping
[i
].pAsciiLanguage
) )
214 _out_rScriptType
= aLanguageMapping
[i
].eScriptType
;
218 OSL_FAIL( "lcl_getScriptTypeFromLanguage: unknown language!" );
222 OUString
lcl_getSubDocumentDescription( const SubDocument
& _rDocument
)
224 OUString
sObjectName(
226 _rDocument
.eType
== eForm
? STR_FORM
: STR_REPORT
).toString().
227 replaceFirst("$name$", _rDocument
.sHierarchicalName
));
231 static Any
lcl_executeCommand_throw( const Reference
< XCommandProcessor
>& _rxCommandProc
,
232 const sal_Char
* _pAsciiCommand
)
234 OSL_PRECOND( _rxCommandProc
.is(), "lcl_executeCommand_throw: illegal object!" );
235 if ( !_rxCommandProc
.is() )
239 aCommand
.Name
= OUString::createFromAscii( _pAsciiCommand
);
240 return _rxCommandProc
->execute(
241 aCommand
, _rxCommandProc
->createCommandIdentifier(), NULL
);
244 OUString
lcl_getMimeType_nothrow( const Reference
< XCommandProcessor
>& _rxContent
)
249 Reference
< XContent
> xContent( _rxContent
, UNO_QUERY_THROW
);
250 sMimeType
= xContent
->getContentType();
252 catch( const Exception
& )
254 DBG_UNHANDLED_EXCEPTION();
266 static OpenDocResult
lcl_loadSubDocument_nothrow( SubDocument
& _rDocument
,
267 const Reference
< XStatusIndicator
>& _rxProgress
, MigrationLog
& _rLogger
)
269 OSL_PRECOND( !_rDocument
.xDocument
.is(), "lcl_loadSubDocument_nothrow: already loaded!" );
273 ::comphelper::NamedValueCollection aLoadArgs
;
274 aLoadArgs
.put( "Hidden", true );
275 aLoadArgs
.put( "StatusIndicator", _rxProgress
);
277 Reference
< XCommandProcessor
> xCommandProcessor( _rDocument
.xCommandProcessor
, UNO_SET_THROW
);
279 aCommand
.Name
= "openDesign";
280 aCommand
.Argument
<<= aLoadArgs
.getPropertyValues();
281 Reference
< XComponent
> xDocComponent(
282 xCommandProcessor
->execute(
283 aCommand
, xCommandProcessor
->createCommandIdentifier(), NULL
287 OSL_ENSURE( xDocComponent
.is(), "lcl_loadSubDocument_nothrow: no component loaded!" );
289 _rDocument
.xDocument
.set( xDocComponent
, UNO_QUERY_THROW
);
291 catch( const Exception
& )
293 Any
aError( ::cppu::getCaughtException() );
295 bool bCausedByNewStyleReport
=
296 ( _rDocument
.eType
== eReport
)
297 && ( aError
.isExtractableTo( ::cppu::UnoType
< WrongFormatException
>::get() ) )
298 && ( lcl_getMimeType_nothrow( _rDocument
.xCommandProcessor
) == "application/vnd.sun.xml.report" );
300 if ( bCausedByNewStyleReport
)
302 _rLogger
.logRecoverable( MigrationError(
303 ERR_NEW_STYLE_REPORT
,
304 lcl_getSubDocumentDescription( _rDocument
)
310 _rLogger
.logFailure( MigrationError(
311 ERR_OPENING_SUB_DOCUMENT_FAILED
,
312 lcl_getSubDocumentDescription( _rDocument
),
317 return _rDocument
.xDocument
.is() ? eOpenedDoc
: eFailure
;
320 static bool lcl_unloadSubDocument_nothrow( SubDocument
& _rDocument
, MigrationLog
& _rLogger
)
322 bool bSuccess
= false;
326 OSL_VERIFY( lcl_executeCommand_throw( _rDocument
.xCommandProcessor
, "close" ) >>= bSuccess
);
328 catch( const Exception
& )
330 aException
= ::cppu::getCaughtException();
333 // log the failure, if any
336 _rLogger
.logFailure( MigrationError(
337 ERR_CLOSING_SUB_DOCUMENT_FAILED
,
338 lcl_getSubDocumentDescription( _rDocument
),
343 _rDocument
.xDocument
.clear();
347 bool lcl_commitStorage_nothrow( const Reference
< XStorage
>& _rxStorage
)
351 Reference
< XTransactedObject
> xTrans( _rxStorage
, UNO_QUERY_THROW
);
354 catch( const Exception
& )
361 bool lcl_commitDocumentStorage_nothrow( const Reference
< XModel
>& _rxDocument
, MigrationLog
& _rLogger
)
363 bool bSuccess
= false;
367 Reference
< XStorageBasedDocument
> xStorageDoc( _rxDocument
, UNO_QUERY_THROW
);
368 Reference
< XStorage
> xDocStorage( xStorageDoc
->getDocumentStorage(), UNO_QUERY_THROW
);
369 bSuccess
= lcl_commitStorage_nothrow( xDocStorage
);
371 catch( const Exception
& )
373 aException
= ::cppu::getCaughtException();
376 // log the failure, if any
379 _rLogger
.logFailure( MigrationError(
380 ERR_STORAGE_COMMIT_FAILED
,
381 ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument
),
388 bool lcl_storeDocument_nothrow( const Reference
< XModel
>& _rxDocument
, MigrationLog
& _rLogger
)
390 bool bSuccess
= false;
394 Reference
< XStorable
> xStorable( _rxDocument
, UNO_QUERY_THROW
);
398 catch( const Exception
& )
400 aException
= ::cppu::getCaughtException();
403 // log the failure, if any
406 _rLogger
.logFailure( MigrationError(
407 ERR_STORING_DATABASEDOC_FAILED
,
414 bool lcl_storeEmbeddedDocument_nothrow( const SubDocument
& _rDocument
)
418 lcl_executeCommand_throw( _rDocument
.xCommandProcessor
, "store" );
420 catch( const Exception
& )
422 DBG_UNHANDLED_EXCEPTION();
430 class DrawPageIterator
433 DrawPageIterator( const Reference
< XModel
>& _rxDocument
)
434 :m_xDocument( _rxDocument
)
438 Reference
< XDrawPageSupplier
> xSingle( _rxDocument
, UNO_QUERY
);
439 Reference
< XDrawPagesSupplier
> xMulti( _rxDocument
, UNO_QUERY
);
442 m_xSinglePage
.set( xSingle
->getDrawPage(), UNO_SET_THROW
);
445 else if ( xMulti
.is() )
447 m_xMultiPages
.set( xMulti
->getDrawPages(), UNO_SET_THROW
);
448 m_nPageCount
= m_xMultiPages
->getCount();
454 return m_nCurrentPage
< m_nPageCount
;
457 Reference
< XDrawPage
> next()
459 Reference
< XDrawPage
> xNextPage
;
461 if ( m_xSinglePage
.is() )
463 xNextPage
= m_xSinglePage
;
465 else if ( m_xMultiPages
.is() )
467 xNextPage
.set( m_xMultiPages
->getByIndex( m_nCurrentPage
), UNO_QUERY_THROW
);
474 const Reference
< XModel
> m_xDocument
;
475 Reference
< XDrawPage
> m_xSinglePage
;
476 Reference
< XDrawPages
> m_xMultiPages
;
477 sal_Int32 m_nPageCount
;
478 sal_Int32 m_nCurrentPage
;
481 // FormComponentScripts
482 class FormComponentScripts
485 FormComponentScripts(
486 const Reference
< XInterface
>& _rxComponent
,
487 const Reference
< XEventAttacherManager
>& _rxManager
,
488 const sal_Int32 _nIndex
490 :m_xComponent( _rxComponent
)
491 ,m_xManager( _rxManager
)
496 Sequence
< ScriptEventDescriptor
> getEvents() const
498 return m_xManager
->getScriptEvents( m_nIndex
);
501 void setEvents( const Sequence
< ScriptEventDescriptor
>& _rEvents
) const
503 m_xManager
->registerScriptEvents( m_nIndex
, _rEvents
);
506 const Reference
< XInterface
>& getComponent() const
512 const Reference
< XInterface
> m_xComponent
;
513 const Reference
< XEventAttacherManager
> m_xManager
;
514 const sal_Int32 m_nIndex
;
517 // FormComponentIterator
518 class FormComponentIterator
521 FormComponentIterator( const Reference
< XIndexAccess
>& _rxContainer
)
522 :m_xContainer( _rxContainer
)
523 ,m_xEventManager( _rxContainer
, UNO_QUERY_THROW
)
524 ,m_nElementCount( _rxContainer
->getCount() )
525 ,m_nCurrentElement( 0 )
531 return m_nCurrentElement
< m_nElementCount
;
534 FormComponentScripts
next()
536 FormComponentScripts
aComponent(
537 Reference
< XInterface
>( m_xContainer
->getByIndex( m_nCurrentElement
), UNO_QUERY_THROW
),
546 const Reference
< XIndexAccess
> m_xContainer
;
547 const Reference
< XEventAttacherManager
> m_xEventManager
;
548 const sal_Int32 m_nElementCount
;
549 sal_Int32 m_nCurrentElement
;
553 // ScriptsStorage - declaration
554 /** a helper class which encapsulates access to the storages for Java/Script, BeanShell, and Python scripts,
555 i.e. all script types which can be manipulated on storage level.
560 ScriptsStorage( MigrationLog
& _rLogger
);
561 ScriptsStorage( const Reference
< XModel
>& _rxDocument
, MigrationLog
& _rLogger
);
564 /** determines whether the instance is valid, i.e. refers to a valid root storage
565 for reading/storing scripts
567 inline bool isValid() const { return m_xScriptsStorage
.is(); }
569 /** binds the instance to a new document. Only to be called when the instance is not yet
570 bound (i.e. isValid returns <FALSE/>).
572 void bind( const Reference
< XModel
>& _rxDocument
);
574 /// determines whether scripts of the given type are present
575 bool hasScripts( const ScriptType _eType
) const;
577 /// returns the root storage for the scripts of the given type
579 getScriptsRoot( const ScriptType _eType
) const;
581 /** returns the names of the elements in the "Scripts" storage
583 ::std::set
< OUString
>
584 getElementNames() const;
586 /** removes the sub storage for a given script type
588 the respective storage is empty
590 the ScriptsStorage instance was opened for writing
592 void removeScriptTypeStorage( const ScriptType _eType
) const;
594 /** commits the changes at our XStorage object
598 /** removes the "Scripts" sub storage from the given document's root storage
600 the "Scripts" storage is empty
603 removeFromDocument( const Reference
< XModel
>& _rxDocument
, MigrationLog
& _rLogger
);
606 MigrationLog
& m_rLogger
;
607 SharedStorage m_xScriptsStorage
;
610 // ScriptsStorage - implementation
611 ScriptsStorage::ScriptsStorage( MigrationLog
& _rLogger
)
612 :m_rLogger( _rLogger
)
617 ScriptsStorage::ScriptsStorage( const Reference
< XModel
>& _rxDocument
, MigrationLog
& _rLogger
)
618 :m_rLogger( _rLogger
)
624 ScriptsStorage::~ScriptsStorage()
628 bool ScriptsStorage::commit()
630 return lcl_commitStorage_nothrow( m_xScriptsStorage
);
633 void ScriptsStorage::bind( const Reference
< XModel
>& _rxDocument
)
635 OSL_PRECOND( !isValid(), "ScriptsStorage:bind: did not bother, yet, to check whether this is allowed!" );
638 Reference
< XStorageBasedDocument
> xStorageDoc( _rxDocument
, UNO_QUERY_THROW
);
639 Reference
< XStorage
> xDocStorage( xStorageDoc
->getDocumentStorage(), UNO_QUERY_THROW
);
641 // the "Scripts" storage exist, or if it does not (yet) exist and we are in write mode
642 // => open the storage
643 if ( ( xDocStorage
->hasByName( sScriptsStorageName
)
644 && xDocStorage
->isStorageElement( sScriptsStorageName
)
646 || !xDocStorage
->hasByName( sScriptsStorageName
)
649 m_xScriptsStorage
.set(
650 xDocStorage
->openStorageElement(
651 sScriptsStorageName
, ElementModes::READWRITE
657 catch( const Exception
& )
659 m_rLogger
.logFailure( MigrationError(
660 ERR_BIND_SCRIPT_STORAGE_FAILED
,
661 ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument
),
662 ::cppu::getCaughtException()
667 bool ScriptsStorage::hasScripts( const ScriptType _eType
) const
669 OSL_PRECOND( isValid(), "ScriptsStorage::hasScripts: illegal call!" );
673 const OUString
& rSubStorageName( lcl_getScriptsSubStorageName( _eType
) );
674 return m_xScriptsStorage
->hasByName( rSubStorageName
)
675 && m_xScriptsStorage
->isStorageElement( rSubStorageName
);
678 SharedStorage
ScriptsStorage::getScriptsRoot( const ScriptType _eType
) const
680 SharedStorage xStorage
;
683 xStorage
.reset( m_xScriptsStorage
->openStorageElement(
684 lcl_getScriptsSubStorageName( _eType
), ElementModes::READWRITE
690 ::std::set
< OUString
> ScriptsStorage::getElementNames() const
692 Sequence
< OUString
> aElementNames
;
694 aElementNames
= m_xScriptsStorage
->getElementNames();
696 ::std::set
< OUString
> aNames
;
698 aElementNames
.getConstArray(),
699 aElementNames
.getConstArray() + aElementNames
.getLength(),
700 ::std::insert_iterator
< ::std::set
< OUString
> >( aNames
, aNames
.end() )
705 void ScriptsStorage::removeScriptTypeStorage( const ScriptType _eType
) const
707 OUString
sSubStorageName( lcl_getScriptsSubStorageName( _eType
) );
708 if ( m_xScriptsStorage
->hasByName( sSubStorageName
) )
709 m_xScriptsStorage
->removeElement( sSubStorageName
);
712 bool ScriptsStorage::removeFromDocument( const Reference
< XModel
>& _rxDocument
, MigrationLog
& _rLogger
)
716 Reference
< XStorageBasedDocument
> xStorageDoc( _rxDocument
, UNO_QUERY_THROW
);
717 Reference
< XStorage
> xDocStorage( xStorageDoc
->getDocumentStorage(), UNO_QUERY_THROW
);
718 xDocStorage
->removeElement( sScriptsStorageName
);
720 catch( const Exception
& )
722 _rLogger
.logFailure( MigrationError(
723 ERR_REMOVE_SCRIPTS_STORAGE_FAILED
,
724 ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument
),
725 ::cppu::getCaughtException()
733 class ProgressDelegator
: public IProgressConsumer
736 ProgressDelegator( IMigrationProgress
& _rDelegator
,
737 const OUString
& _rObjectName
,
738 const OUString
& _rAction
740 :m_rDelegator( _rDelegator
)
741 ,m_sObjectName( _rObjectName
)
742 ,m_sAction( _rAction
)
745 virtual ~ProgressDelegator()
750 virtual void start( sal_uInt32 _nRange
) SAL_OVERRIDE
752 m_rDelegator
.startObject( m_sObjectName
, m_sAction
, _nRange
);
754 virtual void advance( sal_uInt32 _nValue
) SAL_OVERRIDE
756 m_rDelegator
.setObjectProgressValue( _nValue
);
758 virtual void end() SAL_OVERRIDE
760 m_rDelegator
.endObject();
764 IMigrationProgress
& m_rDelegator
;
765 OUString m_sObjectName
;
773 PhaseGuard( ProgressMixer
& _rMixer
)
783 void start( const PhaseID _nID
, const sal_uInt32 _nPhaseRange
)
785 m_rMixer
.startPhase( _nID
, _nPhaseRange
);
789 ProgressMixer
& m_rMixer
;
792 // MigrationEngine_Impl - declaration
793 class MigrationEngine_Impl
796 MigrationEngine_Impl(
797 const Reference
<XComponentContext
>& _rContext
,
798 const Reference
< XOfficeDatabaseDocument
>& _rxDocument
,
799 IMigrationProgress
& _rProgress
,
800 MigrationLog
& _rLogger
802 ~MigrationEngine_Impl();
804 inline size_t getFormCount() const { return m_nFormCount
; }
805 inline size_t getReportCount()const { return m_nReportCount
; }
809 Reference
<XComponentContext
> m_aContext
;
810 const Reference
< XOfficeDatabaseDocument
> m_xDocument
;
811 const Reference
< XModel
> m_xDocumentModel
;
812 IMigrationProgress
& m_rProgress
;
813 MigrationLog
& m_rLogger
;
814 mutable DocumentID m_nCurrentDocumentID
;
815 SubDocuments m_aSubDocs
;
817 size_t m_nReportCount
;
820 /** collects a description of all sub documents of our database document
823 <TRUE/> if and only if collecting the documents was successful
825 bool impl_collectSubDocuments_nothrow();
827 /** migrates the macros/scripts of the given sub document
829 bool impl_handleDocument_nothrow( const SubDocument
& _rDocument
) const;
831 /** checks the structure of the 'Scripts' folder of a sub document
835 <TRUE/> if and only if the 'Scripts' folder contains known elements only.
837 bool impl_checkScriptStorageStructure_nothrow( const SubDocument
& _rDocument
) const;
839 /** migrates the scripts of the given "storage-based" script type
841 bool impl_migrateScriptStorage_nothrow(
842 const SubDocument
& _rDocument
,
843 const ScriptType _eScriptType
,
844 ProgressMixer
& _rProgress
,
845 const PhaseID _nPhaseID
848 /** migrates the content of the given "container based" libraries (Basic/Dialogs)
850 bool impl_migrateContainerLibraries_nothrow(
851 const SubDocument
& _rDocument
,
852 const ScriptType _eScriptType
,
853 ProgressMixer
& _rProgress
,
854 const PhaseID _nPhaseID
857 /** adjusts the events for the given dialog/element, taking into account the new names
858 of the moved libraries
860 void impl_adjustDialogElementEvents_throw(
861 const Reference
< XInterface
>& _rxElement
864 /** adjusts the events in the given dialog, and its controls, taking into account the new names
865 of the moved libraries
867 bool impl_adjustDialogEvents_nothrow(
868 Any
& _inout_rDialogLibraryElement
,
869 const OUString
& _rDocName
,
870 const OUString
& _rDialogLibName
,
871 const OUString
& _rDialogName
874 /** adjust the document-events which refer to macros/scripts in the document, taking into
875 account the new names of the moved libraries
877 bool impl_adjustDocumentEvents_nothrow(
878 const SubDocument
& _rDocument
881 /** adjusts the script references bound to form component events
883 bool impl_adjustFormComponentEvents_nothrow(
884 const SubDocument
& _rDocument
887 /** adjusts the script references for the elements of the given form component container
889 void impl_adjustFormComponentEvents_throw(
890 const Reference
< XIndexAccess
>& _rxComponentContainer
893 /** adjusts the library name in the given script URL, so that it reflects
894 the new name of the library
897 if and only if adjustments to the script code have been made
899 bool impl_adjustScriptLibrary_nothrow(
900 const OUString
& _rScriptType
,
901 OUString
& _inout_rScriptCode
904 bool impl_adjustScriptLibrary_nothrow( Any
& _inout_rScriptDescriptor
) const;
905 bool impl_adjustScriptLibrary_nothrow( ScriptEventDescriptor
& _inout_rScriptEvent
) const;
907 /** asks the user for a password for the given library, and unprotects the library
910 if and only if the library could be successfully unprotected
912 bool impl_unprotectPasswordLibrary_throw(
913 const Reference
< XLibraryContainerPassword
>& _rxPasswordManager
,
914 const ScriptType _eScriptType
,
915 const OUString
& _rLibraryName
919 // MigrationEngine_Impl - implementation
920 MigrationEngine_Impl::MigrationEngine_Impl( const Reference
<XComponentContext
>& _rContext
,
921 const Reference
< XOfficeDatabaseDocument
>& _rxDocument
, IMigrationProgress
& _rProgress
, MigrationLog
& _rLogger
)
922 :m_aContext( _rContext
)
923 ,m_xDocument( _rxDocument
)
924 ,m_xDocumentModel( _rxDocument
, UNO_QUERY_THROW
)
925 ,m_rProgress( _rProgress
)
926 ,m_rLogger( _rLogger
)
927 ,m_nCurrentDocumentID( - 1 )
932 OSL_VERIFY( impl_collectSubDocuments_nothrow() );
935 MigrationEngine_Impl::~MigrationEngine_Impl()
939 bool MigrationEngine_Impl::migrateAll()
941 if ( m_aSubDocs
.empty() )
943 OSL_FAIL( "MigrationEngine_Impl::migrateAll: no forms/reports found!" );
944 // The whole migration wizard is not expected to be called when there are no forms/reports
945 // with macros, not to mention when there are no forms/reports at all.
949 // initialize global progress
950 sal_Int32
nOverallRange( m_aSubDocs
.size() );
951 OUString
sProgressSkeleton(
952 MacroMigrationResId( STR_OVERALL_PROGRESS
).toString().
953 replaceFirst("$overall$", OUString::number(nOverallRange
)));
955 m_rProgress
.start( nOverallRange
);
957 for ( SubDocuments::const_iterator doc
= m_aSubDocs
.begin();
958 doc
!= m_aSubDocs
.end();
962 sal_Int32
nOverallProgressValue( doc
- m_aSubDocs
.begin() + 1 );
963 // update overall progress text
964 OUString
sOverallProgress(
965 sProgressSkeleton
.replaceFirst("$current$",
966 OUString::number(nOverallProgressValue
)));
967 m_rProgress
.setOverallProgressText( sOverallProgress
);
970 if ( !impl_handleDocument_nothrow( *doc
) )
973 // update overall progress vallue
974 m_rProgress
.setOverallProgressValue( nOverallProgressValue
);
977 // commit the root storage of the database document, for all changes made so far to take effect
978 if ( !lcl_commitDocumentStorage_nothrow( m_xDocumentModel
, m_rLogger
) )
982 if ( !lcl_storeDocument_nothrow( m_xDocumentModel
, m_rLogger
) )
990 void lcl_collectHierarchicalElementNames_throw(
991 const Reference
< XNameAccess
>& _rxContainer
, const OUString
& _rContainerLoc
,
992 SubDocuments
& _out_rDocs
, const SubDocumentType _eType
, size_t& _io_counter
)
994 const OUString
sHierarhicalBase(
995 _rContainerLoc
.isEmpty() ? OUString() :
996 OUStringBuffer( _rContainerLoc
).appendAscii( "/" ).makeStringAndClear());
998 Sequence
< OUString
> aElementNames( _rxContainer
->getElementNames() );
999 for ( const OUString
* elementName
= aElementNames
.getConstArray();
1000 elementName
!= aElementNames
.getConstArray() + aElementNames
.getLength();
1004 Any
aElement( _rxContainer
->getByName( *elementName
) );
1005 OUString
sElementName( sHierarhicalBase
+ *elementName
);
1007 Reference
< XNameAccess
> xSubContainer( aElement
, UNO_QUERY
);
1008 if ( xSubContainer
.is() )
1010 lcl_collectHierarchicalElementNames_throw( xSubContainer
, sElementName
, _out_rDocs
, _eType
, _io_counter
);
1014 Reference
< XCommandProcessor
> xCommandProcessor( aElement
, UNO_QUERY
);
1015 OSL_ENSURE( xCommandProcessor
.is(), "lcl_collectHierarchicalElementNames_throw: no container, and no command processor? What *is* it, then?!" );
1016 if ( xCommandProcessor
.is() )
1018 _out_rDocs
.push_back( SubDocument( xCommandProcessor
, sElementName
, _eType
, ++_io_counter
) );
1025 bool MigrationEngine_Impl::impl_collectSubDocuments_nothrow()
1027 OSL_PRECOND( m_xDocument
.is(), "MigrationEngine_Impl::impl_collectSubDocuments_nothrow: invalid document!" );
1028 if ( !m_xDocument
.is() )
1033 Reference
< XNameAccess
> xDocContainer( m_xDocument
->getFormDocuments(), UNO_SET_THROW
);
1035 lcl_collectHierarchicalElementNames_throw( xDocContainer
, OUString(), m_aSubDocs
, eForm
, m_nFormCount
);
1037 xDocContainer
.set( m_xDocument
->getReportDocuments(), UNO_SET_THROW
);
1039 lcl_collectHierarchicalElementNames_throw( xDocContainer
, OUString(), m_aSubDocs
, eReport
, m_nReportCount
);
1041 catch( const Exception
& )
1043 m_rLogger
.logFailure( MigrationError(
1044 ERR_COLLECTING_DOCUMENTS_FAILED
,
1045 ::cppu::getCaughtException()
1052 bool MigrationEngine_Impl::impl_handleDocument_nothrow( const SubDocument
& _rDocument
) const
1054 OSL_ENSURE( m_nCurrentDocumentID
== -1,
1055 "MigrationEngine_Impl::impl_handleDocument_nothrow: there already is a current document!");
1056 m_nCurrentDocumentID
= m_rLogger
.startedDocument( _rDocument
.eType
, _rDocument
.sHierarchicalName
);
1058 // start the progress
1059 OUString
sObjectName( lcl_getSubDocumentDescription( _rDocument
) );
1060 m_rProgress
.startObject( sObjectName
, OUString(), DEFAULT_DOC_PROGRESS_RANGE
);
1062 // load the document
1063 Reference
< ProgressCapture
> pStatusIndicator( new ProgressCapture( sObjectName
, m_rProgress
) );
1064 SubDocument
aSubDocument( _rDocument
);
1065 OpenDocResult eResult
= lcl_loadSubDocument_nothrow( aSubDocument
, pStatusIndicator
.get(), m_rLogger
);
1066 if ( eResult
!= eOpenedDoc
)
1068 pStatusIndicator
->dispose();
1069 m_rProgress
.endObject();
1070 m_rLogger
.finishedDocument( m_nCurrentDocumentID
);
1071 m_nCurrentDocumentID
= -1;
1072 return ( eResult
== eIgnoreDoc
);
1075 // migrate the libraries
1076 ProgressDelegator
aDelegator(m_rProgress
, sObjectName
, MacroMigrationResId(STR_MIGRATING_LIBS
).toString());
1077 ProgressMixer
aProgressMixer( aDelegator
);
1078 aProgressMixer
.registerPhase( PHASE_JAVASCRIPT
, 1 );
1079 aProgressMixer
.registerPhase( PHASE_BEANSHELL
, 1 );
1080 aProgressMixer
.registerPhase( PHASE_PYTHON
, 1 );
1081 aProgressMixer
.registerPhase( PHASE_JAVA
, 1 );
1082 aProgressMixer
.registerPhase( PHASE_BASIC
, 5 );
1083 // more weight than the others, assuming that usually, there are many more Basic macros than any other scripts
1084 aProgressMixer
.registerPhase( PHASE_DIALOGS
, 1 );
1086 bool bSuccess
= impl_checkScriptStorageStructure_nothrow( aSubDocument
);
1088 // migrate storage-based script libraries (which can be handled by mere storage operations)
1090 && impl_migrateScriptStorage_nothrow( aSubDocument
, eJavaScript
, aProgressMixer
, PHASE_JAVASCRIPT
)
1091 && impl_migrateScriptStorage_nothrow( aSubDocument
, eBeanShell
, aProgressMixer
, PHASE_BEANSHELL
)
1092 && impl_migrateScriptStorage_nothrow( aSubDocument
, ePython
, aProgressMixer
, PHASE_PYTHON
)
1093 && impl_migrateScriptStorage_nothrow( aSubDocument
, eJava
, aProgressMixer
, PHASE_JAVA
);
1095 // migrate Basic and dialog libraries
1097 && impl_migrateContainerLibraries_nothrow( aSubDocument
, eBasic
, aProgressMixer
, PHASE_BASIC
)
1098 && impl_migrateContainerLibraries_nothrow( aSubDocument
, eDialog
, aProgressMixer
, PHASE_DIALOGS
);
1099 // order matters: First Basic scripts, then dialogs. So we can adjust references from the latter
1102 // adjust the events in the document
1103 // (note that errors are ignored here - failure to convert a script reference
1104 // is not considered a critical error)
1107 impl_adjustDocumentEvents_nothrow( aSubDocument
);
1108 impl_adjustFormComponentEvents_nothrow( aSubDocument
);
1112 // store the sub document, including removal of the (now obsolete) "Scripts" sub folder
1113 if ( m_rLogger
.movedAnyLibrary( m_nCurrentDocumentID
) )
1116 && ScriptsStorage::removeFromDocument( aSubDocument
.xDocument
, m_rLogger
)
1117 && lcl_commitDocumentStorage_nothrow( aSubDocument
.xDocument
, m_rLogger
)
1118 && lcl_storeEmbeddedDocument_nothrow( aSubDocument
);
1121 // unload in any case, even if we were not successful
1122 bSuccess
= lcl_unloadSubDocument_nothrow( aSubDocument
, m_rLogger
)
1125 pStatusIndicator
->dispose();
1127 // end the progress, just in case the ProgressCapture didn't receive the XStatusIndicator::end event
1128 m_rProgress
.endObject();
1130 m_rLogger
.finishedDocument( m_nCurrentDocumentID
);
1131 m_nCurrentDocumentID
= -1;
1137 static OUString
lcl_createTargetLibName( const SubDocument
& _rDocument
,
1138 const OUString
& _rSourceLibName
, const Reference
< XNameAccess
>& _rxTargetContainer
)
1140 // The new library name is composed from the prefix, the base name, and the old library name.
1141 const OUString sPrefix
= (_rDocument
.eType
== eForm
)?OUString("Form_"): OUString("Report_");
1143 OUString
sBaseName( _rDocument
.sHierarchicalName
.copy(
1144 _rDocument
.sHierarchicalName
.lastIndexOf( '/' ) + 1 ) );
1145 // Normalize this name. In our current storage implementation (and script containers in a document
1146 // are finally mapped to sub storages of the document storage), not all characters are allowed.
1147 // The bug requesting to change this is #i95409#.
1148 // Unfortunately, the storage implementation does not complain if you use invalid characters/names, but instead
1149 // it silently accepts them, and produces garbage in the file (#i95408).
1150 // So, until especially the former is fixed, we need to strip all invalid characters from the name.
1153 // The general idea is to replace invalid characters with '_'. However, since "valid" essentially means
1154 // ASCII only, this implies that for a lot of languages, we would simply replace everything with '_',
1155 // which of course is not desired.
1156 // So, we use a heuristics: If the name contains at most 3 invalid characters, and as many valid as invalid
1157 // characters, then we use the replacement. Otherwise, we just use a unambiguous number for the sub document.
1158 sal_Int32 nValid
=0, nInvalid
=0;
1159 const sal_Unicode
* pBaseName
= sBaseName
.getStr();
1160 const sal_Int32 nBaseNameLen
= sBaseName
.getLength();
1161 for ( sal_Int32 i
=0; i
<nBaseNameLen
; ++i
)
1163 if ( ::comphelper::OStorageHelper::IsValidZipEntryFileName( pBaseName
+ i
, 1, false ) )
1168 if ( ( nInvalid
<= 3 ) && ( nInvalid
* 2 <= nValid
) )
1169 { // not "too many" invalid => replace them
1170 OUStringBuffer aReplacement
;
1171 aReplacement
.ensureCapacity( nBaseNameLen
);
1172 aReplacement
.append( sBaseName
);
1173 const sal_Unicode
* pReplacement
= aReplacement
.getStr();
1174 for ( sal_Int32 i
=0; i
<nBaseNameLen
; ++i
)
1176 if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( pReplacement
+ i
, 1, false ) )
1177 aReplacement
[i
] = '_';
1179 sBaseName
= aReplacement
.makeStringAndClear();
1181 OUString
sTargetName( sPrefix
+ sBaseName
+ "_" + _rSourceLibName
);
1182 if ( !_rxTargetContainer
->hasByName( sTargetName
) )
1186 // "too many" invalid characters, or the name composed with the base name was already used.
1187 // (The latter is valid, since there can be multiple sub documents with the same base name,
1188 // in different levels in the hierarchy.)
1189 // In this case, just use the umambiguous sub document number.
1190 return sPrefix
+ OUString::number( _rDocument
.nNumber
) + "_" + _rSourceLibName
;
1194 bool MigrationEngine_Impl::impl_checkScriptStorageStructure_nothrow( const SubDocument
& _rDocument
) const
1196 OSL_PRECOND( _rDocument
.xDocument
.is(), "MigrationEngine_Impl::impl_checkScriptStorageStructure_nothrow: invalid document!" );
1197 if ( !_rDocument
.xDocument
.is() )
1202 // the root storage of the document whose scripts are to be migrated
1203 ScriptsStorage
aDocStorage( _rDocument
.xDocument
, m_rLogger
);
1204 if ( !aDocStorage
.isValid() )
1205 { // no scripts at all, or no scripts of the given type
1206 return !m_rLogger
.hadFailure();
1208 ::std::set
< OUString
> aElementNames( aDocStorage
.getElementNames() );
1210 ScriptType aKnownStorageBasedTypes
[] = {
1211 eBeanShell
, eJavaScript
, ePython
, eJava
1213 for ( size_t i
=0; i
<sizeof( aKnownStorageBasedTypes
) / sizeof( aKnownStorageBasedTypes
[0] ); ++i
)
1214 aElementNames
.erase( lcl_getScriptsSubStorageName( aKnownStorageBasedTypes
[i
] ) );
1216 if ( !aElementNames
.empty() )
1218 m_rLogger
.logFailure( MigrationError(
1219 ERR_UNKNOWN_SCRIPT_FOLDER
,
1220 lcl_getSubDocumentDescription( _rDocument
),
1221 *aElementNames
.begin()
1226 catch( const Exception
& )
1228 m_rLogger
.logFailure( MigrationError(
1229 ERR_EXAMINING_SCRIPTS_FOLDER_FAILED
,
1230 lcl_getSubDocumentDescription( _rDocument
),
1231 ::cppu::getCaughtException()
1238 bool MigrationEngine_Impl::impl_migrateScriptStorage_nothrow( const SubDocument
& _rDocument
,
1239 const ScriptType _eScriptType
, ProgressMixer
& _rProgress
, const PhaseID _nPhaseID
) const
1241 OSL_PRECOND( _rDocument
.xDocument
.is(), "MigrationEngine_Impl::impl_migrateScriptStorage_nothrow: invalid document!" );
1242 if ( !_rDocument
.xDocument
.is() )
1245 ScriptsStorage
aDatabaseScripts( m_rLogger
);
1246 // the scripts of our complete database document - created on demand only
1247 SharedStorage xTargetStorage
;
1248 // the target for moving the scripts storages - created on demand only
1250 PhaseGuard
aPhase( _rProgress
);
1251 bool bSuccess
= false;
1255 // the root storage of the document whose scripts are to be migrated
1256 ScriptsStorage
aDocStorage( _rDocument
.xDocument
, m_rLogger
);
1257 if ( !aDocStorage
.isValid()
1258 || !aDocStorage
.hasScripts( _eScriptType
)
1261 // no scripts at all, or no scripts of the given type
1262 _rProgress
.startPhase( _nPhaseID
, 1 );
1263 _rProgress
.endPhase();
1264 return !m_rLogger
.hadFailure();
1267 SharedStorage
xScriptsRoot( aDocStorage
.getScriptsRoot( _eScriptType
) );
1268 if ( !xScriptsRoot
.is() )
1269 throw RuntimeException("internal error");
1271 // loop through the script libraries
1272 Sequence
< OUString
> aStorageElements( xScriptsRoot
->getElementNames() );
1273 aPhase
.start( _nPhaseID
, aStorageElements
.getLength() );
1275 for ( const OUString
* element
= aStorageElements
.getConstArray();
1276 element
!= aStorageElements
.getConstArray() + aStorageElements
.getLength();
1280 bool bIsScriptLibrary
= xScriptsRoot
->isStorageElement( *element
);
1281 OSL_ENSURE( bIsScriptLibrary
,
1282 "MigrationEngine_Impl::impl_migrateScriptStorage_nothrow: warning: unknown scripts storage structure!" );
1283 // we cannot handle this. We would need to copy this stream to the respective scripts storage
1284 // of the database document, but we cannot guarantee that the name is not used, yet, and we cannot
1285 // simply rename the thing.
1286 if ( !bIsScriptLibrary
)
1288 m_rLogger
.logFailure( MigrationError(
1289 ERR_UNEXPECTED_LIBSTORAGE_ELEMENT
,
1290 lcl_getSubDocumentDescription( _rDocument
),
1291 getScriptTypeDisplayName( _eScriptType
),
1297 // ensure we have access to the DBDoc's scripts storage
1298 if ( !aDatabaseScripts
.isValid() )
1299 { // not needed 'til now
1300 aDatabaseScripts
.bind( m_xDocumentModel
);
1301 if ( aDatabaseScripts
.isValid() )
1302 xTargetStorage
= aDatabaseScripts
.getScriptsRoot( _eScriptType
);
1304 if ( !xTargetStorage
.is() )
1306 m_rLogger
.logFailure( MigrationError(
1307 ERR_CREATING_DBDOC_SCRIPT_STORAGE_FAILED
,
1308 getScriptTypeDisplayName( _eScriptType
)
1314 // move the library to the DBDoc's scripts library, under the new name
1315 OUString
sNewLibName( lcl_createTargetLibName( _rDocument
, *element
, xTargetStorage
.getTyped().get() ) );
1316 xScriptsRoot
->moveElementTo( *element
, xTargetStorage
, sNewLibName
);
1318 // log the fact that we moved the library
1319 m_rLogger
.movedLibrary( m_nCurrentDocumentID
, _eScriptType
, *element
, sNewLibName
);
1322 _rProgress
.advancePhase( element
- aStorageElements
.getConstArray() );
1325 // commit the storages, so the changes we made persist
1326 if ( !lcl_commitStorage_nothrow( xScriptsRoot
)
1327 || ( xTargetStorage
.is() && !lcl_commitStorage_nothrow( xTargetStorage
) )
1330 m_rLogger
.logFailure( MigrationError(
1331 ERR_COMMITTING_SCRIPT_STORAGES_FAILED
,
1332 getScriptTypeDisplayName( _eScriptType
),
1333 lcl_getSubDocumentDescription( _rDocument
)
1338 // now that the concrete scripts storage does not have any elements anymore,
1340 xScriptsRoot
.reset( NULL
); // need to reset the storage to be allowed to remove it
1341 aDocStorage
.removeScriptTypeStorage( _eScriptType
);
1344 bSuccess
= aDocStorage
.commit()
1345 && aDatabaseScripts
.commit();
1347 catch( const Exception
& )
1349 aException
= ::cppu::getCaughtException();
1353 // log the error, if any
1356 m_rLogger
.logFailure( MigrationError(
1357 ERR_GENERAL_SCRIPT_MIGRATION_FAILURE
,
1358 getScriptTypeDisplayName( _eScriptType
),
1359 lcl_getSubDocumentDescription( _rDocument
),
1367 bool MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow( const SubDocument
& _rDocument
,
1368 const ScriptType _eScriptType
, ProgressMixer
& _rProgress
, const PhaseID _nPhaseID
) const
1370 OSL_PRECOND( ( _eScriptType
== eBasic
) || ( _eScriptType
== eDialog
),
1371 "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: illegal script type!" );
1373 bool bSuccess
= false;
1374 PhaseGuard
aPhase( _rProgress
);
1376 do // artificial loop for flow control only
1380 // access library container of the sub document
1381 Reference
< XEmbeddedScripts
> xSubDocScripts( _rDocument
.xDocument
, UNO_QUERY
);
1382 if ( !xSubDocScripts
.is() )
1383 { // no script support in the sub document -> nothing to migrate
1384 // (though ... this is suspicious, at least ...)
1389 Reference
< XStorageBasedLibraryContainer
> xSourceLibraries(
1390 _eScriptType
== eBasic
? xSubDocScripts
->getBasicLibraries() : xSubDocScripts
->getDialogLibraries(),
1393 Reference
< XLibraryContainerPassword
> xSourcePasswords( xSourceLibraries
, UNO_QUERY
);
1394 OSL_ENSURE( xSourcePasswords
.is(),
1395 "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: suspicious: no password management for the source libraries!" );
1397 Sequence
< OUString
> aSourceLibNames( xSourceLibraries
->getElementNames() );
1398 aPhase
.start( _nPhaseID
, aSourceLibNames
.getLength() );
1400 if ( !xSourceLibraries
->hasElements() )
1406 // create library containers for the document - those will be the target for the migration
1407 Reference
< XStorageBasedDocument
> xStorageDoc( m_xDocument
, UNO_QUERY_THROW
);
1408 Reference
< XStorageBasedLibraryContainer
> xTargetLibraries
;
1409 if ( _eScriptType
== eBasic
)
1411 xTargetLibraries
.set( DocumentScriptLibraryContainer::create(
1412 m_aContext
, xStorageDoc
), UNO_QUERY_THROW
);
1416 xTargetLibraries
.set( DocumentDialogLibraryContainer::create(
1417 m_aContext
, xStorageDoc
), UNO_QUERY_THROW
);
1420 // copy all libs to the target, with potentially renaming them
1421 const OUString
* pSourceLibBegin
= aSourceLibNames
.getConstArray();
1422 const OUString
* pSourceLibEnd
= pSourceLibBegin
+ aSourceLibNames
.getLength();
1423 for ( const OUString
* pSourceLibName
= pSourceLibBegin
;
1424 pSourceLibName
!= pSourceLibEnd
;
1428 // if the library is password-protected, ask the user to unprotect it
1429 if ( xSourcePasswords
.is()
1430 && xSourcePasswords
->isLibraryPasswordProtected( *pSourceLibName
)
1431 && !xSourcePasswords
->isLibraryPasswordVerified( *pSourceLibName
)
1434 if ( !impl_unprotectPasswordLibrary_throw( xSourcePasswords
, _eScriptType
, *pSourceLibName
) )
1436 m_rLogger
.logFailure( MigrationError(
1437 ERR_PASSWORD_VERIFICATION_FAILED
,
1438 _rDocument
.sHierarchicalName
,
1439 getScriptTypeDisplayName( _eScriptType
),
1446 OUString
sNewLibName( lcl_createTargetLibName( _rDocument
, *pSourceLibName
, xTargetLibraries
.get() ) );
1448 if ( xSourceLibraries
->isLibraryLink( *pSourceLibName
) )
1450 // just re-create the link in the target library
1451 xTargetLibraries
->createLibraryLink(
1453 xSourceLibraries
->getLibraryLinkURL( *pSourceLibName
),
1454 xSourceLibraries
->isLibraryReadOnly( *pSourceLibName
)
1459 if ( !xSourceLibraries
->isLibraryLoaded( *pSourceLibName
) )
1460 xSourceLibraries
->loadLibrary( *pSourceLibName
);
1462 // copy the content of this particular library
1463 Reference
< XNameAccess
> xSourceLib( xSourceLibraries
->getByName( *pSourceLibName
), UNO_QUERY_THROW
);
1464 Reference
< XNameContainer
> xTargetLib( xTargetLibraries
->createLibrary( sNewLibName
), UNO_QUERY_THROW
);
1466 Sequence
< OUString
> aLibElementNames( xSourceLib
->getElementNames() );
1467 for ( const OUString
* pSourceElementName
= aLibElementNames
.getConstArray();
1468 pSourceElementName
!= aLibElementNames
.getConstArray() + aLibElementNames
.getLength();
1469 ++pSourceElementName
1472 Any aElement
= xSourceLib
->getByName( *pSourceElementName
);
1473 OSL_ENSURE( aElement
.hasValue(),
1474 "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: invalid (empty) lib element!" );
1476 // if this is a dialog, adjust the references to scripts
1477 if ( _eScriptType
== eDialog
)
1479 impl_adjustDialogEvents_nothrow( aElement
, lcl_getSubDocumentDescription( _rDocument
),
1480 *pSourceLibName
, *pSourceElementName
);
1483 xTargetLib
->insertByName( *pSourceElementName
, aElement
);
1486 // transfer the read-only flag
1487 xTargetLibraries
->setLibraryReadOnly(
1488 sNewLibName
, xSourceLibraries
->isLibraryReadOnly( *pSourceLibName
) );
1491 // remove the source lib
1492 xSourceLibraries
->removeLibrary( *pSourceLibName
);
1495 m_rLogger
.movedLibrary( m_nCurrentDocumentID
, _eScriptType
, *pSourceLibName
, sNewLibName
);
1497 // tell the progress
1498 _rProgress
.advancePhase( pSourceLibName
- pSourceLibBegin
);
1502 xSourceLibraries
->storeLibraries();
1504 xTargetLibraries
->storeLibraries();
1505 Reference
< XStorage
> xTargetRoot( xTargetLibraries
->getRootLocation(), UNO_QUERY_THROW
);
1506 bSuccess
= lcl_commitStorage_nothrow( xTargetRoot
);
1508 catch( const Exception
& )
1510 aException
= ::cppu::getCaughtException();
1515 // log the error, if any
1518 m_rLogger
.logFailure( MigrationError(
1519 ERR_GENERAL_MACRO_MIGRATION_FAILURE
,
1520 lcl_getSubDocumentDescription( _rDocument
),
1528 bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( const OUString
& _rScriptType
,
1529 OUString
& _inout_rScriptCode
) const
1531 OSL_PRECOND( !_inout_rScriptCode
.isEmpty(), "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: invalid script!" );
1532 if ( _inout_rScriptCode
.isEmpty() )
1535 bool bSuccess
= false;
1539 if ( _rScriptType
!= "Script" || _rScriptType
.isEmpty() )
1542 "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: no or unknown script type!" );
1543 m_rLogger
.logRecoverable( MigrationError(
1544 ERR_UNKNOWN_SCRIPT_TYPE
,
1550 // analyze the script URI
1551 Reference
< XUriReferenceFactory
> xUriRefFac
= UriReferenceFactory::create( m_aContext
);
1552 Reference
< XVndSunStarScriptUrlReference
> xUri( xUriRefFac
->parse( _inout_rScriptCode
), UNO_QUERY_THROW
);
1554 OUString sScriptLanguage
= xUri
->getParameter( OUString( "language" ) );
1555 ScriptType eScriptType
= eBasic
;
1556 if ( !lcl_getScriptTypeFromLanguage( sScriptLanguage
, eScriptType
) )
1559 "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: unknown script language!" );
1560 m_rLogger
.logRecoverable( MigrationError(
1561 ERR_UNKNOWN_SCRIPT_LANGUAGE
,
1567 OUString sLocation
= xUri
->getParameter( OUString( "location" ) );
1568 if ( sLocation
!= "document" )
1570 // only document libraries must be migrated, of course
1574 OUString sScriptName
= xUri
->getName();
1575 sal_Int32 nLibModuleSeparator
= sScriptName
.indexOf( '.' );
1576 if ( nLibModuleSeparator
< 0 )
1579 "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: invalid/unknown location format!" );
1580 m_rLogger
.logRecoverable( MigrationError(
1581 ERR_UNKNOWN_SCRIPT_NAME_FORMAT
,
1587 // replace the library name
1588 OUString sLibrary
= sScriptName
.copy( 0, nLibModuleSeparator
);
1589 OUString sNewLibName
= m_rLogger
.getNewLibraryName(
1590 m_nCurrentDocumentID
, eScriptType
, sLibrary
);
1591 OSL_ENSURE( sLibrary
!= sNewLibName
,
1592 "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: a library which has not been migrated?" );
1594 xUri
->setName( sNewLibName
+ sScriptName
.copy( nLibModuleSeparator
) );
1596 // update the new script URL
1597 _inout_rScriptCode
= xUri
->getUriReference();
1600 catch( const Exception
& )
1602 aException
= ::cppu::getCaughtException();
1606 // log the failure, if any
1609 m_rLogger
.logRecoverable( MigrationError(
1610 ERR_SCRIPT_TRANSLATION_FAILURE
,
1620 bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( ScriptEventDescriptor
& _inout_rScriptEvent
) const
1622 if ( !(_inout_rScriptEvent
.ScriptType
.isEmpty() || _inout_rScriptEvent
.ScriptCode
.isEmpty()) )
1623 return impl_adjustScriptLibrary_nothrow( _inout_rScriptEvent
.ScriptType
, _inout_rScriptEvent
.ScriptCode
);
1627 bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( Any
& _inout_rScriptDescriptor
) const
1629 ::comphelper::NamedValueCollection
aScriptDesc( _inout_rScriptDescriptor
);
1631 OUString sScriptType
;
1635 OSL_VERIFY( aScriptDesc
.get_ensureType( "EventType", sScriptType
) );
1636 OSL_VERIFY( aScriptDesc
.get_ensureType( "Script", sScript
) );
1638 catch( const Exception
& )
1640 m_rLogger
.logRecoverable( MigrationError(
1641 ERR_INVALID_SCRIPT_DESCRIPTOR_FORMAT
,
1642 ::cppu::getCaughtException()
1646 if ( !(sScriptType
.isEmpty() || sScript
.isEmpty()) )
1647 if ( !impl_adjustScriptLibrary_nothrow( sScriptType
, sScript
) )
1650 aScriptDesc
.put( "Script", sScript
);
1651 _inout_rScriptDescriptor
<<= aScriptDesc
.getPropertyValues();
1655 bool MigrationEngine_Impl::impl_adjustDocumentEvents_nothrow( const SubDocument
& _rDocument
) const
1659 Reference
< XEventsSupplier
> xSuppEvents( _rDocument
.xDocument
, UNO_QUERY
);
1660 if ( !xSuppEvents
.is() )
1661 // this is allowed. E.g. new-style reports currently do not support this
1664 Reference
< XNameReplace
> xEvents( xSuppEvents
->getEvents(), UNO_SET_THROW
);
1665 Sequence
< OUString
> aEventNames
= xEvents
->getElementNames();
1668 for ( const OUString
* eventName
= aEventNames
.getConstArray();
1669 eventName
!= aEventNames
.getConstArray() + aEventNames
.getLength();
1673 aEvent
= xEvents
->getByName( *eventName
);
1674 if ( !aEvent
.hasValue() )
1678 if ( !impl_adjustScriptLibrary_nothrow( aEvent
) )
1682 xEvents
->replaceByName( *eventName
, aEvent
);
1685 catch( const Exception
& )
1687 m_rLogger
.logRecoverable( MigrationError(
1688 ERR_ADJUSTING_DOCUMENT_EVENTS_FAILED
,
1689 lcl_getSubDocumentDescription( _rDocument
),
1690 ::cppu::getCaughtException()
1697 void MigrationEngine_Impl::impl_adjustDialogElementEvents_throw( const Reference
< XInterface
>& _rxElement
) const
1699 Reference
< XScriptEventsSupplier
> xEventsSupplier( _rxElement
, UNO_QUERY_THROW
);
1700 Reference
< XNameReplace
> xEvents( xEventsSupplier
->getEvents(), UNO_QUERY_THROW
);
1701 Sequence
< OUString
> aEventNames( xEvents
->getElementNames() );
1703 const OUString
* eventName
= aEventNames
.getArray();
1704 const OUString
* eventNamesEnd
= eventName
+ aEventNames
.getLength();
1706 ScriptEventDescriptor aScriptEvent
;
1707 for ( ; eventName
!= eventNamesEnd
; ++eventName
)
1709 OSL_VERIFY( xEvents
->getByName( *eventName
) >>= aScriptEvent
);
1711 if ( !impl_adjustScriptLibrary_nothrow( aScriptEvent
) )
1714 xEvents
->replaceByName( *eventName
, makeAny( aScriptEvent
) );
1718 bool MigrationEngine_Impl::impl_adjustDialogEvents_nothrow( Any
& _inout_rDialogLibraryElement
,
1719 const OUString
& _rDocName
, const OUString
& _rDialogLibName
, const OUString
& _rDialogName
) const
1723 // load a dialog model from the stream describing it
1724 Reference
< XInputStreamProvider
> xISP( _inout_rDialogLibraryElement
, UNO_QUERY_THROW
);
1725 Reference
< XInputStream
> xInput( xISP
->createInputStream(), UNO_QUERY_THROW
);
1727 Reference
< XNameContainer
> xDialogModel( m_aContext
->getServiceManager()->createInstanceWithContext("com.sun.star.awt.UnoControlDialogModel", m_aContext
), UNO_QUERY_THROW
);
1728 ::xmlscript::importDialogModel( xInput
, xDialogModel
, m_aContext
, m_xDocumentModel
);
1730 // adjust the events of the dialog
1731 impl_adjustDialogElementEvents_throw( xDialogModel
);
1733 // adjust the events of the controls
1734 Sequence
< OUString
> aControlNames( xDialogModel
->getElementNames() );
1735 const OUString
* controlName
= aControlNames
.getConstArray();
1736 const OUString
* controlNamesEnd
= controlName
+ aControlNames
.getLength();
1737 for ( ; controlName
!= controlNamesEnd
; ++controlName
)
1739 impl_adjustDialogElementEvents_throw( Reference
< XInterface
>( xDialogModel
->getByName( *controlName
), UNO_QUERY
) );
1742 // export dialog model
1743 xISP
= ::xmlscript::exportDialogModel( xDialogModel
, m_aContext
, m_xDocumentModel
);
1744 _inout_rDialogLibraryElement
<<= xISP
;
1746 catch( const Exception
& )
1748 m_rLogger
.logRecoverable( MigrationError(
1749 ERR_ADJUSTING_DIALOG_EVENTS_FAILED
,
1753 ::cppu::getCaughtException()
1760 void MigrationEngine_Impl::impl_adjustFormComponentEvents_throw( const Reference
< XIndexAccess
>& _rxComponentContainer
) const
1762 FormComponentIterator
aCompIter( _rxComponentContainer
);
1763 while ( aCompIter
.hasMore() )
1765 // 1. adjust the component's scripts of the current component
1766 FormComponentScripts
aComponent( aCompIter
.next() );
1767 Sequence
< ScriptEventDescriptor
> aEvents( aComponent
.getEvents() );
1769 bool bChangedComponentEvents
= false;
1770 for ( ScriptEventDescriptor
* scriptEvent
= aEvents
.getArray();
1771 scriptEvent
!= aEvents
.getArray() + aEvents
.getLength();
1775 if ( !impl_adjustScriptLibrary_nothrow( *scriptEvent
) )
1778 bChangedComponentEvents
= true;
1781 if ( bChangedComponentEvents
)
1782 aComponent
.setEvents( aEvents
);
1784 // 2. step down if the component is a container itself
1785 Reference
< XIndexAccess
> xContainer( aComponent
.getComponent(), UNO_QUERY
);
1786 if ( xContainer
.is() )
1787 impl_adjustFormComponentEvents_throw( xContainer
);
1791 bool MigrationEngine_Impl::impl_adjustFormComponentEvents_nothrow( const SubDocument
& _rDocument
) const
1795 DrawPageIterator
aPageIter( _rDocument
.xDocument
);
1796 while ( aPageIter
.hasMore() )
1798 Reference
< XFormsSupplier
> xSuppForms( aPageIter
.next(), UNO_QUERY_THROW
);
1799 Reference
< XIndexAccess
> xForms( xSuppForms
->getForms(), UNO_QUERY_THROW
);
1800 impl_adjustFormComponentEvents_throw( xForms
);
1803 catch( const Exception
& )
1805 m_rLogger
.logRecoverable( MigrationError(
1806 ERR_ADJUSTING_FORMCOMP_EVENTS_FAILED
,
1807 lcl_getSubDocumentDescription( _rDocument
),
1808 ::cppu::getCaughtException()
1815 bool MigrationEngine_Impl::impl_unprotectPasswordLibrary_throw( const Reference
< XLibraryContainerPassword
>& _rxPasswordManager
,
1816 const ScriptType _eScriptType
, const OUString
& _rLibraryName
) const
1818 // a human-readable description of the affected library
1819 OUString
sLibraryDescription(
1820 MacroMigrationResId(STR_LIBRARY_TYPE_AND_NAME
).toString().
1821 replaceFirst("$type$",
1822 getScriptTypeDisplayName(_eScriptType
)).
1823 replaceFirst("$library$", _rLibraryName
));
1824 //TODO: probably broken if first replaceFirst can produce
1825 // fresh instance of "$library$" in subject string of second
1828 InteractionHandler
aHandler( m_aContext
, m_xDocumentModel
);
1832 if ( !aHandler
.requestDocumentPassword( sLibraryDescription
, sPassword
) )
1833 // aborted by the user
1836 bool bSuccessVerification
= _rxPasswordManager
->verifyLibraryPassword( _rLibraryName
, sPassword
);
1837 if ( bSuccessVerification
)
1844 MigrationEngine::MigrationEngine( const Reference
<XComponentContext
>& _rContext
,
1845 const Reference
< XOfficeDatabaseDocument
>& _rxDocument
, IMigrationProgress
& _rProgress
,
1846 MigrationLog
& _rLogger
)
1847 :m_pImpl( new MigrationEngine_Impl( _rContext
, _rxDocument
, _rProgress
, _rLogger
) )
1851 MigrationEngine::~MigrationEngine()
1855 sal_Int32
MigrationEngine::getFormCount() const
1857 return m_pImpl
->getFormCount();
1860 sal_Int32
MigrationEngine::getReportCount() const
1862 return m_pImpl
->getReportCount();
1865 bool MigrationEngine::migrateAll()
1867 return m_pImpl
->migrateAll();
1872 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */