1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <vcl/svapp.hxx>
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/configuration/theDefaultProvider.hpp>
25 #include <com/sun/star/deployment/DeploymentException.hpp>
26 #include <com/sun/star/deployment/ExtensionManager.hpp>
27 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
28 #include <com/sun/star/frame/Desktop.hpp>
29 #include <com/sun/star/frame/TerminationVetoException.hpp>
30 #include <com/sun/star/ucb/CommandAbortedException.hpp>
31 #include <com/sun/star/ucb/CommandFailedException.hpp>
32 #include <comphelper/propertysequence.hxx>
33 #include <cppuhelper/exc_hlp.hxx>
34 #include <osl/diagnose.h>
35 #include <comphelper/diagnose_ex.hxx>
37 #include "dp_gui_dialog2.hxx"
38 #include "dp_gui_extensioncmdqueue.hxx"
39 #include "dp_gui_theextmgr.hxx"
41 #include <dp_update.hxx>
43 constexpr OUStringLiteral USER_PACKAGE_MANAGER
= u
"user";
44 constexpr OUString SHARED_PACKAGE_MANAGER
= u
"shared"_ustr
;
46 using namespace ::com::sun::star
;
51 ::rtl::Reference
< TheExtensionManager
> TheExtensionManager::s_ExtMgr
;
54 // TheExtensionManager
57 TheExtensionManager::TheExtensionManager( uno::Reference
< awt::XWindow
> xParent
,
58 const uno::Reference
< uno::XComponentContext
> &xContext
) :
59 m_xContext( xContext
),
60 m_xParent(std::move( xParent
)),
62 m_bExtMgrDialogExecuting(false)
64 m_xExtensionManager
= deployment::ExtensionManager::get( xContext
);
65 m_xExtensionManager
->addModifyListener( this );
67 uno::Reference
< lang::XMultiServiceFactory
> xConfig(
68 configuration::theDefaultProvider::get(xContext
));
69 uno::Sequence
<uno::Any
> args(comphelper::InitAnyPropertySequence(
71 {"nodepath", uno::Any(u
"/org.openoffice.Office.OptionsDialog/Nodes"_ustr
)}
73 m_xNameAccessNodes
.set(
74 xConfig
->createInstanceWithArguments( u
"com.sun.star.configuration.ConfigurationAccess"_ustr
, args
),
75 uno::UNO_QUERY_THROW
);
77 // get the 'get more extensions here' url
78 uno::Sequence
<uno::Any
> args2(comphelper::InitAnyPropertySequence(
80 {"nodepath", uno::Any(u
"/org.openoffice.Office.ExtensionManager/ExtensionRepositories"_ustr
)}
82 uno::Reference
< container::XNameAccess
> xNameAccessRepositories
;
83 xNameAccessRepositories
.set(
84 xConfig
->createInstanceWithArguments( u
"com.sun.star.configuration.ConfigurationAccess"_ustr
, args2
),
85 uno::UNO_QUERY_THROW
);
87 { //throws css::container::NoSuchElementException, css::lang::WrappedTargetException
88 uno::Any value
= xNameAccessRepositories
->getByName(u
"WebsiteLink"_ustr
);
89 m_sGetExtensionsURL
= value
.get
< OUString
> ();
91 catch ( const uno::Exception
& )
94 if ( dp_misc::office_is_running() )
96 // the registration should be done after the construction has been ended
97 // otherwise an exception prevents object creation, but it is registered as a listener
98 m_xDesktop
.set( frame::Desktop::create(xContext
), uno::UNO_SET_THROW
);
99 m_xDesktop
->addTerminateListener( this );
103 TheExtensionManager::~TheExtensionManager()
106 m_xUpdReqDialog
->response(RET_CANCEL
);
107 assert(!m_xUpdReqDialog
);
110 if (m_bExtMgrDialogExecuting
)
111 m_xExtMgrDialog
->response(RET_CANCEL
);
114 m_xExtMgrDialog
->Close();
115 m_xExtMgrDialog
.reset();
118 assert(!m_xExtMgrDialog
);
121 void TheExtensionManager::createDialog( const bool bCreateUpdDlg
)
123 const SolarMutexGuard guard
;
127 if ( !m_xUpdReqDialog
)
129 m_xUpdReqDialog
.reset(new UpdateRequiredDialog(Application::GetFrameWeld(m_xParent
), this));
130 m_xExecuteCmdQueue
.reset( new ExtensionCmdQueue( m_xUpdReqDialog
.get(), this, m_xContext
) );
134 else if ( !m_xExtMgrDialog
)
136 m_xExtMgrDialog
= std::make_shared
<ExtMgrDialog
>(Application::GetFrameWeld(m_xParent
), this);
137 m_xExecuteCmdQueue
.reset( new ExtensionCmdQueue( m_xExtMgrDialog
.get(), this, m_xContext
) );
138 m_xExtMgrDialog
->setGetExtensionsURL( m_sGetExtensionsURL
);
143 void TheExtensionManager::Show()
145 const SolarMutexGuard guard
;
147 m_bExtMgrDialogExecuting
= true;
149 weld::DialogController::runAsync(m_xExtMgrDialog
, [this](sal_Int32
/*nResult*/) {
150 m_bExtMgrDialogExecuting
= false;
151 auto xExtMgrDialog
= m_xExtMgrDialog
;
152 m_xExtMgrDialog
.reset();
153 xExtMgrDialog
->Close();
157 void TheExtensionManager::SetText( const OUString
&rTitle
)
159 const SolarMutexGuard guard
;
161 if (weld::Window
* pDialog
= getDialog())
162 pDialog
->set_title( rTitle
);
166 void TheExtensionManager::ToTop()
168 const SolarMutexGuard guard
;
170 if (weld::Window
* pDialog
= getDialog())
174 void TheExtensionManager::Close()
178 if (m_bExtMgrDialogExecuting
)
179 m_xExtMgrDialog
->response(RET_CANCEL
);
181 m_xExtMgrDialog
->Close();
183 else if (m_xUpdReqDialog
)
184 m_xUpdReqDialog
->response(RET_CANCEL
);
187 sal_Int16
TheExtensionManager::execute()
191 if ( m_xUpdReqDialog
)
193 nRet
= m_xUpdReqDialog
->run();
194 m_xUpdReqDialog
.reset();
200 bool TheExtensionManager::isVisible()
202 weld::Window
* pDialog
= getDialog();
203 return pDialog
&& pDialog
->get_visible();
206 void TheExtensionManager::checkUpdates()
208 std::vector
< uno::Reference
< deployment::XPackage
> > vEntries
;
209 uno::Sequence
< uno::Sequence
< uno::Reference
< deployment::XPackage
> > > xAllPackages
;
212 xAllPackages
= m_xExtensionManager
->getAllExtensions( uno::Reference
< task::XAbortChannel
>(),
213 uno::Reference
< ucb::XCommandEnvironment
>() );
214 } catch ( const deployment::DeploymentException
& ) {
216 } catch ( const ucb::CommandFailedException
& ) {
218 } catch ( const ucb::CommandAbortedException
& ) {
220 } catch ( const lang::IllegalArgumentException
& e
) {
221 css::uno::Any anyEx
= cppu::getCaughtException();
222 throw css::lang::WrappedTargetRuntimeException( e
.Message
,
226 for (auto const& i
: xAllPackages
)
228 uno::Reference
< deployment::XPackage
> xPackage
= dp_misc::getExtensionWithHighestVersion(i
);
229 OSL_ASSERT(xPackage
.is());
232 vEntries
.push_back( xPackage
);
236 m_xExecuteCmdQueue
->checkForUpdates( std::move(vEntries
) );
240 bool TheExtensionManager::installPackage( const OUString
&rPackageURL
, bool bWarnUser
)
242 if ( rPackageURL
.isEmpty() )
245 createDialog( false );
247 bool bInstall
= true;
248 bool bInstallForAll
= false;
250 // DV! missing function is read only repository from extension manager
251 if ( !bWarnUser
&& ! m_xExtensionManager
->isReadOnlyRepository( SHARED_PACKAGE_MANAGER
) )
252 bInstall
= getDialogHelper()->installForAllUsers( bInstallForAll
);
257 if ( bInstallForAll
)
258 m_xExecuteCmdQueue
->addExtension( rPackageURL
, SHARED_PACKAGE_MANAGER
, false );
260 m_xExecuteCmdQueue
->addExtension( rPackageURL
, USER_PACKAGE_MANAGER
, bWarnUser
);
266 void TheExtensionManager::terminateDialog()
268 if ( dp_misc::office_is_running() )
271 const SolarMutexGuard guard
;
274 if (m_bExtMgrDialogExecuting
)
275 m_xExtMgrDialog
->response(RET_CANCEL
);
278 m_xExtMgrDialog
->Close();
279 m_xExtMgrDialog
.reset();
282 assert(!m_xExtMgrDialog
);
284 m_xUpdReqDialog
->response(RET_CANCEL
);
285 assert(!m_xUpdReqDialog
);
290 void TheExtensionManager::createPackageList()
292 uno::Sequence
< uno::Sequence
< uno::Reference
< deployment::XPackage
> > > xAllPackages
;
295 xAllPackages
= m_xExtensionManager
->getAllExtensions( uno::Reference
< task::XAbortChannel
>(),
296 uno::Reference
< ucb::XCommandEnvironment
>() );
297 } catch ( const deployment::DeploymentException
& ) {
299 } catch ( const ucb::CommandFailedException
& ) {
301 } catch ( const ucb::CommandAbortedException
& ) {
303 } catch ( const lang::IllegalArgumentException
& e
) {
304 css::uno::Any anyEx
= cppu::getCaughtException();
305 throw css::lang::WrappedTargetRuntimeException( e
.Message
,
309 for (uno::Sequence
<uno::Reference
<deployment::XPackage
>> const& xPackageList
: xAllPackages
)
311 for ( uno::Reference
< deployment::XPackage
> const & xPackage
: xPackageList
)
315 PackageState eState
= getPackageState( xPackage
);
316 getDialogHelper()->addPackageToList( xPackage
);
317 // When the package is enabled, we can stop here, otherwise we have to look for
318 // another version of this package
319 if ( ( eState
== REGISTERED
) || ( eState
== NOT_AVAILABLE
) )
325 const uno::Sequence
< uno::Reference
< deployment::XPackage
> > xNoLicPackages
= m_xExtensionManager
->getExtensionsWithUnacceptedLicenses( SHARED_PACKAGE_MANAGER
,
326 uno::Reference
< ucb::XCommandEnvironment
>() );
327 for ( uno::Reference
< deployment::XPackage
> const & xPackage
: xNoLicPackages
)
331 getDialogHelper()->addPackageToList( xPackage
, true );
337 PackageState
TheExtensionManager::getPackageState( const uno::Reference
< deployment::XPackage
> &xPackage
)
340 beans::Optional
< beans::Ambiguous
< sal_Bool
> > option(
341 xPackage
->isRegistered( uno::Reference
< task::XAbortChannel
>(),
342 uno::Reference
< ucb::XCommandEnvironment
>() ) );
343 if ( option
.IsPresent
)
345 ::beans::Ambiguous
< sal_Bool
> const & reg
= option
.Value
;
346 if ( reg
.IsAmbiguous
)
349 return reg
.Value
? REGISTERED
: NOT_REGISTERED
;
352 return NOT_AVAILABLE
;
354 catch ( const uno::RuntimeException
& ) {
357 catch (const uno::Exception
&) {
358 TOOLS_WARN_EXCEPTION( "desktop", "" );
359 return NOT_AVAILABLE
;
364 bool TheExtensionManager::isReadOnly( const uno::Reference
< deployment::XPackage
> &xPackage
) const
366 if ( m_xExtensionManager
.is() && xPackage
.is() )
368 return m_xExtensionManager
->isReadOnlyRepository( xPackage
->getRepositoryName() );
375 // The function investigates if the extension supports options.
376 bool TheExtensionManager::supportsOptions( const uno::Reference
< deployment::XPackage
> &xPackage
) const
378 bool bOptions
= false;
380 if ( ! xPackage
->isBundle() )
383 beans::Optional
< OUString
> aId
= xPackage
->getIdentifier();
385 //a bundle must always have an id
386 OSL_ASSERT( aId
.IsPresent
);
388 //iterate over all available nodes
389 const uno::Sequence
< OUString
> seqNames
= m_xNameAccessNodes
->getElementNames();
391 for ( OUString
const & nodeName
: seqNames
)
393 uno::Any anyNode
= m_xNameAccessNodes
->getByName( nodeName
);
394 //If we have a node then it must contain the set of leaves. This is part of OptionsDialog.xcs
395 uno::Reference
< XInterface
> xIntNode
= anyNode
.get
< uno::Reference
< XInterface
> >();
396 uno::Reference
< container::XNameAccess
> xNode( xIntNode
, uno::UNO_QUERY_THROW
);
398 uno::Any anyLeaves
= xNode
->getByName(u
"Leaves"_ustr
);
399 uno::Reference
< XInterface
> xIntLeaves
= anyLeaves
.get
< uno::Reference
< XInterface
> >();
400 uno::Reference
< container::XNameAccess
> xLeaves( xIntLeaves
, uno::UNO_QUERY_THROW
);
402 //iterate over all available leaves
403 const uno::Sequence
< OUString
> seqLeafNames
= xLeaves
->getElementNames();
404 for ( OUString
const & leafName
: seqLeafNames
)
406 uno::Any anyLeaf
= xLeaves
->getByName( leafName
);
407 uno::Reference
< XInterface
> xIntLeaf
= anyLeaf
.get
< uno::Reference
< XInterface
> >();
408 uno::Reference
< beans::XPropertySet
> xLeaf( xIntLeaf
, uno::UNO_QUERY_THROW
);
409 //investigate the Id property if it matches the extension identifier which
410 //has been passed in.
411 uno::Any anyValue
= xLeaf
->getPropertyValue(u
"Id"_ustr
);
413 OUString sId
= anyValue
.get
< OUString
>();
414 if ( sId
== aId
.Value
)
428 void TheExtensionManager::disposing( lang::EventObject
const & rEvt
)
430 bool shutDown
= (rEvt
.Source
== m_xDesktop
);
432 if ( shutDown
&& m_xDesktop
.is() )
434 m_xDesktop
->removeTerminateListener( this );
441 if ( dp_misc::office_is_running() )
443 const SolarMutexGuard guard
;
446 if (m_bExtMgrDialogExecuting
)
447 m_xExtMgrDialog
->response(RET_CANCEL
);
450 m_xExtMgrDialog
->Close();
451 m_xExtMgrDialog
.reset();
454 assert(!m_xExtMgrDialog
);
456 m_xUpdReqDialog
->response(RET_CANCEL
);
457 assert(!m_xUpdReqDialog
);
462 // XTerminateListener
463 void TheExtensionManager::queryTermination( ::lang::EventObject
const & )
465 DialogHelper
*pDialogHelper
= getDialogHelper();
467 if ( m_xExecuteCmdQueue
->isBusy() || ( pDialogHelper
&& pDialogHelper
->isBusy() ) )
470 throw frame::TerminationVetoException(
471 u
"The office cannot be closed while the Extension Manager is running"_ustr
,
472 static_cast<frame::XTerminateListener
*>(this));
479 if (m_bExtMgrDialogExecuting
)
480 m_xExtMgrDialog
->response(RET_CANCEL
);
483 m_xExtMgrDialog
->Close();
484 m_xExtMgrDialog
.reset();
488 m_xUpdReqDialog
->response(RET_CANCEL
);
492 void TheExtensionManager::notifyTermination( ::lang::EventObject
const & rEvt
)
498 void TheExtensionManager::modified( ::lang::EventObject
const & /*rEvt*/ )
501 DialogHelper
*pDialogHelper
= getDialogHelper();
504 pDialogHelper
->prepareChecking();
506 pDialogHelper
->checkEntries();
510 ::rtl::Reference
< TheExtensionManager
> TheExtensionManager::get( const uno::Reference
< uno::XComponentContext
> &xContext
,
511 const uno::Reference
< awt::XWindow
> &xParent
,
512 const OUString
& extensionURL
)
516 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
517 if ( !extensionURL
.isEmpty() )
518 s_ExtMgr
->installPackage( extensionURL
, true );
522 ::rtl::Reference
<TheExtensionManager
> that( new TheExtensionManager( xParent
, xContext
) );
524 const SolarMutexGuard guard
;
525 if ( ! s_ExtMgr
.is() )
527 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
528 s_ExtMgr
= std::move(that
);
531 if ( !extensionURL
.isEmpty() )
532 s_ExtMgr
->installPackage( extensionURL
, true );
539 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */