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/frame/XModel.hpp>
32 #include <com/sun/star/ucb/XCommandProcessor.hpp>
33 #include <com/sun/star/ucb/XContent.hpp>
34 #include <com/sun/star/embed/ElementModes.hpp>
35 #include <com/sun/star/document/XStorageBasedDocument.hpp>
36 #include <com/sun/star/embed/XTransactedObject.hpp>
37 #include <com/sun/star/frame/XStorable.hpp>
38 #include <com/sun/star/script/DocumentScriptLibraryContainer.hpp>
39 #include <com/sun/star/script/DocumentDialogLibraryContainer.hpp>
40 #include <com/sun/star/document/XEmbeddedScripts.hpp>
41 #include <com/sun/star/document/XEventsSupplier.hpp>
42 #include <com/sun/star/uri/UriReferenceFactory.hpp>
43 #include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp>
44 #include <com/sun/star/form/XFormsSupplier.hpp>
45 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
46 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
47 #include <com/sun/star/script/XEventAttacherManager.hpp>
48 #include <com/sun/star/script/XLibraryContainerPassword.hpp>
49 #include <com/sun/star/io/WrongFormatException.hpp>
50 #include <com/sun/star/script/XScriptEventsSupplier.hpp>
51 #include <com/sun/star/io/XInputStreamProvider.hpp>
53 #include <comphelper/documentinfo.hxx>
54 #include <comphelper/interaction.hxx>
55 #include <comphelper/namedvaluecollection.hxx>
56 #include <comphelper/storagehelper.hxx>
57 #include <comphelper/types.hxx>
58 #include <cppuhelper/exc_hlp.hxx>
59 #include <tools/diagnose_ex.h>
60 #include <rtl/ustrbuf.hxx>
61 #include <rtl/ref.hxx>
62 #include <unotools/sharedunocomponent.hxx>
63 #include <xmlscript/xmldlg_imexp.hxx>
69 #define DEFAULT_DOC_PROGRESS_RANGE 100000
74 using ::com::sun::star::uno::Reference
;
75 using ::com::sun::star::uno::XInterface
;
76 using ::com::sun::star::uno::UNO_QUERY
;
77 using ::com::sun::star::uno::UNO_QUERY_THROW
;
78 using ::com::sun::star::uno::UNO_SET_THROW
;
79 using ::com::sun::star::uno::Exception
;
80 using ::com::sun::star::uno::RuntimeException
;
81 using ::com::sun::star::uno::Any
;
82 using ::com::sun::star::uno::makeAny
;
83 using ::com::sun::star::uno::XComponentContext
;
84 using ::com::sun::star::sdb::XOfficeDatabaseDocument
;
85 using ::com::sun::star::container::XNameAccess
;
86 using ::com::sun::star::uno::Sequence
;
87 using ::com::sun::star::lang::XComponent
;
88 using ::com::sun::star::frame::XModel
;
89 using ::com::sun::star::ucb::XCommandProcessor
;
90 using ::com::sun::star::ucb::XContent
;
91 using ::com::sun::star::ucb::Command
;
92 using ::com::sun::star::task::XStatusIndicator
;
93 using ::com::sun::star::embed::XStorage
;
94 using ::com::sun::star::document::XStorageBasedDocument
;
95 using ::com::sun::star::embed::XTransactedObject
;
96 using ::com::sun::star::frame::XStorable
;
97 using ::com::sun::star::script::DocumentDialogLibraryContainer
;
98 using ::com::sun::star::script::DocumentScriptLibraryContainer
;
99 using ::com::sun::star::script::XStorageBasedLibraryContainer
;
100 using ::com::sun::star::document::XEmbeddedScripts
;
101 using ::com::sun::star::container::XNameContainer
;
102 using ::com::sun::star::document::XEventsSupplier
;
103 using ::com::sun::star::container::XNameReplace
;
104 using com::sun::star::uri::UriReferenceFactory
;
105 using com::sun::star::uri::XUriReferenceFactory
;
106 using com::sun::star::uri::XVndSunStarScriptUrlReference
;
107 using ::com::sun::star::form::XFormsSupplier
;
108 using ::com::sun::star::drawing::XDrawPageSupplier
;
109 using ::com::sun::star::drawing::XDrawPagesSupplier
;
110 using ::com::sun::star::drawing::XDrawPage
;
111 using ::com::sun::star::drawing::XDrawPages
;
112 using ::com::sun::star::container::XIndexAccess
;
113 using ::com::sun::star::script::XEventAttacherManager
;
114 using ::com::sun::star::script::ScriptEventDescriptor
;
115 using ::com::sun::star::script::XLibraryContainerPassword
;
116 using ::com::sun::star::io::WrongFormatException
;
117 using ::com::sun::star::script::XScriptEventsSupplier
;
118 using ::com::sun::star::io::XInputStreamProvider
;
119 using ::com::sun::star::io::XInputStream
;
121 namespace ElementModes
= ::com::sun::star::embed::ElementModes
;
123 // migration phases whose progresses are to be mixed into one progress
124 #define PHASE_JAVASCRIPT 1
125 #define PHASE_BEANSHELL 2
126 #define PHASE_PYTHON 3
128 #define PHASE_BASIC 5
129 #define PHASE_DIALOGS 6
134 Reference
< XCommandProcessor
> xCommandProcessor
;
135 Reference
< XModel
> xDocument
; // valid only temporarily
136 OUString sHierarchicalName
;
137 SubDocumentType eType
;
140 SubDocument( const Reference
< XCommandProcessor
>& _rxCommandProcessor
, const OUString
& _rName
,
141 const SubDocumentType _eType
, const size_t _nNumber
)
142 :xCommandProcessor( _rxCommandProcessor
)
144 ,sHierarchicalName( _rName
)
151 typedef ::std::vector
< SubDocument
> SubDocuments
;
154 typedef ::utl::SharedUNOComponent
< XStorage
> SharedStorage
;
158 static const char sScriptsStorageName
[] = "Scripts";
160 OUString
lcl_getScriptsSubStorageName( const ScriptType _eType
)
164 case eBeanShell
: return OUString("beanshell");
165 case eJavaScript
: return OUString("javascript");
166 case ePython
: return OUString("python"); // TODO: is this correct?
167 case eJava
: return OUString("java");
172 OSL_FAIL( "lcl_getScriptsSubStorageName: illegal type!" );
176 bool lcl_getScriptTypeFromLanguage( const OUString
& _rLanguage
, ScriptType
& _out_rScriptType
)
178 struct LanguageMapping
180 const char* pAsciiLanguage
;
181 const ScriptType eScriptType
;
183 LanguageMapping( const char* _pAsciiLanguage
, const ScriptType _eScriptType
)
184 :pAsciiLanguage( _pAsciiLanguage
)
185 ,eScriptType( _eScriptType
)
189 const LanguageMapping aLanguageMapping
[] =
191 LanguageMapping( "JavaScript", eJavaScript
),
192 LanguageMapping( "BeanShell", eBeanShell
),
193 LanguageMapping( "Java", eJava
),
194 LanguageMapping( "Python", ePython
), // TODO: is this correct?
195 LanguageMapping( "Basic", eBasic
)
197 for (const LanguageMapping
& i
: aLanguageMapping
)
199 if ( _rLanguage
.equalsAscii( i
.pAsciiLanguage
) )
201 _out_rScriptType
= i
.eScriptType
;
205 OSL_FAIL( "lcl_getScriptTypeFromLanguage: unknown language!" );
209 OUString
lcl_getSubDocumentDescription( const SubDocument
& _rDocument
)
211 OUString
sObjectName(
213 _rDocument
.eType
== eForm
? STR_FORM
: STR_REPORT
).toString().
214 replaceFirst("$name$", _rDocument
.sHierarchicalName
));
218 Any
lcl_executeCommand_throw( const Reference
< XCommandProcessor
>& _rxCommandProc
,
219 const sal_Char
* _pAsciiCommand
)
221 OSL_PRECOND( _rxCommandProc
.is(), "lcl_executeCommand_throw: illegal object!" );
222 if ( !_rxCommandProc
.is() )
226 aCommand
.Name
= OUString::createFromAscii( _pAsciiCommand
);
227 return _rxCommandProc
->execute(
228 aCommand
, _rxCommandProc
->createCommandIdentifier(), nullptr );
231 OUString
lcl_getMimeType_nothrow( const Reference
< XCommandProcessor
>& _rxContent
)
236 Reference
< XContent
> xContent( _rxContent
, UNO_QUERY_THROW
);
237 sMimeType
= xContent
->getContentType();
239 catch( const Exception
& )
241 DBG_UNHANDLED_EXCEPTION();
253 OpenDocResult
lcl_loadSubDocument_nothrow( SubDocument
& _rDocument
,
254 const Reference
< XStatusIndicator
>& _rxProgress
, MigrationLog
& _rLogger
)
256 OSL_PRECOND( !_rDocument
.xDocument
.is(), "lcl_loadSubDocument_nothrow: already loaded!" );
260 ::comphelper::NamedValueCollection aLoadArgs
;
261 aLoadArgs
.put( "Hidden", true );
262 aLoadArgs
.put( "StatusIndicator", _rxProgress
);
264 Reference
< XCommandProcessor
> xCommandProcessor( _rDocument
.xCommandProcessor
, UNO_SET_THROW
);
266 aCommand
.Name
= "openDesign";
267 aCommand
.Argument
<<= aLoadArgs
.getPropertyValues();
268 Reference
< XComponent
> xDocComponent(
269 xCommandProcessor
->execute(
270 aCommand
, xCommandProcessor
->createCommandIdentifier(), nullptr
274 OSL_ENSURE( xDocComponent
.is(), "lcl_loadSubDocument_nothrow: no component loaded!" );
276 _rDocument
.xDocument
.set( xDocComponent
, UNO_QUERY_THROW
);
278 catch( const Exception
& )
280 Any
aError( ::cppu::getCaughtException() );
282 bool bCausedByNewStyleReport
=
283 ( _rDocument
.eType
== eReport
)
284 && ( aError
.isExtractableTo( ::cppu::UnoType
< WrongFormatException
>::get() ) )
285 && ( lcl_getMimeType_nothrow( _rDocument
.xCommandProcessor
) == "application/vnd.sun.xml.report" );
287 if ( bCausedByNewStyleReport
)
289 _rLogger
.logRecoverable( MigrationError(
290 ERR_NEW_STYLE_REPORT
,
291 lcl_getSubDocumentDescription( _rDocument
)
297 _rLogger
.logFailure( MigrationError(
298 ERR_OPENING_SUB_DOCUMENT_FAILED
,
299 lcl_getSubDocumentDescription( _rDocument
),
304 return _rDocument
.xDocument
.is() ? eOpenedDoc
: eFailure
;
307 bool lcl_unloadSubDocument_nothrow( SubDocument
& _rDocument
, MigrationLog
& _rLogger
)
309 bool bSuccess
= false;
313 OSL_VERIFY( lcl_executeCommand_throw( _rDocument
.xCommandProcessor
, "close" ) >>= bSuccess
);
315 catch( const Exception
& )
317 aException
= ::cppu::getCaughtException();
320 // log the failure, if any
323 _rLogger
.logFailure( MigrationError(
324 ERR_CLOSING_SUB_DOCUMENT_FAILED
,
325 lcl_getSubDocumentDescription( _rDocument
),
330 _rDocument
.xDocument
.clear();
334 bool lcl_commitStorage_nothrow( const Reference
< XStorage
>& _rxStorage
)
338 Reference
< XTransactedObject
> xTrans( _rxStorage
, UNO_QUERY_THROW
);
341 catch( const Exception
& )
348 bool lcl_commitDocumentStorage_nothrow( const Reference
< XModel
>& _rxDocument
, MigrationLog
& _rLogger
)
350 bool bSuccess
= false;
354 Reference
< XStorageBasedDocument
> xStorageDoc( _rxDocument
, UNO_QUERY_THROW
);
355 Reference
< XStorage
> xDocStorage( xStorageDoc
->getDocumentStorage(), UNO_QUERY_THROW
);
356 bSuccess
= lcl_commitStorage_nothrow( xDocStorage
);
358 catch( const Exception
& )
360 aException
= ::cppu::getCaughtException();
363 // log the failure, if any
366 _rLogger
.logFailure( MigrationError(
367 ERR_STORAGE_COMMIT_FAILED
,
368 ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument
),
375 bool lcl_storeDocument_nothrow( const Reference
< XModel
>& _rxDocument
, MigrationLog
& _rLogger
)
377 bool bSuccess
= false;
381 Reference
< XStorable
> xStorable( _rxDocument
, UNO_QUERY_THROW
);
385 catch( const Exception
& )
387 aException
= ::cppu::getCaughtException();
390 // log the failure, if any
393 _rLogger
.logFailure( MigrationError(
394 ERR_STORING_DATABASEDOC_FAILED
,
401 bool lcl_storeEmbeddedDocument_nothrow( const SubDocument
& _rDocument
)
405 lcl_executeCommand_throw( _rDocument
.xCommandProcessor
, "store" );
407 catch( const Exception
& )
409 DBG_UNHANDLED_EXCEPTION();
417 class DrawPageIterator
420 explicit DrawPageIterator( const Reference
< XModel
>& _rxDocument
)
424 Reference
< XDrawPageSupplier
> xSingle( _rxDocument
, UNO_QUERY
);
425 Reference
< XDrawPagesSupplier
> xMulti( _rxDocument
, UNO_QUERY
);
428 m_xSinglePage
.set( xSingle
->getDrawPage(), UNO_SET_THROW
);
431 else if ( xMulti
.is() )
433 m_xMultiPages
.set( xMulti
->getDrawPages(), UNO_SET_THROW
);
434 m_nPageCount
= m_xMultiPages
->getCount();
440 return m_nCurrentPage
< m_nPageCount
;
443 Reference
< XDrawPage
> next()
445 Reference
< XDrawPage
> xNextPage
;
447 if ( m_xSinglePage
.is() )
449 xNextPage
= m_xSinglePage
;
451 else if ( m_xMultiPages
.is() )
453 xNextPage
.set( m_xMultiPages
->getByIndex( m_nCurrentPage
), UNO_QUERY_THROW
);
460 Reference
< XDrawPage
> m_xSinglePage
;
461 Reference
< XDrawPages
> m_xMultiPages
;
462 sal_Int32 m_nPageCount
;
463 sal_Int32 m_nCurrentPage
;
466 // FormComponentScripts
467 class FormComponentScripts
470 FormComponentScripts(
471 const Reference
< XInterface
>& _rxComponent
,
472 const Reference
< XEventAttacherManager
>& _rxManager
,
473 const sal_Int32 _nIndex
475 :m_xComponent( _rxComponent
)
476 ,m_xManager( _rxManager
)
481 Sequence
< ScriptEventDescriptor
> getEvents() const
483 return m_xManager
->getScriptEvents( m_nIndex
);
486 void setEvents( const Sequence
< ScriptEventDescriptor
>& _rEvents
) const
488 m_xManager
->registerScriptEvents( m_nIndex
, _rEvents
);
491 const Reference
< XInterface
>& getComponent() const
497 const Reference
< XInterface
> m_xComponent
;
498 const Reference
< XEventAttacherManager
> m_xManager
;
499 const sal_Int32 m_nIndex
;
502 // FormComponentIterator
503 class FormComponentIterator
506 explicit FormComponentIterator( const Reference
< XIndexAccess
>& _rxContainer
)
507 :m_xContainer( _rxContainer
)
508 ,m_xEventManager( _rxContainer
, UNO_QUERY_THROW
)
509 ,m_nElementCount( _rxContainer
->getCount() )
510 ,m_nCurrentElement( 0 )
516 return m_nCurrentElement
< m_nElementCount
;
519 FormComponentScripts
next()
521 FormComponentScripts
aComponent(
522 Reference
< XInterface
>( m_xContainer
->getByIndex( m_nCurrentElement
), UNO_QUERY_THROW
),
531 const Reference
< XIndexAccess
> m_xContainer
;
532 const Reference
< XEventAttacherManager
> m_xEventManager
;
533 const sal_Int32 m_nElementCount
;
534 sal_Int32 m_nCurrentElement
;
538 // ScriptsStorage - declaration
539 /** a helper class which encapsulates access to the storages for Java/Script, BeanShell, and Python scripts,
540 i.e. all script types which can be manipulated on storage level.
545 explicit ScriptsStorage( MigrationLog
& _rLogger
);
546 ScriptsStorage( const Reference
< XModel
>& _rxDocument
, MigrationLog
& _rLogger
);
549 /** determines whether the instance is valid, i.e. refers to a valid root storage
550 for reading/storing scripts
552 inline bool isValid() const { return m_xScriptsStorage
.is(); }
554 /** binds the instance to a new document. Only to be called when the instance is not yet
555 bound (i.e. isValid returns <FALSE/>).
557 void bind( const Reference
< XModel
>& _rxDocument
);
559 /// determines whether scripts of the given type are present
560 bool hasScripts( const ScriptType _eType
) const;
562 /// returns the root storage for the scripts of the given type
564 getScriptsRoot( const ScriptType _eType
) const;
566 /** returns the names of the elements in the "Scripts" storage
568 ::std::set
< OUString
>
569 getElementNames() const;
571 /** removes the sub storage for a given script type
573 the respective storage is empty
575 the ScriptsStorage instance was opened for writing
577 void removeScriptTypeStorage( const ScriptType _eType
) const;
579 /** commits the changes at our XStorage object
583 /** removes the "Scripts" sub storage from the given document's root storage
585 the "Scripts" storage is empty
588 removeFromDocument( const Reference
< XModel
>& _rxDocument
, MigrationLog
& _rLogger
);
591 MigrationLog
& m_rLogger
;
592 SharedStorage m_xScriptsStorage
;
595 // ScriptsStorage - implementation
596 ScriptsStorage::ScriptsStorage( MigrationLog
& _rLogger
)
597 :m_rLogger( _rLogger
)
602 ScriptsStorage::ScriptsStorage( const Reference
< XModel
>& _rxDocument
, MigrationLog
& _rLogger
)
603 :m_rLogger( _rLogger
)
609 ScriptsStorage::~ScriptsStorage()
613 bool ScriptsStorage::commit()
615 return lcl_commitStorage_nothrow( m_xScriptsStorage
);
618 void ScriptsStorage::bind( const Reference
< XModel
>& _rxDocument
)
620 OSL_PRECOND( !isValid(), "ScriptsStorage:bind: did not bother, yet, to check whether this is allowed!" );
623 Reference
< XStorageBasedDocument
> xStorageDoc( _rxDocument
, UNO_QUERY_THROW
);
624 Reference
< XStorage
> xDocStorage( xStorageDoc
->getDocumentStorage(), UNO_QUERY_THROW
);
626 // the "Scripts" storage exist, or if it does not (yet) exist and we are in write mode
627 // => open the storage
628 if ( ( xDocStorage
->hasByName( sScriptsStorageName
)
629 && xDocStorage
->isStorageElement( sScriptsStorageName
)
631 || !xDocStorage
->hasByName( sScriptsStorageName
)
634 m_xScriptsStorage
.set(
635 xDocStorage
->openStorageElement(
636 sScriptsStorageName
, ElementModes::READWRITE
642 catch( const Exception
& )
644 m_rLogger
.logFailure( MigrationError(
645 ERR_BIND_SCRIPT_STORAGE_FAILED
,
646 ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument
),
647 ::cppu::getCaughtException()
652 bool ScriptsStorage::hasScripts( const ScriptType _eType
) const
654 OSL_PRECOND( isValid(), "ScriptsStorage::hasScripts: illegal call!" );
658 const OUString
& rSubStorageName( lcl_getScriptsSubStorageName( _eType
) );
659 return m_xScriptsStorage
->hasByName( rSubStorageName
)
660 && m_xScriptsStorage
->isStorageElement( rSubStorageName
);
663 SharedStorage
ScriptsStorage::getScriptsRoot( const ScriptType _eType
) const
665 SharedStorage xStorage
;
668 xStorage
.reset( m_xScriptsStorage
->openStorageElement(
669 lcl_getScriptsSubStorageName( _eType
), ElementModes::READWRITE
675 ::std::set
< OUString
> ScriptsStorage::getElementNames() const
677 Sequence
< OUString
> aElementNames
;
679 aElementNames
= m_xScriptsStorage
->getElementNames();
681 ::std::set
< OUString
> aNames
;
683 aElementNames
.getConstArray(),
684 aElementNames
.getConstArray() + aElementNames
.getLength(),
685 ::std::insert_iterator
< ::std::set
< OUString
> >( aNames
, aNames
.end() )
690 void ScriptsStorage::removeScriptTypeStorage( const ScriptType _eType
) const
692 OUString
sSubStorageName( lcl_getScriptsSubStorageName( _eType
) );
693 if ( m_xScriptsStorage
->hasByName( sSubStorageName
) )
694 m_xScriptsStorage
->removeElement( sSubStorageName
);
697 bool ScriptsStorage::removeFromDocument( const Reference
< XModel
>& _rxDocument
, MigrationLog
& _rLogger
)
701 Reference
< XStorageBasedDocument
> xStorageDoc( _rxDocument
, UNO_QUERY_THROW
);
702 Reference
< XStorage
> xDocStorage( xStorageDoc
->getDocumentStorage(), UNO_QUERY_THROW
);
703 xDocStorage
->removeElement( sScriptsStorageName
);
705 catch( const Exception
& )
707 _rLogger
.logFailure( MigrationError(
708 ERR_REMOVE_SCRIPTS_STORAGE_FAILED
,
709 ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument
),
710 ::cppu::getCaughtException()
718 class ProgressDelegator
: public IProgressConsumer
721 ProgressDelegator( IMigrationProgress
& _rDelegator
,
722 const OUString
& _rObjectName
,
723 const OUString
& _rAction
725 :m_rDelegator( _rDelegator
)
726 ,m_sObjectName( _rObjectName
)
727 ,m_sAction( _rAction
)
730 virtual ~ProgressDelegator()
735 virtual void start( sal_uInt32 _nRange
) override
737 m_rDelegator
.startObject( m_sObjectName
, m_sAction
, _nRange
);
739 virtual void advance( sal_uInt32 _nValue
) override
741 m_rDelegator
.setObjectProgressValue( _nValue
);
743 virtual void end() override
745 m_rDelegator
.endObject();
749 IMigrationProgress
& m_rDelegator
;
750 OUString m_sObjectName
;
758 explicit PhaseGuard( ProgressMixer
& _rMixer
)
768 void start( const PhaseID _nID
, const sal_uInt32 _nPhaseRange
)
770 m_rMixer
.startPhase( _nID
, _nPhaseRange
);
774 ProgressMixer
& m_rMixer
;
777 // MigrationEngine_Impl - declaration
778 class MigrationEngine_Impl
781 MigrationEngine_Impl(
782 const Reference
<XComponentContext
>& _rContext
,
783 const Reference
< XOfficeDatabaseDocument
>& _rxDocument
,
784 IMigrationProgress
& _rProgress
,
785 MigrationLog
& _rLogger
787 ~MigrationEngine_Impl();
789 inline size_t getFormCount() const { return m_nFormCount
; }
790 inline size_t getReportCount()const { return m_nReportCount
; }
794 Reference
<XComponentContext
> m_aContext
;
795 const Reference
< XOfficeDatabaseDocument
> m_xDocument
;
796 const Reference
< XModel
> m_xDocumentModel
;
797 IMigrationProgress
& m_rProgress
;
798 MigrationLog
& m_rLogger
;
799 mutable DocumentID m_nCurrentDocumentID
;
800 SubDocuments m_aSubDocs
;
802 size_t m_nReportCount
;
805 /** collects a description of all sub documents of our database document
808 <TRUE/> if and only if collecting the documents was successful
810 bool impl_collectSubDocuments_nothrow();
812 /** migrates the macros/scripts of the given sub document
814 bool impl_handleDocument_nothrow( const SubDocument
& _rDocument
) const;
816 /** checks the structure of the 'Scripts' folder of a sub document
820 <TRUE/> if and only if the 'Scripts' folder contains known elements only.
822 bool impl_checkScriptStorageStructure_nothrow( const SubDocument
& _rDocument
) const;
824 /** migrates the scripts of the given "storage-based" script type
826 bool impl_migrateScriptStorage_nothrow(
827 const SubDocument
& _rDocument
,
828 const ScriptType _eScriptType
,
829 ProgressMixer
& _rProgress
,
830 const PhaseID _nPhaseID
833 /** migrates the content of the given "container based" libraries (Basic/Dialogs)
835 bool impl_migrateContainerLibraries_nothrow(
836 const SubDocument
& _rDocument
,
837 const ScriptType _eScriptType
,
838 ProgressMixer
& _rProgress
,
839 const PhaseID _nPhaseID
842 /** adjusts the events for the given dialog/element, taking into account the new names
843 of the moved libraries
845 void impl_adjustDialogElementEvents_throw(
846 const Reference
< XInterface
>& _rxElement
849 /** adjusts the events in the given dialog, and its controls, taking into account the new names
850 of the moved libraries
852 bool impl_adjustDialogEvents_nothrow(
853 Any
& _inout_rDialogLibraryElement
,
854 const OUString
& _rDocName
,
855 const OUString
& _rDialogLibName
,
856 const OUString
& _rDialogName
859 /** adjust the document-events which refer to macros/scripts in the document, taking into
860 account the new names of the moved libraries
862 void impl_adjustDocumentEvents_nothrow(
863 const SubDocument
& _rDocument
866 /** adjusts the script references bound to form component events
868 void impl_adjustFormComponentEvents_nothrow(
869 const SubDocument
& _rDocument
872 /** adjusts the script references for the elements of the given form component container
874 void impl_adjustFormComponentEvents_throw(
875 const Reference
< XIndexAccess
>& _rxComponentContainer
878 /** adjusts the library name in the given script URL, so that it reflects
879 the new name of the library
882 if and only if adjustments to the script code have been made
884 bool impl_adjustScriptLibrary_nothrow(
885 const OUString
& _rScriptType
,
886 OUString
& _inout_rScriptCode
889 bool impl_adjustScriptLibrary_nothrow( Any
& _inout_rScriptDescriptor
) const;
890 bool impl_adjustScriptLibrary_nothrow( ScriptEventDescriptor
& _inout_rScriptEvent
) const;
892 /** asks the user for a password for the given library, and unprotects the library
895 if and only if the library could be successfully unprotected
897 bool impl_unprotectPasswordLibrary_throw(
898 const Reference
< XLibraryContainerPassword
>& _rxPasswordManager
,
899 const ScriptType _eScriptType
,
900 const OUString
& _rLibraryName
904 // MigrationEngine_Impl - implementation
905 MigrationEngine_Impl::MigrationEngine_Impl( const Reference
<XComponentContext
>& _rContext
,
906 const Reference
< XOfficeDatabaseDocument
>& _rxDocument
, IMigrationProgress
& _rProgress
, MigrationLog
& _rLogger
)
907 :m_aContext( _rContext
)
908 ,m_xDocument( _rxDocument
)
909 ,m_xDocumentModel( _rxDocument
, UNO_QUERY_THROW
)
910 ,m_rProgress( _rProgress
)
911 ,m_rLogger( _rLogger
)
912 ,m_nCurrentDocumentID( - 1 )
917 OSL_VERIFY( impl_collectSubDocuments_nothrow() );
920 MigrationEngine_Impl::~MigrationEngine_Impl()
924 bool MigrationEngine_Impl::migrateAll()
926 if ( m_aSubDocs
.empty() )
928 OSL_FAIL( "MigrationEngine_Impl::migrateAll: no forms/reports found!" );
929 // The whole migration wizard is not expected to be called when there are no forms/reports
930 // with macros, not to mention when there are no forms/reports at all.
934 // initialize global progress
935 sal_Int32
nOverallRange( m_aSubDocs
.size() );
936 OUString
sProgressSkeleton(
937 MacroMigrationResId( STR_OVERALL_PROGRESS
).toString().
938 replaceFirst("$overall$", OUString::number(nOverallRange
)));
940 m_rProgress
.start( nOverallRange
);
942 for ( SubDocuments::const_iterator doc
= m_aSubDocs
.begin();
943 doc
!= m_aSubDocs
.end();
947 sal_Int32
nOverallProgressValue( doc
- m_aSubDocs
.begin() + 1 );
948 // update overall progress text
949 OUString
sOverallProgress(
950 sProgressSkeleton
.replaceFirst("$current$",
951 OUString::number(nOverallProgressValue
)));
952 m_rProgress
.setOverallProgressText( sOverallProgress
);
955 if ( !impl_handleDocument_nothrow( *doc
) )
958 // update overall progress value
959 m_rProgress
.setOverallProgressValue( nOverallProgressValue
);
962 // commit the root storage of the database document, for all changes made so far to take effect
963 if ( !lcl_commitDocumentStorage_nothrow( m_xDocumentModel
, m_rLogger
) )
967 if ( !lcl_storeDocument_nothrow( m_xDocumentModel
, m_rLogger
) )
975 void lcl_collectHierarchicalElementNames_throw(
976 const Reference
< XNameAccess
>& _rxContainer
, const OUString
& _rContainerLoc
,
977 SubDocuments
& _out_rDocs
, const SubDocumentType _eType
, size_t& _io_counter
)
979 const OUString
sHierarhicalBase(
980 _rContainerLoc
.isEmpty() ? OUString() :
981 OUString( _rContainerLoc
+ "/" ) );
983 Sequence
< OUString
> aElementNames( _rxContainer
->getElementNames() );
984 for ( const OUString
* elementName
= aElementNames
.getConstArray();
985 elementName
!= aElementNames
.getConstArray() + aElementNames
.getLength();
989 Any
aElement( _rxContainer
->getByName( *elementName
) );
990 OUString
sElementName( sHierarhicalBase
+ *elementName
);
992 Reference
< XNameAccess
> xSubContainer( aElement
, UNO_QUERY
);
993 if ( xSubContainer
.is() )
995 lcl_collectHierarchicalElementNames_throw( xSubContainer
, sElementName
, _out_rDocs
, _eType
, _io_counter
);
999 Reference
< XCommandProcessor
> xCommandProcessor( aElement
, UNO_QUERY
);
1000 OSL_ENSURE( xCommandProcessor
.is(), "lcl_collectHierarchicalElementNames_throw: no container, and no command processor? What *is* it, then?!" );
1001 if ( xCommandProcessor
.is() )
1003 _out_rDocs
.push_back( SubDocument( xCommandProcessor
, sElementName
, _eType
, ++_io_counter
) );
1010 bool MigrationEngine_Impl::impl_collectSubDocuments_nothrow()
1012 OSL_PRECOND( m_xDocument
.is(), "MigrationEngine_Impl::impl_collectSubDocuments_nothrow: invalid document!" );
1013 if ( !m_xDocument
.is() )
1018 Reference
< XNameAccess
> xDocContainer( m_xDocument
->getFormDocuments(), UNO_SET_THROW
);
1020 lcl_collectHierarchicalElementNames_throw( xDocContainer
, OUString(), m_aSubDocs
, eForm
, m_nFormCount
);
1022 xDocContainer
.set( m_xDocument
->getReportDocuments(), UNO_SET_THROW
);
1024 lcl_collectHierarchicalElementNames_throw( xDocContainer
, OUString(), m_aSubDocs
, eReport
, m_nReportCount
);
1026 catch( const Exception
& )
1028 m_rLogger
.logFailure( MigrationError(
1029 ERR_COLLECTING_DOCUMENTS_FAILED
,
1030 ::cppu::getCaughtException()
1037 bool MigrationEngine_Impl::impl_handleDocument_nothrow( const SubDocument
& _rDocument
) const
1039 OSL_ENSURE( m_nCurrentDocumentID
== -1,
1040 "MigrationEngine_Impl::impl_handleDocument_nothrow: there already is a current document!");
1041 m_nCurrentDocumentID
= m_rLogger
.startedDocument( _rDocument
.eType
, _rDocument
.sHierarchicalName
);
1043 // start the progress
1044 OUString
sObjectName( lcl_getSubDocumentDescription( _rDocument
) );
1045 m_rProgress
.startObject( sObjectName
, OUString(), DEFAULT_DOC_PROGRESS_RANGE
);
1047 // load the document
1048 Reference
< ProgressCapture
> pStatusIndicator( new ProgressCapture( sObjectName
, m_rProgress
) );
1049 SubDocument
aSubDocument( _rDocument
);
1050 OpenDocResult eResult
= lcl_loadSubDocument_nothrow( aSubDocument
, pStatusIndicator
.get(), m_rLogger
);
1051 if ( eResult
!= eOpenedDoc
)
1053 pStatusIndicator
->dispose();
1054 m_rProgress
.endObject();
1055 m_rLogger
.finishedDocument( m_nCurrentDocumentID
);
1056 m_nCurrentDocumentID
= -1;
1057 return ( eResult
== eIgnoreDoc
);
1060 // migrate the libraries
1061 ProgressDelegator
aDelegator(m_rProgress
, sObjectName
, MacroMigrationResId(STR_MIGRATING_LIBS
).toString());
1062 ProgressMixer
aProgressMixer( aDelegator
);
1063 aProgressMixer
.registerPhase( PHASE_JAVASCRIPT
, 1 );
1064 aProgressMixer
.registerPhase( PHASE_BEANSHELL
, 1 );
1065 aProgressMixer
.registerPhase( PHASE_PYTHON
, 1 );
1066 aProgressMixer
.registerPhase( PHASE_JAVA
, 1 );
1067 aProgressMixer
.registerPhase( PHASE_BASIC
, 5 );
1068 // more weight than the others, assuming that usually, there are many more Basic macros than any other scripts
1069 aProgressMixer
.registerPhase( PHASE_DIALOGS
, 1 );
1071 bool bSuccess
= impl_checkScriptStorageStructure_nothrow( aSubDocument
);
1073 // migrate storage-based script libraries (which can be handled by mere storage operations)
1075 && impl_migrateScriptStorage_nothrow( aSubDocument
, eJavaScript
, aProgressMixer
, PHASE_JAVASCRIPT
)
1076 && impl_migrateScriptStorage_nothrow( aSubDocument
, eBeanShell
, aProgressMixer
, PHASE_BEANSHELL
)
1077 && impl_migrateScriptStorage_nothrow( aSubDocument
, ePython
, aProgressMixer
, PHASE_PYTHON
)
1078 && impl_migrateScriptStorage_nothrow( aSubDocument
, eJava
, aProgressMixer
, PHASE_JAVA
);
1080 // migrate Basic and dialog libraries
1082 && impl_migrateContainerLibraries_nothrow( aSubDocument
, eBasic
, aProgressMixer
, PHASE_BASIC
)
1083 && impl_migrateContainerLibraries_nothrow( aSubDocument
, eDialog
, aProgressMixer
, PHASE_DIALOGS
);
1084 // order matters: First Basic scripts, then dialogs. So we can adjust references from the latter
1087 // adjust the events in the document
1088 // (note that errors are ignored here - failure to convert a script reference
1089 // is not considered a critical error)
1092 impl_adjustDocumentEvents_nothrow( aSubDocument
);
1093 impl_adjustFormComponentEvents_nothrow( aSubDocument
);
1097 // store the sub document, including removal of the (now obsolete) "Scripts" sub folder
1098 if ( m_rLogger
.movedAnyLibrary( m_nCurrentDocumentID
) )
1101 && ScriptsStorage::removeFromDocument( aSubDocument
.xDocument
, m_rLogger
)
1102 && lcl_commitDocumentStorage_nothrow( aSubDocument
.xDocument
, m_rLogger
)
1103 && lcl_storeEmbeddedDocument_nothrow( aSubDocument
);
1106 // unload in any case, even if we were not successful
1107 bSuccess
= lcl_unloadSubDocument_nothrow( aSubDocument
, m_rLogger
)
1110 pStatusIndicator
->dispose();
1112 // end the progress, just in case the ProgressCapture didn't receive the XStatusIndicator::end event
1113 m_rProgress
.endObject();
1115 m_rLogger
.finishedDocument( m_nCurrentDocumentID
);
1116 m_nCurrentDocumentID
= -1;
1122 OUString
lcl_createTargetLibName( const SubDocument
& _rDocument
,
1123 const OUString
& _rSourceLibName
, const Reference
< XNameAccess
>& _rxTargetContainer
)
1125 // The new library name is composed from the prefix, the base name, and the old library name.
1126 const OUString sPrefix
= (_rDocument
.eType
== eForm
)?OUString("Form_"): OUString("Report_");
1128 OUString
sBaseName( _rDocument
.sHierarchicalName
.copy(
1129 _rDocument
.sHierarchicalName
.lastIndexOf( '/' ) + 1 ) );
1130 // Normalize this name. In our current storage implementation (and script containers in a document
1131 // are finally mapped to sub storages of the document storage), not all characters are allowed.
1132 // The bug requesting to change this is #i95409#.
1133 // Unfortunately, the storage implementation does not complain if you use invalid characters/names, but instead
1134 // it silently accepts them, and produces garbage in the file (#i95408).
1135 // So, until especially the former is fixed, we need to strip all invalid characters from the name.
1138 // The general idea is to replace invalid characters with '_'. However, since "valid" essentially means
1139 // ASCII only, this implies that for a lot of languages, we would simply replace everything with '_',
1140 // which of course is not desired.
1141 // So, we use a heuristics: If the name contains at most 3 invalid characters, and as many valid as invalid
1142 // characters, then we use the replacement. Otherwise, we just use a unambiguous number for the sub document.
1143 sal_Int32 nValid
=0, nInvalid
=0;
1144 const sal_Unicode
* pBaseName
= sBaseName
.getStr();
1145 const sal_Int32 nBaseNameLen
= sBaseName
.getLength();
1146 for ( sal_Int32 i
=0; i
<nBaseNameLen
; ++i
)
1148 if ( ::comphelper::OStorageHelper::IsValidZipEntryFileName( pBaseName
+ i
, 1, false ) )
1153 if ( ( nInvalid
<= 3 ) && ( nInvalid
* 2 <= nValid
) )
1154 { // not "too many" invalid => replace them
1155 OUStringBuffer aReplacement
;
1156 aReplacement
.ensureCapacity( nBaseNameLen
);
1157 aReplacement
.append( sBaseName
);
1158 const sal_Unicode
* pReplacement
= aReplacement
.getStr();
1159 for ( sal_Int32 i
=0; i
<nBaseNameLen
; ++i
)
1161 if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( pReplacement
+ i
, 1, false ) )
1162 aReplacement
[i
] = '_';
1164 sBaseName
= aReplacement
.makeStringAndClear();
1166 OUString
sTargetName( sPrefix
+ sBaseName
+ "_" + _rSourceLibName
);
1167 if ( !_rxTargetContainer
->hasByName( sTargetName
) )
1171 // "too many" invalid characters, or the name composed with the base name was already used.
1172 // (The latter is valid, since there can be multiple sub documents with the same base name,
1173 // in different levels in the hierarchy.)
1174 // In this case, just use the umambiguous sub document number.
1175 return sPrefix
+ OUString::number( _rDocument
.nNumber
) + "_" + _rSourceLibName
;
1179 bool MigrationEngine_Impl::impl_checkScriptStorageStructure_nothrow( const SubDocument
& _rDocument
) const
1181 OSL_PRECOND( _rDocument
.xDocument
.is(), "MigrationEngine_Impl::impl_checkScriptStorageStructure_nothrow: invalid document!" );
1182 if ( !_rDocument
.xDocument
.is() )
1187 // the root storage of the document whose scripts are to be migrated
1188 ScriptsStorage
aDocStorage( _rDocument
.xDocument
, m_rLogger
);
1189 if ( !aDocStorage
.isValid() )
1190 { // no scripts at all, or no scripts of the given type
1191 return !m_rLogger
.hadFailure();
1193 ::std::set
< OUString
> aElementNames( aDocStorage
.getElementNames() );
1195 const ScriptType aKnownStorageBasedTypes
[] = {
1196 eBeanShell
, eJavaScript
, ePython
, eJava
1198 for (ScriptType aKnownStorageBasedType
: aKnownStorageBasedTypes
)
1199 aElementNames
.erase( lcl_getScriptsSubStorageName( aKnownStorageBasedType
) );
1201 if ( !aElementNames
.empty() )
1203 m_rLogger
.logFailure( MigrationError(
1204 ERR_UNKNOWN_SCRIPT_FOLDER
,
1205 lcl_getSubDocumentDescription( _rDocument
),
1206 *aElementNames
.begin()
1211 catch( const Exception
& )
1213 m_rLogger
.logFailure( MigrationError(
1214 ERR_EXAMINING_SCRIPTS_FOLDER_FAILED
,
1215 lcl_getSubDocumentDescription( _rDocument
),
1216 ::cppu::getCaughtException()
1223 bool MigrationEngine_Impl::impl_migrateScriptStorage_nothrow( const SubDocument
& _rDocument
,
1224 const ScriptType _eScriptType
, ProgressMixer
& _rProgress
, const PhaseID _nPhaseID
) const
1226 OSL_PRECOND( _rDocument
.xDocument
.is(), "MigrationEngine_Impl::impl_migrateScriptStorage_nothrow: invalid document!" );
1227 if ( !_rDocument
.xDocument
.is() )
1230 ScriptsStorage
aDatabaseScripts( m_rLogger
);
1231 // the scripts of our complete database document - created on demand only
1232 SharedStorage xTargetStorage
;
1233 // the target for moving the scripts storages - created on demand only
1235 PhaseGuard
aPhase( _rProgress
);
1236 bool bSuccess
= false;
1240 // the root storage of the document whose scripts are to be migrated
1241 ScriptsStorage
aDocStorage( _rDocument
.xDocument
, m_rLogger
);
1242 if ( !aDocStorage
.isValid()
1243 || !aDocStorage
.hasScripts( _eScriptType
)
1246 // no scripts at all, or no scripts of the given type
1247 _rProgress
.startPhase( _nPhaseID
, 1 );
1248 _rProgress
.endPhase();
1249 return !m_rLogger
.hadFailure();
1252 SharedStorage
xScriptsRoot( aDocStorage
.getScriptsRoot( _eScriptType
) );
1253 if ( !xScriptsRoot
.is() )
1254 throw RuntimeException("internal error");
1256 // loop through the script libraries
1257 Sequence
< OUString
> aStorageElements( xScriptsRoot
->getElementNames() );
1258 aPhase
.start( _nPhaseID
, aStorageElements
.getLength() );
1260 for ( const OUString
* element
= aStorageElements
.getConstArray();
1261 element
!= aStorageElements
.getConstArray() + aStorageElements
.getLength();
1265 bool bIsScriptLibrary
= xScriptsRoot
->isStorageElement( *element
);
1266 OSL_ENSURE( bIsScriptLibrary
,
1267 "MigrationEngine_Impl::impl_migrateScriptStorage_nothrow: warning: unknown scripts storage structure!" );
1268 // we cannot handle this. We would need to copy this stream to the respective scripts storage
1269 // of the database document, but we cannot guarantee that the name is not used, yet, and we cannot
1270 // simply rename the thing.
1271 if ( !bIsScriptLibrary
)
1273 m_rLogger
.logFailure( MigrationError(
1274 ERR_UNEXPECTED_LIBSTORAGE_ELEMENT
,
1275 lcl_getSubDocumentDescription( _rDocument
),
1276 getScriptTypeDisplayName( _eScriptType
),
1282 // ensure we have access to the DBDoc's scripts storage
1283 if ( !aDatabaseScripts
.isValid() )
1284 { // not needed 'til now
1285 aDatabaseScripts
.bind( m_xDocumentModel
);
1286 if ( aDatabaseScripts
.isValid() )
1287 xTargetStorage
= aDatabaseScripts
.getScriptsRoot( _eScriptType
);
1289 if ( !xTargetStorage
.is() )
1291 m_rLogger
.logFailure( MigrationError(
1292 ERR_CREATING_DBDOC_SCRIPT_STORAGE_FAILED
,
1293 getScriptTypeDisplayName( _eScriptType
)
1299 // move the library to the DBDoc's scripts library, under the new name
1300 OUString
sNewLibName( lcl_createTargetLibName( _rDocument
, *element
, xTargetStorage
.getTyped().get() ) );
1301 xScriptsRoot
->moveElementTo( *element
, xTargetStorage
, sNewLibName
);
1303 // log the fact that we moved the library
1304 m_rLogger
.movedLibrary( m_nCurrentDocumentID
, _eScriptType
, *element
, sNewLibName
);
1307 _rProgress
.advancePhase( element
- aStorageElements
.getConstArray() );
1310 // commit the storages, so the changes we made persist
1311 if ( !lcl_commitStorage_nothrow( xScriptsRoot
)
1312 || ( xTargetStorage
.is() && !lcl_commitStorage_nothrow( xTargetStorage
) )
1315 m_rLogger
.logFailure( MigrationError(
1316 ERR_COMMITTING_SCRIPT_STORAGES_FAILED
,
1317 getScriptTypeDisplayName( _eScriptType
),
1318 lcl_getSubDocumentDescription( _rDocument
)
1323 // now that the concrete scripts storage does not have any elements anymore,
1325 xScriptsRoot
.reset( nullptr ); // need to reset the storage to be allowed to remove it
1326 aDocStorage
.removeScriptTypeStorage( _eScriptType
);
1329 bSuccess
= aDocStorage
.commit()
1330 && aDatabaseScripts
.commit();
1332 catch( const Exception
& )
1334 aException
= ::cppu::getCaughtException();
1338 // log the error, if any
1341 m_rLogger
.logFailure( MigrationError(
1342 ERR_GENERAL_SCRIPT_MIGRATION_FAILURE
,
1343 getScriptTypeDisplayName( _eScriptType
),
1344 lcl_getSubDocumentDescription( _rDocument
),
1352 bool MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow( const SubDocument
& _rDocument
,
1353 const ScriptType _eScriptType
, ProgressMixer
& _rProgress
, const PhaseID _nPhaseID
) const
1355 OSL_PRECOND( ( _eScriptType
== eBasic
) || ( _eScriptType
== eDialog
),
1356 "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: illegal script type!" );
1358 bool bSuccess
= false;
1359 PhaseGuard
aPhase( _rProgress
);
1361 do // artificial loop for flow control only
1365 // access library container of the sub document
1366 Reference
< XEmbeddedScripts
> xSubDocScripts( _rDocument
.xDocument
, UNO_QUERY
);
1367 if ( !xSubDocScripts
.is() )
1368 { // no script support in the sub document -> nothing to migrate
1369 // (though ... this is suspicious, at least ...)
1374 Reference
< XStorageBasedLibraryContainer
> xSourceLibraries(
1375 _eScriptType
== eBasic
? xSubDocScripts
->getBasicLibraries() : xSubDocScripts
->getDialogLibraries(),
1378 Reference
< XLibraryContainerPassword
> xSourcePasswords( xSourceLibraries
, UNO_QUERY
);
1379 OSL_ENSURE( xSourcePasswords
.is(),
1380 "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: suspicious: no password management for the source libraries!" );
1382 Sequence
< OUString
> aSourceLibNames( xSourceLibraries
->getElementNames() );
1383 aPhase
.start( _nPhaseID
, aSourceLibNames
.getLength() );
1385 if ( !xSourceLibraries
->hasElements() )
1391 // create library containers for the document - those will be the target for the migration
1392 Reference
< XStorageBasedDocument
> xStorageDoc( m_xDocument
, UNO_QUERY_THROW
);
1393 Reference
< XStorageBasedLibraryContainer
> xTargetLibraries
;
1394 if ( _eScriptType
== eBasic
)
1396 xTargetLibraries
.set( DocumentScriptLibraryContainer::create(
1397 m_aContext
, xStorageDoc
), UNO_QUERY_THROW
);
1401 xTargetLibraries
.set( DocumentDialogLibraryContainer::create(
1402 m_aContext
, xStorageDoc
), UNO_QUERY_THROW
);
1405 // copy all libs to the target, with potentially renaming them
1406 const OUString
* pSourceLibBegin
= aSourceLibNames
.getConstArray();
1407 const OUString
* pSourceLibEnd
= pSourceLibBegin
+ aSourceLibNames
.getLength();
1408 for ( const OUString
* pSourceLibName
= pSourceLibBegin
;
1409 pSourceLibName
!= pSourceLibEnd
;
1413 // if the library is password-protected, ask the user to unprotect it
1414 if ( xSourcePasswords
.is()
1415 && xSourcePasswords
->isLibraryPasswordProtected( *pSourceLibName
)
1416 && !xSourcePasswords
->isLibraryPasswordVerified( *pSourceLibName
)
1419 if ( !impl_unprotectPasswordLibrary_throw( xSourcePasswords
, _eScriptType
, *pSourceLibName
) )
1421 m_rLogger
.logFailure( MigrationError(
1422 ERR_PASSWORD_VERIFICATION_FAILED
,
1423 _rDocument
.sHierarchicalName
,
1424 getScriptTypeDisplayName( _eScriptType
),
1431 OUString
sNewLibName( lcl_createTargetLibName( _rDocument
, *pSourceLibName
, xTargetLibraries
.get() ) );
1433 if ( xSourceLibraries
->isLibraryLink( *pSourceLibName
) )
1435 // just re-create the link in the target library
1436 xTargetLibraries
->createLibraryLink(
1438 xSourceLibraries
->getLibraryLinkURL( *pSourceLibName
),
1439 xSourceLibraries
->isLibraryReadOnly( *pSourceLibName
)
1444 if ( !xSourceLibraries
->isLibraryLoaded( *pSourceLibName
) )
1445 xSourceLibraries
->loadLibrary( *pSourceLibName
);
1447 // copy the content of this particular library
1448 Reference
< XNameAccess
> xSourceLib( xSourceLibraries
->getByName( *pSourceLibName
), UNO_QUERY_THROW
);
1449 Reference
< XNameContainer
> xTargetLib( xTargetLibraries
->createLibrary( sNewLibName
), UNO_QUERY_THROW
);
1451 Sequence
< OUString
> aLibElementNames( xSourceLib
->getElementNames() );
1452 for ( const OUString
* pSourceElementName
= aLibElementNames
.getConstArray();
1453 pSourceElementName
!= aLibElementNames
.getConstArray() + aLibElementNames
.getLength();
1454 ++pSourceElementName
1457 Any aElement
= xSourceLib
->getByName( *pSourceElementName
);
1458 OSL_ENSURE( aElement
.hasValue(),
1459 "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: invalid (empty) lib element!" );
1461 // if this is a dialog, adjust the references to scripts
1462 if ( _eScriptType
== eDialog
)
1464 impl_adjustDialogEvents_nothrow( aElement
, lcl_getSubDocumentDescription( _rDocument
),
1465 *pSourceLibName
, *pSourceElementName
);
1468 xTargetLib
->insertByName( *pSourceElementName
, aElement
);
1471 // transfer the read-only flag
1472 xTargetLibraries
->setLibraryReadOnly(
1473 sNewLibName
, xSourceLibraries
->isLibraryReadOnly( *pSourceLibName
) );
1476 // remove the source lib
1477 xSourceLibraries
->removeLibrary( *pSourceLibName
);
1480 m_rLogger
.movedLibrary( m_nCurrentDocumentID
, _eScriptType
, *pSourceLibName
, sNewLibName
);
1482 // tell the progress
1483 _rProgress
.advancePhase( pSourceLibName
- pSourceLibBegin
);
1487 xSourceLibraries
->storeLibraries();
1489 xTargetLibraries
->storeLibraries();
1490 Reference
< XStorage
> xTargetRoot( xTargetLibraries
->getRootLocation(), UNO_QUERY_THROW
);
1491 bSuccess
= lcl_commitStorage_nothrow( xTargetRoot
);
1493 catch( const Exception
& )
1495 aException
= ::cppu::getCaughtException();
1500 // log the error, if any
1503 m_rLogger
.logFailure( MigrationError(
1504 ERR_GENERAL_MACRO_MIGRATION_FAILURE
,
1505 lcl_getSubDocumentDescription( _rDocument
),
1513 bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( const OUString
& _rScriptType
,
1514 OUString
& _inout_rScriptCode
) const
1516 OSL_PRECOND( !_inout_rScriptCode
.isEmpty(), "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: invalid script!" );
1517 if ( _inout_rScriptCode
.isEmpty() )
1520 bool bSuccess
= false;
1524 if ( _rScriptType
!= "Script" || _rScriptType
.isEmpty() )
1527 "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: no or unknown script type!" );
1528 m_rLogger
.logRecoverable( MigrationError(
1529 ERR_UNKNOWN_SCRIPT_TYPE
,
1535 // analyze the script URI
1536 Reference
< XUriReferenceFactory
> xUriRefFac
= UriReferenceFactory::create( m_aContext
);
1537 Reference
< XVndSunStarScriptUrlReference
> xUri( xUriRefFac
->parse( _inout_rScriptCode
), UNO_QUERY_THROW
);
1539 OUString sScriptLanguage
= xUri
->getParameter( "language" );
1540 ScriptType eScriptType
= eBasic
;
1541 if ( !lcl_getScriptTypeFromLanguage( sScriptLanguage
, eScriptType
) )
1544 "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: unknown script language!" );
1545 m_rLogger
.logRecoverable( MigrationError(
1546 ERR_UNKNOWN_SCRIPT_LANGUAGE
,
1552 OUString sLocation
= xUri
->getParameter( "location" );
1553 if ( sLocation
!= "document" )
1555 // only document libraries must be migrated, of course
1559 OUString sScriptName
= xUri
->getName();
1560 sal_Int32 nLibModuleSeparator
= sScriptName
.indexOf( '.' );
1561 if ( nLibModuleSeparator
< 0 )
1564 "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: invalid/unknown location format!" );
1565 m_rLogger
.logRecoverable( MigrationError(
1566 ERR_UNKNOWN_SCRIPT_NAME_FORMAT
,
1572 // replace the library name
1573 OUString sLibrary
= sScriptName
.copy( 0, nLibModuleSeparator
);
1574 OUString sNewLibName
= m_rLogger
.getNewLibraryName(
1575 m_nCurrentDocumentID
, eScriptType
, sLibrary
);
1576 OSL_ENSURE( sLibrary
!= sNewLibName
,
1577 "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: a library which has not been migrated?" );
1579 xUri
->setName( sNewLibName
+ sScriptName
.copy( nLibModuleSeparator
) );
1581 // update the new script URL
1582 _inout_rScriptCode
= xUri
->getUriReference();
1585 catch( const Exception
& )
1587 aException
= ::cppu::getCaughtException();
1591 // log the failure, if any
1594 m_rLogger
.logRecoverable( MigrationError(
1595 ERR_SCRIPT_TRANSLATION_FAILURE
,
1605 bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( ScriptEventDescriptor
& _inout_rScriptEvent
) const
1607 if ( !(_inout_rScriptEvent
.ScriptType
.isEmpty() || _inout_rScriptEvent
.ScriptCode
.isEmpty()) )
1608 return impl_adjustScriptLibrary_nothrow( _inout_rScriptEvent
.ScriptType
, _inout_rScriptEvent
.ScriptCode
);
1612 bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( Any
& _inout_rScriptDescriptor
) const
1614 ::comphelper::NamedValueCollection
aScriptDesc( _inout_rScriptDescriptor
);
1616 OUString sScriptType
;
1620 OSL_VERIFY( aScriptDesc
.get_ensureType( "EventType", sScriptType
) );
1621 OSL_VERIFY( aScriptDesc
.get_ensureType( "Script", sScript
) );
1623 catch( const Exception
& )
1625 m_rLogger
.logRecoverable( MigrationError(
1626 ERR_INVALID_SCRIPT_DESCRIPTOR_FORMAT
,
1627 ::cppu::getCaughtException()
1631 if ( !(sScriptType
.isEmpty() || sScript
.isEmpty()) )
1632 if ( !impl_adjustScriptLibrary_nothrow( sScriptType
, sScript
) )
1635 aScriptDesc
.put( "Script", sScript
);
1636 _inout_rScriptDescriptor
<<= aScriptDesc
.getPropertyValues();
1640 void MigrationEngine_Impl::impl_adjustDocumentEvents_nothrow( const SubDocument
& _rDocument
) const
1644 Reference
< XEventsSupplier
> xSuppEvents( _rDocument
.xDocument
, UNO_QUERY
);
1645 if ( !xSuppEvents
.is() )
1646 // this is allowed. E.g. new-style reports currently do not support this
1649 Reference
< XNameReplace
> xEvents( xSuppEvents
->getEvents(), UNO_SET_THROW
);
1650 Sequence
< OUString
> aEventNames
= xEvents
->getElementNames();
1653 for ( const OUString
* eventName
= aEventNames
.getConstArray();
1654 eventName
!= aEventNames
.getConstArray() + aEventNames
.getLength();
1658 aEvent
= xEvents
->getByName( *eventName
);
1659 if ( !aEvent
.hasValue() )
1663 if ( !impl_adjustScriptLibrary_nothrow( aEvent
) )
1667 xEvents
->replaceByName( *eventName
, aEvent
);
1670 catch( const Exception
& )
1672 m_rLogger
.logRecoverable( MigrationError(
1673 ERR_ADJUSTING_DOCUMENT_EVENTS_FAILED
,
1674 lcl_getSubDocumentDescription( _rDocument
),
1675 ::cppu::getCaughtException()
1680 void MigrationEngine_Impl::impl_adjustDialogElementEvents_throw( const Reference
< XInterface
>& _rxElement
) const
1682 Reference
< XScriptEventsSupplier
> xEventsSupplier( _rxElement
, UNO_QUERY_THROW
);
1683 Reference
< XNameReplace
> xEvents( xEventsSupplier
->getEvents(), UNO_QUERY_THROW
);
1684 Sequence
< OUString
> aEventNames( xEvents
->getElementNames() );
1686 const OUString
* eventName
= aEventNames
.getArray();
1687 const OUString
* eventNamesEnd
= eventName
+ aEventNames
.getLength();
1689 ScriptEventDescriptor aScriptEvent
;
1690 for ( ; eventName
!= eventNamesEnd
; ++eventName
)
1692 OSL_VERIFY( xEvents
->getByName( *eventName
) >>= aScriptEvent
);
1694 if ( !impl_adjustScriptLibrary_nothrow( aScriptEvent
) )
1697 xEvents
->replaceByName( *eventName
, makeAny( aScriptEvent
) );
1701 bool MigrationEngine_Impl::impl_adjustDialogEvents_nothrow( Any
& _inout_rDialogLibraryElement
,
1702 const OUString
& _rDocName
, const OUString
& _rDialogLibName
, const OUString
& _rDialogName
) const
1706 // load a dialog model from the stream describing it
1707 Reference
< XInputStreamProvider
> xISP( _inout_rDialogLibraryElement
, UNO_QUERY_THROW
);
1708 Reference
< XInputStream
> xInput( xISP
->createInputStream(), UNO_QUERY_THROW
);
1710 Reference
< XNameContainer
> xDialogModel( m_aContext
->getServiceManager()->createInstanceWithContext("com.sun.star.awt.UnoControlDialogModel", m_aContext
), UNO_QUERY_THROW
);
1711 ::xmlscript::importDialogModel( xInput
, xDialogModel
, m_aContext
, m_xDocumentModel
);
1713 // adjust the events of the dialog
1714 impl_adjustDialogElementEvents_throw( xDialogModel
);
1716 // adjust the events of the controls
1717 Sequence
< OUString
> aControlNames( xDialogModel
->getElementNames() );
1718 const OUString
* controlName
= aControlNames
.getConstArray();
1719 const OUString
* controlNamesEnd
= controlName
+ aControlNames
.getLength();
1720 for ( ; controlName
!= controlNamesEnd
; ++controlName
)
1722 impl_adjustDialogElementEvents_throw( Reference
< XInterface
>( xDialogModel
->getByName( *controlName
), UNO_QUERY
) );
1725 // export dialog model
1726 xISP
= ::xmlscript::exportDialogModel( xDialogModel
, m_aContext
, m_xDocumentModel
);
1727 _inout_rDialogLibraryElement
<<= xISP
;
1729 catch( const Exception
& )
1731 m_rLogger
.logRecoverable( MigrationError(
1732 ERR_ADJUSTING_DIALOG_EVENTS_FAILED
,
1736 ::cppu::getCaughtException()
1743 void MigrationEngine_Impl::impl_adjustFormComponentEvents_throw( const Reference
< XIndexAccess
>& _rxComponentContainer
) const
1745 FormComponentIterator
aCompIter( _rxComponentContainer
);
1746 while ( aCompIter
.hasMore() )
1748 // 1. adjust the component's scripts of the current component
1749 FormComponentScripts
aComponent( aCompIter
.next() );
1750 Sequence
< ScriptEventDescriptor
> aEvents( aComponent
.getEvents() );
1752 bool bChangedComponentEvents
= false;
1753 for ( ScriptEventDescriptor
* scriptEvent
= aEvents
.getArray();
1754 scriptEvent
!= aEvents
.getArray() + aEvents
.getLength();
1758 if ( !impl_adjustScriptLibrary_nothrow( *scriptEvent
) )
1761 bChangedComponentEvents
= true;
1764 if ( bChangedComponentEvents
)
1765 aComponent
.setEvents( aEvents
);
1767 // 2. step down if the component is a container itself
1768 Reference
< XIndexAccess
> xContainer( aComponent
.getComponent(), UNO_QUERY
);
1769 if ( xContainer
.is() )
1770 impl_adjustFormComponentEvents_throw( xContainer
);
1774 void MigrationEngine_Impl::impl_adjustFormComponentEvents_nothrow( const SubDocument
& _rDocument
) const
1778 DrawPageIterator
aPageIter( _rDocument
.xDocument
);
1779 while ( aPageIter
.hasMore() )
1781 Reference
< XFormsSupplier
> xSuppForms( aPageIter
.next(), UNO_QUERY_THROW
);
1782 Reference
< XIndexAccess
> xForms( xSuppForms
->getForms(), UNO_QUERY_THROW
);
1783 impl_adjustFormComponentEvents_throw( xForms
);
1786 catch( const Exception
& )
1788 m_rLogger
.logRecoverable( MigrationError(
1789 ERR_ADJUSTING_FORMCOMP_EVENTS_FAILED
,
1790 lcl_getSubDocumentDescription( _rDocument
),
1791 ::cppu::getCaughtException()
1796 bool MigrationEngine_Impl::impl_unprotectPasswordLibrary_throw( const Reference
< XLibraryContainerPassword
>& _rxPasswordManager
,
1797 const ScriptType _eScriptType
, const OUString
& _rLibraryName
) const
1799 // a human-readable description of the affected library
1800 OUString
sLibraryDescription(
1801 MacroMigrationResId(STR_LIBRARY_TYPE_AND_NAME
).toString().
1802 replaceFirst("$type$",
1803 getScriptTypeDisplayName(_eScriptType
)).
1804 replaceFirst("$library$", _rLibraryName
));
1805 //TODO: probably broken if first replaceFirst can produce
1806 // fresh instance of "$library$" in subject string of second
1809 InteractionHandler
aHandler( m_aContext
, m_xDocumentModel
);
1813 if ( !aHandler
.requestDocumentPassword( sLibraryDescription
, sPassword
) )
1814 // aborted by the user
1817 bool bSuccessVerification
= _rxPasswordManager
->verifyLibraryPassword( _rLibraryName
, sPassword
);
1818 if ( bSuccessVerification
)
1825 MigrationEngine::MigrationEngine( const Reference
<XComponentContext
>& _rContext
,
1826 const Reference
< XOfficeDatabaseDocument
>& _rxDocument
, IMigrationProgress
& _rProgress
,
1827 MigrationLog
& _rLogger
)
1828 :m_pImpl( new MigrationEngine_Impl( _rContext
, _rxDocument
, _rProgress
, _rLogger
) )
1832 MigrationEngine::~MigrationEngine()
1836 sal_Int32
MigrationEngine::getFormCount() const
1838 return m_pImpl
->getFormCount();
1841 sal_Int32
MigrationEngine::getReportCount() const
1843 return m_pImpl
->getReportCount();
1846 bool MigrationEngine::migrateAll()
1848 return m_pImpl
->migrateAll();
1853 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */