diff options
author | Kurt Zenker <kz@openoffice.org> | 2008-05-21 11:26:33 +0000 |
---|---|---|
committer | Kurt Zenker <kz@openoffice.org> | 2008-05-21 11:26:33 +0000 |
commit | f167d090345c9c7950665e50006aff4fc0ace078 (patch) | |
tree | 32adad557a62211fd13ab0b8bfc1c45425a69d1f /desktop | |
parent | 8ee302b04c5b12cfbb25e7021225ea8dc3635333 (diff) |
INTEGRATION: CWS extmgrui01 (1.1.2); FILE ADDED
2008/05/21 11:31:39 kz 1.1.2.13: license updated
2008/04/29 06:12:50 dv 1.1.2.12: Better progress handling
2008/04/29 06:03:34 dv 1.1.2.11: Added changes from CWS JL94
2008/03/28 07:01:27 dv 1.1.2.10: Some more dialog changed a little bit
2008/03/27 13:02:50 dv 1.1.2.9: Better handling of adding extensions via system integration
2008/03/27 08:06:18 dv 1.1.2.8: Adopted 'Already installed' request to latest version handling
2008/03/26 09:57:06 dv 1.1.2.7: fixed some merge problems with resource ids
2008/02/29 09:53:47 dv 1.1.2.6: #i83902# Changed some strings
2008/02/28 15:16:51 dv 1.1.2.5: #i83902# Added support for updating a single extension via context menu
2008/02/27 12:58:54 dv 1.1.2.4: #i83902# Better handling of external adding of extensions
2008/02/26 07:19:53 dv 1.1.2.3: #i83902# Some strings changed for new dialog
2008/02/22 08:14:15 dv 1.1.2.2: Fixes for unix compiler
2008/02/22 07:49:45 dv 1.1.2.1: #i83902# Added progress bar
Diffstat (limited to 'desktop')
-rw-r--r-- | desktop/source/deployment/gui/dp_gui_extensioncmdqueue.cxx | 1161 |
1 files changed, 1161 insertions, 0 deletions
diff --git a/desktop/source/deployment/gui/dp_gui_extensioncmdqueue.cxx b/desktop/source/deployment/gui/dp_gui_extensioncmdqueue.cxx new file mode 100644 index 000000000000..50aad1743fdd --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_extensioncmdqueue.cxx @@ -0,0 +1,1161 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dp_gui_extensioncmdqueue.cxx,v $ + * + * $Revision: 1.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "sal/config.h" + +#include <cstddef> + +#include "com/sun/star/beans/PropertyValue.hpp" + +#include "com/sun/star/deployment/DependencyException.hpp" +#include "com/sun/star/deployment/LicenseException.hpp" +#include "com/sun/star/deployment/LicenseIndividualAgreementException.hpp" +#include "com/sun/star/deployment/VersionException.hpp" +#include "com/sun/star/deployment/InstallException.hpp" +#include "com/sun/star/deployment/PlatformException.hpp" + +#include "com/sun/star/deployment/ui/LicenseDialog.hpp" +#include "com/sun/star/deployment/DeploymentException.hpp" +#include "com/sun/star/deployment/UpdateInformationProvider.hpp" +#include "com/sun/star/deployment/XPackage.hpp" +#include "com/sun/star/deployment/XPackageManager.hpp" + +#include "com/sun/star/task/XAbortChannel.hpp" +#include "com/sun/star/task/XInteractionAbort.hpp" +#include "com/sun/star/task/XInteractionApprove.hpp" + +#include "com/sun/star/ucb/CommandAbortedException.hpp" +#include "com/sun/star/ucb/CommandFailedException.hpp" +#include "com/sun/star/ucb/XCommandEnvironment.hpp" + +#include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp" + +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "com/sun/star/uno/XInterface.hpp" +#include "com/sun/star/uno/TypeClass.hpp" +#include "osl/diagnose.h" +#include "osl/mutex.hxx" +#include "rtl/ref.hxx" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "ucbhelper/content.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "cppuhelper/implbase3.hxx" +#include "comphelper/anytostring.hxx" +#include "vcl/msgbox.hxx" +#include "toolkit/helper/vclunohelper.hxx" + +#include "dp_gui.h" +#include "dp_gui_thread.hxx" +#include "dp_gui_extensioncmdqueue.hxx" +#include "dp_gui_dependencydialog.hxx" +#include "dp_gui_dialog2.hxx" +#include "dp_gui_shared.hxx" +#include "dp_gui_theextmgr.hxx" +#include "dp_gui_updatedialog.hxx" +#include "dp_gui_updateinstalldialog.hxx" +#include "dp_dependencies.hxx" +#include "dp_identifier.hxx" +#include "dp_version.hxx" + +#include <queue> +#include <boost/shared_ptr.hpp> + +#if 0 +#include "dp_gui.hrc" +#include "dp_gui.h" +#include "dp_gui_cmdenv.h" +#include "comphelper/anytostring.hxx" +#include "com/sun/star/lang/WrappedTargetException.hpp" +#include "tools/resid.hxx" +#include "tools/rcid.h" +#include "vcl/msgbox.hxx" +#include "vcl/threadex.hxx" +#include "boost/bind.hpp" + +#endif + +using namespace ::com::sun::star; +using ::rtl::OUString; + +namespace { + +OUString getVersion( const uno::Reference< deployment::XPackage > &rPackage ) +{ + OUString sVersion( rPackage->getVersion()); + return ( sVersion.getLength() == 0 ) ? OUString( RTL_CONSTASCII_USTRINGPARAM( "0" ) ) : sVersion; +} + +} + + +namespace dp_gui { + +//============================================================================== +//Only if the class is consructed with the DialogImpl then the ProgressDialog can be +//displayed. Otherwise this class can still be used to forward an interaction. This +//is done by the interaction handler of the "Download and Installation" dialog. + +class ProgressCmdEnv + : public ::cppu::WeakImplHelper3< ucb::XCommandEnvironment, + task::XInteractionHandler, + ucb::XProgressHandler > +{ + uno::Reference< task::XInteractionHandler> m_xHandler; + uno::Reference< uno::XComponentContext > m_xContext; + uno::Reference< task::XAbortChannel> m_xAbortChannel; + + ExtMgrDialog *m_pDialog; + OUString m_sTitle; + bool m_bAborted; + bool m_bWarnUser; + sal_Int32 m_nCurrentProgress; + + void updateProgress(); + + void update_( uno::Any const & Status ) throw ( uno::RuntimeException ); + +public: + virtual ~ProgressCmdEnv(); + + /** When param bAskWhenInstalling = true, then the user is asked if he + agrees to install this extension. In case this extension is already installed + then the user is also notified and asked if he wants to replace that existing + extension. In first case an interaction request with an InstallException + will be handled and in the second case a VersionException will be handled. + */ + + ProgressCmdEnv( const uno::Reference< uno::XComponentContext > rContext, + ExtMgrDialog *pDialog, + const OUString &rTitle ) + : m_xContext( rContext ), + m_pDialog( pDialog ), + m_sTitle( rTitle ), + m_bAborted( false ), + m_bWarnUser( false ) + {} + + Dialog * activeDialog() { return m_pDialog; } + + void startProgress(); + void stopProgress(); + void progressSection( const OUString &rText, + const uno::Reference< task::XAbortChannel > &xAbortChannel = 0 ); + inline bool isAborted() const { return m_bAborted; } + inline void setWarnUser( bool bNewVal ) { m_bWarnUser = bNewVal; } + + // XCommandEnvironment + virtual uno::Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler() + throw ( uno::RuntimeException ); + virtual uno::Reference< ucb::XProgressHandler > SAL_CALL getProgressHandler() + throw ( uno::RuntimeException ); + + // XInteractionHandler + virtual void SAL_CALL handle( uno::Reference< task::XInteractionRequest > const & xRequest ) + throw ( uno::RuntimeException ); + + // XProgressHandler + virtual void SAL_CALL push( uno::Any const & Status ) + throw ( uno::RuntimeException ); + virtual void SAL_CALL update( uno::Any const & Status ) + throw ( uno::RuntimeException ); + virtual void SAL_CALL pop() throw ( uno::RuntimeException ); +}; + +//------------------------------------------------------------------------------ +struct ExtensionCmd +{ + enum E_CMD_TYPE { ADD, ENABLE, DISABLE, REMOVE, CHECK_FOR_UPDATE, CHECK_FOR_UPDATES }; + + E_CMD_TYPE m_eCmdType; + bool m_bWarnUser; + OUString m_sExtensionURL; + uno::Reference< deployment::XPackageManager > m_xPackageManager; + uno::Reference< deployment::XPackage > m_xPackage; + uno::Sequence< uno::Reference< deployment::XPackageManager > > m_xPackageManagers; + + ExtensionCmd( const E_CMD_TYPE eCommand, + const uno::Reference< deployment::XPackageManager > &rPackageManager, + const OUString &rExtensionURL, + const bool bWarnUser ) + : m_eCmdType( eCommand ), + m_bWarnUser( bWarnUser ), + m_sExtensionURL( rExtensionURL ), + m_xPackageManager( rPackageManager ) {}; + ExtensionCmd( const E_CMD_TYPE eCommand, + const uno::Reference< deployment::XPackageManager > &rPackageManager, + const uno::Reference< deployment::XPackage > &rPackage ) + : m_eCmdType( eCommand ), + m_bWarnUser( false ), + m_xPackageManager( rPackageManager ), + m_xPackage( rPackage ) {}; + ExtensionCmd( const E_CMD_TYPE eCommand, + const uno::Reference< deployment::XPackage > &rPackage ) + : m_eCmdType( eCommand ), + m_bWarnUser( false ), + m_xPackage( rPackage ) {}; + ExtensionCmd( const E_CMD_TYPE eCommand, + const uno::Sequence< uno::Reference< deployment::XPackageManager > > &rPackageManagers ) + : m_eCmdType( eCommand ), + m_bWarnUser( false ), + m_xPackageManagers( rPackageManagers ) {}; +}; + +typedef ::boost::shared_ptr< ExtensionCmd > TExtensionCmd; + +//------------------------------------------------------------------------------ +class ExtensionCmdQueue::Thread: public dp_gui::Thread +{ +public: + Thread( ExtMgrDialog *pDialog, + TheExtensionManager *pManager, + const uno::Reference< uno::XComponentContext > & rContext ); + + void addExtension( const uno::Reference< deployment::XPackageManager > &rPackageManager, + const OUString &rExtensionURL, + const bool bWarnUser ); + void removeExtension( const uno::Reference< deployment::XPackageManager > &rPackageManager, + const uno::Reference< deployment::XPackage > &rPackage ); + void enableExtension( const uno::Reference< deployment::XPackage > &rPackage, + const bool bEnable ); + void checkForUpdates( const uno::Sequence< uno::Reference< deployment::XPackageManager > > &rPackageManagers ); + void checkForUpdate( const uno::Reference< deployment::XPackageManager > &rPackageManager, + const uno::Reference< deployment::XPackage > &rPackage ); + void stop(); + bool hasTerminated(); + + static OUString searchAndReplaceAll( const OUString &rSource, + const OUString &rWhat, + const OUString &rWith ); +private: + Thread( Thread & ); // not defined + void operator =( Thread & ); // not defined + + virtual ~Thread(); + + virtual void execute(); + virtual void SAL_CALL onTerminated(); + + void _addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackageManager > &xPackageManager, + const OUString &rPackageURL, + const bool bWarnUser ); + void _removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackageManager > &xPackageManager, + const uno::Reference< deployment::XPackage > &xPackage ); + void _enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackage > &xPackage ); + void _disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackage > &xPackage ); + void _checkForUpdates( const uno::Sequence< uno::Reference< deployment::XPackageManager > > &rPackageManagers, + const uno::Reference< deployment::XPackageManager > &xPackageManager, + const uno::Reference< deployment::XPackage > &xPackage ); + + enum Input { NONE, START, STOP }; + + uno::Reference< uno::XComponentContext > m_xContext; + std::queue< TExtensionCmd > m_queue; + + ExtMgrDialog *m_pDialog; + TheExtensionManager *m_pManager; + + const OUString m_sEnablingPackages; + const OUString m_sDisablingPackages; + const OUString m_sAddingPackages; + const OUString m_sRemovingPackages; + osl::Condition m_wakeup; + osl::Mutex m_mutex; + Input m_eInput; + bool m_bTerminated; + bool m_bStopped; +}; + +//------------------------------------------------------------------------------ +void ProgressCmdEnv::startProgress() +{ + m_nCurrentProgress = 0; + + m_pDialog->showProgress( true ); +} + +//------------------------------------------------------------------------------ +void ProgressCmdEnv::stopProgress() +{ + m_pDialog->showProgress( false ); +} + +//------------------------------------------------------------------------------ +void ProgressCmdEnv::progressSection( const OUString &rText, + const uno::Reference< task::XAbortChannel > &xAbortChannel ) +{ + m_xAbortChannel = xAbortChannel; + if (! m_bAborted) + { + m_nCurrentProgress = 0; + m_pDialog->updateProgress( rText, xAbortChannel ); + m_pDialog->updateProgress( 5 ); + } +} + +//------------------------------------------------------------------------------ +void ProgressCmdEnv::updateProgress() +{ + if ( ! m_bAborted ) + { + long nProgress = ((m_nCurrentProgress*5) % 100) + 5; + m_pDialog->updateProgress( nProgress ); + } +} + +//------------------------------------------------------------------------------ +ProgressCmdEnv::~ProgressCmdEnv() +{ + // TODO: stop all threads and wait +} + + +//------------------------------------------------------------------------------ +// XCommandEnvironment +//------------------------------------------------------------------------------ +uno::Reference< task::XInteractionHandler > ProgressCmdEnv::getInteractionHandler() + throw ( uno::RuntimeException ) +{ + return this; +} + +//------------------------------------------------------------------------------ +uno::Reference< ucb::XProgressHandler > ProgressCmdEnv::getProgressHandler() + throw ( uno::RuntimeException ) +{ + return this; +} + +//------------------------------------------------------------------------------ +// XInteractionHandler +//------------------------------------------------------------------------------ +void ProgressCmdEnv::handle( uno::Reference< task::XInteractionRequest > const & xRequest ) + throw ( uno::RuntimeException ) +{ + uno::Any request( xRequest->getRequest() ); + OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION ); +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE( "[dp_gui_cmdenv.cxx] incoming request:\n%s\n", + ::rtl::OUStringToOString( ::comphelper::anyToString(request), + RTL_TEXTENCODING_UTF8 ).getStr() ); +#endif + + lang::WrappedTargetException wtExc; + deployment::DependencyException depExc; + deployment::LicenseException licExc; + deployment::LicenseIndividualAgreementException licAgreementExc; + deployment::VersionException verExc; + deployment::InstallException instExc; + deployment::PlatformException platExc; + + // selections: + bool approve = false; + bool abort = false; + + if (request >>= wtExc) { + // handable deployment error signalled, e.g. + // bundle item registration failed, notify cause only: + uno::Any cause; + deployment::DeploymentException dpExc; + if (wtExc.TargetException >>= dpExc) + cause = dpExc.Cause; + else { + ucb::CommandFailedException cfExc; + if (wtExc.TargetException >>= cfExc) + cause = cfExc.Reason; + else + cause = wtExc.TargetException; + } + update_( cause ); + + // ignore intermediate errors of legacy packages, i.e. + // former pkgchk behaviour: + const uno::Reference< deployment::XPackage > xPackage( wtExc.Context, uno::UNO_QUERY ); + OSL_ASSERT( xPackage.is() ); + if ( xPackage.is() ) + { + const uno::Reference< deployment::XPackageTypeInfo > xPackageType( xPackage->getPackageType() ); + OSL_ASSERT( xPackageType.is() ); + if (xPackageType.is()) + { + approve = ( xPackage->isBundle() && + xPackageType->getMediaType().matchAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/" + "vnd.sun.star.legacy-package-bundle") )); + } + } + abort = !approve; + } + else if (request >>= depExc) + { + std::vector< rtl::OUString > deps; + for (sal_Int32 i = 0; i < depExc.UnsatisfiedDependencies.getLength(); + ++i) + { + deps.push_back( + dp_misc::Dependencies::name( depExc.UnsatisfiedDependencies[i]) ); + } + { + vos::OGuard guard(Application::GetSolarMutex()); + short n = DependencyDialog( m_pDialog, deps ).Execute(); + // Distinguish between closing the dialog and programatically + // canceling the dialog (headless VCL): + approve = n == RET_OK + || n == RET_CANCEL && !Application::IsDialogCancelEnabled(); + } + } + else if (request >>= licAgreementExc) + { + vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ResId warnId(WARNINGBOX_NOSHAREDALLOWED, *DeploymentGuiResMgr::get()); + WarningBox warn( m_pDialog, warnId); + String msgText = warn.GetMessText(); + msgText.SearchAndReplaceAllAscii( "%PRODUCTNAME", BrandName::get() ); + msgText.SearchAndReplaceAllAscii("%NAME", licAgreementExc.ExtensionName); + warn.SetMessText(msgText); + warn.Execute(); + abort = true; + } + else if (request >>= licExc) + { + uno::Reference< ui::dialogs::XExecutableDialog > xDialog( + deployment::ui::LicenseDialog::create( + m_xContext, VCLUnoHelper::GetInterface( m_pDialog ), licExc.Text ) ); + sal_Int16 res = xDialog->execute(); + if ( res == ui::dialogs::ExecutableDialogResults::CANCEL ) + abort = true; + else if ( res == ui::dialogs::ExecutableDialogResults::OK ) + approve = true; + else + { + OSL_ASSERT(0); + } + } + else if (request >>= verExc) + { + sal_uInt32 id; + switch (dp_misc::comparePackageVersions( verExc.New, verExc.Deployed )) + { + case dp_misc::LESS: + id = RID_WARNINGBOX_VERSION_LESS; + break; + case dp_misc::EQUAL: + id = RID_WARNINGBOX_VERSION_EQUAL; + break; + default: // dp_misc::GREATER + id = RID_WARNINGBOX_VERSION_GREATER; + break; + } + OSL_ASSERT( verExc.New.is() && verExc.Deployed.is() ); + bool bEqualNames = verExc.New->getDisplayName().equals( + verExc.Deployed->getDisplayName()); + { + vos::OGuard guard(Application::GetSolarMutex()); + WarningBox box( m_pDialog, ResId(id, *DeploymentGuiResMgr::get())); + String s; + if (bEqualNames) + { + s = box.GetMessText(); + } + else if (id == RID_WARNINGBOX_VERSION_EQUAL) + { + //hypothetical: requires two instances of an extension with the same + //version to have different display names. Probably the developer forgot + //to change the version. + s = String(ResId(RID_STR_WARNINGBOX_VERSION_EQUAL_DIFFERENT_NAMES, *DeploymentGuiResMgr::get())); + } + else if (id == RID_WARNINGBOX_VERSION_LESS) + { + s = String(ResId(RID_STR_WARNINGBOX_VERSION_LESS_DIFFERENT_NAMES, *DeploymentGuiResMgr::get())); + } + else if (id == RID_WARNINGBOX_VERSION_GREATER) + { + s = String(ResId(RID_STR_WARNINGBOX_VERSION_GREATER_DIFFERENT_NAMES, *DeploymentGuiResMgr::get())); + } + s.SearchAndReplaceAllAscii( "$NAME", verExc.New->getDisplayName()); + s.SearchAndReplaceAllAscii( "$OLDNAME", verExc.Deployed->getDisplayName()); + s.SearchAndReplaceAllAscii( "$NEW", getVersion(verExc.New) ); + s.SearchAndReplaceAllAscii( "$DEPLOYED", getVersion(verExc.Deployed) ); + box.SetMessText(s); + approve = box.Execute() == RET_OK; + abort = !approve; + } + } + else if (request >>= instExc) + { + if ( ! m_bWarnUser ) + { + approve = true; + } + else + { + vos::OGuard guard(Application::GetSolarMutex()); + + approve = m_pDialog->installExtensionWarn( instExc.New->getDisplayName() ); + abort = !approve; + } + } + else if (request >>= platExc) + { + vos::OGuard guard( Application::GetSolarMutex() ); + String sMsg( ResId( RID_STR_UNSUPPORTED_PLATFORM, *DeploymentGuiResMgr::get() ) ); + sMsg.SearchAndReplaceAllAscii( "%Name", platExc.package->getDisplayName() ); + ErrorBox box( m_pDialog, WB_OK, sMsg ); + box.Execute(); + approve = true; + } + + if (approve == false && abort == false) + { + // forward to UUI handler: + if (! m_xHandler.is()) { + // late init: + uno::Sequence< uno::Any > handlerArgs( 1 ); + handlerArgs[ 0 ] <<= beans::PropertyValue( + OUSTR("Context"), -1, uno::Any( m_sTitle ), + beans::PropertyState_DIRECT_VALUE ); + m_xHandler.set( m_xContext->getServiceManager() + ->createInstanceWithArgumentsAndContext( + OUSTR("com.sun.star.uui.InteractionHandler"), + handlerArgs, m_xContext ), uno::UNO_QUERY_THROW ); + } + m_xHandler->handle( xRequest ); + } + else + { + // select: + uno::Sequence< uno::Reference< task::XInteractionContinuation > > conts( + xRequest->getContinuations() ); + uno::Reference< task::XInteractionContinuation > const * pConts = conts.getConstArray(); + sal_Int32 len = conts.getLength(); + for ( sal_Int32 pos = 0; pos < len; ++pos ) + { + if (approve) { + uno::Reference< task::XInteractionApprove > xInteractionApprove( pConts[ pos ], uno::UNO_QUERY ); + if (xInteractionApprove.is()) { + xInteractionApprove->select(); + // don't query again for ongoing continuations: + approve = false; + } + } + else if (abort) { + uno::Reference< task::XInteractionAbort > xInteractionAbort( pConts[ pos ], uno::UNO_QUERY ); + if (xInteractionAbort.is()) { + xInteractionAbort->select(); + // don't query again for ongoing continuations: + abort = false; + } + } + } + } +} + +//------------------------------------------------------------------------------ +// XProgressHandler +//------------------------------------------------------------------------------ +void ProgressCmdEnv::push( uno::Any const & rStatus ) + throw( uno::RuntimeException ) +{ + update_( rStatus ); +} + +//------------------------------------------------------------------------------ +void ProgressCmdEnv::update_( uno::Any const & rStatus ) + throw( uno::RuntimeException ) +{ + OUString text; + if ( rStatus.hasValue() && !( rStatus >>= text) ) + { + if ( rStatus.getValueTypeClass() == uno::TypeClass_EXCEPTION ) + text = static_cast< uno::Exception const *>( rStatus.getValue() )->Message; + if ( text.getLength() == 0 ) + text = ::comphelper::anyToString( rStatus ); // fallback + + const ::vos::OGuard aGuard( Application::GetSolarMutex() ); + const ::std::auto_ptr< ErrorBox > aBox( new ErrorBox( m_pDialog, WB_OK, text ) ); + aBox->Execute(); + } + ++m_nCurrentProgress; + updateProgress(); +} + +//------------------------------------------------------------------------------ +void ProgressCmdEnv::update( uno::Any const & rStatus ) + throw( uno::RuntimeException ) +{ + update_( rStatus ); +} + +//------------------------------------------------------------------------------ +void ProgressCmdEnv::pop() + throw( uno::RuntimeException ) +{ + update_( uno::Any() ); // no message +} + +//------------------------------------------------------------------------------ +ExtensionCmdQueue::Thread::Thread( ExtMgrDialog *pDialog, + TheExtensionManager *pManager, + const uno::Reference< uno::XComponentContext > & rContext ) : + m_xContext( rContext ), + m_pDialog( pDialog ), + m_pManager( pManager ), + m_sEnablingPackages( ExtMgrDialog::getResourceString( RID_STR_ENABLING_PACKAGES ) ), + m_sDisablingPackages( ExtMgrDialog::getResourceString( RID_STR_DISABLING_PACKAGES ) ), + m_sAddingPackages( ExtMgrDialog::getResourceString( RID_STR_ADDING_PACKAGES ) ), + m_sRemovingPackages( ExtMgrDialog::getResourceString( RID_STR_REMOVING_PACKAGES ) ), + m_eInput( NONE ), + m_bTerminated( false ), + m_bStopped( false ) +{ + OSL_ASSERT( pDialog ); +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::addExtension( const uno::Reference< deployment::XPackageManager > &rPackageManager, + const ::rtl::OUString &rExtensionURL, + const bool bWarnUser ) +{ + ::osl::MutexGuard aGuard( m_mutex ); + + //If someone called stop then we do not add the extension -> game over! + if ( m_bStopped ) + return; + + if ( rExtensionURL.getLength() ) + { + TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ADD, rPackageManager, rExtensionURL, bWarnUser ) ); + + m_queue.push( pEntry ); + m_eInput = START; + m_wakeup.set(); + } +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::removeExtension( const uno::Reference< deployment::XPackageManager > &rPackageManager, + const uno::Reference< deployment::XPackage > &rPackage ) +{ + ::osl::MutexGuard aGuard( m_mutex ); + + //If someone called stop then we do not remove the extension -> game over! + if ( m_bStopped ) + return; + + if ( rPackageManager.is() && rPackage.is() ) + { + TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::REMOVE, rPackageManager, rPackage ) ); + + m_queue.push( pEntry ); + m_eInput = START; + m_wakeup.set(); + } +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::enableExtension( const uno::Reference< deployment::XPackage > &rPackage, + const bool bEnable ) +{ + ::osl::MutexGuard aGuard( m_mutex ); + + //If someone called stop then we do not remove the extension -> game over! + if ( m_bStopped ) + return; + + if ( rPackage.is() ) + { + TExtensionCmd pEntry( new ExtensionCmd( bEnable ? ExtensionCmd::ENABLE : + ExtensionCmd::DISABLE, + rPackage ) ); + m_queue.push( pEntry ); + m_eInput = START; + m_wakeup.set(); + } +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::checkForUpdates( const uno::Sequence< uno::Reference< deployment::XPackageManager > > &rPackageManagers ) +{ + ::osl::MutexGuard aGuard( m_mutex ); + + //If someone called stop then we do not remove the extension -> game over! + if ( m_bStopped ) + return; + + TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::CHECK_FOR_UPDATES, rPackageManagers ) ); + m_queue.push( pEntry ); + m_eInput = START; + m_wakeup.set(); +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::checkForUpdate( const uno::Reference< deployment::XPackageManager > &rPackageManager, + const uno::Reference< deployment::XPackage > &rPackage ) +{ + ::osl::MutexGuard aGuard( m_mutex ); + + //If someone called stop then we do not remove the extension -> game over! + if ( m_bStopped ) + return; + + if ( rPackageManager.is() && rPackage.is() ) + { + TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::CHECK_FOR_UPDATE, rPackageManager, rPackage ) ); + + m_queue.push( pEntry ); + m_eInput = START; + m_wakeup.set(); + } +} + +//------------------------------------------------------------------------------ +//Stopping this thread will not abort the installation of extensions. +void ExtensionCmdQueue::Thread::stop() +{ + osl::MutexGuard aGuard( m_mutex ); + m_bStopped = true; + m_eInput = STOP; + m_wakeup.set(); +} + +//------------------------------------------------------------------------------ +bool ExtensionCmdQueue::Thread::hasTerminated() +{ + osl::MutexGuard aGuard( m_mutex ); + return m_bTerminated; +} + +//------------------------------------------------------------------------------ +ExtensionCmdQueue::Thread::~Thread() {} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::execute() +{ + for (;;) + { + if ( m_wakeup.wait() != osl::Condition::result_ok ) + { + OSL_TRACE( "dp_gui::ExtensionCmdQueue::Thread::run: ignored " + "osl::Condition::wait failure" ); + } + m_wakeup.reset(); + + int nSize; + Input eInput; + { + osl::MutexGuard aGuard( m_mutex ); + eInput = m_eInput; + m_eInput = NONE; + nSize = m_queue.size(); + } + + // If this thread has been woken up by anything else except start, stop + // then input is NONE and we wait again. + // We only install the extension which are currently in the queue. + // The progressbar will be set to show the progress of the current number + // of extensions. If we allowed to add extensions now then the progressbar may + // have reached the end while we still install newly added extensions. + if ( ( eInput == NONE ) || ( nSize == 0 ) ) + continue; + if ( eInput == STOP ) + break; + + ::rtl::Reference< ProgressCmdEnv > currentCmdEnv( new ProgressCmdEnv( m_xContext, m_pDialog, m_sAddingPackages ) ); + + // Do not lock the following part with addExtension. addExtension may be called in the main thread. + // If the message box "Do you want to install the extension (or similar)" is shown and then + // addExtension is called, which then blocks the main thread, then we deadlock. + bool bStartProgress = true; + + while ( !currentCmdEnv->isAborted() && --nSize >= 0 ) + { + try + { + TExtensionCmd pEntry; + { + ::osl::MutexGuard queueGuard( m_mutex ); + pEntry = m_queue.front(); + m_queue.pop(); + } + + if ( bStartProgress && ( pEntry->m_eCmdType != ExtensionCmd::CHECK_FOR_UPDATE ) && + ( pEntry->m_eCmdType != ExtensionCmd::CHECK_FOR_UPDATES ) ) + { + currentCmdEnv->startProgress(); + bStartProgress = false; + } + + switch ( pEntry->m_eCmdType ) { + case ExtensionCmd::ADD : + _addExtension( currentCmdEnv, pEntry->m_xPackageManager, pEntry->m_sExtensionURL, pEntry->m_bWarnUser ); + break; + case ExtensionCmd::REMOVE : + _removeExtension( currentCmdEnv, pEntry->m_xPackageManager, pEntry->m_xPackage ); + break; + case ExtensionCmd::ENABLE : + _enableExtension( currentCmdEnv, pEntry->m_xPackage ); + break; + case ExtensionCmd::DISABLE : + _disableExtension( currentCmdEnv, pEntry->m_xPackage ); + break; + case ExtensionCmd::CHECK_FOR_UPDATE : + case ExtensionCmd::CHECK_FOR_UPDATES : + _checkForUpdates( pEntry->m_xPackageManagers, pEntry->m_xPackageManager, pEntry->m_xPackage ); + break; + } + } + //catch ( deployment::DeploymentException &) + //{ + //} + //catch ( lang::IllegalArgumentException &) + //{ + //} + catch ( ucb::CommandAbortedException & ) + { + //This exception is thrown when the user clicks cancel on the progressbar. + //Then we cancel the installation of all extensions and remove them from + //the queue. + { + ::osl::MutexGuard queueGuard2(m_mutex); + while ( --nSize >= 0 ) + m_queue.pop(); + } + break; + } + catch ( ucb::CommandFailedException & ) + { + //This exception is thrown when a user clicked cancel in the messagebox which was + //startet by the interaction handler. For example the user will be asked if he/she + //really wants to install the extension. + //These interaction are run for exectly one extension at a time. Therefore we continue + //with installing the remaining extensions. + continue; + } + catch ( uno::Exception & ) + { + //Todo display the user an error + //see also DialogImpl::SyncPushButton::Click() + uno::Any exc( ::cppu::getCaughtException() ); + OUString msg; + deployment::DeploymentException dpExc; + if ((exc >>= dpExc) && + dpExc.Cause.getValueTypeClass() == uno::TypeClass_EXCEPTION) + { + // notify error cause only: + msg = reinterpret_cast< uno::Exception const * >( dpExc.Cause.getValue() )->Message; + } + if (msg.getLength() == 0) // fallback for debugging purposes + msg = ::comphelper::anyToString(exc); + + const ::vos::OGuard guard( Application::GetSolarMutex() ); + ::std::auto_ptr<ErrorBox> box( + new ErrorBox( currentCmdEnv->activeDialog(), WB_OK, msg ) ); + box->SetText( m_pDialog->GetText() ); + box->Execute(); + //Continue with installation of the remaining extensions + } + + } + + if ( !bStartProgress ) + currentCmdEnv->stopProgress(); + } + //end for + //enable all buttons +// m_pDialog->m_bAddingExtensions = false; +// m_pDialog->updateButtonStates(); +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::_addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackageManager > &xPackageManager, + const OUString &rPackageURL, + const bool bWarnUser ) +{ + //check if we have a string in anyTitle. For example "unopkg gui \" caused anyTitle to be void + //and anyTitle.get<OUString> throws as RuntimeException. + uno::Any anyTitle = ::ucbhelper::Content( rPackageURL, rCmdEnv.get() ).getPropertyValue( OUSTR("Title") ); + OUString sName; + if ( ! (anyTitle >>= sName) ) + { + OSL_ENSURE(0, "Could not get file name for extension."); + return; + } + + rCmdEnv->setWarnUser( bWarnUser ); + uno::Reference< task::XAbortChannel > xAbortChannel( xPackageManager->createAbortChannel() ); + OUString sTitle = searchAndReplaceAll( m_sAddingPackages, OUSTR("%EXTENSION_NAME"), sName ); + rCmdEnv->progressSection( sTitle, xAbortChannel ); + + try + { + uno::Reference< deployment::XPackage > xPackage( xPackageManager->addPackage( + rPackageURL, OUString() /* detect media-type */, + xAbortChannel, rCmdEnv.get() ) ); + OSL_ASSERT( xPackage.is() ); +// long nPos = m_pDialog->addPackageToList( xPackage, xPackageManager ); +// m_pDialog->selectEntry( nPos ); + } + catch ( ucb::CommandFailedException & ) + { + // When the extension is already installed we'll get a dialog asking if we want to overwrite. If we then press + // cancel this exception is thrown. + } + catch ( ucb::CommandAbortedException & ) + { + // User clicked the cancel button + // TODO: handle cancel + } + rCmdEnv->setWarnUser( false ); +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::_removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackageManager > &xPackageManager, + const uno::Reference< deployment::XPackage > &xPackage ) +{ + uno::Reference< task::XAbortChannel > xAbortChannel( xPackageManager->createAbortChannel() ); + OUString sTitle = searchAndReplaceAll( m_sRemovingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); + rCmdEnv->progressSection( sTitle, xAbortChannel ); + + OUString id( dp_misc::getIdentifier( xPackage ) ); + try + { + xPackageManager->removePackage( id, xPackage->getName(), xAbortChannel, rCmdEnv.get() ); + m_pDialog->removeEntry( xPackage ); + } + catch ( ucb::CommandAbortedException & ) + {} + + // Check, if there are still updates to be notified via menu bar icon + uno::Sequence< uno::Sequence< rtl::OUString > > aItemList; + UpdateDialog::createNotifyJob( false, aItemList ); +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::_checkForUpdates( const uno::Sequence< uno::Reference< deployment::XPackageManager > > &rPackageManagers, + const uno::Reference< deployment::XPackageManager > &xPackageManager, + const uno::Reference< deployment::XPackage > &xPackage ) +{ + UpdateDialog* pUpdateDialog; + std::vector< UpdateData > vData; + + const ::vos::OGuard guard( Application::GetSolarMutex() ); + + if ( xPackageManager.is() && xPackage.is() ) + pUpdateDialog = new UpdateDialog( m_xContext, m_pDialog, new SelectedPackage( xPackage, xPackageManager ), + uno::Sequence< uno::Reference< deployment::XPackageManager > >(), &vData ); + else + pUpdateDialog = new UpdateDialog( m_xContext, m_pDialog, rtl::Reference< SelectedPackage >(), + rPackageManagers, &vData ); + + if ( ( pUpdateDialog->Execute() == RET_OK ) && !vData.empty() ) + { + pUpdateDialog->notifyMenubar( true, false ); // prepare the checking, if there updates to be notified via menu bar icon + // If there is at least one directly downloadable dialog then we + // open the install dialog. + ::std::vector< UpdateData > dataDownload; + int countWebsiteDownload = 0; + typedef std::vector< dp_gui::UpdateData >::const_iterator cit; + + for ( cit i = vData.begin(); i < vData.end(); i++ ) + { + if ( i->sWebsiteURL.getLength() > 0 ) + countWebsiteDownload ++; + else + dataDownload.push_back( *i ); + } + + short nDialogResult = RET_OK; + if ( !dataDownload.empty() ) + { + nDialogResult = UpdateInstallDialog( m_pDialog, dataDownload, m_xContext ).Execute(); + pUpdateDialog->notifyMenubar( false, true ); // Check, if there are still pending updates to be notified via menu bar icon + } + else + pUpdateDialog->notifyMenubar( false, false ); // Check, if there are pending updates to be notified via menu bar icon + + //Now start the webbrowser and navigate to the websites where we get the updates + if ( RET_OK == nDialogResult ) + { + for ( cit i = vData.begin(); i < vData.end(); i++ ) + { + if ( i->sWebsiteURL.getLength() > 0 ) + m_pDialog->openWebBrowser( i->sWebsiteURL ); + } + } + } + + delete pUpdateDialog; +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::_enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackage > &xPackage ) +{ + if ( !xPackage.is() ) + return; + + uno::Reference< task::XAbortChannel > xAbortChannel( xPackage->createAbortChannel() ); + OUString sTitle = searchAndReplaceAll( m_sEnablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); + rCmdEnv->progressSection( sTitle, xAbortChannel ); + + try + { + xPackage->registerPackage( xAbortChannel, rCmdEnv.get() ); + m_pDialog->updatePackageInfo( xPackage ); + } + catch ( ::ucb::CommandAbortedException & ) + {} +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::_disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackage > &xPackage ) +{ + if ( !xPackage.is() ) + return; + + uno::Reference< task::XAbortChannel > xAbortChannel( xPackage->createAbortChannel() ); + OUString sTitle = searchAndReplaceAll( m_sDisablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); + rCmdEnv->progressSection( sTitle, xAbortChannel ); + + try + { + xPackage->revokePackage( xAbortChannel, rCmdEnv.get() ); + m_pDialog->updatePackageInfo( xPackage ); + } + catch ( ::ucb::CommandAbortedException & ) + {} +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::onTerminated() +{ + ::osl::MutexGuard g(m_mutex); + m_bTerminated = true; +} + +//------------------------------------------------------------------------------ +OUString ExtensionCmdQueue::Thread::searchAndReplaceAll( const OUString &rSource, + const OUString &rWhat, + const OUString &rWith ) +{ + OUString aRet( rSource ); + sal_Int32 nLen = rWhat.getLength(); + + if ( !nLen ) + return aRet; + + sal_Int32 nIndex = rSource.indexOf( rWhat ); + while ( nIndex != -1 ) + { + aRet = aRet.replaceAt( nIndex, nLen, rWith ); + nIndex = aRet.indexOf( rWhat, nIndex + rWith.getLength() ); + } + return aRet; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +ExtensionCmdQueue::ExtensionCmdQueue( ExtMgrDialog * pDialog, + TheExtensionManager *pManager, + const uno::Reference< uno::XComponentContext > &rContext ) + : m_thread( new Thread( pDialog, pManager, rContext ) ) +{ + m_thread->launch(); +} + +ExtensionCmdQueue::~ExtensionCmdQueue() { + stop(); +} + +void ExtensionCmdQueue::addExtension( const uno::Reference< deployment::XPackageManager > &rPackageManager, + const ::rtl::OUString & extensionURL, + const bool bWarnUser ) +{ + m_thread->addExtension( rPackageManager, extensionURL, bWarnUser ); +} + +void ExtensionCmdQueue::removeExtension( const uno::Reference< deployment::XPackageManager > &rPackageManager, + const uno::Reference< deployment::XPackage > &rPackage ) +{ + m_thread->removeExtension( rPackageManager, rPackage ); +} + +void ExtensionCmdQueue::enableExtension( const uno::Reference< deployment::XPackage > &rPackage, + const bool bEnable ) +{ + m_thread->enableExtension( rPackage, bEnable ); +} + +void ExtensionCmdQueue::checkForUpdates( const uno::Sequence< uno::Reference< deployment::XPackageManager > > &rPackageManagers ) +{ + m_thread->checkForUpdates( rPackageManagers ); +} + +void ExtensionCmdQueue::checkForUpdate( const uno::Reference< deployment::XPackageManager > &rPackageManager, + const uno::Reference< deployment::XPackage > &rPackage ) +{ + m_thread->checkForUpdate( rPackageManager, rPackage ); +} + +void ExtensionCmdQueue::stop() +{ + m_thread->stop(); +} + +void ExtensionCmdQueue::stopAndWait() +{ + m_thread->stop(); + m_thread->join(); +} + +bool ExtensionCmdQueue::hasTerminated() +{ + return m_thread->hasTerminated(); +} + +} //namespace dp_gui + |