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 .
20 #include <vcl/svapp.hxx>
22 #include <toolkit/helper/vclunohelper.hxx>
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>
32 #include <comphelper/propertysequence.hxx>
33 #include <cppuhelper/exc_hlp.hxx>
34 #include <sal/log.hxx>
35 #include <osl/diagnose.h>
36 #include <tools/diagnose_ex.h>
38 #include "dp_gui_dialog2.hxx"
39 #include "dp_gui_extensioncmdqueue.hxx"
40 #include "dp_gui_theextmgr.hxx"
41 #include <dp_identifier.hxx>
42 #include <dp_update.hxx>
44 #define USER_PACKAGE_MANAGER "user"
45 #define SHARED_PACKAGE_MANAGER "shared"
47 using namespace ::com::sun::star
;
52 ::rtl::Reference
< TheExtensionManager
> TheExtensionManager::s_ExtMgr
;
55 // TheExtensionManager
58 TheExtensionManager::TheExtensionManager( const uno::Reference
< awt::XWindow
> &xParent
,
59 const uno::Reference
< uno::XComponentContext
> &xContext
) :
60 m_xContext( xContext
),
63 m_bExtMgrDialogExecuting(false)
65 m_xExtensionManager
= deployment::ExtensionManager::get( xContext
);
66 m_xExtensionManager
->addModifyListener( this );
68 uno::Reference
< lang::XMultiServiceFactory
> xConfig(
69 configuration::theDefaultProvider::get(xContext
));
70 uno::Sequence
<uno::Any
> args(comphelper::InitAnyPropertySequence(
72 {"nodepath", uno::Any(OUString("/org.openoffice.Office.OptionsDialog/Nodes"))}
74 m_xNameAccessNodes
.set(
75 xConfig
->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", args
),
76 uno::UNO_QUERY_THROW
);
78 // get the 'get more extensions here' url
79 uno::Sequence
<uno::Any
> args2(comphelper::InitAnyPropertySequence(
81 {"nodepath", uno::Any(OUString("/org.openoffice.Office.ExtensionManager/ExtensionRepositories"))}
83 uno::Reference
< container::XNameAccess
> xNameAccessRepositories
;
84 xNameAccessRepositories
.set(
85 xConfig
->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", args2
),
86 uno::UNO_QUERY_THROW
);
88 { //throws css::container::NoSuchElementException, css::lang::WrappedTargetException
89 uno::Any value
= xNameAccessRepositories
->getByName("WebsiteLink");
90 m_sGetExtensionsURL
= value
.get
< OUString
> ();
92 catch ( const uno::Exception
& )
95 if ( dp_misc::office_is_running() )
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 );
104 TheExtensionManager::~TheExtensionManager()
107 m_xUpdReqDialog
->response(RET_CANCEL
);
108 assert(!m_xUpdReqDialog
);
111 if (m_bExtMgrDialogExecuting
)
112 m_xExtMgrDialog
->response(RET_CANCEL
);
115 m_xExtMgrDialog
->Close();
116 m_xExtMgrDialog
.reset();
119 assert(!m_xExtMgrDialog
);
122 void TheExtensionManager::createDialog( const bool bCreateUpdDlg
)
124 const SolarMutexGuard guard
;
128 if ( !m_xUpdReqDialog
)
130 m_xUpdReqDialog
.reset(new UpdateRequiredDialog(Application::GetFrameWeld(m_xParent
), this));
131 m_xExecuteCmdQueue
.reset( new ExtensionCmdQueue( m_xUpdReqDialog
.get(), this, m_xContext
) );
135 else if ( !m_xExtMgrDialog
)
137 m_xExtMgrDialog
.reset(new ExtMgrDialog(Application::GetFrameWeld(m_xParent
), this));
138 m_xExecuteCmdQueue
.reset( new ExtensionCmdQueue( m_xExtMgrDialog
.get(), this, m_xContext
) );
139 m_xExtMgrDialog
->setGetExtensionsURL( m_sGetExtensionsURL
);
144 void TheExtensionManager::Show()
146 const SolarMutexGuard guard
;
148 m_bExtMgrDialogExecuting
= true;
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();
158 void TheExtensionManager::SetText( const OUString
&rTitle
)
160 const SolarMutexGuard guard
;
162 getDialog()->set_title( rTitle
);
166 void TheExtensionManager::ToTop()
168 const SolarMutexGuard guard
;
170 getDialog()->present();
173 void TheExtensionManager::Close()
177 if (m_bExtMgrDialogExecuting
)
178 m_xExtMgrDialog
->response(RET_CANCEL
);
180 m_xExtMgrDialog
->Close();
182 else if (m_xUpdReqDialog
)
183 m_xUpdReqDialog
->response(RET_CANCEL
);
186 sal_Int16
TheExtensionManager::execute()
190 if ( m_xUpdReqDialog
)
192 nRet
= m_xUpdReqDialog
->run();
193 m_xUpdReqDialog
.reset();
199 bool TheExtensionManager::isVisible()
201 weld::Window
* pDialog
= getDialog();
202 return pDialog
&& pDialog
->get_visible();
205 void TheExtensionManager::checkUpdates()
207 std::vector
< uno::Reference
< deployment::XPackage
> > vEntries
;
208 uno::Sequence
< uno::Sequence
< uno::Reference
< deployment::XPackage
> > > xAllPackages
;
211 xAllPackages
= m_xExtensionManager
->getAllExtensions( uno::Reference
< task::XAbortChannel
>(),
212 uno::Reference
< ucb::XCommandEnvironment
>() );
213 } catch ( const deployment::DeploymentException
& ) {
215 } catch ( const ucb::CommandFailedException
& ) {
217 } catch ( const ucb::CommandAbortedException
& ) {
219 } catch ( const lang::IllegalArgumentException
& e
) {
220 css::uno::Any anyEx
= cppu::getCaughtException();
221 throw css::lang::WrappedTargetRuntimeException( e
.Message
,
225 for ( sal_Int32 i
= 0; i
< xAllPackages
.getLength(); ++i
)
227 uno::Reference
< deployment::XPackage
> xPackage
= dp_misc::getExtensionWithHighestVersion(xAllPackages
[i
]);
228 OSL_ASSERT(xPackage
.is());
231 vEntries
.push_back( xPackage
);
235 m_xExecuteCmdQueue
->checkForUpdates( vEntries
);
239 bool TheExtensionManager::installPackage( const OUString
&rPackageURL
, bool bWarnUser
)
241 if ( rPackageURL
.isEmpty() )
244 createDialog( false );
246 bool bInstall
= true;
247 bool bInstallForAll
= false;
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
);
256 if ( bInstallForAll
)
257 m_xExecuteCmdQueue
->addExtension( rPackageURL
, SHARED_PACKAGE_MANAGER
, false );
259 m_xExecuteCmdQueue
->addExtension( rPackageURL
, USER_PACKAGE_MANAGER
, bWarnUser
);
265 void TheExtensionManager::terminateDialog()
267 if ( ! dp_misc::office_is_running() )
269 const SolarMutexGuard guard
;
272 if (m_bExtMgrDialogExecuting
)
273 m_xExtMgrDialog
->response(RET_CANCEL
);
276 m_xExtMgrDialog
->Close();
277 m_xExtMgrDialog
.reset();
280 assert(!m_xExtMgrDialog
);
282 m_xUpdReqDialog
->response(RET_CANCEL
);
283 assert(!m_xUpdReqDialog
);
289 void TheExtensionManager::createPackageList()
291 uno::Sequence
< uno::Sequence
< uno::Reference
< deployment::XPackage
> > > xAllPackages
;
294 xAllPackages
= m_xExtensionManager
->getAllExtensions( uno::Reference
< task::XAbortChannel
>(),
295 uno::Reference
< ucb::XCommandEnvironment
>() );
296 } catch ( const deployment::DeploymentException
& ) {
298 } catch ( const ucb::CommandFailedException
& ) {
300 } catch ( const ucb::CommandAbortedException
& ) {
302 } catch ( const lang::IllegalArgumentException
& e
) {
303 css::uno::Any anyEx
= cppu::getCaughtException();
304 throw css::lang::WrappedTargetRuntimeException( e
.Message
,
308 for ( sal_Int32 i
= 0; i
< xAllPackages
.getLength(); ++i
)
310 uno::Sequence
< uno::Reference
< deployment::XPackage
> > xPackageList
= xAllPackages
[i
];
312 for ( sal_Int32 j
= 0; j
< xPackageList
.getLength(); ++j
)
314 uno::Reference
< deployment::XPackage
> xPackage
= xPackageList
[j
];
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
) )
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
)
331 uno::Reference
< deployment::XPackage
> xPackage
= xNoLicPackages
[i
];
334 getDialogHelper()->addPackageToList( xPackage
, true );
340 PackageState
TheExtensionManager::getPackageState( const uno::Reference
< deployment::XPackage
> &xPackage
)
343 beans::Optional
< beans::Ambiguous
< sal_Bool
> > option(
344 xPackage
->isRegistered( uno::Reference
< task::XAbortChannel
>(),
345 uno::Reference
< ucb::XCommandEnvironment
>() ) );
346 if ( option
.IsPresent
)
348 ::beans::Ambiguous
< sal_Bool
> const & reg
= option
.Value
;
349 if ( reg
.IsAmbiguous
)
352 return reg
.Value
? REGISTERED
: NOT_REGISTERED
;
355 return NOT_AVAILABLE
;
357 catch ( const uno::RuntimeException
& ) {
360 catch (const uno::Exception
&) {
361 TOOLS_WARN_EXCEPTION( "desktop", "" );
362 return NOT_AVAILABLE
;
367 bool TheExtensionManager::isReadOnly( const uno::Reference
< deployment::XPackage
> &xPackage
) const
369 if ( m_xExtensionManager
.is() && xPackage
.is() )
371 return m_xExtensionManager
->isReadOnlyRepository( xPackage
->getRepositoryName() );
378 // The function investigates if the extension supports options.
379 bool TheExtensionManager::supportsOptions( const uno::Reference
< deployment::XPackage
> &xPackage
) const
381 bool bOptions
= false;
383 if ( ! xPackage
->isBundle() )
386 beans::Optional
< OUString
> aId
= xPackage
->getIdentifier();
388 //a bundle must always have an id
389 OSL_ASSERT( aId
.IsPresent
);
391 //iterate over all available nodes
392 uno::Sequence
< OUString
> seqNames
= m_xNameAccessNodes
->getElementNames();
394 for ( int i
= 0; i
< seqNames
.getLength(); i
++ )
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
);
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
);
405 //iterate over all available leaves
406 uno::Sequence
< OUString
> seqLeafNames
= xLeaves
->getElementNames();
407 for ( int j
= 0; j
< seqLeafNames
.getLength(); j
++ )
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");
416 OUString sId
= anyValue
.get
< OUString
>();
417 if ( sId
== aId
.Value
)
431 void TheExtensionManager::disposing( lang::EventObject
const & rEvt
)
433 bool shutDown
= (rEvt
.Source
== m_xDesktop
);
435 if ( shutDown
&& m_xDesktop
.is() )
437 m_xDesktop
->removeTerminateListener( this );
443 if ( dp_misc::office_is_running() )
445 const SolarMutexGuard guard
;
448 if (m_bExtMgrDialogExecuting
)
449 m_xExtMgrDialog
->response(RET_CANCEL
);
452 m_xExtMgrDialog
->Close();
453 m_xExtMgrDialog
.reset();
456 assert(!m_xExtMgrDialog
);
458 m_xUpdReqDialog
->response(RET_CANCEL
);
459 assert(!m_xUpdReqDialog
);
465 // XTerminateListener
466 void TheExtensionManager::queryTermination( ::lang::EventObject
const & )
468 DialogHelper
*pDialogHelper
= getDialogHelper();
470 if ( m_xExecuteCmdQueue
->isBusy() || ( pDialogHelper
&& pDialogHelper
->isBusy() ) )
473 throw frame::TerminationVetoException(
474 "The office cannot be closed while the Extension Manager is running",
475 static_cast<frame::XTerminateListener
*>(this));
482 if (m_bExtMgrDialogExecuting
)
483 m_xExtMgrDialog
->response(RET_CANCEL
);
486 m_xExtMgrDialog
->Close();
487 m_xExtMgrDialog
.reset();
491 m_xUpdReqDialog
->response(RET_CANCEL
);
495 void TheExtensionManager::notifyTermination( ::lang::EventObject
const & rEvt
)
501 void TheExtensionManager::modified( ::lang::EventObject
const & /*rEvt*/ )
504 getDialogHelper()->prepareChecking();
506 getDialogHelper()->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();
531 if ( !extensionURL
.isEmpty() )
532 s_ExtMgr
->installPackage( extensionURL
, true );
539 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */