1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: macromigrationdialog.cxx,v $
10 * $Revision: 1.3.2.9 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_dbaccess.hxx"
34 #include "dbmm_global.hrc"
35 #include "dbmm_module.hxx"
36 #include "docinteraction.hxx"
37 #include "macromigration.hrc"
38 #include "macromigrationdialog.hxx"
39 #include "macromigrationpages.hxx"
40 #include "migrationengine.hxx"
41 #include "migrationerror.hxx"
42 #include "migrationlog.hxx"
44 /** === begin UNO includes === **/
45 #include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
46 #include <com/sun/star/frame/XModel2.hpp>
47 #include <com/sun/star/frame/XStorable.hpp>
48 #include <com/sun/star/util/XCloseable.hpp>
49 #include <com/sun/star/frame/XComponentLoader.hpp>
50 #include <com/sun/star/util/XModifiable.hpp>
51 #include <com/sun/star/ucb/XContent.hpp>
52 #include <com/sun/star/ucb/XContentProvider.hpp>
53 /** === end UNO includes === **/
55 #include <comphelper/namedvaluecollection.hxx>
56 #include <cppuhelper/exc_hlp.hxx>
57 #include <cppuhelper/implbase1.hxx>
58 #include <rtl/ref.hxx>
59 #include <svtools/filenotation.hxx>
60 #include <tools/diagnose_ex.h>
61 #include <ucbhelper/content.hxx>
62 #include <ucbhelper/contentbroker.hxx>
63 #include <vcl/msgbox.hxx>
67 //........................................................................
70 //........................................................................
72 #define STATE_CLOSE_SUB_DOCS 0
73 #define STATE_BACKUP_DBDOC 1
74 #define STATE_MIGRATE 2
75 #define STATE_SUMMARY 3
77 #define PATH_DEFAULT 1
79 /** === begin UNO using === **/
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::sdb::application::XDatabaseDocumentUI
;
90 using ::com::sun::star::sdb::XOfficeDatabaseDocument
;
91 using ::com::sun::star::frame::XModel2
;
92 using ::com::sun::star::frame::XController
;
93 using ::com::sun::star::frame::XController2
;
94 using ::com::sun::star::container::XEnumeration
;
95 using ::com::sun::star::frame::XStorable
;
96 using ::com::sun::star::uno::Sequence
;
97 using ::com::sun::star::beans::PropertyValue
;
98 using ::com::sun::star::frame::XFrame
;
99 using ::com::sun::star::awt::XWindow
;
100 using ::com::sun::star::util::XCloseable
;
101 using ::com::sun::star::util::XCloseListener
;
102 using ::com::sun::star::util::CloseVetoException
;
103 using ::com::sun::star::lang::EventObject
;
104 using ::com::sun::star::frame::XComponentLoader
;
105 using ::com::sun::star::util::XModifiable
;
106 using ::com::sun::star::ucb::XCommandEnvironment
;
107 using ::com::sun::star::ucb::XContent
;
108 using ::com::sun::star::ucb::XContentIdentifier
;
109 using ::com::sun::star::ucb::XContentProvider
;
110 /** === end UNO using === **/
112 //====================================================================
114 //====================================================================
115 //--------------------------------------------------------------------
116 static void lcl_getControllers_throw( const Reference
< XModel2
>& _rxDocument
,
117 ::std::list
< Reference
< XController2
> >& _out_rControllers
)
119 _out_rControllers
.clear();
120 Reference
< XEnumeration
> xControllerEnum( _rxDocument
->getControllers(), UNO_SET_THROW
);
121 while ( xControllerEnum
->hasMoreElements() )
122 _out_rControllers
.push_back( Reference
< XController2
>( xControllerEnum
->nextElement(), UNO_QUERY_THROW
) );
125 //====================================================================
126 //= MacroMigrationDialog_Data
127 //====================================================================
128 struct MacroMigrationDialog_Data
130 ::comphelper::ComponentContext aContext
;
131 MigrationLog aLogger
;
132 Reference
< XOfficeDatabaseDocument
> xDocument
;
133 Reference
< XModel2
> xDocumentModel
;
134 ::rtl::OUString sSuccessfulBackupLocation
;
135 bool bMigrationIsRunning
;
136 bool bMigrationFailure
;
137 bool bMigrationSuccess
;
139 MacroMigrationDialog_Data(
140 const ::comphelper::ComponentContext
& _rContext
,
141 const Reference
< XOfficeDatabaseDocument
>& _rxDocument
)
142 :aContext( _rContext
)
144 ,xDocument( _rxDocument
)
145 ,xDocumentModel( _rxDocument
, UNO_QUERY
)
146 ,bMigrationIsRunning( false )
147 ,bMigrationFailure( false )
148 ,bMigrationSuccess( false )
153 //====================================================================
154 //= MacroMigrationDialog
155 //====================================================================
156 //--------------------------------------------------------------------
157 MacroMigrationDialog::MacroMigrationDialog( Window
* _pParent
, const ::comphelper::ComponentContext
& _rContext
,
158 const Reference
< XOfficeDatabaseDocument
>& _rxDocument
)
159 :MacroMigrationDialog_Base( _pParent
, MacroMigrationResId( DLG_MACRO_MIGRATION
) )
160 ,m_pData( new MacroMigrationDialog_Data( _rContext
, _rxDocument
) )
162 String
sTitlePrepare( MacroMigrationResId( STR_STATE_CLOSE_SUB_DOCS
) );
163 String
sTitleStoreAs( MacroMigrationResId( STR_STATE_BACKUP_DBDOC
) );
164 String
sTitleMigrate( MacroMigrationResId( STR_STATE_MIGRATE
) );
165 String
sTitleSummary( MacroMigrationResId( STR_STATE_SUMMARY
) );
168 describeState( STATE_CLOSE_SUB_DOCS
, sTitlePrepare
, &PreparationPage::Create
);
169 describeState( STATE_BACKUP_DBDOC
, sTitleStoreAs
, &SaveDBDocPage::Create
);
170 describeState( STATE_MIGRATE
, sTitleMigrate
, &ProgressPage::Create
);
171 describeState( STATE_SUMMARY
, sTitleSummary
, &ResultPage::Create
);
173 declarePath( PATH_DEFAULT
, STATE_CLOSE_SUB_DOCS
, STATE_BACKUP_DBDOC
, STATE_MIGRATE
, STATE_SUMMARY
, WZS_INVALID_STATE
);
175 SetPageSizePixel( LogicToPixel( ::Size( TAB_PAGE_WIDTH
, TAB_PAGE_HEIGHT
), MAP_APPFONT
) );
176 ShowButtonFixedLine( true );
177 SetRoadmapInteractive( true );
178 enableAutomaticNextButtonState();
179 defaultButton( WZB_NEXT
);
180 enableButtons( WZB_FINISH
, true );
183 OSL_PRECOND( m_pData
->xDocumentModel
.is(), "MacroMigrationDialog::MacroMigrationDialog: illegal document!" );
186 //--------------------------------------------------------------------
187 MacroMigrationDialog::~MacroMigrationDialog()
191 //--------------------------------------------------------------------
192 const ::comphelper::ComponentContext
& MacroMigrationDialog::getComponentContext() const
194 return m_pData
->aContext
;
197 //--------------------------------------------------------------------
198 const Reference
< XOfficeDatabaseDocument
>& MacroMigrationDialog::getDocument() const
200 return m_pData
->xDocument
;
203 //--------------------------------------------------------------------
204 short MacroMigrationDialog::Execute()
206 short nResult
= MacroMigrationDialog_Base::Execute();
207 if ( !m_pData
->bMigrationFailure
&& !m_pData
->bMigrationSuccess
)
208 // migration did not even start
211 OSL_ENSURE( !m_pData
->bMigrationFailure
|| !m_pData
->bMigrationSuccess
,
212 "MacroMigrationDialog::Execute: success *and* failure at the same time?!" );
213 impl_reloadDocument_nothrow( m_pData
->bMigrationSuccess
);
218 //--------------------------------------------------------------------
219 BOOL
MacroMigrationDialog::Close()
221 if ( m_pData
->bMigrationIsRunning
)
223 return MacroMigrationDialog_Base::Close();
226 //--------------------------------------------------------------------
227 void MacroMigrationDialog::enterState( WizardState _nState
)
229 MacroMigrationDialog_Base::enterState( _nState
);
233 case STATE_CLOSE_SUB_DOCS
:
234 enableButtons( WZB_FINISH
, false );
235 enableState( STATE_MIGRATE
, false );
236 enableState( STATE_SUMMARY
, false );
239 case STATE_BACKUP_DBDOC
:
240 enableState( STATE_MIGRATE
, true );
241 // Note that the state is automatically disabled if the current page
242 // (SaveDBDocPage) returns false in its canAdvance, not caring that
243 // we enabled it here.
248 // disable everything. The process we will start here cannot be cancelled, the user
249 // needs to wait 'til it's finished.
250 enableState( STATE_CLOSE_SUB_DOCS
, false );
251 enableState( STATE_BACKUP_DBDOC
, false );
252 enableState( STATE_SUMMARY
, false );
254 enableButtons( WZB_FINISH
| WZB_CANCEL
| WZB_PREVIOUS
| WZB_NEXT
, false );
256 // start the migration asynchronously
257 PostUserEvent( LINK( this, MacroMigrationDialog
, OnStartMigration
) );
262 // disable the previous step - we can't return to the actual migration, it already happened (or failed)
263 enableState( STATE_MIGRATE
, false );
266 // display the results
267 dynamic_cast< ResultPage
& >( *GetPage( STATE_SUMMARY
) ).displayMigrationLog(
268 m_pData
->bMigrationSuccess
, m_pData
->aLogger
.getCompleteLog() );
270 enableButtons( WZB_FINISH
, m_pData
->bMigrationSuccess
);
271 enableButtons( WZB_CANCEL
, m_pData
->bMigrationFailure
);
272 defaultButton( m_pData
->bMigrationSuccess
? WZB_FINISH
: WZB_CANCEL
);
276 OSL_ENSURE( false, "MacroMigrationDialog::enterState: unhandled state!" );
280 //--------------------------------------------------------------------
281 sal_Bool
MacroMigrationDialog::prepareLeaveCurrentState( CommitPageReason _eReason
)
283 if ( !MacroMigrationDialog_Base::prepareLeaveCurrentState( _eReason
) )
286 switch ( getCurrentState() )
288 case STATE_CLOSE_SUB_DOCS
:
289 if ( !impl_closeSubDocs_nothrow() )
292 case STATE_BACKUP_DBDOC
:
293 if ( !impl_backupDocument_nothrow() )
301 OSL_ENSURE( false, "MacroMigrationDialog::prepareLeaveCurrentState: unhandled state!" );
307 //--------------------------------------------------------------------
308 sal_Bool
MacroMigrationDialog::leaveState( WizardState _nState
)
310 return MacroMigrationDialog_Base::leaveState( _nState
);
313 //--------------------------------------------------------------------
314 MacroMigrationDialog::WizardState
MacroMigrationDialog::determineNextState( WizardState _nCurrentState
) const
316 return MacroMigrationDialog_Base::determineNextState( _nCurrentState
);
319 //--------------------------------------------------------------------
320 sal_Bool
MacroMigrationDialog::onFinish( sal_Int32 _nResult
)
322 return MacroMigrationDialog_Base::onFinish( _nResult
);
325 //--------------------------------------------------------------------
326 IMPL_LINK( MacroMigrationDialog
, OnStartMigration
, void*, /*_pNotInterestedIn*/ )
329 m_pData
->bMigrationIsRunning
= true;
331 // initialize migration engine and progress
332 ProgressPage
& rProgressPage( dynamic_cast< ProgressPage
& >( *GetPage( STATE_MIGRATE
) ) );
333 MigrationEngine
aEngine( m_pData
->aContext
, m_pData
->xDocument
, rProgressPage
, m_pData
->aLogger
);
334 rProgressPage
.setDocumentCounts( aEngine
.getFormCount(), aEngine
.getReportCount() );
337 m_pData
->bMigrationSuccess
= aEngine
.migrateAll();
338 m_pData
->bMigrationFailure
= !m_pData
->bMigrationSuccess
;
341 enableButtons( WZB_FINISH
| WZB_NEXT
, true );
342 enableState( STATE_SUMMARY
, true );
345 m_pData
->bMigrationIsRunning
= false;
347 if ( m_pData
->bMigrationSuccess
)
349 rProgressPage
.onFinishedSuccessfully();
352 { // if there was an error, show the summary automatically
360 //--------------------------------------------------------------------
361 void MacroMigrationDialog::impl_showCloseDocsError( bool _bShow
)
363 PreparationPage
* pPreparationPage
= dynamic_cast< PreparationPage
* >( GetPage( STATE_CLOSE_SUB_DOCS
) );
364 OSL_ENSURE( pPreparationPage
, "MacroMigrationDialog::impl_showCloseDocsError: did not find the page!" );
365 if ( pPreparationPage
)
366 pPreparationPage
->showCloseDocsError( _bShow
);
369 //--------------------------------------------------------------------
370 bool MacroMigrationDialog::impl_closeSubDocs_nothrow()
372 OSL_PRECOND( m_pData
->xDocument
.is(), "MacroMigrationDialog::impl_closeSubDocs_nothrow: no document!" );
373 if ( !m_pData
->xDocument
.is() )
376 impl_showCloseDocsError( false );
378 bool bSuccess
= true;
381 // collect all controllers of our document
382 ::std::list
< Reference
< XController2
> > aControllers
;
383 lcl_getControllers_throw( m_pData
->xDocumentModel
, aControllers
);
385 // close all sub documents of all controllers
386 for ( ::std::list
< Reference
< XController2
> >::const_iterator pos
= aControllers
.begin();
387 pos
!= aControllers
.end() && bSuccess
;
391 Reference
< XDatabaseDocumentUI
> xController( *pos
, UNO_QUERY
);
392 OSL_ENSURE( xController
.is(), "MacroMigrationDialog::impl_closeSubDocs_nothrow: unexpected: controller is missing an important interface!" );
393 // at the moment, only one implementation for a DBDoc's controller exists, which should
394 // support this interface
395 if ( !xController
.is() )
398 bSuccess
= xController
->closeSubComponents();
401 catch( const Exception
& )
403 DBG_UNHANDLED_EXCEPTION();
407 impl_showCloseDocsError( !bSuccess
);
411 //--------------------------------------------------------------------
414 bool lcl_equalURLs_nothrow( const ::rtl::OUString
& _lhs
, const ::rtl::OUString _rhs
)
416 // the cheap situation: the URLs are equal
423 ::ucbhelper::Content aContentLHS
= ::ucbhelper::Content( _lhs
, Reference
< XCommandEnvironment
>() );
424 ::ucbhelper::Content aContentRHS
= ::ucbhelper::Content( _rhs
, Reference
< XCommandEnvironment
>() );
425 Reference
< XContent
> xContentLHS( aContentLHS
.get(), UNO_SET_THROW
);
426 Reference
< XContent
> xContentRHS( aContentRHS
.get(), UNO_SET_THROW
);
427 Reference
< XContentIdentifier
> xID1( xContentLHS
->getIdentifier(), UNO_SET_THROW
);
428 Reference
< XContentIdentifier
> xID2( xContentRHS
->getIdentifier(), UNO_SET_THROW
);
430 ::ucbhelper::ContentBroker
* pBroker
= ::ucbhelper::ContentBroker::get();
431 Reference
< XContentProvider
> xProvider(
432 pBroker
? pBroker
->getContentProviderInterface() : Reference
< XContentProvider
>(), UNO_SET_THROW
);
434 bEqual
= ( 0 == xProvider
->compareContentIds( xID1
, xID2
) );
436 catch( const Exception
& )
438 DBG_UNHANDLED_EXCEPTION();
444 //--------------------------------------------------------------------
445 bool MacroMigrationDialog::impl_backupDocument_nothrow() const
447 if ( !m_pData
->xDocumentModel
.is() )
448 // should never happen, but has been reported as assertion before
451 SaveDBDocPage
& rBackupPage
= dynamic_cast< SaveDBDocPage
& >( *GetPage( STATE_BACKUP_DBDOC
) );
452 ::rtl::OUString
sBackupLocation( rBackupPage
.getBackupLocation() );
457 // check that the backup location isn't the same as the document itself
458 if ( lcl_equalURLs_nothrow( sBackupLocation
, m_pData
->xDocumentModel
->getURL() ) )
460 ErrorBox
aErrorBox( const_cast< MacroMigrationDialog
* >( this ), MacroMigrationResId( ERR_INVALID_BACKUP_LOCATION
) );
462 rBackupPage
.grabLocationFocus();
466 // store to the backup location
467 const Reference
< XStorable
> xDocument( getDocument(), UNO_QUERY_THROW
);
468 xDocument
->storeToURL( sBackupLocation
, Sequence
< PropertyValue
>() );
469 m_pData
->sSuccessfulBackupLocation
= sBackupLocation
;
471 catch( const Exception
& )
473 aError
= ::cppu::getCaughtException();
475 if ( !aError
.hasValue() )
477 ::svt::OFileNotation
aFileNotation( sBackupLocation
);
478 m_pData
->aLogger
.backedUpDocument( aFileNotation
.get( ::svt::OFileNotation::N_SYSTEM
) );
482 // display the error to the user
483 InteractionHandler
aHandler( m_pData
->aContext
, m_pData
->xDocumentModel
.get() );
484 aHandler
.reportError( aError
);
486 m_pData
->aLogger
.logFailure( MigrationError(
487 ERR_DOCUMENT_BACKUP_FAILED
,
495 //--------------------------------------------------------------------
496 void MacroMigrationDialog::impl_reloadDocument_nothrow( bool _bMigrationSuccess
)
498 typedef ::std::pair
< Reference
< XFrame
>, ::rtl::OUString
> ViewDescriptor
;
499 ::std::list
< ViewDescriptor
> aViews
;
503 // the information which is necessary to reload the document
504 ::rtl::OUString
sDocumentURL ( m_pData
->xDocumentModel
->getURL() );
505 ::comphelper::NamedValueCollection
aDocumentArgs( m_pData
->xDocumentModel
->getArgs() );
506 if ( !_bMigrationSuccess
)
508 // if the migration was not successful, then reload from the backup
509 aDocumentArgs
.put( "SalvagedFile", m_pData
->sSuccessfulBackupLocation
);
510 // reset the modified flag of the document, so the controller can be suspended later
511 Reference
< XModifiable
> xModify( m_pData
->xDocument
, UNO_QUERY_THROW
);
512 xModify
->setModified( sal_False
);
513 // after this reload, don't show the migration warning, again
514 aDocumentArgs
.put( "SuppressMigrationWarning", sal_Bool(sal_True
) );
517 // remove anything from the args which might refer to the old document
518 aDocumentArgs
.remove( "Model" );
519 aDocumentArgs
.remove( "Stream" );
520 aDocumentArgs
.remove( "InputStream" );
521 aDocumentArgs
.remove( "FileName" );
522 aDocumentArgs
.remove( "URL" );
524 // collect all controllers of our document
525 ::std::list
< Reference
< XController2
> > aControllers
;
526 lcl_getControllers_throw( m_pData
->xDocumentModel
, aControllers
);
528 // close all those controllers
529 while ( !aControllers
.empty() )
531 Reference
< XController2
> xController( aControllers
.front(), UNO_SET_THROW
);
532 aControllers
.pop_front();
534 Reference
< XFrame
> xFrame( xController
->getFrame(), UNO_SET_THROW
);
535 ::rtl::OUString
sViewName( xController
->getViewControllerName() );
537 if ( !xController
->suspend( sal_True
) )
538 { // ouch. There shouldn't be any modal dialogs and such, so there
539 // really is no reason why suspending shouldn't work.
540 OSL_ENSURE( false, "MacroMigrationDialog::impl_reloadDocument_nothrow: could not suspend a controller!" );
541 // ignoring this would be at the cost of a crash (potentially)
542 // so, we cannot continue here.
543 throw CloseVetoException();
546 aViews
.push_back( ViewDescriptor( xFrame
, sViewName
) );
547 xFrame
->setComponent( NULL
, NULL
);
548 xController
->dispose();
551 // Note the document is closed now - disconnecting the last controller
552 // closes it automatically.
554 Reference
< XOfficeDatabaseDocument
> xNewDocument
;
556 // re-create the views
557 while ( !aViews
.empty() )
559 ViewDescriptor
aView( aViews
.front() );
562 // load the document into this frame
563 Reference
< XComponentLoader
> xLoader( aView
.first
, UNO_QUERY_THROW
);
564 aDocumentArgs
.put( "ViewName", aView
.second
);
565 Reference
< XInterface
> xReloaded( xLoader
->loadComponentFromURL(
567 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_self" ) ),
569 aDocumentArgs
.getPropertyValues()
572 OSL_ENSURE( xReloaded
!= m_pData
->xDocumentModel
,
573 "MacroMigrationDialog::impl_reloadDocument_nothrow: this should have been a new instance!" );
574 // this would be unexpected, but recoverable: The loader should at least have done
575 // this: really *load* the document, even if it loaded it into the old document instance
576 if ( !xNewDocument
.is() )
578 xNewDocument
.set( xReloaded
, UNO_QUERY_THROW
);
579 // for subsequent loads, into different frames, put the document into the load args
580 aDocumentArgs
.put( "Model", xNewDocument
);
582 #if OSL_DEBUG_LEVEL > 0
585 OSL_ENSURE( xNewDocument
== xReloaded
,
586 "MacroMigrationDialog::impl_reloadDocument_nothrow: unexpected: subsequent load attempt returned a wrong document!" );
591 m_pData
->xDocument
= xNewDocument
;
592 m_pData
->xDocumentModel
.set( xNewDocument
, UNO_QUERY
);
594 // finally, now that the document has been reloaded - if the migration was not successful,
595 // then it was reloaded from the backup, but the real document still is broken. So, save
596 // the document once, which will write the content loaded from the backup to the real docfile.
597 if ( !_bMigrationSuccess
)
599 Reference
< XModifiable
> xModify( m_pData
->xDocument
, UNO_QUERY_THROW
);
600 xModify
->setModified( sal_True
);
601 // this is just parnoia - in case saving the doc fails, perhaps the user is tempted to do so
602 Reference
< XStorable
> xStor( m_pData
->xDocument
, UNO_QUERY_THROW
);
606 catch( const Exception
& )
608 DBG_UNHANDLED_EXCEPTION();
611 // close all frames from aViews - the respective controllers have been closed, but
612 // reloading didn't work, so the frames are zombies now.
613 while ( !aViews
.empty() )
615 ViewDescriptor
aView( aViews
.front() );
619 Reference
< XCloseable
> xFrameClose( aView
.first
, UNO_QUERY_THROW
);
620 xFrameClose
->close( sal_True
);
622 catch( const Exception
& )
624 DBG_UNHANDLED_EXCEPTION();
629 //........................................................................
631 //........................................................................