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