Update ooo320-m1
[ooovba.git] / desktop / source / deployment / gui / dp_gui_extensioncmdqueue.cxx
blobf31d63a7039a12cb662f95ae850f6e05326f8808
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dp_gui_extensioncmdqueue.cxx,v $
11 * $Revision: 1.7.4.3 $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************/
32 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_desktop.hxx"
38 #include "sal/config.h"
40 #include <cstddef>
42 #include "com/sun/star/beans/PropertyValue.hpp"
44 #include "com/sun/star/deployment/DependencyException.hpp"
45 #include "com/sun/star/deployment/LicenseException.hpp"
46 #include "com/sun/star/deployment/LicenseIndividualAgreementException.hpp"
47 #include "com/sun/star/deployment/VersionException.hpp"
48 #include "com/sun/star/deployment/InstallException.hpp"
49 #include "com/sun/star/deployment/PlatformException.hpp"
51 #include "com/sun/star/deployment/ui/LicenseDialog.hpp"
52 #include "com/sun/star/deployment/DeploymentException.hpp"
53 #include "com/sun/star/deployment/UpdateInformationProvider.hpp"
54 #include "com/sun/star/deployment/XPackage.hpp"
55 #include "com/sun/star/deployment/XPackageManager.hpp"
57 #include "com/sun/star/task/XAbortChannel.hpp"
58 #include "com/sun/star/task/XInteractionAbort.hpp"
59 #include "com/sun/star/task/XInteractionApprove.hpp"
61 #include "com/sun/star/ucb/CommandAbortedException.hpp"
62 #include "com/sun/star/ucb/CommandFailedException.hpp"
63 #include "com/sun/star/ucb/XCommandEnvironment.hpp"
65 #include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp"
67 #include "com/sun/star/uno/Reference.hxx"
68 #include "com/sun/star/uno/RuntimeException.hpp"
69 #include "com/sun/star/uno/Sequence.hxx"
70 #include "com/sun/star/uno/XInterface.hpp"
71 #include "com/sun/star/uno/TypeClass.hpp"
72 #include "osl/diagnose.h"
73 #include "osl/mutex.hxx"
74 #include "rtl/ref.hxx"
75 #include "rtl/ustring.h"
76 #include "rtl/ustring.hxx"
77 #include "sal/types.h"
78 #include "ucbhelper/content.hxx"
79 #include "cppuhelper/exc_hlp.hxx"
80 #include "cppuhelper/implbase3.hxx"
81 #include "comphelper/anytostring.hxx"
82 #include "vcl/msgbox.hxx"
83 #include "toolkit/helper/vclunohelper.hxx"
85 #include "dp_gui.h"
86 #include "dp_gui_thread.hxx"
87 #include "dp_gui_extensioncmdqueue.hxx"
88 #include "dp_gui_dependencydialog.hxx"
89 #include "dp_gui_dialog2.hxx"
90 #include "dp_gui_shared.hxx"
91 #include "dp_gui_theextmgr.hxx"
92 #include "dp_gui_updatedialog.hxx"
93 #include "dp_gui_updateinstalldialog.hxx"
94 #include "dp_dependencies.hxx"
95 #include "dp_identifier.hxx"
96 #include "dp_version.hxx"
98 #include <queue>
99 #include <boost/shared_ptr.hpp>
101 #if (defined(_MSC_VER) && (_MSC_VER < 1400))
102 #define _WIN32_WINNT 0x0400
103 #endif
105 #ifdef WNT
106 #include "tools/prewin.h"
107 #include <objbase.h>
108 #include "tools/postwin.h"
109 #endif
112 using namespace ::com::sun::star;
113 using ::rtl::OUString;
115 namespace {
117 OUString getVersion( const uno::Reference< deployment::XPackage > &rPackage )
119 OUString sVersion( rPackage->getVersion());
120 return ( sVersion.getLength() == 0 ) ? OUString( RTL_CONSTASCII_USTRINGPARAM( "0" ) ) : sVersion;
126 namespace dp_gui {
128 //==============================================================================
130 class ProgressCmdEnv
131 : public ::cppu::WeakImplHelper3< ucb::XCommandEnvironment,
132 task::XInteractionHandler,
133 ucb::XProgressHandler >
135 uno::Reference< task::XInteractionHandler> m_xHandler;
136 uno::Reference< uno::XComponentContext > m_xContext;
137 uno::Reference< task::XAbortChannel> m_xAbortChannel;
139 DialogHelper *m_pDialogHelper;
140 OUString m_sTitle;
141 bool m_bAborted;
142 bool m_bWarnUser;
143 sal_Int32 m_nCurrentProgress;
145 void updateProgress();
147 void update_( uno::Any const & Status ) throw ( uno::RuntimeException );
149 public:
150 virtual ~ProgressCmdEnv();
152 /** When param bAskWhenInstalling = true, then the user is asked if he
153 agrees to install this extension. In case this extension is already installed
154 then the user is also notified and asked if he wants to replace that existing
155 extension. In first case an interaction request with an InstallException
156 will be handled and in the second case a VersionException will be handled.
159 ProgressCmdEnv( const uno::Reference< uno::XComponentContext > rContext,
160 DialogHelper *pDialogHelper,
161 const OUString &rTitle )
162 : m_xContext( rContext ),
163 m_pDialogHelper( pDialogHelper ),
164 m_sTitle( rTitle ),
165 m_bAborted( false ),
166 m_bWarnUser( false )
169 Dialog * activeDialog() { return m_pDialogHelper->getWindow(); }
171 void setTitle( const OUString& rNewTitle ) { m_sTitle = rNewTitle; }
172 void startProgress();
173 void stopProgress();
174 void progressSection( const OUString &rText,
175 const uno::Reference< task::XAbortChannel > &xAbortChannel = 0 );
176 inline bool isAborted() const { return m_bAborted; }
177 inline void setWarnUser( bool bNewVal ) { m_bWarnUser = bNewVal; }
179 // XCommandEnvironment
180 virtual uno::Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler()
181 throw ( uno::RuntimeException );
182 virtual uno::Reference< ucb::XProgressHandler > SAL_CALL getProgressHandler()
183 throw ( uno::RuntimeException );
185 // XInteractionHandler
186 virtual void SAL_CALL handle( uno::Reference< task::XInteractionRequest > const & xRequest )
187 throw ( uno::RuntimeException );
189 // XProgressHandler
190 virtual void SAL_CALL push( uno::Any const & Status )
191 throw ( uno::RuntimeException );
192 virtual void SAL_CALL update( uno::Any const & Status )
193 throw ( uno::RuntimeException );
194 virtual void SAL_CALL pop() throw ( uno::RuntimeException );
197 //------------------------------------------------------------------------------
198 struct ExtensionCmd
200 enum E_CMD_TYPE { ADD, ENABLE, DISABLE, REMOVE, CHECK_FOR_UPDATES };
202 E_CMD_TYPE m_eCmdType;
203 bool m_bWarnUser;
204 OUString m_sExtensionURL;
205 uno::Reference< deployment::XPackageManager > m_xPackageManager;
206 uno::Reference< deployment::XPackage > m_xPackage;
207 std::vector< TUpdateListEntry > m_vExtensionList;
209 ExtensionCmd( const E_CMD_TYPE eCommand,
210 const uno::Reference< deployment::XPackageManager > &rPackageManager,
211 const OUString &rExtensionURL,
212 const bool bWarnUser )
213 : m_eCmdType( eCommand ),
214 m_bWarnUser( bWarnUser ),
215 m_sExtensionURL( rExtensionURL ),
216 m_xPackageManager( rPackageManager ) {};
217 ExtensionCmd( const E_CMD_TYPE eCommand,
218 const uno::Reference< deployment::XPackageManager > &rPackageManager,
219 const uno::Reference< deployment::XPackage > &rPackage )
220 : m_eCmdType( eCommand ),
221 m_bWarnUser( false ),
222 m_xPackageManager( rPackageManager ),
223 m_xPackage( rPackage ) {};
224 ExtensionCmd( const E_CMD_TYPE eCommand,
225 const uno::Reference< deployment::XPackage > &rPackage )
226 : m_eCmdType( eCommand ),
227 m_bWarnUser( false ),
228 m_xPackage( rPackage ) {};
229 ExtensionCmd( const E_CMD_TYPE eCommand,
230 const std::vector< TUpdateListEntry > &vExtensionList )
231 : m_eCmdType( eCommand ),
232 m_bWarnUser( false ),
233 m_vExtensionList( vExtensionList ) {};
236 typedef ::boost::shared_ptr< ExtensionCmd > TExtensionCmd;
238 //------------------------------------------------------------------------------
239 class ExtensionCmdQueue::Thread: public dp_gui::Thread
241 public:
242 Thread( DialogHelper *pDialogHelper,
243 TheExtensionManager *pManager,
244 const uno::Reference< uno::XComponentContext > & rContext );
246 void addExtension( const uno::Reference< deployment::XPackageManager > &rPackageManager,
247 const OUString &rExtensionURL,
248 const bool bWarnUser );
249 void removeExtension( const uno::Reference< deployment::XPackageManager > &rPackageManager,
250 const uno::Reference< deployment::XPackage > &rPackage );
251 void enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
252 const bool bEnable );
253 void checkForUpdates( const std::vector< TUpdateListEntry > &vExtensionList );
254 void stop();
255 bool hasTerminated();
256 bool isBusy();
258 static OUString searchAndReplaceAll( const OUString &rSource,
259 const OUString &rWhat,
260 const OUString &rWith );
261 private:
262 Thread( Thread & ); // not defined
263 void operator =( Thread & ); // not defined
265 virtual ~Thread();
267 virtual void execute();
268 virtual void SAL_CALL onTerminated();
270 void _addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
271 const uno::Reference< deployment::XPackageManager > &xPackageManager,
272 const OUString &rPackageURL,
273 const bool bWarnUser );
274 void _removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
275 const uno::Reference< deployment::XPackageManager > &xPackageManager,
276 const uno::Reference< deployment::XPackage > &xPackage );
277 void _enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
278 const uno::Reference< deployment::XPackage > &xPackage );
279 void _disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
280 const uno::Reference< deployment::XPackage > &xPackage );
281 void _checkForUpdates( const std::vector< TUpdateListEntry > &vExtensionList );
283 enum Input { NONE, START, STOP };
285 uno::Reference< uno::XComponentContext > m_xContext;
286 std::queue< TExtensionCmd > m_queue;
288 DialogHelper *m_pDialogHelper;
289 TheExtensionManager *m_pManager;
291 const OUString m_sEnablingPackages;
292 const OUString m_sDisablingPackages;
293 const OUString m_sAddingPackages;
294 const OUString m_sRemovingPackages;
295 const OUString m_sDefaultCmd;
296 osl::Condition m_wakeup;
297 osl::Mutex m_mutex;
298 Input m_eInput;
299 bool m_bTerminated;
300 bool m_bStopped;
301 bool m_bWorking;
304 //------------------------------------------------------------------------------
305 void ProgressCmdEnv::startProgress()
307 m_nCurrentProgress = 0;
309 if ( m_pDialogHelper )
310 m_pDialogHelper->showProgress( true );
313 //------------------------------------------------------------------------------
314 void ProgressCmdEnv::stopProgress()
316 if ( m_pDialogHelper )
317 m_pDialogHelper->showProgress( false );
320 //------------------------------------------------------------------------------
321 void ProgressCmdEnv::progressSection( const OUString &rText,
322 const uno::Reference< task::XAbortChannel > &xAbortChannel )
324 m_xAbortChannel = xAbortChannel;
325 if (! m_bAborted)
327 m_nCurrentProgress = 0;
328 if ( m_pDialogHelper )
330 m_pDialogHelper->updateProgress( rText, xAbortChannel );
331 m_pDialogHelper->updateProgress( 5 );
336 //------------------------------------------------------------------------------
337 void ProgressCmdEnv::updateProgress()
339 if ( ! m_bAborted )
341 long nProgress = ((m_nCurrentProgress*5) % 100) + 5;
342 if ( m_pDialogHelper )
343 m_pDialogHelper->updateProgress( nProgress );
347 //------------------------------------------------------------------------------
348 ProgressCmdEnv::~ProgressCmdEnv()
350 // TODO: stop all threads and wait
354 //------------------------------------------------------------------------------
355 // XCommandEnvironment
356 //------------------------------------------------------------------------------
357 uno::Reference< task::XInteractionHandler > ProgressCmdEnv::getInteractionHandler()
358 throw ( uno::RuntimeException )
360 return this;
363 //------------------------------------------------------------------------------
364 uno::Reference< ucb::XProgressHandler > ProgressCmdEnv::getProgressHandler()
365 throw ( uno::RuntimeException )
367 return this;
370 //------------------------------------------------------------------------------
371 // XInteractionHandler
372 //------------------------------------------------------------------------------
373 void ProgressCmdEnv::handle( uno::Reference< task::XInteractionRequest > const & xRequest )
374 throw ( uno::RuntimeException )
376 uno::Any request( xRequest->getRequest() );
377 OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION );
378 dp_misc::TRACE( OUSTR("[dp_gui_cmdenv.cxx] incoming request:\n")
379 + ::comphelper::anyToString(request) + OUSTR("\n"));
381 lang::WrappedTargetException wtExc;
382 deployment::DependencyException depExc;
383 deployment::LicenseException licExc;
384 deployment::LicenseIndividualAgreementException licAgreementExc;
385 deployment::VersionException verExc;
386 deployment::InstallException instExc;
387 deployment::PlatformException platExc;
389 // selections:
390 bool approve = false;
391 bool abort = false;
393 if (request >>= wtExc) {
394 // handable deployment error signalled, e.g.
395 // bundle item registration failed, notify cause only:
396 uno::Any cause;
397 deployment::DeploymentException dpExc;
398 if (wtExc.TargetException >>= dpExc)
399 cause = dpExc.Cause;
400 else {
401 ucb::CommandFailedException cfExc;
402 if (wtExc.TargetException >>= cfExc)
403 cause = cfExc.Reason;
404 else
405 cause = wtExc.TargetException;
407 update_( cause );
409 // ignore intermediate errors of legacy packages, i.e.
410 // former pkgchk behaviour:
411 const uno::Reference< deployment::XPackage > xPackage( wtExc.Context, uno::UNO_QUERY );
412 OSL_ASSERT( xPackage.is() );
413 if ( xPackage.is() )
415 const uno::Reference< deployment::XPackageTypeInfo > xPackageType( xPackage->getPackageType() );
416 OSL_ASSERT( xPackageType.is() );
417 if (xPackageType.is())
419 approve = ( xPackage->isBundle() &&
420 xPackageType->getMediaType().matchAsciiL(
421 RTL_CONSTASCII_STRINGPARAM(
422 "application/"
423 "vnd.sun.star.legacy-package-bundle") ));
426 abort = !approve;
428 else if (request >>= depExc)
430 std::vector< rtl::OUString > deps;
431 for (sal_Int32 i = 0; i < depExc.UnsatisfiedDependencies.getLength();
432 ++i)
434 deps.push_back(
435 dp_misc::Dependencies::getErrorText( depExc.UnsatisfiedDependencies[i]) );
438 vos::OGuard guard(Application::GetSolarMutex());
439 short n = DependencyDialog( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, deps ).Execute();
440 // Distinguish between closing the dialog and programatically
441 // canceling the dialog (headless VCL):
442 approve = n == RET_OK
443 || (n == RET_CANCEL && !Application::IsDialogCancelEnabled());
446 else if (request >>= licAgreementExc)
448 vos::OGuard aSolarGuard( Application::GetSolarMutex() );
449 ResId warnId(WARNINGBOX_NOSHAREDALLOWED, *DeploymentGuiResMgr::get());
450 WarningBox warn( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, warnId);
451 String msgText = warn.GetMessText();
452 msgText.SearchAndReplaceAllAscii( "%PRODUCTNAME", BrandName::get() );
453 msgText.SearchAndReplaceAllAscii("%NAME", licAgreementExc.ExtensionName);
454 warn.SetMessText(msgText);
455 warn.Execute();
456 abort = true;
458 else if (request >>= licExc)
460 uno::Reference< ui::dialogs::XExecutableDialog > xDialog(
461 deployment::ui::LicenseDialog::create(
462 m_xContext, VCLUnoHelper::GetInterface( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL ), licExc.Text ) );
463 sal_Int16 res = xDialog->execute();
464 if ( res == ui::dialogs::ExecutableDialogResults::CANCEL )
465 abort = true;
466 else if ( res == ui::dialogs::ExecutableDialogResults::OK )
467 approve = true;
468 else
470 OSL_ASSERT(0);
473 else if (request >>= verExc)
475 sal_uInt32 id;
476 switch (dp_misc::comparePackageVersions( verExc.New, verExc.Deployed ))
478 case dp_misc::LESS:
479 id = RID_WARNINGBOX_VERSION_LESS;
480 break;
481 case dp_misc::EQUAL:
482 id = RID_WARNINGBOX_VERSION_EQUAL;
483 break;
484 default: // dp_misc::GREATER
485 id = RID_WARNINGBOX_VERSION_GREATER;
486 break;
488 OSL_ASSERT( verExc.New.is() && verExc.Deployed.is() );
489 bool bEqualNames = verExc.New->getDisplayName().equals(
490 verExc.Deployed->getDisplayName());
492 vos::OGuard guard(Application::GetSolarMutex());
493 WarningBox box( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, ResId(id, *DeploymentGuiResMgr::get()));
494 String s;
495 if (bEqualNames)
497 s = box.GetMessText();
499 else if (id == RID_WARNINGBOX_VERSION_EQUAL)
501 //hypothetical: requires two instances of an extension with the same
502 //version to have different display names. Probably the developer forgot
503 //to change the version.
504 s = String(ResId(RID_STR_WARNINGBOX_VERSION_EQUAL_DIFFERENT_NAMES, *DeploymentGuiResMgr::get()));
506 else if (id == RID_WARNINGBOX_VERSION_LESS)
508 s = String(ResId(RID_STR_WARNINGBOX_VERSION_LESS_DIFFERENT_NAMES, *DeploymentGuiResMgr::get()));
510 else if (id == RID_WARNINGBOX_VERSION_GREATER)
512 s = String(ResId(RID_STR_WARNINGBOX_VERSION_GREATER_DIFFERENT_NAMES, *DeploymentGuiResMgr::get()));
514 s.SearchAndReplaceAllAscii( "$NAME", verExc.New->getDisplayName());
515 s.SearchAndReplaceAllAscii( "$OLDNAME", verExc.Deployed->getDisplayName());
516 s.SearchAndReplaceAllAscii( "$NEW", getVersion(verExc.New) );
517 s.SearchAndReplaceAllAscii( "$DEPLOYED", getVersion(verExc.Deployed) );
518 box.SetMessText(s);
519 approve = box.Execute() == RET_OK;
520 abort = !approve;
523 else if (request >>= instExc)
525 if ( ! m_bWarnUser )
527 approve = true;
529 else
531 if ( m_pDialogHelper )
533 vos::OGuard guard(Application::GetSolarMutex());
535 approve = m_pDialogHelper->installExtensionWarn( instExc.New->getDisplayName() );
537 else
538 approve = false;
539 abort = !approve;
542 else if (request >>= platExc)
544 vos::OGuard guard( Application::GetSolarMutex() );
545 String sMsg( ResId( RID_STR_UNSUPPORTED_PLATFORM, *DeploymentGuiResMgr::get() ) );
546 sMsg.SearchAndReplaceAllAscii( "%Name", platExc.package->getDisplayName() );
547 ErrorBox box( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, WB_OK, sMsg );
548 box.Execute();
549 approve = true;
552 if (approve == false && abort == false)
554 // forward to UUI handler:
555 if (! m_xHandler.is()) {
556 // late init:
557 uno::Sequence< uno::Any > handlerArgs( 1 );
558 handlerArgs[ 0 ] <<= beans::PropertyValue(
559 OUSTR("Context"), -1, uno::Any( m_sTitle ),
560 beans::PropertyState_DIRECT_VALUE );
561 m_xHandler.set( m_xContext->getServiceManager()
562 ->createInstanceWithArgumentsAndContext(
563 OUSTR("com.sun.star.uui.InteractionHandler"),
564 handlerArgs, m_xContext ), uno::UNO_QUERY_THROW );
566 m_xHandler->handle( xRequest );
568 else
570 // select:
571 uno::Sequence< uno::Reference< task::XInteractionContinuation > > conts(
572 xRequest->getContinuations() );
573 uno::Reference< task::XInteractionContinuation > const * pConts = conts.getConstArray();
574 sal_Int32 len = conts.getLength();
575 for ( sal_Int32 pos = 0; pos < len; ++pos )
577 if (approve) {
578 uno::Reference< task::XInteractionApprove > xInteractionApprove( pConts[ pos ], uno::UNO_QUERY );
579 if (xInteractionApprove.is()) {
580 xInteractionApprove->select();
581 // don't query again for ongoing continuations:
582 approve = false;
585 else if (abort) {
586 uno::Reference< task::XInteractionAbort > xInteractionAbort( pConts[ pos ], uno::UNO_QUERY );
587 if (xInteractionAbort.is()) {
588 xInteractionAbort->select();
589 // don't query again for ongoing continuations:
590 abort = false;
597 //------------------------------------------------------------------------------
598 // XProgressHandler
599 //------------------------------------------------------------------------------
600 void ProgressCmdEnv::push( uno::Any const & rStatus )
601 throw( uno::RuntimeException )
603 update_( rStatus );
606 //------------------------------------------------------------------------------
607 void ProgressCmdEnv::update_( uno::Any const & rStatus )
608 throw( uno::RuntimeException )
610 OUString text;
611 if ( rStatus.hasValue() && !( rStatus >>= text) )
613 if ( rStatus.getValueTypeClass() == uno::TypeClass_EXCEPTION )
614 text = static_cast< uno::Exception const *>( rStatus.getValue() )->Message;
615 if ( text.getLength() == 0 )
616 text = ::comphelper::anyToString( rStatus ); // fallback
618 const ::vos::OGuard aGuard( Application::GetSolarMutex() );
619 const ::std::auto_ptr< ErrorBox > aBox( new ErrorBox( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, WB_OK, text ) );
620 aBox->Execute();
622 ++m_nCurrentProgress;
623 updateProgress();
626 //------------------------------------------------------------------------------
627 void ProgressCmdEnv::update( uno::Any const & rStatus )
628 throw( uno::RuntimeException )
630 update_( rStatus );
633 //------------------------------------------------------------------------------
634 void ProgressCmdEnv::pop()
635 throw( uno::RuntimeException )
637 update_( uno::Any() ); // no message
640 //------------------------------------------------------------------------------
641 ExtensionCmdQueue::Thread::Thread( DialogHelper *pDialogHelper,
642 TheExtensionManager *pManager,
643 const uno::Reference< uno::XComponentContext > & rContext ) :
644 m_xContext( rContext ),
645 m_pDialogHelper( pDialogHelper ),
646 m_pManager( pManager ),
647 m_sEnablingPackages( DialogHelper::getResourceString( RID_STR_ENABLING_PACKAGES ) ),
648 m_sDisablingPackages( DialogHelper::getResourceString( RID_STR_DISABLING_PACKAGES ) ),
649 m_sAddingPackages( DialogHelper::getResourceString( RID_STR_ADDING_PACKAGES ) ),
650 m_sRemovingPackages( DialogHelper::getResourceString( RID_STR_REMOVING_PACKAGES ) ),
651 m_sDefaultCmd( DialogHelper::getResourceString( RID_STR_ADD_PACKAGES ) ),
652 m_eInput( NONE ),
653 m_bTerminated( false ),
654 m_bStopped( false ),
655 m_bWorking( false )
657 OSL_ASSERT( pDialogHelper );
660 //------------------------------------------------------------------------------
661 void ExtensionCmdQueue::Thread::addExtension( const uno::Reference< deployment::XPackageManager > &rPackageManager,
662 const ::rtl::OUString &rExtensionURL,
663 const bool bWarnUser )
665 ::osl::MutexGuard aGuard( m_mutex );
667 //If someone called stop then we do not add the extension -> game over!
668 if ( m_bStopped )
669 return;
671 if ( rExtensionURL.getLength() )
673 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ADD, rPackageManager, rExtensionURL, bWarnUser ) );
675 m_queue.push( pEntry );
676 m_eInput = START;
677 m_wakeup.set();
681 //------------------------------------------------------------------------------
682 void ExtensionCmdQueue::Thread::removeExtension( const uno::Reference< deployment::XPackageManager > &rPackageManager,
683 const uno::Reference< deployment::XPackage > &rPackage )
685 ::osl::MutexGuard aGuard( m_mutex );
687 //If someone called stop then we do not remove the extension -> game over!
688 if ( m_bStopped )
689 return;
691 if ( rPackageManager.is() && rPackage.is() )
693 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::REMOVE, rPackageManager, rPackage ) );
695 m_queue.push( pEntry );
696 m_eInput = START;
697 m_wakeup.set();
701 //------------------------------------------------------------------------------
702 void ExtensionCmdQueue::Thread::enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
703 const bool bEnable )
705 ::osl::MutexGuard aGuard( m_mutex );
707 //If someone called stop then we do not remove the extension -> game over!
708 if ( m_bStopped )
709 return;
711 if ( rPackage.is() )
713 TExtensionCmd pEntry( new ExtensionCmd( bEnable ? ExtensionCmd::ENABLE :
714 ExtensionCmd::DISABLE,
715 rPackage ) );
716 m_queue.push( pEntry );
717 m_eInput = START;
718 m_wakeup.set();
722 //------------------------------------------------------------------------------
723 void ExtensionCmdQueue::Thread::checkForUpdates( const std::vector< TUpdateListEntry > &vExtensionList )
725 ::osl::MutexGuard aGuard( m_mutex );
727 //If someone called stop then we do not update the extension -> game over!
728 if ( m_bStopped )
729 return;
731 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::CHECK_FOR_UPDATES, vExtensionList ) );
732 m_queue.push( pEntry );
733 m_eInput = START;
734 m_wakeup.set();
737 //------------------------------------------------------------------------------
738 //Stopping this thread will not abort the installation of extensions.
739 void ExtensionCmdQueue::Thread::stop()
741 osl::MutexGuard aGuard( m_mutex );
742 m_bStopped = true;
743 m_eInput = STOP;
744 m_wakeup.set();
747 //------------------------------------------------------------------------------
748 bool ExtensionCmdQueue::Thread::hasTerminated()
750 osl::MutexGuard aGuard( m_mutex );
751 return m_bTerminated;
754 //------------------------------------------------------------------------------
755 bool ExtensionCmdQueue::Thread::isBusy()
757 osl::MutexGuard aGuard( m_mutex );
758 return m_bWorking;
761 //------------------------------------------------------------------------------
762 ExtensionCmdQueue::Thread::~Thread() {}
764 //------------------------------------------------------------------------------
765 void ExtensionCmdQueue::Thread::execute()
767 #ifdef WNT
768 //Needed for use of the service "com.sun.star.system.SystemShellExecute" in
769 //DialogHelper::openWebBrowser
770 CoUninitialize();
771 HRESULT r = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
772 #endif
773 for (;;)
775 if ( m_wakeup.wait() != osl::Condition::result_ok )
777 dp_misc::TRACE( "dp_gui::ExtensionCmdQueue::Thread::run: ignored "
778 "osl::Condition::wait failure\n" );
780 m_wakeup.reset();
782 int nSize;
783 Input eInput;
785 osl::MutexGuard aGuard( m_mutex );
786 eInput = m_eInput;
787 m_eInput = NONE;
788 nSize = m_queue.size();
789 m_bWorking = false;
792 // If this thread has been woken up by anything else except start, stop
793 // then input is NONE and we wait again.
794 // We only install the extension which are currently in the queue.
795 // The progressbar will be set to show the progress of the current number
796 // of extensions. If we allowed to add extensions now then the progressbar may
797 // have reached the end while we still install newly added extensions.
798 if ( ( eInput == NONE ) || ( nSize == 0 ) )
799 continue;
800 if ( eInput == STOP )
801 break;
803 ::rtl::Reference< ProgressCmdEnv > currentCmdEnv( new ProgressCmdEnv( m_xContext, m_pDialogHelper, m_sDefaultCmd ) );
805 // Do not lock the following part with addExtension. addExtension may be called in the main thread.
806 // If the message box "Do you want to install the extension (or similar)" is shown and then
807 // addExtension is called, which then blocks the main thread, then we deadlock.
808 bool bStartProgress = true;
810 while ( !currentCmdEnv->isAborted() && --nSize >= 0 )
813 osl::MutexGuard aGuard( m_mutex );
814 m_bWorking = true;
819 TExtensionCmd pEntry;
821 ::osl::MutexGuard queueGuard( m_mutex );
822 pEntry = m_queue.front();
823 m_queue.pop();
826 if ( bStartProgress && ( pEntry->m_eCmdType != ExtensionCmd::CHECK_FOR_UPDATES ) )
828 currentCmdEnv->startProgress();
829 bStartProgress = false;
832 switch ( pEntry->m_eCmdType ) {
833 case ExtensionCmd::ADD :
834 _addExtension( currentCmdEnv, pEntry->m_xPackageManager, pEntry->m_sExtensionURL, pEntry->m_bWarnUser );
835 break;
836 case ExtensionCmd::REMOVE :
837 _removeExtension( currentCmdEnv, pEntry->m_xPackageManager, pEntry->m_xPackage );
838 break;
839 case ExtensionCmd::ENABLE :
840 _enableExtension( currentCmdEnv, pEntry->m_xPackage );
841 break;
842 case ExtensionCmd::DISABLE :
843 _disableExtension( currentCmdEnv, pEntry->m_xPackage );
844 break;
845 case ExtensionCmd::CHECK_FOR_UPDATES :
846 _checkForUpdates( pEntry->m_vExtensionList );
847 break;
850 //catch ( deployment::DeploymentException &)
851 //{
853 //catch ( lang::IllegalArgumentException &)
856 catch ( ucb::CommandAbortedException & )
858 //This exception is thrown when the user clicks cancel on the progressbar.
859 //Then we cancel the installation of all extensions and remove them from
860 //the queue.
862 ::osl::MutexGuard queueGuard2(m_mutex);
863 while ( --nSize >= 0 )
864 m_queue.pop();
866 break;
868 catch ( ucb::CommandFailedException & )
870 //This exception is thrown when a user clicked cancel in the messagebox which was
871 //startet by the interaction handler. For example the user will be asked if he/she
872 //really wants to install the extension.
873 //These interaction are run for exectly one extension at a time. Therefore we continue
874 //with installing the remaining extensions.
875 continue;
877 catch ( uno::Exception & )
879 //Todo display the user an error
880 //see also DialogImpl::SyncPushButton::Click()
881 uno::Any exc( ::cppu::getCaughtException() );
882 OUString msg;
883 deployment::DeploymentException dpExc;
884 if ((exc >>= dpExc) &&
885 dpExc.Cause.getValueTypeClass() == uno::TypeClass_EXCEPTION)
887 // notify error cause only:
888 msg = reinterpret_cast< uno::Exception const * >( dpExc.Cause.getValue() )->Message;
890 if (msg.getLength() == 0) // fallback for debugging purposes
891 msg = ::comphelper::anyToString(exc);
893 const ::vos::OGuard guard( Application::GetSolarMutex() );
894 ::std::auto_ptr<ErrorBox> box(
895 new ErrorBox( currentCmdEnv->activeDialog(), WB_OK, msg ) );
896 if ( m_pDialogHelper )
897 box->SetText( m_pDialogHelper->getWindow()->GetText() );
898 box->Execute();
899 //Continue with installation of the remaining extensions
902 osl::MutexGuard aGuard( m_mutex );
903 m_bWorking = false;
908 // when leaving the while loop with break, we should set working to false, too
909 osl::MutexGuard aGuard( m_mutex );
910 m_bWorking = false;
913 if ( !bStartProgress )
914 currentCmdEnv->stopProgress();
916 //end for
917 //enable all buttons
918 // m_pDialog->m_bAddingExtensions = false;
919 // m_pDialog->updateButtonStates();
920 #ifdef WNT
921 CoUninitialize();
922 #endif
925 //------------------------------------------------------------------------------
926 void ExtensionCmdQueue::Thread::_addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
927 const uno::Reference< deployment::XPackageManager > &xPackageManager,
928 const OUString &rPackageURL,
929 const bool bWarnUser )
931 //check if we have a string in anyTitle. For example "unopkg gui \" caused anyTitle to be void
932 //and anyTitle.get<OUString> throws as RuntimeException.
933 uno::Any anyTitle;
936 anyTitle = ::ucbhelper::Content( rPackageURL, rCmdEnv.get() ).getPropertyValue( OUSTR("Title") );
938 catch ( uno::Exception & )
940 return;
943 OUString sName;
944 if ( ! (anyTitle >>= sName) )
946 OSL_ENSURE(0, "Could not get file name for extension.");
947 return;
950 rCmdEnv->setWarnUser( bWarnUser );
951 uno::Reference< task::XAbortChannel > xAbortChannel( xPackageManager->createAbortChannel() );
952 OUString sTitle = searchAndReplaceAll( m_sAddingPackages, OUSTR("%EXTENSION_NAME"), sName );
953 rCmdEnv->progressSection( sTitle, xAbortChannel );
957 uno::Reference< deployment::XPackage > xPackage( xPackageManager->addPackage(
958 rPackageURL, OUString() /* detect media-type */,
959 xAbortChannel, rCmdEnv.get() ) );
960 OSL_ASSERT( xPackage.is() );
962 catch ( ucb::CommandFailedException & )
964 // When the extension is already installed we'll get a dialog asking if we want to overwrite. If we then press
965 // cancel this exception is thrown.
967 catch ( ucb::CommandAbortedException & )
969 // User clicked the cancel button
970 // TODO: handle cancel
972 rCmdEnv->setWarnUser( false );
975 //------------------------------------------------------------------------------
976 void ExtensionCmdQueue::Thread::_removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
977 const uno::Reference< deployment::XPackageManager > &xPackageManager,
978 const uno::Reference< deployment::XPackage > &xPackage )
980 uno::Reference< task::XAbortChannel > xAbortChannel( xPackageManager->createAbortChannel() );
981 OUString sTitle = searchAndReplaceAll( m_sRemovingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
982 rCmdEnv->progressSection( sTitle, xAbortChannel );
984 OUString id( dp_misc::getIdentifier( xPackage ) );
987 xPackageManager->removePackage( id, xPackage->getName(), xAbortChannel, rCmdEnv.get() );
989 catch ( ucb::CommandAbortedException & )
992 // Check, if there are still updates to be notified via menu bar icon
993 uno::Sequence< uno::Sequence< rtl::OUString > > aItemList;
994 UpdateDialog::createNotifyJob( false, aItemList );
997 //------------------------------------------------------------------------------
998 void ExtensionCmdQueue::Thread::_checkForUpdates( const std::vector< TUpdateListEntry > &vExtensionList )
1000 UpdateDialog* pUpdateDialog;
1001 std::vector< UpdateData > vData;
1003 const ::vos::OGuard guard( Application::GetSolarMutex() );
1005 pUpdateDialog = new UpdateDialog( m_xContext, m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, vExtensionList, &vData );
1007 pUpdateDialog->notifyMenubar( true, false ); // prepare the checking, if there updates to be notified via menu bar icon
1009 if ( ( pUpdateDialog->Execute() == RET_OK ) && !vData.empty() )
1011 // If there is at least one directly downloadable dialog then we
1012 // open the install dialog.
1013 ::std::vector< UpdateData > dataDownload;
1014 int countWebsiteDownload = 0;
1015 typedef std::vector< dp_gui::UpdateData >::const_iterator cit;
1017 for ( cit i = vData.begin(); i < vData.end(); i++ )
1019 if ( i->sWebsiteURL.getLength() > 0 )
1020 countWebsiteDownload ++;
1021 else
1022 dataDownload.push_back( *i );
1025 short nDialogResult = RET_OK;
1026 if ( !dataDownload.empty() )
1028 nDialogResult = UpdateInstallDialog( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, dataDownload, m_xContext ).Execute();
1029 pUpdateDialog->notifyMenubar( false, true ); // Check, if there are still pending updates to be notified via menu bar icon
1031 else
1032 pUpdateDialog->notifyMenubar( false, false ); // Check, if there are pending updates to be notified via menu bar icon
1034 //Now start the webbrowser and navigate to the websites where we get the updates
1035 if ( RET_OK == nDialogResult )
1037 for ( cit i = vData.begin(); i < vData.end(); i++ )
1039 if ( m_pDialogHelper && ( i->sWebsiteURL.getLength() > 0 ) )
1040 m_pDialogHelper->openWebBrowser( i->sWebsiteURL, m_pDialogHelper->getWindow()->GetText() );
1044 else
1045 pUpdateDialog->notifyMenubar( false, false ); // check if there updates to be notified via menu bar icon
1047 delete pUpdateDialog;
1050 //------------------------------------------------------------------------------
1051 void ExtensionCmdQueue::Thread::_enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
1052 const uno::Reference< deployment::XPackage > &xPackage )
1054 if ( !xPackage.is() )
1055 return;
1057 uno::Reference< task::XAbortChannel > xAbortChannel( xPackage->createAbortChannel() );
1058 OUString sTitle = searchAndReplaceAll( m_sEnablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
1059 rCmdEnv->progressSection( sTitle, xAbortChannel );
1063 xPackage->registerPackage( xAbortChannel, rCmdEnv.get() );
1064 if ( m_pDialogHelper )
1065 m_pDialogHelper->updatePackageInfo( xPackage );
1067 catch ( ::ucb::CommandAbortedException & )
1071 //------------------------------------------------------------------------------
1072 void ExtensionCmdQueue::Thread::_disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
1073 const uno::Reference< deployment::XPackage > &xPackage )
1075 if ( !xPackage.is() )
1076 return;
1078 uno::Reference< task::XAbortChannel > xAbortChannel( xPackage->createAbortChannel() );
1079 OUString sTitle = searchAndReplaceAll( m_sDisablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
1080 rCmdEnv->progressSection( sTitle, xAbortChannel );
1084 xPackage->revokePackage( xAbortChannel, rCmdEnv.get() );
1085 if ( m_pDialogHelper )
1086 m_pDialogHelper->updatePackageInfo( xPackage );
1088 catch ( ::ucb::CommandAbortedException & )
1092 //------------------------------------------------------------------------------
1093 void ExtensionCmdQueue::Thread::onTerminated()
1095 ::osl::MutexGuard g(m_mutex);
1096 m_bTerminated = true;
1099 //------------------------------------------------------------------------------
1100 OUString ExtensionCmdQueue::Thread::searchAndReplaceAll( const OUString &rSource,
1101 const OUString &rWhat,
1102 const OUString &rWith )
1104 OUString aRet( rSource );
1105 sal_Int32 nLen = rWhat.getLength();
1107 if ( !nLen )
1108 return aRet;
1110 sal_Int32 nIndex = rSource.indexOf( rWhat );
1111 while ( nIndex != -1 )
1113 aRet = aRet.replaceAt( nIndex, nLen, rWith );
1114 nIndex = aRet.indexOf( rWhat, nIndex + rWith.getLength() );
1116 return aRet;
1120 //------------------------------------------------------------------------------
1121 //------------------------------------------------------------------------------
1122 //------------------------------------------------------------------------------
1123 ExtensionCmdQueue::ExtensionCmdQueue( DialogHelper * pDialogHelper,
1124 TheExtensionManager *pManager,
1125 const uno::Reference< uno::XComponentContext > &rContext )
1126 : m_thread( new Thread( pDialogHelper, pManager, rContext ) )
1128 m_thread->launch();
1131 ExtensionCmdQueue::~ExtensionCmdQueue() {
1132 stop();
1135 void ExtensionCmdQueue::addExtension( const uno::Reference< deployment::XPackageManager > &rPackageManager,
1136 const ::rtl::OUString & extensionURL,
1137 const bool bWarnUser )
1139 m_thread->addExtension( rPackageManager, extensionURL, bWarnUser );
1142 void ExtensionCmdQueue::removeExtension( const uno::Reference< deployment::XPackageManager > &rPackageManager,
1143 const uno::Reference< deployment::XPackage > &rPackage )
1145 m_thread->removeExtension( rPackageManager, rPackage );
1148 void ExtensionCmdQueue::enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
1149 const bool bEnable )
1151 m_thread->enableExtension( rPackage, bEnable );
1154 void ExtensionCmdQueue::checkForUpdates( const std::vector< TUpdateListEntry > &vExtensionList )
1156 m_thread->checkForUpdates( vExtensionList );
1159 void ExtensionCmdQueue::stop()
1161 m_thread->stop();
1164 void ExtensionCmdQueue::stopAndWait()
1166 m_thread->stop();
1167 m_thread->join();
1170 bool ExtensionCmdQueue::hasTerminated()
1172 return m_thread->hasTerminated();
1175 bool ExtensionCmdQueue::isBusy()
1177 return m_thread->isBusy();
1180 void handleInteractionRequest( const uno::Reference< uno::XComponentContext > & xContext,
1181 const uno::Reference< task::XInteractionRequest > & xRequest )
1183 ::rtl::Reference< ProgressCmdEnv > xCmdEnv( new ProgressCmdEnv( xContext, NULL, OUSTR("Extension Manager") ) );
1184 xCmdEnv->handle( xRequest );
1187 } //namespace dp_gui