summaryrefslogtreecommitdiff
path: root/desktop/source/deployment/gui/dp_gui_extensioncmdqueue.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/source/deployment/gui/dp_gui_extensioncmdqueue.cxx')
-rw-r--r--desktop/source/deployment/gui/dp_gui_extensioncmdqueue.cxx1178
1 files changed, 1178 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..96a279f481a2
--- /dev/null
+++ b/desktop/source/deployment/gui/dp_gui_extensioncmdqueue.cxx
@@ -0,0 +1,1178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#define _WIN32_WINNT 0x0500
+
+// 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/beans/NamedValue.hpp"
+
+#include "com/sun/star/deployment/DependencyException.hpp"
+#include "com/sun/star/deployment/LicenseException.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/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 "comphelper/processfactory.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 (defined(_MSC_VER) && (_MSC_VER < 1400))
+#define _WIN32_WINNT 0x0400
+#endif
+
+#ifdef WNT
+#define GradientStyle_RECT BLA_GradientStyle_RECT
+#include <windows.h>
+#include <objbase.h>
+#undef GradientStyle_RECT
+#endif
+
+
+using namespace ::com::sun::star;
+using ::rtl::OUString;
+
+namespace {
+
+OUString getVersion( OUString const & sVersion )
+{
+ return ( sVersion.getLength() == 0 ) ? OUString( RTL_CONSTASCII_USTRINGPARAM( "0" ) ) : sVersion;
+}
+
+OUString getVersion( const uno::Reference< deployment::XPackage > &rPackage )
+{
+ return getVersion( rPackage->getVersion());
+}
+}
+
+
+namespace dp_gui {
+
+//==============================================================================
+
+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;
+
+ DialogHelper *m_pDialogHelper;
+ 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,
+ DialogHelper *pDialogHelper,
+ const OUString &rTitle )
+ : m_xContext( rContext ),
+ m_pDialogHelper( pDialogHelper ),
+ m_sTitle( rTitle ),
+ m_bAborted( false ),
+ m_bWarnUser( false )
+ {}
+
+ Dialog * activeDialog() { return m_pDialogHelper ? m_pDialogHelper->getWindow() : NULL; }
+
+ void setTitle( const OUString& rNewTitle ) { m_sTitle = rNewTitle; }
+ 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_UPDATES, ACCEPT_LICENSE };
+
+ E_CMD_TYPE m_eCmdType;
+ bool m_bWarnUser;
+ OUString m_sExtensionURL;
+ OUString m_sRepository;
+ uno::Reference< deployment::XPackage > m_xPackage;
+ std::vector< uno::Reference< deployment::XPackage > > m_vExtensionList;
+
+ ExtensionCmd( const E_CMD_TYPE eCommand,
+ const OUString &rExtensionURL,
+ const OUString &rRepository,
+ const bool bWarnUser )
+ : m_eCmdType( eCommand ),
+ m_bWarnUser( bWarnUser ),
+ m_sExtensionURL( rExtensionURL ),
+ m_sRepository( rRepository ) {};
+ 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 std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
+ : m_eCmdType( eCommand ),
+ m_bWarnUser( false ),
+ m_vExtensionList( vExtensionList ) {};
+};
+
+typedef ::boost::shared_ptr< ExtensionCmd > TExtensionCmd;
+
+//------------------------------------------------------------------------------
+class ExtensionCmdQueue::Thread: public dp_gui::Thread
+{
+public:
+ Thread( DialogHelper *pDialogHelper,
+ TheExtensionManager *pManager,
+ const uno::Reference< uno::XComponentContext > & rContext );
+
+ void addExtension( const OUString &rExtensionURL,
+ const OUString &rRepository,
+ const bool bWarnUser );
+ void removeExtension( const uno::Reference< deployment::XPackage > &rPackage );
+ void enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
+ const bool bEnable );
+ void checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList );
+ void acceptLicense( const uno::Reference< deployment::XPackage > &rPackage );
+ void stop();
+ bool isBusy();
+
+ 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 _insert(const TExtensionCmd& rExtCmd);
+
+ void _addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
+ const OUString &rPackageURL,
+ const OUString &rRepository,
+ const bool bWarnUser );
+ void _removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
+ 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 std::vector<uno::Reference<deployment::XPackage > > &vExtensionList );
+ void _acceptLicense( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
+ const uno::Reference< deployment::XPackage > &xPackage );
+
+ enum Input { NONE, START, STOP };
+
+ uno::Reference< uno::XComponentContext > m_xContext;
+ std::queue< TExtensionCmd > m_queue;
+
+ DialogHelper *m_pDialogHelper;
+ TheExtensionManager *m_pManager;
+
+ const OUString m_sEnablingPackages;
+ const OUString m_sDisablingPackages;
+ const OUString m_sAddingPackages;
+ const OUString m_sRemovingPackages;
+ const OUString m_sDefaultCmd;
+ const OUString m_sAcceptLicense;
+ osl::Condition m_wakeup;
+ osl::Mutex m_mutex;
+ Input m_eInput;
+ bool m_bTerminated;
+ bool m_bStopped;
+ bool m_bWorking;
+};
+
+//------------------------------------------------------------------------------
+void ProgressCmdEnv::startProgress()
+{
+ m_nCurrentProgress = 0;
+
+ if ( m_pDialogHelper )
+ m_pDialogHelper->showProgress( true );
+}
+
+//------------------------------------------------------------------------------
+void ProgressCmdEnv::stopProgress()
+{
+ if ( m_pDialogHelper )
+ m_pDialogHelper->showProgress( false );
+}
+
+//------------------------------------------------------------------------------
+void ProgressCmdEnv::progressSection( const OUString &rText,
+ const uno::Reference< task::XAbortChannel > &xAbortChannel )
+{
+ m_xAbortChannel = xAbortChannel;
+ if (! m_bAborted)
+ {
+ m_nCurrentProgress = 0;
+ if ( m_pDialogHelper )
+ {
+ m_pDialogHelper->updateProgress( rText, xAbortChannel );
+ m_pDialogHelper->updateProgress( 5 );
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+void ProgressCmdEnv::updateProgress()
+{
+ if ( ! m_bAborted )
+ {
+ long nProgress = ((m_nCurrentProgress*5) % 100) + 5;
+ if ( m_pDialogHelper )
+ m_pDialogHelper->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 );
+ dp_misc::TRACE( OUSTR("[dp_gui_cmdenv.cxx] incoming request:\n")
+ + ::comphelper::anyToString(request) + OUSTR("\n"));
+
+ lang::WrappedTargetException wtExc;
+ deployment::DependencyException depExc;
+ deployment::LicenseException licExc;
+ 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::getErrorText( depExc.UnsatisfiedDependencies[i]) );
+ }
+ {
+ SolarMutexGuard guard;
+ short n = DependencyDialog( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, 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 >>= licExc)
+ {
+ uno::Reference< ui::dialogs::XExecutableDialog > xDialog(
+ deployment::ui::LicenseDialog::create(
+ m_xContext, VCLUnoHelper::GetInterface( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL ),
+ licExc.ExtensionName, 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::compareVersions(
+ verExc.NewVersion, verExc.Deployed->getVersion() ))
+ {
+ 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.Deployed.is() );
+ bool bEqualNames = verExc.NewDisplayName.equals(
+ verExc.Deployed->getDisplayName());
+ {
+ SolarMutexGuard guard;
+ WarningBox box( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, 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.NewDisplayName);
+ s.SearchAndReplaceAllAscii( "$OLDNAME", verExc.Deployed->getDisplayName());
+ s.SearchAndReplaceAllAscii( "$NEW", getVersion(verExc.NewVersion) );
+ 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
+ {
+ if ( m_pDialogHelper )
+ {
+ SolarMutexGuard guard;
+
+ approve = m_pDialogHelper->installExtensionWarn( instExc.displayName );
+ }
+ else
+ approve = false;
+ abort = !approve;
+ }
+ }
+ else if (request >>= platExc)
+ {
+ SolarMutexGuard guard;
+ String sMsg( ResId( RID_STR_UNSUPPORTED_PLATFORM, *DeploymentGuiResMgr::get() ) );
+ sMsg.SearchAndReplaceAllAscii( "%Name", platExc.package->getDisplayName() );
+ ErrorBox box( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, 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 SolarMutexGuard aGuard;
+ const ::std::auto_ptr< ErrorBox > aBox( new ErrorBox( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, 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( DialogHelper *pDialogHelper,
+ TheExtensionManager *pManager,
+ const uno::Reference< uno::XComponentContext > & rContext ) :
+ m_xContext( rContext ),
+ m_pDialogHelper( pDialogHelper ),
+ m_pManager( pManager ),
+ m_sEnablingPackages( DialogHelper::getResourceString( RID_STR_ENABLING_PACKAGES ) ),
+ m_sDisablingPackages( DialogHelper::getResourceString( RID_STR_DISABLING_PACKAGES ) ),
+ m_sAddingPackages( DialogHelper::getResourceString( RID_STR_ADDING_PACKAGES ) ),
+ m_sRemovingPackages( DialogHelper::getResourceString( RID_STR_REMOVING_PACKAGES ) ),
+ m_sDefaultCmd( DialogHelper::getResourceString( RID_STR_ADD_PACKAGES ) ),
+ m_sAcceptLicense( DialogHelper::getResourceString( RID_STR_ACCEPT_LICENSE ) ),
+ m_eInput( NONE ),
+ m_bTerminated( false ),
+ m_bStopped( false ),
+ m_bWorking( false )
+{
+ OSL_ASSERT( pDialogHelper );
+}
+
+//------------------------------------------------------------------------------
+void ExtensionCmdQueue::Thread::addExtension( const ::rtl::OUString &rExtensionURL,
+ const ::rtl::OUString &rRepository,
+ const bool bWarnUser )
+{
+ if ( rExtensionURL.getLength() )
+ {
+ TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ADD, rExtensionURL, rRepository, bWarnUser ) );
+ _insert( pEntry );
+ }
+}
+
+//------------------------------------------------------------------------------
+void ExtensionCmdQueue::Thread::removeExtension( const uno::Reference< deployment::XPackage > &rPackage )
+{
+ if ( rPackage.is() )
+ {
+ TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::REMOVE, rPackage ) );
+ _insert( pEntry );
+ }
+}
+
+//------------------------------------------------------------------------------
+void ExtensionCmdQueue::Thread::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage )
+{
+ if ( rPackage.is() )
+ {
+ TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ACCEPT_LICENSE, rPackage ) );
+ _insert( pEntry );
+ }
+}
+
+//------------------------------------------------------------------------------
+void ExtensionCmdQueue::Thread::enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
+ const bool bEnable )
+{
+ if ( rPackage.is() )
+ {
+ TExtensionCmd pEntry( new ExtensionCmd( bEnable ? ExtensionCmd::ENABLE :
+ ExtensionCmd::DISABLE,
+ rPackage ) );
+ _insert( pEntry );
+ }
+}
+
+//------------------------------------------------------------------------------
+void ExtensionCmdQueue::Thread::checkForUpdates(
+ const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
+{
+ TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::CHECK_FOR_UPDATES, vExtensionList ) );
+ _insert( pEntry );
+}
+
+//------------------------------------------------------------------------------
+//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::isBusy()
+{
+ osl::MutexGuard aGuard( m_mutex );
+ return m_bWorking;
+}
+
+//------------------------------------------------------------------------------
+ExtensionCmdQueue::Thread::~Thread() {}
+
+//------------------------------------------------------------------------------
+void ExtensionCmdQueue::Thread::execute()
+{
+#ifdef WNT
+ //Needed for use of the service "com.sun.star.system.SystemShellExecute" in
+ //DialogHelper::openWebBrowser
+ CoUninitialize();
+ HRESULT r = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+#endif
+ for (;;)
+ {
+ if ( m_wakeup.wait() != osl::Condition::result_ok )
+ {
+ dp_misc::TRACE( "dp_gui::ExtensionCmdQueue::Thread::run: ignored "
+ "osl::Condition::wait failure\n" );
+ }
+ m_wakeup.reset();
+
+ int nSize;
+ Input eInput;
+ {
+ osl::MutexGuard aGuard( m_mutex );
+ eInput = m_eInput;
+ m_eInput = NONE;
+ nSize = m_queue.size();
+ m_bWorking = false;
+ }
+
+ // 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_pDialogHelper, m_sDefaultCmd ) );
+
+ // 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 )
+ {
+ {
+ osl::MutexGuard aGuard( m_mutex );
+ m_bWorking = true;
+ }
+
+ try
+ {
+ TExtensionCmd pEntry;
+ {
+ ::osl::MutexGuard queueGuard( m_mutex );
+ pEntry = m_queue.front();
+ m_queue.pop();
+ }
+
+ if ( bStartProgress && ( pEntry->m_eCmdType != ExtensionCmd::CHECK_FOR_UPDATES ) )
+ {
+ currentCmdEnv->startProgress();
+ bStartProgress = false;
+ }
+
+ switch ( pEntry->m_eCmdType ) {
+ case ExtensionCmd::ADD :
+ _addExtension( currentCmdEnv, pEntry->m_sExtensionURL, pEntry->m_sRepository, pEntry->m_bWarnUser );
+ break;
+ case ExtensionCmd::REMOVE :
+ _removeExtension( currentCmdEnv, 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_UPDATES :
+ _checkForUpdates( pEntry->m_vExtensionList );
+ break;
+ case ExtensionCmd::ACCEPT_LICENSE :
+ _acceptLicense( currentCmdEnv, pEntry->m_xPackage );
+ break;
+ }
+ }
+ 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 SolarMutexGuard guard;
+ ::std::auto_ptr<ErrorBox> box(
+ new ErrorBox( currentCmdEnv->activeDialog(), WB_OK, msg ) );
+ if ( m_pDialogHelper )
+ box->SetText( m_pDialogHelper->getWindow()->GetText() );
+ box->Execute();
+ //Continue with installation of the remaining extensions
+ }
+ {
+ osl::MutexGuard aGuard( m_mutex );
+ m_bWorking = false;
+ }
+ }
+
+ {
+ // when leaving the while loop with break, we should set working to false, too
+ osl::MutexGuard aGuard( m_mutex );
+ m_bWorking = false;
+ }
+
+ if ( !bStartProgress )
+ currentCmdEnv->stopProgress();
+ }
+ //end for
+#ifdef WNT
+ CoUninitialize();
+#endif
+}
+
+//------------------------------------------------------------------------------
+void ExtensionCmdQueue::Thread::_addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
+ const OUString &rPackageURL,
+ const OUString &rRepository,
+ 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;
+ try
+ {
+ anyTitle = ::ucbhelper::Content( rPackageURL, rCmdEnv.get() ).getPropertyValue( OUSTR("Title") );
+ }
+ catch ( uno::Exception & )
+ {
+ return;
+ }
+
+ OUString sName;
+ if ( ! (anyTitle >>= sName) )
+ {
+ OSL_FAIL("Could not get file name for extension.");
+ return;
+ }
+
+ rCmdEnv->setWarnUser( bWarnUser );
+ uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
+ uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
+ OUString sTitle = searchAndReplaceAll( m_sAddingPackages, OUSTR("%EXTENSION_NAME"), sName );
+ rCmdEnv->progressSection( sTitle, xAbortChannel );
+
+ try
+ {
+ xExtMgr->addExtension(rPackageURL, uno::Sequence<beans::NamedValue>(),
+ rRepository, xAbortChannel, rCmdEnv.get() );
+ }
+ 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::XPackage > &xPackage )
+{
+ uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
+ uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
+ OUString sTitle = searchAndReplaceAll( m_sRemovingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
+ rCmdEnv->progressSection( sTitle, xAbortChannel );
+
+ OUString id( dp_misc::getIdentifier( xPackage ) );
+ try
+ {
+ xExtMgr->removeExtension( id, xPackage->getName(), xPackage->getRepositoryName(), xAbortChannel, rCmdEnv.get() );
+ }
+ catch ( deployment::DeploymentException & )
+ {}
+ catch ( ucb::CommandFailedException & )
+ {}
+ 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 std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
+{
+ UpdateDialog* pUpdateDialog;
+ std::vector< UpdateData > vData;
+
+ const SolarMutexGuard guard;
+
+ pUpdateDialog = new UpdateDialog( m_xContext, m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, vExtensionList, &vData );
+
+ pUpdateDialog->notifyMenubar( true, false ); // prepare the checking, if there updates to be notified via menu bar icon
+
+ if ( ( pUpdateDialog->Execute() == RET_OK ) && !vData.empty() )
+ {
+ // If there is at least one directly downloadable extension 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_pDialogHelper? m_pDialogHelper->getWindow() : NULL, 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 ( m_pDialogHelper && ( i->sWebsiteURL.getLength() > 0 ) )
+ m_pDialogHelper->openWebBrowser( i->sWebsiteURL, m_pDialogHelper->getWindow()->GetText() );
+ }
+ }
+ }
+ else
+ pUpdateDialog->notifyMenubar( false, false ); // check if there updates to be notified via menu bar icon
+
+ delete pUpdateDialog;
+}
+
+//------------------------------------------------------------------------------
+void ExtensionCmdQueue::Thread::_enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
+ const uno::Reference< deployment::XPackage > &xPackage )
+{
+ if ( !xPackage.is() )
+ return;
+
+ uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
+ uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
+ OUString sTitle = searchAndReplaceAll( m_sEnablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
+ rCmdEnv->progressSection( sTitle, xAbortChannel );
+
+ try
+ {
+ xExtMgr->enableExtension( xPackage, xAbortChannel, rCmdEnv.get() );
+ if ( m_pDialogHelper )
+ m_pDialogHelper->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< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
+ uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
+ OUString sTitle = searchAndReplaceAll( m_sDisablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
+ rCmdEnv->progressSection( sTitle, xAbortChannel );
+
+ try
+ {
+ xExtMgr->disableExtension( xPackage, xAbortChannel, rCmdEnv.get() );
+ if ( m_pDialogHelper )
+ m_pDialogHelper->updatePackageInfo( xPackage );
+ }
+ catch ( ::ucb::CommandAbortedException & )
+ {}
+}
+
+//------------------------------------------------------------------------------
+void ExtensionCmdQueue::Thread::_acceptLicense( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
+ const uno::Reference< deployment::XPackage > &xPackage )
+{
+ if ( !xPackage.is() )
+ return;
+
+ uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
+ uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
+ OUString sTitle = searchAndReplaceAll( m_sAcceptLicense, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
+ rCmdEnv->progressSection( sTitle, xAbortChannel );
+
+ try
+ {
+ xExtMgr->checkPrerequisitesAndEnable( xPackage, xAbortChannel, rCmdEnv.get() );
+ if ( m_pDialogHelper )
+ m_pDialogHelper->updatePackageInfo( xPackage );
+ }
+ catch ( ::ucb::CommandAbortedException & )
+ {}
+}
+
+//------------------------------------------------------------------------------
+void ExtensionCmdQueue::Thread::onTerminated()
+{
+ ::osl::MutexGuard g(m_mutex);
+ m_bTerminated = true;
+}
+
+void ExtensionCmdQueue::Thread::_insert(const TExtensionCmd& rExtCmd)
+{
+ ::osl::MutexGuard aGuard( m_mutex );
+
+ // If someone called stop then we do not process the command -> game over!
+ if ( m_bStopped )
+ return;
+
+ m_queue.push( rExtCmd );
+ m_eInput = START;
+ m_wakeup.set();
+}
+
+//------------------------------------------------------------------------------
+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( DialogHelper * pDialogHelper,
+ TheExtensionManager *pManager,
+ const uno::Reference< uno::XComponentContext > &rContext )
+ : m_thread( new Thread( pDialogHelper, pManager, rContext ) )
+{
+ m_thread->launch();
+}
+
+ExtensionCmdQueue::~ExtensionCmdQueue() {
+ stop();
+}
+
+void ExtensionCmdQueue::addExtension( const ::rtl::OUString & extensionURL,
+ const ::rtl::OUString & repository,
+ const bool bWarnUser )
+{
+ m_thread->addExtension( extensionURL, repository, bWarnUser );
+}
+
+void ExtensionCmdQueue::removeExtension( const uno::Reference< deployment::XPackage > &rPackage )
+{
+ m_thread->removeExtension( rPackage );
+}
+
+void ExtensionCmdQueue::enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
+ const bool bEnable )
+{
+ m_thread->enableExtension( rPackage, bEnable );
+}
+
+void ExtensionCmdQueue::checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
+{
+ m_thread->checkForUpdates( vExtensionList );
+}
+
+void ExtensionCmdQueue::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage )
+{
+ m_thread->acceptLicense( rPackage );
+}
+
+void ExtensionCmdQueue::syncRepositories( const uno::Reference< uno::XComponentContext > &xContext )
+{
+ dp_misc::syncRepositories( new ProgressCmdEnv( xContext, NULL, OUSTR("Extension Manager") ) );
+}
+
+void ExtensionCmdQueue::stop()
+{
+ m_thread->stop();
+}
+
+bool ExtensionCmdQueue::isBusy()
+{
+ return m_thread->isBusy();
+}
+
+void handleInteractionRequest( const uno::Reference< uno::XComponentContext > & xContext,
+ const uno::Reference< task::XInteractionRequest > & xRequest )
+{
+ ::rtl::Reference< ProgressCmdEnv > xCmdEnv( new ProgressCmdEnv( xContext, NULL, OUSTR("Extension Manager") ) );
+ xCmdEnv->handle( xRequest );
+}
+
+} //namespace dp_gui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */