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 <sal/config.h>
22 #include <com/sun/star/beans/NamedValue.hpp>
24 #include <com/sun/star/deployment/DependencyException.hpp>
25 #include <com/sun/star/deployment/LicenseException.hpp>
26 #include <com/sun/star/deployment/VersionException.hpp>
27 #include <com/sun/star/deployment/InstallException.hpp>
28 #include <com/sun/star/deployment/PlatformException.hpp>
30 #include <com/sun/star/deployment/ui/LicenseDialog.hpp>
31 #include <com/sun/star/deployment/DeploymentException.hpp>
32 #include <com/sun/star/deployment/XPackage.hpp>
34 #include <com/sun/star/task/InteractionHandler.hpp>
35 #include <com/sun/star/task/XAbortChannel.hpp>
36 #include <com/sun/star/task/XInteractionAbort.hpp>
37 #include <com/sun/star/task/XInteractionApprove.hpp>
39 #include <com/sun/star/ucb/CommandAbortedException.hpp>
40 #include <com/sun/star/ucb/CommandFailedException.hpp>
41 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
43 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
45 #include <com/sun/star/uno/Reference.hxx>
46 #include <com/sun/star/uno/Sequence.hxx>
47 #include <com/sun/star/uno/TypeClass.hpp>
48 #include <o3tl/any.hxx>
49 #include <osl/diagnose.h>
50 #include <rtl/ref.hxx>
51 #include <rtl/ustring.hxx>
52 #include <sal/types.h>
53 #include <salhelper/thread.hxx>
54 #include <ucbhelper/content.hxx>
55 #include <cppuhelper/exc_hlp.hxx>
56 #include <cppuhelper/implbase.hxx>
57 #include <comphelper/anytostring.hxx>
59 #include <vcl/svapp.hxx>
60 #include <vcl/weld.hxx>
62 #include "dp_gui_extensioncmdqueue.hxx"
63 #include "dp_gui_dependencydialog.hxx"
64 #include "dp_gui_dialog2.hxx"
65 #include <dp_shared.hxx>
66 #include <strings.hrc>
67 #include "dp_gui_theextmgr.hxx"
68 #include "dp_gui_updatedialog.hxx"
69 #include "dp_gui_updateinstalldialog.hxx"
70 #include <dp_dependencies.hxx>
72 #include <dp_identifier.hxx>
73 #include <dp_version.hxx>
75 #include <condition_variable>
81 #include <o3tl/safeCoInitUninit.hxx>
85 using namespace ::com::sun::star
;
89 OUString
getVersion( OUString
const & sVersion
)
91 return ( sVersion
.isEmpty() ) ? OUString( "0" ) : sVersion
;
94 OUString
getVersion( const uno::Reference
< deployment::XPackage
> &rPackage
)
96 return getVersion( rPackage
->getVersion());
106 : public ::cppu::WeakImplHelper
< ucb::XCommandEnvironment
,
107 task::XInteractionHandler
,
108 ucb::XProgressHandler
>
110 uno::Reference
< task::XInteractionHandler2
> m_xHandler
;
111 uno::Reference
< uno::XComponentContext
> m_xContext
;
113 DialogHelper
* m_pDialogHelper
;
116 sal_Int32 m_nCurrentProgress
;
118 void updateProgress();
120 /// @throws uno::RuntimeException
121 void update_( uno::Any
const & Status
);
124 /** When param bAskWhenInstalling = true, then the user is asked if he
125 agrees to install this extension. In case this extension is already installed
126 then the user is also notified and asked if he wants to replace that existing
127 extension. In first case an interaction request with an InstallException
128 will be handled and in the second case a VersionException will be handled.
131 ProgressCmdEnv( uno::Reference
< uno::XComponentContext
> xContext
,
132 DialogHelper
* pDialogHelper
,
134 : m_xContext(std::move( xContext
))
135 , m_pDialogHelper( pDialogHelper
)
136 , m_sTitle(std::move( aTitle
))
137 , m_bWarnUser( false )
138 , m_nCurrentProgress(0)
141 weld::Window
* activeDialog() { return m_pDialogHelper
? m_pDialogHelper
->getFrameWeld() : nullptr; }
143 void startProgress();
145 void progressSection( const OUString
&rText
,
146 const uno::Reference
< task::XAbortChannel
> &xAbortChannel
);
147 void setWarnUser( bool bNewVal
) { m_bWarnUser
= bNewVal
; }
149 // XCommandEnvironment
150 virtual uno::Reference
< task::XInteractionHandler
> SAL_CALL
getInteractionHandler() override
;
151 virtual uno::Reference
< ucb::XProgressHandler
> SAL_CALL
getProgressHandler() override
;
153 // XInteractionHandler
154 virtual void SAL_CALL
handle( uno::Reference
< task::XInteractionRequest
> const & xRequest
) override
;
157 virtual void SAL_CALL
push( uno::Any
const & Status
) override
;
158 virtual void SAL_CALL
update( uno::Any
const & Status
) override
;
159 virtual void SAL_CALL
pop() override
;
165 enum E_CMD_TYPE
{ ADD
, ENABLE
, DISABLE
, REMOVE
, CHECK_FOR_UPDATES
, ACCEPT_LICENSE
};
167 E_CMD_TYPE m_eCmdType
;
169 OUString m_sExtensionURL
;
170 OUString m_sRepository
;
171 uno::Reference
< deployment::XPackage
> m_xPackage
;
172 std::vector
< uno::Reference
< deployment::XPackage
> > m_vExtensionList
;
174 ExtensionCmd( const E_CMD_TYPE eCommand
,
175 OUString aExtensionURL
,
176 OUString aRepository
,
177 const bool bWarnUser
)
178 : m_eCmdType( eCommand
),
179 m_bWarnUser( bWarnUser
),
180 m_sExtensionURL(std::move( aExtensionURL
)),
181 m_sRepository(std::move( aRepository
)) {};
182 ExtensionCmd( const E_CMD_TYPE eCommand
,
183 uno::Reference
< deployment::XPackage
> xPackage
)
184 : m_eCmdType( eCommand
),
185 m_bWarnUser( false ),
186 m_xPackage(std::move( xPackage
)) {};
187 ExtensionCmd( const E_CMD_TYPE eCommand
,
188 std::vector
<uno::Reference
<deployment::XPackage
> >&&vExtensionList
)
189 : m_eCmdType( eCommand
),
190 m_bWarnUser( false ),
191 m_vExtensionList( std::move(vExtensionList
) ) {};
196 typedef std::shared_ptr
< ExtensionCmd
> TExtensionCmd
;
199 class ExtensionCmdQueue::Thread
: public salhelper::Thread
202 Thread( DialogHelper
*pDialogHelper
,
203 TheExtensionManager
*pManager
,
204 uno::Reference
< uno::XComponentContext
> xContext
);
206 void addExtension( const OUString
&rExtensionURL
,
207 const OUString
&rRepository
,
208 const bool bWarnUser
);
209 void removeExtension( const uno::Reference
< deployment::XPackage
> &rPackage
);
210 void enableExtension( const uno::Reference
< deployment::XPackage
> &rPackage
,
211 const bool bEnable
);
212 void checkForUpdates( std::vector
<uno::Reference
<deployment::XPackage
> > && vExtensionList
);
213 void acceptLicense( const uno::Reference
< deployment::XPackage
> &rPackage
);
218 virtual ~Thread() override
;
220 virtual void execute() override
;
222 void _insert(const TExtensionCmd
& rExtCmd
);
224 void _addExtension( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
225 const OUString
&rPackageURL
,
226 const OUString
&rRepository
,
227 const bool bWarnUser
);
228 void _removeExtension( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
229 const uno::Reference
< deployment::XPackage
> &xPackage
);
230 void _enableExtension( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
231 const uno::Reference
< deployment::XPackage
> &xPackage
);
232 void _disableExtension( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
233 const uno::Reference
< deployment::XPackage
> &xPackage
);
234 void _checkForUpdates( std::vector
<uno::Reference
<deployment::XPackage
> > &&vExtensionList
);
235 void _acceptLicense( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
236 const uno::Reference
< deployment::XPackage
> &xPackage
);
238 enum Input
{ NONE
, START
, STOP
};
240 uno::Reference
< uno::XComponentContext
> m_xContext
;
241 std::queue
< TExtensionCmd
> m_queue
;
243 DialogHelper
*m_pDialogHelper
;
244 TheExtensionManager
*m_pManager
;
246 const OUString m_sEnablingPackages
;
247 const OUString m_sDisablingPackages
;
248 const OUString m_sAddingPackages
;
249 const OUString m_sRemovingPackages
;
250 const OUString m_sDefaultCmd
;
251 const OUString m_sAcceptLicense
;
252 std::condition_variable m_wakeup
;
260 void ProgressCmdEnv::startProgress()
262 m_nCurrentProgress
= 0;
264 if ( m_pDialogHelper
)
265 m_pDialogHelper
->showProgress( true );
269 void ProgressCmdEnv::stopProgress()
271 if ( m_pDialogHelper
)
272 m_pDialogHelper
->showProgress( false );
276 void ProgressCmdEnv::progressSection( const OUString
&rText
,
277 const uno::Reference
< task::XAbortChannel
> &xAbortChannel
)
279 m_nCurrentProgress
= 0;
280 if ( m_pDialogHelper
)
282 m_pDialogHelper
->updateProgress( rText
, xAbortChannel
);
283 m_pDialogHelper
->updateProgress( 5 );
288 void ProgressCmdEnv::updateProgress()
290 tools::Long nProgress
= ((m_nCurrentProgress
*5) % 100) + 5;
291 if ( m_pDialogHelper
)
292 m_pDialogHelper
->updateProgress( nProgress
);
295 // XCommandEnvironment
297 uno::Reference
< task::XInteractionHandler
> ProgressCmdEnv::getInteractionHandler()
303 uno::Reference
< ucb::XProgressHandler
> ProgressCmdEnv::getProgressHandler()
309 // XInteractionHandler
311 void ProgressCmdEnv::handle( uno::Reference
< task::XInteractionRequest
> const & xRequest
)
313 uno::Any
request( xRequest
->getRequest() );
314 OSL_ASSERT( request
.getValueTypeClass() == uno::TypeClass_EXCEPTION
);
315 dp_misc::TRACE( "[dp_gui_cmdenv.cxx] incoming request:\n"
316 + ::comphelper::anyToString(request
) + "\n");
318 lang::WrappedTargetException wtExc
;
319 deployment::DependencyException depExc
;
320 deployment::LicenseException licExc
;
321 deployment::VersionException verExc
;
322 deployment::InstallException instExc
;
323 deployment::PlatformException platExc
;
326 bool approve
= false;
329 if (request
>>= wtExc
) {
330 // handable deployment error signalled, e.g.
331 // bundle item registration failed, notify cause only:
333 deployment::DeploymentException dpExc
;
334 if (wtExc
.TargetException
>>= dpExc
)
337 ucb::CommandFailedException cfExc
;
338 if (wtExc
.TargetException
>>= cfExc
)
339 cause
= cfExc
.Reason
;
341 cause
= wtExc
.TargetException
;
345 // ignore intermediate errors of legacy packages, i.e.
346 // former pkgchk behaviour:
347 const uno::Reference
< deployment::XPackage
> xPackage( wtExc
.Context
, uno::UNO_QUERY
);
348 OSL_ASSERT( xPackage
.is() );
351 const uno::Reference
< deployment::XPackageTypeInfo
> xPackageType( xPackage
->getPackageType() );
352 OSL_ASSERT( xPackageType
.is() );
353 if (xPackageType
.is())
355 approve
= ( xPackage
->isBundle() &&
356 xPackageType
->getMediaType().match(
357 "application/vnd.sun.star.legacy-package-bundle" ));
362 else if (request
>>= depExc
)
364 std::vector
< OUString
> deps
;
365 deps
.reserve(depExc
.UnsatisfiedDependencies
.getLength());
366 for (auto const & i
: std::as_const(depExc
.UnsatisfiedDependencies
))
368 deps
.push_back( dp_misc::Dependencies::getErrorText(i
) );
371 SolarMutexGuard guard
;
373 m_pDialogHelper
->incBusy();
374 DependencyDialog
aDlg(activeDialog(), deps
);
375 short n
= aDlg
.run();
377 m_pDialogHelper
->decBusy();
378 // Distinguish between closing the dialog and programmatically
379 // canceling the dialog (headless VCL):
380 approve
= n
== RET_OK
381 || (n
== RET_CANCEL
&& !Application::IsDialogCancelEnabled());
384 else if (request
>>= licExc
)
386 SolarMutexGuard guard
;
388 weld::Window
*pTopLevel
= activeDialog();
390 m_pDialogHelper
->incBusy();
391 uno::Reference
< ui::dialogs::XExecutableDialog
> xDialog(
392 deployment::ui::LicenseDialog::create(
393 m_xContext
, pTopLevel
? pTopLevel
->GetXWindow() : nullptr,
394 licExc
.ExtensionName
, licExc
.Text
) );
395 sal_Int16 res
= xDialog
->execute();
397 m_pDialogHelper
->decBusy();
398 if ( res
== ui::dialogs::ExecutableDialogResults::CANCEL
)
400 else if ( res
== ui::dialogs::ExecutableDialogResults::OK
)
407 else if (request
>>= verExc
)
410 switch (dp_misc::compareVersions(
411 verExc
.NewVersion
, verExc
.Deployed
->getVersion() ))
414 id
= RID_STR_WARNING_VERSION_LESS
;
417 id
= RID_STR_WARNING_VERSION_EQUAL
;
419 default: // dp_misc::GREATER
420 id
= RID_STR_WARNING_VERSION_GREATER
;
423 OSL_ASSERT( verExc
.Deployed
.is() );
424 bool bEqualNames
= verExc
.NewDisplayName
==
425 verExc
.Deployed
->getDisplayName();
427 SolarMutexGuard guard
;
430 m_pDialogHelper
->incBusy();
432 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(activeDialog(),
433 VclMessageType::Warning
, VclButtonsType::OkCancel
, DpResId(id
)));
437 s
= xBox
->get_primary_text();
439 else if (id
!= RID_STR_WARNING_VERSION_EQUAL
)
441 //hypothetical: requires two instances of an extension with the same
442 //version to have different display names. Probably the developer forgot
443 //to change the version.
444 s
= DpResId(RID_STR_WARNINGBOX_VERSION_EQUAL_DIFFERENT_NAMES
);
446 else if (id
!= RID_STR_WARNING_VERSION_LESS
)
448 s
= DpResId(RID_STR_WARNINGBOX_VERSION_LESS_DIFFERENT_NAMES
);
450 else if (id
!= RID_STR_WARNING_VERSION_GREATER
)
452 s
= DpResId(RID_STR_WARNINGBOX_VERSION_GREATER_DIFFERENT_NAMES
);
454 s
= s
.replaceAll("$NAME", verExc
.NewDisplayName
);
455 s
= s
.replaceAll("$OLDNAME", verExc
.Deployed
->getDisplayName());
456 s
= s
.replaceAll("$NEW", getVersion(verExc
.NewVersion
));
457 s
= s
.replaceAll("$DEPLOYED", getVersion(verExc
.Deployed
));
458 xBox
->set_primary_text(s
);
459 approve
= xBox
->run() == RET_OK
;
461 m_pDialogHelper
->decBusy();
465 else if (request
>>= instExc
)
473 if ( m_pDialogHelper
)
475 SolarMutexGuard guard
;
477 approve
= m_pDialogHelper
->installExtensionWarn( instExc
.displayName
);
484 else if (request
>>= platExc
)
486 SolarMutexGuard guard
;
487 OUString
sMsg(DpResId(RID_STR_UNSUPPORTED_PLATFORM
));
488 sMsg
= sMsg
.replaceAll("%Name", platExc
.package
->getDisplayName());
490 m_pDialogHelper
->incBusy();
491 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(activeDialog(),
492 VclMessageType::Warning
, VclButtonsType::Ok
, sMsg
));
495 m_pDialogHelper
->decBusy();
499 if (!approve
&& !abort
)
501 // forward to UUI handler:
502 if (! m_xHandler
.is()) {
504 m_xHandler
= task::InteractionHandler::createWithParentAndContext(m_xContext
, nullptr, m_sTitle
);
506 m_xHandler
->handle( xRequest
);
511 uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> > conts(
512 xRequest
->getContinuations() );
513 uno::Reference
< task::XInteractionContinuation
> const * pConts
= conts
.getConstArray();
514 sal_Int32 len
= conts
.getLength();
515 for ( sal_Int32 pos
= 0; pos
< len
; ++pos
)
518 uno::Reference
< task::XInteractionApprove
> xInteractionApprove( pConts
[ pos
], uno::UNO_QUERY
);
519 if (xInteractionApprove
.is()) {
520 xInteractionApprove
->select();
521 // don't query again for ongoing continuations:
526 uno::Reference
< task::XInteractionAbort
> xInteractionAbort( pConts
[ pos
], uno::UNO_QUERY
);
527 if (xInteractionAbort
.is()) {
528 xInteractionAbort
->select();
529 // don't query again for ongoing continuations:
540 void ProgressCmdEnv::push( uno::Any
const & rStatus
)
546 void ProgressCmdEnv::update_( uno::Any
const & rStatus
)
549 if ( rStatus
.hasValue() && !( rStatus
>>= text
) )
551 if ( auto e
= o3tl::tryAccess
<uno::Exception
>(rStatus
) )
553 if ( text
.isEmpty() )
554 text
= ::comphelper::anyToString( rStatus
); // fallback
556 const SolarMutexGuard aGuard
;
558 m_pDialogHelper
->incBusy();
559 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(activeDialog(),
560 VclMessageType::Warning
, VclButtonsType::Ok
, text
));
563 m_pDialogHelper
->decBusy();
565 ++m_nCurrentProgress
;
570 void ProgressCmdEnv::update( uno::Any
const & rStatus
)
576 void ProgressCmdEnv::pop()
578 update_( uno::Any() ); // no message
582 ExtensionCmdQueue::Thread::Thread( DialogHelper
*pDialogHelper
,
583 TheExtensionManager
*pManager
,
584 uno::Reference
< uno::XComponentContext
> xContext
) :
585 salhelper::Thread( "dp_gui_extensioncmdqueue" ),
586 m_xContext(std::move( xContext
)),
587 m_pDialogHelper( pDialogHelper
),
588 m_pManager( pManager
),
589 m_sEnablingPackages( DpResId( RID_STR_ENABLING_PACKAGES
) ),
590 m_sDisablingPackages( DpResId( RID_STR_DISABLING_PACKAGES
) ),
591 m_sAddingPackages( DpResId( RID_STR_ADDING_PACKAGES
) ),
592 m_sRemovingPackages( DpResId( RID_STR_REMOVING_PACKAGES
) ),
593 m_sDefaultCmd( DpResId( RID_STR_ADD_PACKAGES
) ),
594 m_sAcceptLicense( DpResId( RID_STR_ACCEPT_LICENSE
) ),
599 OSL_ASSERT( pDialogHelper
);
603 void ExtensionCmdQueue::Thread::addExtension( const OUString
&rExtensionURL
,
604 const OUString
&rRepository
,
605 const bool bWarnUser
)
607 if ( !rExtensionURL
.isEmpty() )
609 TExtensionCmd pEntry
= std::make_shared
<ExtensionCmd
>( ExtensionCmd::ADD
, rExtensionURL
, rRepository
, bWarnUser
);
615 void ExtensionCmdQueue::Thread::removeExtension( const uno::Reference
< deployment::XPackage
> &rPackage
)
619 TExtensionCmd pEntry
= std::make_shared
<ExtensionCmd
>( ExtensionCmd::REMOVE
, rPackage
);
625 void ExtensionCmdQueue::Thread::acceptLicense( const uno::Reference
< deployment::XPackage
> &rPackage
)
629 TExtensionCmd pEntry
= std::make_shared
<ExtensionCmd
>( ExtensionCmd::ACCEPT_LICENSE
, rPackage
);
635 void ExtensionCmdQueue::Thread::enableExtension( const uno::Reference
< deployment::XPackage
> &rPackage
,
640 TExtensionCmd pEntry
= std::make_shared
<ExtensionCmd
>( bEnable
? ExtensionCmd::ENABLE
:
641 ExtensionCmd::DISABLE
,
648 void ExtensionCmdQueue::Thread::checkForUpdates(
649 std::vector
<uno::Reference
<deployment::XPackage
> > && vExtensionList
)
651 TExtensionCmd pEntry
= std::make_shared
<ExtensionCmd
>( ExtensionCmd::CHECK_FOR_UPDATES
, std::move(vExtensionList
) );
656 //Stopping this thread will not abort the installation of extensions.
657 void ExtensionCmdQueue::Thread::stop()
659 std::scoped_lock
aGuard( m_mutex
);
662 m_wakeup
.notify_all();
666 bool ExtensionCmdQueue::Thread::isBusy()
668 std::scoped_lock
aGuard( m_mutex
);
673 ExtensionCmdQueue::Thread::~Thread() {}
676 void ExtensionCmdQueue::Thread::execute()
679 //Needed for use of the service "com.sun.star.system.SystemShellExecute" in
680 //DialogHelper::openWebBrowser
681 int nNbCallCoInitializeExForReinit
= 0;
682 o3tl::safeCoInitializeEx(COINIT_APARTMENTTHREADED
, nNbCallCoInitializeExForReinit
);
689 std::unique_lock
aGuard( m_mutex
);
690 while (m_eInput
== NONE
) {
691 m_wakeup
.wait(aGuard
);
695 nSize
= m_queue
.size();
696 // coverity[missing_lock: FALSE] - maybe due to (by-design) unique_lock vs. scoped_lock?
700 if ( eInput
== STOP
)
703 // We only install the extension which are currently in the queue.
704 // The progressbar will be set to show the progress of the current number
705 // of extensions. If we allowed to add extensions now then the progressbar may
706 // have reached the end while we still install newly added extensions.
710 ::rtl::Reference
< ProgressCmdEnv
> currentCmdEnv( new ProgressCmdEnv( m_xContext
, m_pDialogHelper
, m_sDefaultCmd
) );
712 // Do not lock the following part with addExtension. addExtension may be called in the main thread.
713 // If the message box "Do you want to install the extension (or similar)" is shown and then
714 // addExtension is called, which then blocks the main thread, then we deadlock.
715 bool bStartProgress
= true;
717 while ( --nSize
>= 0 )
720 std::scoped_lock
aGuard( m_mutex
);
726 TExtensionCmd pEntry
;
728 std::scoped_lock
queueGuard( m_mutex
);
729 pEntry
= m_queue
.front();
733 if ( bStartProgress
&& ( pEntry
->m_eCmdType
!= ExtensionCmd::CHECK_FOR_UPDATES
) )
735 currentCmdEnv
->startProgress();
736 bStartProgress
= false;
739 switch ( pEntry
->m_eCmdType
) {
740 case ExtensionCmd::ADD
:
741 _addExtension( currentCmdEnv
, pEntry
->m_sExtensionURL
, pEntry
->m_sRepository
, pEntry
->m_bWarnUser
);
743 case ExtensionCmd::REMOVE
:
744 _removeExtension( currentCmdEnv
, pEntry
->m_xPackage
);
746 case ExtensionCmd::ENABLE
:
747 _enableExtension( currentCmdEnv
, pEntry
->m_xPackage
);
749 case ExtensionCmd::DISABLE
:
750 _disableExtension( currentCmdEnv
, pEntry
->m_xPackage
);
752 case ExtensionCmd::CHECK_FOR_UPDATES
:
753 _checkForUpdates( std::vector(pEntry
->m_vExtensionList
) );
755 case ExtensionCmd::ACCEPT_LICENSE
:
756 _acceptLicense( currentCmdEnv
, pEntry
->m_xPackage
);
760 catch ( const ucb::CommandAbortedException
& )
762 //This exception is thrown when the user clicks cancel on the progressbar.
763 //Then we cancel the installation of all extensions and remove them from
766 std::scoped_lock
queueGuard2(m_mutex
);
767 while ( --nSize
>= 0 )
772 catch ( const ucb::CommandFailedException
& )
774 //This exception is thrown when a user clicked cancel in the messagebox which was
775 //started by the interaction handler. For example the user will be asked if he/she
776 //really wants to install the extension.
777 //These interactions run for exactly one extension at a time. Therefore we continue
778 //with installing the remaining extensions.
781 catch ( const uno::Exception
& )
783 //Todo display the user an error
784 //see also DialogImpl::SyncPushButton::Click()
785 uno::Any
exc( ::cppu::getCaughtException() );
787 deployment::DeploymentException dpExc
;
790 if (auto e
= o3tl::tryAccess
<uno::Exception
>(dpExc
.Cause
))
792 // notify error cause only:
796 if (msg
.isEmpty()) // fallback for debugging purposes
797 msg
= ::comphelper::anyToString(exc
);
799 const SolarMutexGuard guard
;
801 m_pDialogHelper
->incBusy();
803 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(currentCmdEnv
->activeDialog(),
804 VclMessageType::Warning
, VclButtonsType::Ok
, msg
));
806 xBox
->set_title(m_pDialogHelper
->getFrameWeld()->get_title());
809 m_pDialogHelper
->decBusy();
810 //Continue with installation of the remaining extensions
813 std::scoped_lock
aGuard( m_mutex
);
819 // when leaving the while loop with break, we should set working to false, too
820 std::scoped_lock
aGuard( m_mutex
);
824 if ( !bStartProgress
)
825 currentCmdEnv
->stopProgress();
829 o3tl::safeCoUninitializeReinit(COINIT_MULTITHREADED
, nNbCallCoInitializeExForReinit
);
834 void ExtensionCmdQueue::Thread::_addExtension( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
835 const OUString
&rPackageURL
,
836 const OUString
&rRepository
,
837 const bool bWarnUser
)
839 //check if we have a string in anyTitle. For example "unopkg gui \" caused anyTitle to be void
840 //and anyTitle.get<OUString> throws as RuntimeException.
844 anyTitle
= ::ucbhelper::Content( rPackageURL
, rCmdEnv
, m_xContext
).getPropertyValue( "Title" );
846 catch ( const uno::Exception
& )
852 if ( ! (anyTitle
>>= sName
) )
854 OSL_FAIL("Could not get file name for extension.");
858 rCmdEnv
->setWarnUser( bWarnUser
);
859 uno::Reference
< deployment::XExtensionManager
> xExtMgr
= m_pManager
->getExtensionManager();
860 uno::Reference
< task::XAbortChannel
> xAbortChannel( xExtMgr
->createAbortChannel() );
862 m_sAddingPackages
.replaceAll("%EXTENSION_NAME", sName
));
863 rCmdEnv
->progressSection( sTitle
, xAbortChannel
);
867 xExtMgr
->addExtension(rPackageURL
, uno::Sequence
<beans::NamedValue
>(),
868 rRepository
, xAbortChannel
, rCmdEnv
);
870 catch ( const ucb::CommandFailedException
& )
872 // When the extension is already installed we'll get a dialog asking if we want to overwrite. If we then press
873 // cancel this exception is thrown.
875 catch ( const ucb::CommandAbortedException
& )
877 // User clicked the cancel button
878 // TODO: handle cancel
880 rCmdEnv
->setWarnUser( false );
884 void ExtensionCmdQueue::Thread::_removeExtension( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
885 const uno::Reference
< deployment::XPackage
> &xPackage
)
887 uno::Reference
< deployment::XExtensionManager
> xExtMgr
= m_pManager
->getExtensionManager();
888 uno::Reference
< task::XAbortChannel
> xAbortChannel( xExtMgr
->createAbortChannel() );
890 m_sRemovingPackages
.replaceAll("%EXTENSION_NAME",
891 xPackage
->getDisplayName()));
892 rCmdEnv
->progressSection( sTitle
, xAbortChannel
);
894 OUString
id( dp_misc::getIdentifier( xPackage
) );
897 xExtMgr
->removeExtension( id
, xPackage
->getName(), xPackage
->getRepositoryName(), xAbortChannel
, rCmdEnv
);
899 catch ( const deployment::DeploymentException
& )
901 catch ( const ucb::CommandFailedException
& )
903 catch ( const ucb::CommandAbortedException
& )
906 // Check, if there are still updates to be notified via menu bar icon
907 uno::Sequence
< uno::Sequence
< OUString
> > aItemList
;
908 UpdateDialog::createNotifyJob( false, aItemList
);
912 void ExtensionCmdQueue::Thread::_checkForUpdates(
913 std::vector
<uno::Reference
<deployment::XPackage
> > && vExtensionList
)
915 const SolarMutexGuard guard
;
918 m_pDialogHelper
->incBusy();
920 std::vector
< UpdateData
> vData
;
921 UpdateDialog
aUpdateDialog(m_xContext
, m_pDialogHelper
? m_pDialogHelper
->getFrameWeld() : nullptr, std::move(vExtensionList
), &vData
);
923 aUpdateDialog
.notifyMenubar( true, false ); // prepare the checking, if there updates to be notified via menu bar icon
925 bool bOk
= aUpdateDialog
.run() == RET_OK
;
927 m_pDialogHelper
->decBusy();
929 if (bOk
&& !vData
.empty())
931 // If there is at least one directly downloadable extension then we
932 // open the install dialog.
933 std::vector
< UpdateData
> dataDownload
;
935 for (auto const& data
: vData
)
937 if ( data
.sWebsiteURL
.isEmpty() )
938 dataDownload
.push_back(data
);
941 short nDialogResult
= RET_OK
;
942 if ( !dataDownload
.empty() )
945 m_pDialogHelper
->incBusy();
946 UpdateInstallDialog
aDlg(m_pDialogHelper
? m_pDialogHelper
->getFrameWeld() : nullptr, dataDownload
, m_xContext
);
947 nDialogResult
= aDlg
.run();
949 m_pDialogHelper
->decBusy();
950 aUpdateDialog
.notifyMenubar( false, true ); // Check, if there are still pending updates to be notified via menu bar icon
953 aUpdateDialog
.notifyMenubar( false, false ); // Check, if there are pending updates to be notified via menu bar icon
955 //Now start the webbrowser and navigate to the websites where we get the updates
956 if ( RET_OK
== nDialogResult
)
958 for (auto const& data
: vData
)
960 if ( m_pDialogHelper
&& ( !data
.sWebsiteURL
.isEmpty() ) )
961 m_pDialogHelper
->openWebBrowser( data
.sWebsiteURL
, m_pDialogHelper
->getFrameWeld()->get_title() );
966 aUpdateDialog
.notifyMenubar( false, false ); // check if there updates to be notified via menu bar icon
970 void ExtensionCmdQueue::Thread::_enableExtension( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
971 const uno::Reference
< deployment::XPackage
> &xPackage
)
973 if ( !xPackage
.is() )
976 uno::Reference
< deployment::XExtensionManager
> xExtMgr
= m_pManager
->getExtensionManager();
977 uno::Reference
< task::XAbortChannel
> xAbortChannel( xExtMgr
->createAbortChannel() );
979 m_sEnablingPackages
.replaceAll("%EXTENSION_NAME",
980 xPackage
->getDisplayName()));
981 rCmdEnv
->progressSection( sTitle
, xAbortChannel
);
985 xExtMgr
->enableExtension( xPackage
, xAbortChannel
, rCmdEnv
);
986 if ( m_pDialogHelper
)
987 m_pDialogHelper
->updatePackageInfo( xPackage
);
989 catch ( const ::ucb::CommandAbortedException
& )
994 void ExtensionCmdQueue::Thread::_disableExtension( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
995 const uno::Reference
< deployment::XPackage
> &xPackage
)
997 if ( !xPackage
.is() )
1000 uno::Reference
< deployment::XExtensionManager
> xExtMgr
= m_pManager
->getExtensionManager();
1001 uno::Reference
< task::XAbortChannel
> xAbortChannel( xExtMgr
->createAbortChannel() );
1003 m_sDisablingPackages
.replaceAll("%EXTENSION_NAME",
1004 xPackage
->getDisplayName()));
1005 rCmdEnv
->progressSection( sTitle
, xAbortChannel
);
1009 xExtMgr
->disableExtension( xPackage
, xAbortChannel
, rCmdEnv
);
1010 if ( m_pDialogHelper
)
1011 m_pDialogHelper
->updatePackageInfo( xPackage
);
1013 catch ( const ::ucb::CommandAbortedException
& )
1018 void ExtensionCmdQueue::Thread::_acceptLicense( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
1019 const uno::Reference
< deployment::XPackage
> &xPackage
)
1021 if ( !xPackage
.is() )
1024 uno::Reference
< deployment::XExtensionManager
> xExtMgr
= m_pManager
->getExtensionManager();
1025 uno::Reference
< task::XAbortChannel
> xAbortChannel( xExtMgr
->createAbortChannel() );
1027 m_sAcceptLicense
.replaceAll("%EXTENSION_NAME",
1028 xPackage
->getDisplayName()));
1029 rCmdEnv
->progressSection( sTitle
, xAbortChannel
);
1033 xExtMgr
->checkPrerequisitesAndEnable( xPackage
, xAbortChannel
, rCmdEnv
);
1034 if ( m_pDialogHelper
)
1035 m_pDialogHelper
->updatePackageInfo( xPackage
);
1037 catch ( const ::ucb::CommandAbortedException
& )
1041 void ExtensionCmdQueue::Thread::_insert(const TExtensionCmd
& rExtCmd
)
1043 std::scoped_lock
aGuard( m_mutex
);
1045 // If someone called stop then we do not process the command -> game over!
1049 m_queue
.push( rExtCmd
);
1051 m_wakeup
.notify_all();
1055 ExtensionCmdQueue::ExtensionCmdQueue( DialogHelper
* pDialogHelper
,
1056 TheExtensionManager
*pManager
,
1057 const uno::Reference
< uno::XComponentContext
> &rContext
)
1058 : m_thread( new Thread( pDialogHelper
, pManager
, rContext
) )
1063 ExtensionCmdQueue::~ExtensionCmdQueue() {
1068 void ExtensionCmdQueue::addExtension( const OUString
& extensionURL
,
1069 const OUString
& repository
,
1070 const bool bWarnUser
)
1072 m_thread
->addExtension( extensionURL
, repository
, bWarnUser
);
1075 void ExtensionCmdQueue::removeExtension( const uno::Reference
< deployment::XPackage
> &rPackage
)
1077 m_thread
->removeExtension( rPackage
);
1080 void ExtensionCmdQueue::enableExtension( const uno::Reference
< deployment::XPackage
> &rPackage
,
1081 const bool bEnable
)
1083 m_thread
->enableExtension( rPackage
, bEnable
);
1086 void ExtensionCmdQueue::checkForUpdates( std::vector
<uno::Reference
<deployment::XPackage
> > && vExtensionList
)
1088 m_thread
->checkForUpdates( std::move(vExtensionList
) );
1091 void ExtensionCmdQueue::acceptLicense( const uno::Reference
< deployment::XPackage
> &rPackage
)
1093 m_thread
->acceptLicense( rPackage
);
1096 void ExtensionCmdQueue::syncRepositories( const uno::Reference
< uno::XComponentContext
> &xContext
)
1098 dp_misc::syncRepositories( false, new ProgressCmdEnv( xContext
, nullptr, "Extension Manager" ) );
1101 bool ExtensionCmdQueue::isBusy()
1103 return m_thread
->isBusy();
1106 void handleInteractionRequest( const uno::Reference
< uno::XComponentContext
> & xContext
,
1107 const uno::Reference
< task::XInteractionRequest
> & xRequest
)
1109 ::rtl::Reference
< ProgressCmdEnv
> xCmdEnv( new ProgressCmdEnv( xContext
, nullptr, "Extension Manager" ) );
1110 xCmdEnv
->handle( xRequest
);
1113 } //namespace dp_gui
1115 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */