LibreOffice Module desktop (master) 1
dp_gui_theextmgr.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <utility>
21#include <vcl/svapp.hxx>
22
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>
34#include <osl/diagnose.h>
36
37#include "dp_gui_dialog2.hxx"
39#include "dp_gui_theextmgr.hxx"
40#include <dp_misc.h>
41#include <dp_update.hxx>
42
43constexpr OUStringLiteral USER_PACKAGE_MANAGER = u"user";
44constexpr OUStringLiteral SHARED_PACKAGE_MANAGER = u"shared";
45
46using namespace ::com::sun::star;
47
48namespace dp_gui {
49
50
52
53
54// TheExtensionManager
55
56
60 m_xParent(std::move( xParent )),
61 m_bModified(false),
62 m_bExtMgrDialogExecuting(false)
63{
64 m_xExtensionManager = deployment::ExtensionManager::get( xContext );
65 m_xExtensionManager->addModifyListener( this );
66
68 configuration::theDefaultProvider::get(xContext));
70 {
71 {"nodepath", uno::Any(OUString("/org.openoffice.Office.OptionsDialog/Nodes"))}
72 }));
74 xConfig->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", args),
75 uno::UNO_QUERY_THROW);
76
77 // get the 'get more extensions here' url
79 {
80 {"nodepath", uno::Any(OUString("/org.openoffice.Office.ExtensionManager/ExtensionRepositories"))}
81 }));
82 uno::Reference< container::XNameAccess > xNameAccessRepositories;
83 xNameAccessRepositories.set(
84 xConfig->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", args2),
85 uno::UNO_QUERY_THROW);
86 try
87 { //throws css::container::NoSuchElementException, css::lang::WrappedTargetException
88 uno::Any value = xNameAccessRepositories->getByName("WebsiteLink");
89 m_sGetExtensionsURL = value.get< OUString > ();
90 }
91 catch ( const uno::Exception& )
92 {}
93
95 {
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 );
100 }
101}
102
104{
105 if (m_xUpdReqDialog)
106 m_xUpdReqDialog->response(RET_CANCEL);
107 assert(!m_xUpdReqDialog);
108 if (m_xExtMgrDialog)
109 {
111 m_xExtMgrDialog->response(RET_CANCEL);
112 else
113 {
114 m_xExtMgrDialog->Close();
115 m_xExtMgrDialog.reset();
116 }
117 }
118 assert(!m_xExtMgrDialog);
119}
120
121void TheExtensionManager::createDialog( const bool bCreateUpdDlg )
122{
123 const SolarMutexGuard guard;
124
125 if ( bCreateUpdDlg )
126 {
127 if ( !m_xUpdReqDialog )
128 {
132 }
133 }
134 else if ( !m_xExtMgrDialog )
135 {
136 m_xExtMgrDialog = std::make_shared<ExtMgrDialog>(Application::GetFrameWeld(m_xParent), this);
138 m_xExtMgrDialog->setGetExtensionsURL( m_sGetExtensionsURL );
140 }
141}
142
144{
145 const SolarMutexGuard guard;
146
148
149 weld::DialogController::runAsync(m_xExtMgrDialog, [this](sal_Int32 /*nResult*/) {
151 auto xExtMgrDialog = m_xExtMgrDialog;
152 m_xExtMgrDialog.reset();
153 xExtMgrDialog->Close();
154 });
155}
156
157void TheExtensionManager::SetText( const OUString &rTitle )
158{
159 const SolarMutexGuard guard;
160
161 if (weld::Window* pDialog = getDialog())
162 pDialog->set_title( rTitle );
163}
164
165
167{
168 const SolarMutexGuard guard;
169
170 if (weld::Window* pDialog = getDialog())
171 pDialog->present();
172}
173
175{
176 if (m_xExtMgrDialog)
177 {
179 m_xExtMgrDialog->response(RET_CANCEL);
180 else
181 m_xExtMgrDialog->Close();
182 }
183 else if (m_xUpdReqDialog)
184 m_xUpdReqDialog->response(RET_CANCEL);
185}
186
188{
189 sal_Int16 nRet = 0;
190
191 if ( m_xUpdReqDialog )
192 {
193 nRet = m_xUpdReqDialog->run();
194 m_xUpdReqDialog.reset();
195 }
196
197 return nRet;
198}
199
201{
202 weld::Window* pDialog = getDialog();
203 return pDialog && pDialog->get_visible();
204}
205
207{
208 std::vector< uno::Reference< deployment::XPackage > > vEntries;
210
211 try {
212 xAllPackages = m_xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
214 } catch ( const deployment::DeploymentException & ) {
215 return;
216 } catch ( const ucb::CommandFailedException & ) {
217 return;
218 } catch ( const ucb::CommandAbortedException & ) {
219 return;
220 } catch ( const lang::IllegalArgumentException & e ) {
221 css::uno::Any anyEx = cppu::getCaughtException();
222 throw css::lang::WrappedTargetRuntimeException( e.Message,
223 e.Context, anyEx );
224 }
225
226 for ( auto const & i : std::as_const(xAllPackages) )
227 {
229 OSL_ASSERT(xPackage.is());
230 if ( xPackage.is() )
231 {
232 vEntries.push_back( xPackage );
233 }
234 }
235
236 m_xExecuteCmdQueue->checkForUpdates( std::move(vEntries) );
237}
238
239
240bool TheExtensionManager::installPackage( const OUString &rPackageURL, bool bWarnUser )
241{
242 if ( rPackageURL.isEmpty() )
243 return false;
244
245 createDialog( false );
246
247 bool bInstall = true;
248 bool bInstallForAll = false;
249
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 );
253
254 if ( !bInstall )
255 return false;
256
257 if ( bInstallForAll )
258 m_xExecuteCmdQueue->addExtension( rPackageURL, SHARED_PACKAGE_MANAGER, false );
259 else
260 m_xExecuteCmdQueue->addExtension( rPackageURL, USER_PACKAGE_MANAGER, bWarnUser );
261
262 return true;
263}
264
265
267{
269 return;
270
271 const SolarMutexGuard guard;
272 if (m_xExtMgrDialog)
273 {
275 m_xExtMgrDialog->response(RET_CANCEL);
276 else
277 {
278 m_xExtMgrDialog->Close();
279 m_xExtMgrDialog.reset();
280 }
281 }
282 assert(!m_xExtMgrDialog);
283 if (m_xUpdReqDialog)
284 m_xUpdReqDialog->response(RET_CANCEL);
285 assert(!m_xUpdReqDialog);
287}
288
289
291{
293
294 try {
295 xAllPackages = m_xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
297 } catch ( const deployment::DeploymentException & ) {
298 return;
299 } catch ( const ucb::CommandFailedException & ) {
300 return;
301 } catch ( const ucb::CommandAbortedException & ) {
302 return;
303 } catch ( const lang::IllegalArgumentException & e ) {
304 css::uno::Any anyEx = cppu::getCaughtException();
305 throw css::lang::WrappedTargetRuntimeException( e.Message,
306 e.Context, anyEx );
307 }
308
309 for ( uno::Sequence< uno::Reference< deployment::XPackage > > const & xPackageList : std::as_const(xAllPackages) )
310 {
311 for ( uno::Reference< deployment::XPackage > const & xPackage : xPackageList )
312 {
313 if ( xPackage.is() )
314 {
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 ) )
320 break;
321 }
322 }
323 }
324
325 const uno::Sequence< uno::Reference< deployment::XPackage > > xNoLicPackages = m_xExtensionManager->getExtensionsWithUnacceptedLicenses( SHARED_PACKAGE_MANAGER,
327 for ( uno::Reference< deployment::XPackage > const & xPackage : xNoLicPackages )
328 {
329 if ( xPackage.is() )
330 {
331 getDialogHelper()->addPackageToList( xPackage, true );
332 }
333 }
334}
335
336
338{
339 try {
340 beans::Optional< beans::Ambiguous< sal_Bool > > option(
341 xPackage->isRegistered( uno::Reference< task::XAbortChannel >(),
343 if ( option.IsPresent )
344 {
345 ::beans::Ambiguous< sal_Bool > const & reg = option.Value;
346 if ( reg.IsAmbiguous )
347 return AMBIGUOUS;
348 else
349 return reg.Value ? REGISTERED : NOT_REGISTERED;
350 }
351 else
352 return NOT_AVAILABLE;
353 }
354 catch ( const uno::RuntimeException & ) {
355 throw;
356 }
357 catch (const uno::Exception &) {
358 TOOLS_WARN_EXCEPTION( "desktop", "" );
359 return NOT_AVAILABLE;
360 }
361}
362
363
365{
366 if ( m_xExtensionManager.is() && xPackage.is() )
367 {
368 return m_xExtensionManager->isReadOnlyRepository( xPackage->getRepositoryName() );
369 }
370 else
371 return true;
372}
373
374
375// The function investigates if the extension supports options.
377{
378 bool bOptions = false;
379
380 if ( ! xPackage->isBundle() )
381 return false;
382
383 beans::Optional< OUString > aId = xPackage->getIdentifier();
384
385 //a bundle must always have an id
386 OSL_ASSERT( aId.IsPresent );
387
388 //iterate over all available nodes
389 const uno::Sequence< OUString > seqNames = m_xNameAccessNodes->getElementNames();
390
391 for ( OUString const & nodeName : seqNames )
392 {
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
396 uno::Reference< container::XNameAccess > xNode( xIntNode, uno::UNO_QUERY_THROW );
397
398 uno::Any anyLeaves = xNode->getByName("Leaves");
399 uno::Reference< XInterface > xIntLeaves = anyLeaves.get< uno::Reference< XInterface > >();
400 uno::Reference< container::XNameAccess > xLeaves( xIntLeaves, uno::UNO_QUERY_THROW );
401
402 //iterate over all available leaves
403 const uno::Sequence< OUString > seqLeafNames = xLeaves->getElementNames();
404 for ( OUString const & leafName : seqLeafNames )
405 {
406 uno::Any anyLeaf = xLeaves->getByName( leafName );
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("Id");
412
413 OUString sId = anyValue.get< OUString >();
414 if ( sId == aId.Value )
415 {
416 bOptions = true;
417 break;
418 }
419 }
420 if ( bOptions )
421 break;
422 }
423 return bOptions;
424}
425
426
427// XEventListener
428void TheExtensionManager::disposing( lang::EventObject const & rEvt )
429{
430 bool shutDown = (rEvt.Source == m_xDesktop);
431
432 if ( shutDown && m_xDesktop.is() )
433 {
434 m_xDesktop->removeTerminateListener( this );
435 m_xDesktop.clear();
436 }
437
438 if ( !shutDown )
439 return;
440
442 {
443 const SolarMutexGuard guard;
444 if (m_xExtMgrDialog)
445 {
447 m_xExtMgrDialog->response(RET_CANCEL);
448 else
449 {
450 m_xExtMgrDialog->Close();
451 m_xExtMgrDialog.reset();
452 }
453 }
454 assert(!m_xExtMgrDialog);
455 if (m_xUpdReqDialog)
456 m_xUpdReqDialog->response(RET_CANCEL);
457 assert(!m_xUpdReqDialog);
458 }
459 s_ExtMgr.clear();
460}
461
462// XTerminateListener
463void TheExtensionManager::queryTermination( ::lang::EventObject const & )
464{
465 DialogHelper *pDialogHelper = getDialogHelper();
466
467 if ( m_xExecuteCmdQueue->isBusy() || ( pDialogHelper && pDialogHelper->isBusy() ) )
468 {
469 ToTop();
470 throw frame::TerminationVetoException(
471 "The office cannot be closed while the Extension Manager is running",
472 static_cast<frame::XTerminateListener*>(this));
473 }
474 else
475 {
477 if (m_xExtMgrDialog)
478 {
480 m_xExtMgrDialog->response(RET_CANCEL);
481 else
482 {
483 m_xExtMgrDialog->Close();
484 m_xExtMgrDialog.reset();
485 }
486 }
487 if (m_xUpdReqDialog)
488 m_xUpdReqDialog->response(RET_CANCEL);
489 }
490}
491
492void TheExtensionManager::notifyTermination( ::lang::EventObject const & rEvt )
493{
494 disposing( rEvt );
495}
496
497// XModifyListener
498void TheExtensionManager::modified( ::lang::EventObject const & /*rEvt*/ )
499{
500 m_bModified = true;
501 DialogHelper *pDialogHelper = getDialogHelper();
502 if (!pDialogHelper)
503 return;
504 pDialogHelper->prepareChecking();
506 pDialogHelper->checkEntries();
507}
508
509
511 const uno::Reference< awt::XWindow > &xParent,
512 const OUString & extensionURL )
513{
514 if ( s_ExtMgr.is() )
515 {
516 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
517 if ( !extensionURL.isEmpty() )
518 s_ExtMgr->installPackage( extensionURL, true );
519 return s_ExtMgr;
520 }
521
523
524 const SolarMutexGuard guard;
525 if ( ! s_ExtMgr.is() )
526 {
527 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
528 s_ExtMgr = that;
529 }
530
531 if ( !extensionURL.isEmpty() )
532 s_ExtMgr->installPackage( extensionURL, true );
533
534 return s_ExtMgr;
535}
536
537} //namespace dp_gui
538
539/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static weld::Window * GetFrameWeld(const css::uno::Reference< css::awt::XWindow > &rWindow)
static void Quit()
bool installForAllUsers(bool &bInstallForAll)
virtual void addPackageToList(const css::uno::Reference< css::deployment::XPackage > &xPackage, bool bLicenseMissing=false)=0
virtual void prepareChecking()=0
virtual void checkEntries()=0
Manages installing of extensions in the GUI mode.
css::uno::Reference< css::deployment::XExtensionManager > m_xExtensionManager
void SetText(const OUString &rTitle)
static ::rtl::Reference< TheExtensionManager > get(css::uno::Reference< css::uno::XComponentContext > const &xContext, css::uno::Reference< css::awt::XWindow > const &xParent=nullptr, OUString const &view=OUString())
css::uno::Reference< css::container::XNameAccess > m_xNameAccessNodes
bool installPackage(const OUString &rPackageURL, bool bWarnUser=false)
virtual void SAL_CALL notifyTermination(css::lang::EventObject const &evt) override
std::shared_ptr< ExtMgrDialog > m_xExtMgrDialog
static PackageState getPackageState(const css::uno::Reference< css::deployment::XPackage > &xPackage)
css::uno::Reference< css::awt::XWindow > m_xParent
static ::rtl::Reference< TheExtensionManager > s_ExtMgr
virtual void SAL_CALL queryTermination(css::lang::EventObject const &evt) override
std::unique_ptr< ExtensionCmdQueue > m_xExecuteCmdQueue
css::uno::Reference< css::uno::XComponentContext > m_xContext
bool isReadOnly(const css::uno::Reference< css::deployment::XPackage > &xPackage) const
std::unique_ptr< UpdateRequiredDialog > m_xUpdReqDialog
TheExtensionManager(css::uno::Reference< css::awt::XWindow > xParent, const css::uno::Reference< css::uno::XComponentContext > &xContext)
virtual void SAL_CALL disposing(css::lang::EventObject const &evt) override
bool supportsOptions(const css::uno::Reference< css::deployment::XPackage > &xPackage) const
virtual ~TheExtensionManager() override
void createDialog(const bool bCreateUpdDlg)
virtual void SAL_CALL modified(css::lang::EventObject const &evt) override
css::uno::Reference< css::frame::XDesktop2 > m_xDesktop
static bool runAsync(const std::shared_ptr< DialogController > &rController, const std::function< void(sal_Int32)> &)
virtual bool get_visible() const=0
Any value
#define TOOLS_WARN_EXCEPTION(area, stream)
uno::Reference< uno::XComponentContext > m_xContext
constexpr OUStringLiteral SHARED_PACKAGE_MANAGER
constexpr OUStringLiteral USER_PACKAGE_MANAGER
float u
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2642
css::uno::Sequence< css::uno::Any > InitAnyPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
Any SAL_CALL getCaughtException()
Definition: dp_gui.h:22
PackageState
Definition: dp_gui.h:24
@ AMBIGUOUS
Definition: dp_gui.h:24
@ REGISTERED
Definition: dp_gui.h:24
@ NOT_REGISTERED
Definition: dp_gui.h:24
@ NOT_AVAILABLE
Definition: dp_gui.h:24
constexpr OUStringLiteral SHARED_PACKAGE_MANAGER
constexpr OUStringLiteral USER_PACKAGE_MANAGER
bool office_is_running()
Definition: dp_misc.cxx:331
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC css::uno::Reference< css::deployment::XPackage > getExtensionWithHighestVersion(css::uno::Sequence< css::uno::Reference< css::deployment::XPackage > > const &seqExtensionsWithSameId)
css::uno::Reference< css::deployment::XPackageRegistry > create(css::uno::Reference< css::deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, css::uno::Reference< css::uno::XComponentContext > const &xComponentContext)
int i
args
JCOPY_OPTION option
OUString sId
RET_CANCEL