use insert function instead of for loop
[LibreOffice.git] / desktop / source / deployment / gui / dp_gui_theextmgr.cxx
blobf942ee349c4b3f4599341ce9d6fe79a456081e22
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <utility>
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"
40 #include <dp_misc.h>
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;
48 namespace dp_gui {
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 )),
61 m_bModified(false),
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)}
72 }));
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)}
81 }));
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);
86 try
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()
105 if (m_xUpdReqDialog)
106 m_xUpdReqDialog->response(RET_CANCEL);
107 assert(!m_xUpdReqDialog);
108 if (m_xExtMgrDialog)
110 if (m_bExtMgrDialogExecuting)
111 m_xExtMgrDialog->response(RET_CANCEL);
112 else
114 m_xExtMgrDialog->Close();
115 m_xExtMgrDialog.reset();
118 assert(!m_xExtMgrDialog);
121 void TheExtensionManager::createDialog( const bool bCreateUpdDlg )
123 const SolarMutexGuard guard;
125 if ( bCreateUpdDlg )
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 ) );
131 createPackageList();
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 );
139 createPackageList();
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())
171 pDialog->present();
174 void TheExtensionManager::Close()
176 if (m_xExtMgrDialog)
178 if (m_bExtMgrDialogExecuting)
179 m_xExtMgrDialog->response(RET_CANCEL);
180 else
181 m_xExtMgrDialog->Close();
183 else if (m_xUpdReqDialog)
184 m_xUpdReqDialog->response(RET_CANCEL);
187 sal_Int16 TheExtensionManager::execute()
189 sal_Int16 nRet = 0;
191 if ( m_xUpdReqDialog )
193 nRet = m_xUpdReqDialog->run();
194 m_xUpdReqDialog.reset();
197 return nRet;
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;
211 try {
212 xAllPackages = m_xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
213 uno::Reference< ucb::XCommandEnvironment >() );
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 );
226 for (auto const& i : xAllPackages)
228 uno::Reference< deployment::XPackage > xPackage = dp_misc::getExtensionWithHighestVersion(i);
229 OSL_ASSERT(xPackage.is());
230 if ( 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() )
243 return false;
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 );
254 if ( !bInstall )
255 return false;
257 if ( bInstallForAll )
258 m_xExecuteCmdQueue->addExtension( rPackageURL, SHARED_PACKAGE_MANAGER, false );
259 else
260 m_xExecuteCmdQueue->addExtension( rPackageURL, USER_PACKAGE_MANAGER, bWarnUser );
262 return true;
266 void TheExtensionManager::terminateDialog()
268 if ( dp_misc::office_is_running() )
269 return;
271 const SolarMutexGuard guard;
272 if (m_xExtMgrDialog)
274 if (m_bExtMgrDialogExecuting)
275 m_xExtMgrDialog->response(RET_CANCEL);
276 else
278 m_xExtMgrDialog->Close();
279 m_xExtMgrDialog.reset();
282 assert(!m_xExtMgrDialog);
283 if (m_xUpdReqDialog)
284 m_xUpdReqDialog->response(RET_CANCEL);
285 assert(!m_xUpdReqDialog);
286 Application::Quit();
290 void TheExtensionManager::createPackageList()
292 uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages;
294 try {
295 xAllPackages = m_xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
296 uno::Reference< ucb::XCommandEnvironment >() );
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 );
309 for (uno::Sequence<uno::Reference<deployment::XPackage>> const& xPackageList : xAllPackages)
311 for ( uno::Reference< deployment::XPackage > const & xPackage : xPackageList )
313 if ( xPackage.is() )
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;
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 )
329 if ( xPackage.is() )
331 getDialogHelper()->addPackageToList( xPackage, true );
337 PackageState TheExtensionManager::getPackageState( const uno::Reference< deployment::XPackage > &xPackage )
339 try {
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 )
347 return AMBIGUOUS;
348 else
349 return reg.Value ? REGISTERED : NOT_REGISTERED;
351 else
352 return NOT_AVAILABLE;
354 catch ( const uno::RuntimeException & ) {
355 throw;
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() );
370 else
371 return true;
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() )
381 return false;
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 )
416 bOptions = true;
417 break;
420 if ( bOptions )
421 break;
423 return bOptions;
427 // XEventListener
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 );
435 m_xDesktop.clear();
438 if ( !shutDown )
439 return;
441 if ( dp_misc::office_is_running() )
443 const SolarMutexGuard guard;
444 if (m_xExtMgrDialog)
446 if (m_bExtMgrDialogExecuting)
447 m_xExtMgrDialog->response(RET_CANCEL);
448 else
450 m_xExtMgrDialog->Close();
451 m_xExtMgrDialog.reset();
454 assert(!m_xExtMgrDialog);
455 if (m_xUpdReqDialog)
456 m_xUpdReqDialog->response(RET_CANCEL);
457 assert(!m_xUpdReqDialog);
459 s_ExtMgr.clear();
462 // XTerminateListener
463 void TheExtensionManager::queryTermination( ::lang::EventObject const & )
465 DialogHelper *pDialogHelper = getDialogHelper();
467 if ( m_xExecuteCmdQueue->isBusy() || ( pDialogHelper && pDialogHelper->isBusy() ) )
469 ToTop();
470 throw frame::TerminationVetoException(
471 u"The office cannot be closed while the Extension Manager is running"_ustr,
472 static_cast<frame::XTerminateListener*>(this));
474 else
476 clearModified();
477 if (m_xExtMgrDialog)
479 if (m_bExtMgrDialogExecuting)
480 m_xExtMgrDialog->response(RET_CANCEL);
481 else
483 m_xExtMgrDialog->Close();
484 m_xExtMgrDialog.reset();
487 if (m_xUpdReqDialog)
488 m_xUpdReqDialog->response(RET_CANCEL);
492 void TheExtensionManager::notifyTermination( ::lang::EventObject const & rEvt )
494 disposing( rEvt );
497 // XModifyListener
498 void TheExtensionManager::modified( ::lang::EventObject const & /*rEvt*/ )
500 m_bModified = true;
501 DialogHelper *pDialogHelper = getDialogHelper();
502 if (!pDialogHelper)
503 return;
504 pDialogHelper->prepareChecking();
505 createPackageList();
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 )
514 if ( s_ExtMgr.is() )
516 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
517 if ( !extensionURL.isEmpty() )
518 s_ExtMgr->installPackage( extensionURL, true );
519 return s_ExtMgr;
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 );
534 return s_ExtMgr;
537 } //namespace dp_gui
539 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */