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 <vcl/svapp.hxx>
21 
22 #include <com/sun/star/beans/XPropertySet.hpp>
23 #include <com/sun/star/configuration/theDefaultProvider.hpp>
24 #include <com/sun/star/deployment/DeploymentException.hpp>
25 #include <com/sun/star/deployment/ExtensionManager.hpp>
26 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
27 #include <com/sun/star/frame/Desktop.hpp>
28 #include <com/sun/star/frame/TerminationVetoException.hpp>
29 #include <com/sun/star/ucb/CommandAbortedException.hpp>
30 #include <com/sun/star/ucb/CommandFailedException.hpp>
32 #include <cppuhelper/exc_hlp.hxx>
33 #include <osl/diagnose.h>
34 #include <tools/diagnose_ex.h>
35 
36 #include "dp_gui_dialog2.hxx"
38 #include "dp_gui_theextmgr.hxx"
39 #include <dp_misc.h>
40 #include <dp_update.hxx>
41 
42 #define USER_PACKAGE_MANAGER "user"
43 #define SHARED_PACKAGE_MANAGER "shared"
44 
45 using namespace ::com::sun::star;
46 
47 namespace dp_gui {
48 
49 
51 
52 
53 // TheExtensionManager
54 
55 
56 TheExtensionManager::TheExtensionManager( const uno::Reference< awt::XWindow > &xParent,
57  const uno::Reference< uno::XComponentContext > &xContext ) :
58  m_xContext( xContext ),
59  m_xParent( xParent ),
60  m_bModified(false),
61  m_bExtMgrDialogExecuting(false)
62 {
63  m_xExtensionManager = deployment::ExtensionManager::get( xContext );
64  m_xExtensionManager->addModifyListener( this );
65 
66  uno::Reference< lang::XMultiServiceFactory > xConfig(
67  configuration::theDefaultProvider::get(xContext));
68  uno::Sequence<uno::Any> args(comphelper::InitAnyPropertySequence(
69  {
70  {"nodepath", uno::Any(OUString("/org.openoffice.Office.OptionsDialog/Nodes"))}
71  }));
73  xConfig->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", args),
74  uno::UNO_QUERY_THROW);
75 
76  // get the 'get more extensions here' url
77  uno::Sequence<uno::Any> args2(comphelper::InitAnyPropertySequence(
78  {
79  {"nodepath", uno::Any(OUString("/org.openoffice.Office.ExtensionManager/ExtensionRepositories"))}
80  }));
81  uno::Reference< container::XNameAccess > xNameAccessRepositories;
82  xNameAccessRepositories.set(
83  xConfig->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", args2),
84  uno::UNO_QUERY_THROW);
85  try
86  { //throws css::container::NoSuchElementException, css::lang::WrappedTargetException
87  uno::Any value = xNameAccessRepositories->getByName("WebsiteLink");
88  m_sGetExtensionsURL = value.get< OUString > ();
89  }
90  catch ( const uno::Exception& )
91  {}
92 
94  {
95  // the registration should be done after the construction has been ended
96  // otherwise an exception prevents object creation, but it is registered as a listener
97  m_xDesktop.set( frame::Desktop::create(xContext), uno::UNO_SET_THROW );
98  m_xDesktop->addTerminateListener( this );
99  }
100 }
101 
103 {
104  if (m_xUpdReqDialog)
105  m_xUpdReqDialog->response(RET_CANCEL);
107  if (m_xExtMgrDialog)
108  {
110  m_xExtMgrDialog->response(RET_CANCEL);
111  else
112  {
113  m_xExtMgrDialog->Close();
114  m_xExtMgrDialog.reset();
115  }
116  }
118 }
119 
120 void TheExtensionManager::createDialog( const bool bCreateUpdDlg )
121 {
122  const SolarMutexGuard guard;
123 
124  if ( bCreateUpdDlg )
125  {
126  if ( !m_xUpdReqDialog )
127  {
129  m_xExecuteCmdQueue.reset( new ExtensionCmdQueue( m_xUpdReqDialog.get(), this, m_xContext ) );
131  }
132  }
133  else if ( !m_xExtMgrDialog )
134  {
135  m_xExtMgrDialog = std::make_shared<ExtMgrDialog>(Application::GetFrameWeld(m_xParent), this);
136  m_xExecuteCmdQueue.reset( new ExtensionCmdQueue( m_xExtMgrDialog.get(), this, m_xContext ) );
137  m_xExtMgrDialog->setGetExtensionsURL( m_sGetExtensionsURL );
139  }
140 }
141 
143 {
144  const SolarMutexGuard guard;
145 
147 
148  weld::DialogController::runAsync(m_xExtMgrDialog, [this](sal_Int32 /*nResult*/) {
149  m_bExtMgrDialogExecuting = false;
150  auto xExtMgrDialog = m_xExtMgrDialog;
151  m_xExtMgrDialog.reset();
152  xExtMgrDialog->Close();
153  });
154 }
155 
156 void TheExtensionManager::SetText( const OUString &rTitle )
157 {
158  const SolarMutexGuard guard;
159 
160  getDialog()->set_title( rTitle );
161 }
162 
163 
165 {
166  const SolarMutexGuard guard;
167 
168  getDialog()->present();
169 }
170 
172 {
173  if (m_xExtMgrDialog)
174  {
176  m_xExtMgrDialog->response(RET_CANCEL);
177  else
178  m_xExtMgrDialog->Close();
179  }
180  else if (m_xUpdReqDialog)
181  m_xUpdReqDialog->response(RET_CANCEL);
182 }
183 
185 {
186  sal_Int16 nRet = 0;
187 
188  if ( m_xUpdReqDialog )
189  {
190  nRet = m_xUpdReqDialog->run();
191  m_xUpdReqDialog.reset();
192  }
193 
194  return nRet;
195 }
196 
198 {
199  weld::Window* pDialog = getDialog();
200  return pDialog && pDialog->get_visible();
201 }
202 
204 {
205  std::vector< uno::Reference< deployment::XPackage > > vEntries;
206  uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages;
207 
208  try {
209  xAllPackages = m_xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
210  uno::Reference< ucb::XCommandEnvironment >() );
211  } catch ( const deployment::DeploymentException & ) {
212  return;
213  } catch ( const ucb::CommandFailedException & ) {
214  return;
215  } catch ( const ucb::CommandAbortedException & ) {
216  return;
217  } catch ( const lang::IllegalArgumentException & e ) {
218  css::uno::Any anyEx = cppu::getCaughtException();
219  throw css::lang::WrappedTargetRuntimeException( e.Message,
220  e.Context, anyEx );
221  }
222 
223  for ( auto const & i : std::as_const(xAllPackages) )
224  {
225  uno::Reference< deployment::XPackage > xPackage = dp_misc::getExtensionWithHighestVersion(i);
226  OSL_ASSERT(xPackage.is());
227  if ( xPackage.is() )
228  {
229  vEntries.push_back( xPackage );
230  }
231  }
232 
233  m_xExecuteCmdQueue->checkForUpdates( vEntries );
234 }
235 
236 
237 bool TheExtensionManager::installPackage( const OUString &rPackageURL, bool bWarnUser )
238 {
239  if ( rPackageURL.isEmpty() )
240  return false;
241 
242  createDialog( false );
243 
244  bool bInstall = true;
245  bool bInstallForAll = false;
246 
247  // DV! missing function is read only repository from extension manager
248  if ( !bWarnUser && ! m_xExtensionManager->isReadOnlyRepository( SHARED_PACKAGE_MANAGER ) )
249  bInstall = getDialogHelper()->installForAllUsers( bInstallForAll );
250 
251  if ( !bInstall )
252  return false;
253 
254  if ( bInstallForAll )
255  m_xExecuteCmdQueue->addExtension( rPackageURL, SHARED_PACKAGE_MANAGER, false );
256  else
257  m_xExecuteCmdQueue->addExtension( rPackageURL, USER_PACKAGE_MANAGER, bWarnUser );
258 
259  return true;
260 }
261 
262 
264 {
266  return;
267 
268  const SolarMutexGuard guard;
269  if (m_xExtMgrDialog)
270  {
272  m_xExtMgrDialog->response(RET_CANCEL);
273  else
274  {
275  m_xExtMgrDialog->Close();
276  m_xExtMgrDialog.reset();
277  }
278  }
280  if (m_xUpdReqDialog)
281  m_xUpdReqDialog->response(RET_CANCEL);
284 }
285 
286 
288 {
289  uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages;
290 
291  try {
292  xAllPackages = m_xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
293  uno::Reference< ucb::XCommandEnvironment >() );
294  } catch ( const deployment::DeploymentException & ) {
295  return;
296  } catch ( const ucb::CommandFailedException & ) {
297  return;
298  } catch ( const ucb::CommandAbortedException & ) {
299  return;
300  } catch ( const lang::IllegalArgumentException & e ) {
301  css::uno::Any anyEx = cppu::getCaughtException();
302  throw css::lang::WrappedTargetRuntimeException( e.Message,
303  e.Context, anyEx );
304  }
305 
306  for ( uno::Sequence< uno::Reference< deployment::XPackage > > const & xPackageList : std::as_const(xAllPackages) )
307  {
308  for ( uno::Reference< deployment::XPackage > const & xPackage : xPackageList )
309  {
310  if ( xPackage.is() )
311  {
312  PackageState eState = getPackageState( xPackage );
313  getDialogHelper()->addPackageToList( xPackage );
314  // When the package is enabled, we can stop here, otherwise we have to look for
315  // another version of this package
316  if ( ( eState == REGISTERED ) || ( eState == NOT_AVAILABLE ) )
317  break;
318  }
319  }
320  }
321 
322  const uno::Sequence< uno::Reference< deployment::XPackage > > xNoLicPackages = m_xExtensionManager->getExtensionsWithUnacceptedLicenses( SHARED_PACKAGE_MANAGER,
323  uno::Reference< ucb::XCommandEnvironment >() );
324  for ( uno::Reference< deployment::XPackage > const & xPackage : xNoLicPackages )
325  {
326  if ( xPackage.is() )
327  {
328  getDialogHelper()->addPackageToList( xPackage, true );
329  }
330  }
331 }
332 
333 
334 PackageState TheExtensionManager::getPackageState( const uno::Reference< deployment::XPackage > &xPackage )
335 {
336  try {
337  beans::Optional< beans::Ambiguous< sal_Bool > > option(
338  xPackage->isRegistered( uno::Reference< task::XAbortChannel >(),
339  uno::Reference< ucb::XCommandEnvironment >() ) );
340  if ( option.IsPresent )
341  {
342  ::beans::Ambiguous< sal_Bool > const & reg = option.Value;
343  if ( reg.IsAmbiguous )
344  return AMBIGUOUS;
345  else
346  return reg.Value ? REGISTERED : NOT_REGISTERED;
347  }
348  else
349  return NOT_AVAILABLE;
350  }
351  catch ( const uno::RuntimeException & ) {
352  throw;
353  }
354  catch (const uno::Exception &) {
355  TOOLS_WARN_EXCEPTION( "desktop", "" );
356  return NOT_AVAILABLE;
357  }
358 }
359 
360 
361 bool TheExtensionManager::isReadOnly( const uno::Reference< deployment::XPackage > &xPackage ) const
362 {
363  if ( m_xExtensionManager.is() && xPackage.is() )
364  {
365  return m_xExtensionManager->isReadOnlyRepository( xPackage->getRepositoryName() );
366  }
367  else
368  return true;
369 }
370 
371 
372 // The function investigates if the extension supports options.
373 bool TheExtensionManager::supportsOptions( const uno::Reference< deployment::XPackage > &xPackage ) const
374 {
375  bool bOptions = false;
376 
377  if ( ! xPackage->isBundle() )
378  return false;
379 
380  beans::Optional< OUString > aId = xPackage->getIdentifier();
381 
382  //a bundle must always have an id
383  OSL_ASSERT( aId.IsPresent );
384 
385  //iterate over all available nodes
386  const uno::Sequence< OUString > seqNames = m_xNameAccessNodes->getElementNames();
387 
388  for ( OUString const & nodeName : seqNames )
389  {
390  uno::Any anyNode = m_xNameAccessNodes->getByName( nodeName );
391  //If we have a node then it must contain the set of leaves. This is part of OptionsDialog.xcs
392  uno::Reference< XInterface> xIntNode = anyNode.get< uno::Reference< XInterface > >();
393  uno::Reference< container::XNameAccess > xNode( xIntNode, uno::UNO_QUERY_THROW );
394 
395  uno::Any anyLeaves = xNode->getByName("Leaves");
396  uno::Reference< XInterface > xIntLeaves = anyLeaves.get< uno::Reference< XInterface > >();
397  uno::Reference< container::XNameAccess > xLeaves( xIntLeaves, uno::UNO_QUERY_THROW );
398 
399  //iterate over all available leaves
400  const uno::Sequence< OUString > seqLeafNames = xLeaves->getElementNames();
401  for ( OUString const & leafName : seqLeafNames )
402  {
403  uno::Any anyLeaf = xLeaves->getByName( leafName );
404  uno::Reference< XInterface > xIntLeaf = anyLeaf.get< uno::Reference< XInterface > >();
405  uno::Reference< beans::XPropertySet > xLeaf( xIntLeaf, uno::UNO_QUERY_THROW );
406  //investigate the Id property if it matches the extension identifier which
407  //has been passed in.
408  uno::Any anyValue = xLeaf->getPropertyValue("Id");
409 
410  OUString sId = anyValue.get< OUString >();
411  if ( sId == aId.Value )
412  {
413  bOptions = true;
414  break;
415  }
416  }
417  if ( bOptions )
418  break;
419  }
420  return bOptions;
421 }
422 
423 
424 // XEventListener
425 void TheExtensionManager::disposing( lang::EventObject const & rEvt )
426 {
427  bool shutDown = (rEvt.Source == m_xDesktop);
428 
429  if ( shutDown && m_xDesktop.is() )
430  {
431  m_xDesktop->removeTerminateListener( this );
432  m_xDesktop.clear();
433  }
434 
435  if ( !shutDown )
436  return;
437 
439  {
440  const SolarMutexGuard guard;
441  if (m_xExtMgrDialog)
442  {
444  m_xExtMgrDialog->response(RET_CANCEL);
445  else
446  {
447  m_xExtMgrDialog->Close();
448  m_xExtMgrDialog.reset();
449  }
450  }
452  if (m_xUpdReqDialog)
453  m_xUpdReqDialog->response(RET_CANCEL);
455  }
456  s_ExtMgr.clear();
457 }
458 
459 // XTerminateListener
460 void TheExtensionManager::queryTermination( ::lang::EventObject const & )
461 {
462  DialogHelper *pDialogHelper = getDialogHelper();
463 
464  if ( m_xExecuteCmdQueue->isBusy() || ( pDialogHelper && pDialogHelper->isBusy() ) )
465  {
466  ToTop();
467  throw frame::TerminationVetoException(
468  "The office cannot be closed while the Extension Manager is running",
469  static_cast<frame::XTerminateListener*>(this));
470  }
471  else
472  {
473  clearModified();
474  if (m_xExtMgrDialog)
475  {
477  m_xExtMgrDialog->response(RET_CANCEL);
478  else
479  {
480  m_xExtMgrDialog->Close();
481  m_xExtMgrDialog.reset();
482  }
483  }
484  if (m_xUpdReqDialog)
485  m_xUpdReqDialog->response(RET_CANCEL);
486  }
487 }
488 
489 void TheExtensionManager::notifyTermination( ::lang::EventObject const & rEvt )
490 {
491  disposing( rEvt );
492 }
493 
494 // XModifyListener
495 void TheExtensionManager::modified( ::lang::EventObject const & /*rEvt*/ )
496 {
497  m_bModified = true;
501 }
502 
503 
504 ::rtl::Reference< TheExtensionManager > TheExtensionManager::get( const uno::Reference< uno::XComponentContext > &xContext,
505  const uno::Reference< awt::XWindow > &xParent,
506  const OUString & extensionURL )
507 {
508  if ( s_ExtMgr.is() )
509  {
510  OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
511  if ( !extensionURL.isEmpty() )
512  s_ExtMgr->installPackage( extensionURL, true );
513  return s_ExtMgr;
514  }
515 
516  ::rtl::Reference<TheExtensionManager> that( new TheExtensionManager( xParent, xContext ) );
517 
518  const SolarMutexGuard guard;
519  if ( ! s_ExtMgr.is() )
520  {
521  OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
522  s_ExtMgr = that;
523  }
524 
525  if ( !extensionURL.isEmpty() )
526  s_ExtMgr->installPackage( extensionURL, true );
527 
528  return s_ExtMgr;
529 }
530 
531 } //namespace dp_gui
532 
533 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::awt::XWindow > m_xParent
void SetText(const OUString &rTitle)
#define USER_PACKAGE_MANAGER
bool office_is_running()
Definition: dp_misc.cxx:333
tuple args
virtual void SAL_CALL disposing(css::lang::EventObject const &evt) override
OUString aId
virtual void addPackageToList(const css::uno::Reference< css::deployment::XPackage > &xPackage, bool bLicenseMissing=false)=0
RET_CANCEL
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)
virtual void checkEntries()=0
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())
static bool runAsync(const std::shared_ptr< DialogController > &rController, const std::function< void(sal_Int32)> &)
TheExtensionManager(const css::uno::Reference< css::awt::XWindow > &xParent, const css::uno::Reference< css::uno::XComponentContext > &xContext)
JCOPY_OPTION option
virtual void SAL_CALL queryTermination(css::lang::EventObject const &evt) override
virtual void prepareChecking()=0
virtual void SAL_CALL modified(css::lang::EventObject const &evt) override
Any SAL_CALL getCaughtException()
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
#define SHARED_PACKAGE_MANAGER
virtual void SAL_CALL notifyTermination(css::lang::EventObject const &evt) override
static void Quit()
virtual bool get_visible() const =0
std::unique_ptr< UpdateRequiredDialog > m_xUpdReqDialog
#define TOOLS_WARN_EXCEPTION(area, stream)
int i
static::rtl::Reference< TheExtensionManager > s_ExtMgr
css::uno::Sequence< css::uno::Any > InitAnyPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
bool isReadOnly(const css::uno::Reference< css::deployment::XPackage > &xPackage) const
std::unique_ptr< ExtensionCmdQueue > m_xExecuteCmdQueue
static weld::Window * GetFrameWeld(const css::uno::Reference< css::awt::XWindow > &rWindow)
css::uno::Reference< css::uno::XComponentContext > m_xContext
virtual void present()=0
bool supportsOptions(const css::uno::Reference< css::deployment::XPackage > &xPackage) const
virtual void set_title(const OUString &rTitle)=0
bool installPackage(const OUString &rPackageURL, bool bWarnUser=false)
std::shared_ptr< ExtMgrDialog > m_xExtMgrDialog
css::uno::Reference< css::deployment::XExtensionManager > m_xExtensionManager
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2142
virtual ~TheExtensionManager() override
bool installForAllUsers(bool &bInstallForAll)
PackageState
Definition: dp_gui.h:25
static PackageState getPackageState(const css::uno::Reference< css::deployment::XPackage > &xPackage)
Any value
OUString sId
css::uno::Reference< css::container::XNameAccess > m_xNameAccessNodes
css::uno::Reference< css::frame::XDesktop2 > m_xDesktop
Definition: dp_gui.h:23
void createDialog(const bool bCreateUpdDlg)
Manages installing of extensions in the GUI mode.
uno::Reference< uno::XComponentContext > m_xContext
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC css::uno::Reference< css::deployment::XPackage > getExtensionWithHighestVersion(css::uno::Sequence< css::uno::Reference< css::deployment::XPackage > > const &seqExtensionsWithSameId)