diff options
Diffstat (limited to 'desktop/source/deployment/gui/dp_gui_theextmgr.cxx')
-rw-r--r-- | desktop/source/deployment/gui/dp_gui_theextmgr.cxx | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/desktop/source/deployment/gui/dp_gui_theextmgr.cxx b/desktop/source/deployment/gui/dp_gui_theextmgr.cxx new file mode 100644 index 000000000..1f3d8d710 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_theextmgr.cxx @@ -0,0 +1,533 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <vcl/svapp.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/deployment/DeploymentException.hpp> +#include <com/sun/star/deployment/ExtensionManager.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/TerminationVetoException.hpp> +#include <com/sun/star/ucb/CommandAbortedException.hpp> +#include <com/sun/star/ucb/CommandFailedException.hpp> +#include <comphelper/propertysequence.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <osl/diagnose.h> +#include <tools/diagnose_ex.h> + +#include "dp_gui_dialog2.hxx" +#include "dp_gui_extensioncmdqueue.hxx" +#include "dp_gui_theextmgr.hxx" +#include <dp_misc.h> +#include <dp_update.hxx> + +#define USER_PACKAGE_MANAGER "user" +#define SHARED_PACKAGE_MANAGER "shared" + +using namespace ::com::sun::star; + +namespace dp_gui { + + +::rtl::Reference< TheExtensionManager > TheExtensionManager::s_ExtMgr; + + +// TheExtensionManager + + +TheExtensionManager::TheExtensionManager( const uno::Reference< awt::XWindow > &xParent, + const uno::Reference< uno::XComponentContext > &xContext ) : + m_xContext( xContext ), + m_xParent( xParent ), + m_bModified(false), + m_bExtMgrDialogExecuting(false) +{ + m_xExtensionManager = deployment::ExtensionManager::get( xContext ); + m_xExtensionManager->addModifyListener( this ); + + uno::Reference< lang::XMultiServiceFactory > xConfig( + configuration::theDefaultProvider::get(xContext)); + uno::Sequence<uno::Any> args(comphelper::InitAnyPropertySequence( + { + {"nodepath", uno::Any(OUString("/org.openoffice.Office.OptionsDialog/Nodes"))} + })); + m_xNameAccessNodes.set( + xConfig->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", args), + uno::UNO_QUERY_THROW); + + // get the 'get more extensions here' url + uno::Sequence<uno::Any> args2(comphelper::InitAnyPropertySequence( + { + {"nodepath", uno::Any(OUString("/org.openoffice.Office.ExtensionManager/ExtensionRepositories"))} + })); + uno::Reference< container::XNameAccess > xNameAccessRepositories; + xNameAccessRepositories.set( + xConfig->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", args2), + uno::UNO_QUERY_THROW); + try + { //throws css::container::NoSuchElementException, css::lang::WrappedTargetException + uno::Any value = xNameAccessRepositories->getByName("WebsiteLink"); + m_sGetExtensionsURL = value.get< OUString > (); + } + catch ( const uno::Exception& ) + {} + + if ( dp_misc::office_is_running() ) + { + // the registration should be done after the construction has been ended + // otherwise an exception prevents object creation, but it is registered as a listener + m_xDesktop.set( frame::Desktop::create(xContext), uno::UNO_SET_THROW ); + m_xDesktop->addTerminateListener( this ); + } +} + +TheExtensionManager::~TheExtensionManager() +{ + if (m_xUpdReqDialog) + m_xUpdReqDialog->response(RET_CANCEL); + assert(!m_xUpdReqDialog); + if (m_xExtMgrDialog) + { + if (m_bExtMgrDialogExecuting) + m_xExtMgrDialog->response(RET_CANCEL); + else + { + m_xExtMgrDialog->Close(); + m_xExtMgrDialog.reset(); + } + } + assert(!m_xExtMgrDialog); +} + +void TheExtensionManager::createDialog( const bool bCreateUpdDlg ) +{ + const SolarMutexGuard guard; + + if ( bCreateUpdDlg ) + { + if ( !m_xUpdReqDialog ) + { + m_xUpdReqDialog.reset(new UpdateRequiredDialog(Application::GetFrameWeld(m_xParent), this)); + m_xExecuteCmdQueue.reset( new ExtensionCmdQueue( m_xUpdReqDialog.get(), this, m_xContext ) ); + createPackageList(); + } + } + else if ( !m_xExtMgrDialog ) + { + m_xExtMgrDialog = std::make_shared<ExtMgrDialog>(Application::GetFrameWeld(m_xParent), this); + m_xExecuteCmdQueue.reset( new ExtensionCmdQueue( m_xExtMgrDialog.get(), this, m_xContext ) ); + m_xExtMgrDialog->setGetExtensionsURL( m_sGetExtensionsURL ); + createPackageList(); + } +} + +void TheExtensionManager::Show() +{ + const SolarMutexGuard guard; + + m_bExtMgrDialogExecuting = true; + + weld::DialogController::runAsync(m_xExtMgrDialog, [this](sal_Int32 /*nResult*/) { + m_bExtMgrDialogExecuting = false; + auto xExtMgrDialog = m_xExtMgrDialog; + m_xExtMgrDialog.reset(); + xExtMgrDialog->Close(); + }); +} + +void TheExtensionManager::SetText( const OUString &rTitle ) +{ + const SolarMutexGuard guard; + + getDialog()->set_title( rTitle ); +} + + +void TheExtensionManager::ToTop() +{ + const SolarMutexGuard guard; + + getDialog()->present(); +} + +void TheExtensionManager::Close() +{ + if (m_xExtMgrDialog) + { + if (m_bExtMgrDialogExecuting) + m_xExtMgrDialog->response(RET_CANCEL); + else + m_xExtMgrDialog->Close(); + } + else if (m_xUpdReqDialog) + m_xUpdReqDialog->response(RET_CANCEL); +} + +sal_Int16 TheExtensionManager::execute() +{ + sal_Int16 nRet = 0; + + if ( m_xUpdReqDialog ) + { + nRet = m_xUpdReqDialog->run(); + m_xUpdReqDialog.reset(); + } + + return nRet; +} + +bool TheExtensionManager::isVisible() +{ + weld::Window* pDialog = getDialog(); + return pDialog && pDialog->get_visible(); +} + +void TheExtensionManager::checkUpdates() +{ + std::vector< uno::Reference< deployment::XPackage > > vEntries; + uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages; + + try { + xAllPackages = m_xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(), + uno::Reference< ucb::XCommandEnvironment >() ); + } catch ( const deployment::DeploymentException & ) { + return; + } catch ( const ucb::CommandFailedException & ) { + return; + } catch ( const ucb::CommandAbortedException & ) { + return; + } catch ( const lang::IllegalArgumentException & e ) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + + for ( auto const & i : std::as_const(xAllPackages) ) + { + uno::Reference< deployment::XPackage > xPackage = dp_misc::getExtensionWithHighestVersion(i); + OSL_ASSERT(xPackage.is()); + if ( xPackage.is() ) + { + vEntries.push_back( xPackage ); + } + } + + m_xExecuteCmdQueue->checkForUpdates( vEntries ); +} + + +bool TheExtensionManager::installPackage( const OUString &rPackageURL, bool bWarnUser ) +{ + if ( rPackageURL.isEmpty() ) + return false; + + createDialog( false ); + + bool bInstall = true; + bool bInstallForAll = false; + + // DV! missing function is read only repository from extension manager + if ( !bWarnUser && ! m_xExtensionManager->isReadOnlyRepository( SHARED_PACKAGE_MANAGER ) ) + bInstall = getDialogHelper()->installForAllUsers( bInstallForAll ); + + if ( !bInstall ) + return false; + + if ( bInstallForAll ) + m_xExecuteCmdQueue->addExtension( rPackageURL, SHARED_PACKAGE_MANAGER, false ); + else + m_xExecuteCmdQueue->addExtension( rPackageURL, USER_PACKAGE_MANAGER, bWarnUser ); + + return true; +} + + +void TheExtensionManager::terminateDialog() +{ + if ( dp_misc::office_is_running() ) + return; + + const SolarMutexGuard guard; + if (m_xExtMgrDialog) + { + if (m_bExtMgrDialogExecuting) + m_xExtMgrDialog->response(RET_CANCEL); + else + { + m_xExtMgrDialog->Close(); + m_xExtMgrDialog.reset(); + } + } + assert(!m_xExtMgrDialog); + if (m_xUpdReqDialog) + m_xUpdReqDialog->response(RET_CANCEL); + assert(!m_xUpdReqDialog); + Application::Quit(); +} + + +void TheExtensionManager::createPackageList() +{ + uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages; + + try { + xAllPackages = m_xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(), + uno::Reference< ucb::XCommandEnvironment >() ); + } catch ( const deployment::DeploymentException & ) { + return; + } catch ( const ucb::CommandFailedException & ) { + return; + } catch ( const ucb::CommandAbortedException & ) { + return; + } catch ( const lang::IllegalArgumentException & e ) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + + for ( uno::Sequence< uno::Reference< deployment::XPackage > > const & xPackageList : std::as_const(xAllPackages) ) + { + for ( uno::Reference< deployment::XPackage > const & xPackage : xPackageList ) + { + if ( xPackage.is() ) + { + PackageState eState = getPackageState( xPackage ); + getDialogHelper()->addPackageToList( xPackage ); + // When the package is enabled, we can stop here, otherwise we have to look for + // another version of this package + if ( ( eState == REGISTERED ) || ( eState == NOT_AVAILABLE ) ) + break; + } + } + } + + const uno::Sequence< uno::Reference< deployment::XPackage > > xNoLicPackages = m_xExtensionManager->getExtensionsWithUnacceptedLicenses( SHARED_PACKAGE_MANAGER, + uno::Reference< ucb::XCommandEnvironment >() ); + for ( uno::Reference< deployment::XPackage > const & xPackage : xNoLicPackages ) + { + if ( xPackage.is() ) + { + getDialogHelper()->addPackageToList( xPackage, true ); + } + } +} + + +PackageState TheExtensionManager::getPackageState( const uno::Reference< deployment::XPackage > &xPackage ) +{ + try { + beans::Optional< beans::Ambiguous< sal_Bool > > option( + xPackage->isRegistered( uno::Reference< task::XAbortChannel >(), + uno::Reference< ucb::XCommandEnvironment >() ) ); + if ( option.IsPresent ) + { + ::beans::Ambiguous< sal_Bool > const & reg = option.Value; + if ( reg.IsAmbiguous ) + return AMBIGUOUS; + else + return reg.Value ? REGISTERED : NOT_REGISTERED; + } + else + return NOT_AVAILABLE; + } + catch ( const uno::RuntimeException & ) { + throw; + } + catch (const uno::Exception &) { + TOOLS_WARN_EXCEPTION( "desktop", "" ); + return NOT_AVAILABLE; + } +} + + +bool TheExtensionManager::isReadOnly( const uno::Reference< deployment::XPackage > &xPackage ) const +{ + if ( m_xExtensionManager.is() && xPackage.is() ) + { + return m_xExtensionManager->isReadOnlyRepository( xPackage->getRepositoryName() ); + } + else + return true; +} + + +// The function investigates if the extension supports options. +bool TheExtensionManager::supportsOptions( const uno::Reference< deployment::XPackage > &xPackage ) const +{ + bool bOptions = false; + + if ( ! xPackage->isBundle() ) + return false; + + beans::Optional< OUString > aId = xPackage->getIdentifier(); + + //a bundle must always have an id + OSL_ASSERT( aId.IsPresent ); + + //iterate over all available nodes + const uno::Sequence< OUString > seqNames = m_xNameAccessNodes->getElementNames(); + + for ( OUString const & nodeName : seqNames ) + { + uno::Any anyNode = m_xNameAccessNodes->getByName( nodeName ); + //If we have a node then it must contain the set of leaves. This is part of OptionsDialog.xcs + uno::Reference< XInterface> xIntNode = anyNode.get< uno::Reference< XInterface > >(); + uno::Reference< container::XNameAccess > xNode( xIntNode, uno::UNO_QUERY_THROW ); + + uno::Any anyLeaves = xNode->getByName("Leaves"); + uno::Reference< XInterface > xIntLeaves = anyLeaves.get< uno::Reference< XInterface > >(); + uno::Reference< container::XNameAccess > xLeaves( xIntLeaves, uno::UNO_QUERY_THROW ); + + //iterate over all available leaves + const uno::Sequence< OUString > seqLeafNames = xLeaves->getElementNames(); + for ( OUString const & leafName : seqLeafNames ) + { + uno::Any anyLeaf = xLeaves->getByName( leafName ); + uno::Reference< XInterface > xIntLeaf = anyLeaf.get< uno::Reference< XInterface > >(); + uno::Reference< beans::XPropertySet > xLeaf( xIntLeaf, uno::UNO_QUERY_THROW ); + //investigate the Id property if it matches the extension identifier which + //has been passed in. + uno::Any anyValue = xLeaf->getPropertyValue("Id"); + + OUString sId = anyValue.get< OUString >(); + if ( sId == aId.Value ) + { + bOptions = true; + break; + } + } + if ( bOptions ) + break; + } + return bOptions; +} + + +// XEventListener +void TheExtensionManager::disposing( lang::EventObject const & rEvt ) +{ + bool shutDown = (rEvt.Source == m_xDesktop); + + if ( shutDown && m_xDesktop.is() ) + { + m_xDesktop->removeTerminateListener( this ); + m_xDesktop.clear(); + } + + if ( !shutDown ) + return; + + if ( dp_misc::office_is_running() ) + { + const SolarMutexGuard guard; + if (m_xExtMgrDialog) + { + if (m_bExtMgrDialogExecuting) + m_xExtMgrDialog->response(RET_CANCEL); + else + { + m_xExtMgrDialog->Close(); + m_xExtMgrDialog.reset(); + } + } + assert(!m_xExtMgrDialog); + if (m_xUpdReqDialog) + m_xUpdReqDialog->response(RET_CANCEL); + assert(!m_xUpdReqDialog); + } + s_ExtMgr.clear(); +} + +// XTerminateListener +void TheExtensionManager::queryTermination( ::lang::EventObject const & ) +{ + DialogHelper *pDialogHelper = getDialogHelper(); + + if ( m_xExecuteCmdQueue->isBusy() || ( pDialogHelper && pDialogHelper->isBusy() ) ) + { + ToTop(); + throw frame::TerminationVetoException( + "The office cannot be closed while the Extension Manager is running", + static_cast<frame::XTerminateListener*>(this)); + } + else + { + clearModified(); + if (m_xExtMgrDialog) + { + if (m_bExtMgrDialogExecuting) + m_xExtMgrDialog->response(RET_CANCEL); + else + { + m_xExtMgrDialog->Close(); + m_xExtMgrDialog.reset(); + } + } + if (m_xUpdReqDialog) + m_xUpdReqDialog->response(RET_CANCEL); + } +} + +void TheExtensionManager::notifyTermination( ::lang::EventObject const & rEvt ) +{ + disposing( rEvt ); +} + +// XModifyListener +void TheExtensionManager::modified( ::lang::EventObject const & /*rEvt*/ ) +{ + m_bModified = true; + getDialogHelper()->prepareChecking(); + createPackageList(); + getDialogHelper()->checkEntries(); +} + + +::rtl::Reference< TheExtensionManager > TheExtensionManager::get( const uno::Reference< uno::XComponentContext > &xContext, + const uno::Reference< awt::XWindow > &xParent, + const OUString & extensionURL ) +{ + if ( s_ExtMgr.is() ) + { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + if ( !extensionURL.isEmpty() ) + s_ExtMgr->installPackage( extensionURL, true ); + return s_ExtMgr; + } + + ::rtl::Reference<TheExtensionManager> that( new TheExtensionManager( xParent, xContext ) ); + + const SolarMutexGuard guard; + if ( ! s_ExtMgr.is() ) + { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + s_ExtMgr = that; + } + + if ( !extensionURL.isEmpty() ) + s_ExtMgr->installPackage( extensionURL, true ); + + return s_ExtMgr; +} + +} //namespace dp_gui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |