1
0
Fork 0
libreoffice/desktop/source/deployment/gui/dp_gui_theextmgr.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

539 lines
17 KiB
C++

/* -*- 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 <utility>
#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 <comphelper/diagnose_ex.hxx>
#include "dp_gui_dialog2.hxx"
#include "dp_gui_extensioncmdqueue.hxx"
#include "dp_gui_theextmgr.hxx"
#include <dp_misc.h>
#include <dp_update.hxx>
constexpr OUStringLiteral USER_PACKAGE_MANAGER = u"user";
constexpr OUString SHARED_PACKAGE_MANAGER = u"shared"_ustr;
using namespace ::com::sun::star;
namespace dp_gui {
::rtl::Reference< TheExtensionManager > TheExtensionManager::s_ExtMgr;
// TheExtensionManager
TheExtensionManager::TheExtensionManager( uno::Reference< awt::XWindow > xParent,
const uno::Reference< uno::XComponentContext > &xContext ) :
m_xContext( xContext ),
m_xParent(std::move( 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(u"/org.openoffice.Office.OptionsDialog/Nodes"_ustr)}
}));
m_xNameAccessNodes.set(
xConfig->createInstanceWithArguments( u"com.sun.star.configuration.ConfigurationAccess"_ustr, args),
uno::UNO_QUERY_THROW);
// get the 'get more extensions here' url
uno::Sequence<uno::Any> args2(comphelper::InitAnyPropertySequence(
{
{"nodepath", uno::Any(u"/org.openoffice.Office.ExtensionManager/ExtensionRepositories"_ustr)}
}));
uno::Reference< container::XNameAccess > xNameAccessRepositories;
xNameAccessRepositories.set(
xConfig->createInstanceWithArguments( u"com.sun.star.configuration.ConfigurationAccess"_ustr, args2),
uno::UNO_QUERY_THROW);
try
{ //throws css::container::NoSuchElementException, css::lang::WrappedTargetException
uno::Any value = xNameAccessRepositories->getByName(u"WebsiteLink"_ustr);
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;
if (weld::Window* pDialog = getDialog())
pDialog->set_title( rTitle );
}
void TheExtensionManager::ToTop()
{
const SolarMutexGuard guard;
if (weld::Window* pDialog = getDialog())
pDialog->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 : xAllPackages)
{
uno::Reference< deployment::XPackage > xPackage = dp_misc::getExtensionWithHighestVersion(i);
OSL_ASSERT(xPackage.is());
if ( xPackage.is() )
{
vEntries.push_back( xPackage );
}
}
m_xExecuteCmdQueue->checkForUpdates( std::move(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 : 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(u"Leaves"_ustr);
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(u"Id"_ustr);
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(
u"The office cannot be closed while the Extension Manager is running"_ustr,
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;
DialogHelper *pDialogHelper = getDialogHelper();
if (!pDialogHelper)
return;
pDialogHelper->prepareChecking();
createPackageList();
pDialogHelper->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 = std::move(that);
}
if ( !extensionURL.isEmpty() )
s_ExtMgr->installPackage( extensionURL, true );
return s_ExtMgr;
}
} //namespace dp_gui
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */