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() ) ? u
"0"_ustr
: 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
: 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
);
510 assert(approve
!= abort
);
512 for (auto& cont
: xRequest
->getContinuations())
515 uno::Reference
<task::XInteractionApprove
> xInteractionApprove(cont
, uno::UNO_QUERY
);
516 if (xInteractionApprove
.is()) {
517 xInteractionApprove
->select();
518 // don't query again for ongoing continuations:
522 else /*if (abort)*/ {
523 uno::Reference
<task::XInteractionAbort
> xInteractionAbort(cont
, uno::UNO_QUERY
);
524 if (xInteractionAbort
.is()) {
525 xInteractionAbort
->select();
526 // don't query again for ongoing continuations:
537 void ProgressCmdEnv::push( uno::Any
const & rStatus
)
543 void ProgressCmdEnv::update_( uno::Any
const & rStatus
)
546 if ( rStatus
.hasValue() && !( rStatus
>>= text
) )
548 if ( auto e
= o3tl::tryAccess
<uno::Exception
>(rStatus
) )
550 if ( text
.isEmpty() )
551 text
= ::comphelper::anyToString( rStatus
); // fallback
553 const SolarMutexGuard aGuard
;
555 m_pDialogHelper
->incBusy();
556 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(activeDialog(),
557 VclMessageType::Warning
, VclButtonsType::Ok
, text
));
560 m_pDialogHelper
->decBusy();
562 ++m_nCurrentProgress
;
567 void ProgressCmdEnv::update( uno::Any
const & rStatus
)
573 void ProgressCmdEnv::pop()
575 update_( uno::Any() ); // no message
579 ExtensionCmdQueue::Thread::Thread( DialogHelper
*pDialogHelper
,
580 TheExtensionManager
*pManager
,
581 uno::Reference
< uno::XComponentContext
> xContext
) :
582 salhelper::Thread( "dp_gui_extensioncmdqueue" ),
583 m_xContext(std::move( xContext
)),
584 m_pDialogHelper( pDialogHelper
),
585 m_pManager( pManager
),
586 m_sEnablingPackages( DpResId( RID_STR_ENABLING_PACKAGES
) ),
587 m_sDisablingPackages( DpResId( RID_STR_DISABLING_PACKAGES
) ),
588 m_sAddingPackages( DpResId( RID_STR_ADDING_PACKAGES
) ),
589 m_sRemovingPackages( DpResId( RID_STR_REMOVING_PACKAGES
) ),
590 m_sDefaultCmd( DpResId( RID_STR_ADD_PACKAGES
) ),
591 m_sAcceptLicense( DpResId( RID_STR_ACCEPT_LICENSE
) ),
596 OSL_ASSERT( pDialogHelper
);
600 void ExtensionCmdQueue::Thread::addExtension( const OUString
&rExtensionURL
,
601 const OUString
&rRepository
,
602 const bool bWarnUser
)
604 if ( !rExtensionURL
.isEmpty() )
606 TExtensionCmd pEntry
= std::make_shared
<ExtensionCmd
>( ExtensionCmd::ADD
, rExtensionURL
, rRepository
, bWarnUser
);
612 void ExtensionCmdQueue::Thread::removeExtension( const uno::Reference
< deployment::XPackage
> &rPackage
)
616 TExtensionCmd pEntry
= std::make_shared
<ExtensionCmd
>( ExtensionCmd::REMOVE
, rPackage
);
622 void ExtensionCmdQueue::Thread::acceptLicense( const uno::Reference
< deployment::XPackage
> &rPackage
)
626 TExtensionCmd pEntry
= std::make_shared
<ExtensionCmd
>( ExtensionCmd::ACCEPT_LICENSE
, rPackage
);
632 void ExtensionCmdQueue::Thread::enableExtension( const uno::Reference
< deployment::XPackage
> &rPackage
,
637 TExtensionCmd pEntry
= std::make_shared
<ExtensionCmd
>( bEnable
? ExtensionCmd::ENABLE
:
638 ExtensionCmd::DISABLE
,
645 void ExtensionCmdQueue::Thread::checkForUpdates(
646 std::vector
<uno::Reference
<deployment::XPackage
> > && vExtensionList
)
648 TExtensionCmd pEntry
= std::make_shared
<ExtensionCmd
>( ExtensionCmd::CHECK_FOR_UPDATES
, std::move(vExtensionList
) );
653 //Stopping this thread will not abort the installation of extensions.
654 void ExtensionCmdQueue::Thread::stop()
656 std::scoped_lock
aGuard( m_mutex
);
659 m_wakeup
.notify_all();
663 bool ExtensionCmdQueue::Thread::isBusy()
665 std::scoped_lock
aGuard( m_mutex
);
670 ExtensionCmdQueue::Thread::~Thread() {}
673 void ExtensionCmdQueue::Thread::execute()
676 //Needed for use of the service "com.sun.star.system.SystemShellExecute" in
677 //DialogHelper::openWebBrowser
678 int nNbCallCoInitializeExForReinit
= 0;
679 o3tl::safeCoInitializeEx(COINIT_APARTMENTTHREADED
, nNbCallCoInitializeExForReinit
);
686 std::unique_lock
aGuard( m_mutex
);
687 while (m_eInput
== NONE
) {
688 m_wakeup
.wait(aGuard
);
692 nSize
= m_queue
.size();
693 // coverity[missing_lock: FALSE] - maybe due to (by-design) unique_lock vs. scoped_lock?
697 if ( eInput
== STOP
)
700 // We only install the extension which are currently in the queue.
701 // The progressbar will be set to show the progress of the current number
702 // of extensions. If we allowed to add extensions now then the progressbar may
703 // have reached the end while we still install newly added extensions.
707 ::rtl::Reference
< ProgressCmdEnv
> currentCmdEnv( new ProgressCmdEnv( m_xContext
, m_pDialogHelper
, m_sDefaultCmd
) );
709 // Do not lock the following part with addExtension. addExtension may be called in the main thread.
710 // If the message box "Do you want to install the extension (or similar)" is shown and then
711 // addExtension is called, which then blocks the main thread, then we deadlock.
712 bool bStartProgress
= true;
714 while ( --nSize
>= 0 )
717 std::scoped_lock
aGuard( m_mutex
);
723 TExtensionCmd pEntry
;
725 std::scoped_lock
queueGuard( m_mutex
);
726 pEntry
= m_queue
.front();
730 if ( bStartProgress
&& ( pEntry
->m_eCmdType
!= ExtensionCmd::CHECK_FOR_UPDATES
) )
732 currentCmdEnv
->startProgress();
733 bStartProgress
= false;
736 switch ( pEntry
->m_eCmdType
) {
737 case ExtensionCmd::ADD
:
738 _addExtension( currentCmdEnv
, pEntry
->m_sExtensionURL
, pEntry
->m_sRepository
, pEntry
->m_bWarnUser
);
740 case ExtensionCmd::REMOVE
:
741 _removeExtension( currentCmdEnv
, pEntry
->m_xPackage
);
743 case ExtensionCmd::ENABLE
:
744 _enableExtension( currentCmdEnv
, pEntry
->m_xPackage
);
746 case ExtensionCmd::DISABLE
:
747 _disableExtension( currentCmdEnv
, pEntry
->m_xPackage
);
749 case ExtensionCmd::CHECK_FOR_UPDATES
:
750 _checkForUpdates( std::vector(pEntry
->m_vExtensionList
) );
752 case ExtensionCmd::ACCEPT_LICENSE
:
753 _acceptLicense( currentCmdEnv
, pEntry
->m_xPackage
);
757 catch ( const ucb::CommandAbortedException
& )
759 //This exception is thrown when the user clicks cancel on the progressbar.
760 //Then we cancel the installation of all extensions and remove them from
763 std::scoped_lock
queueGuard2(m_mutex
);
764 while ( --nSize
>= 0 )
769 catch ( const ucb::CommandFailedException
& )
771 //This exception is thrown when a user clicked cancel in the messagebox which was
772 //started by the interaction handler. For example the user will be asked if he/she
773 //really wants to install the extension.
774 //These interactions run for exactly one extension at a time. Therefore we continue
775 //with installing the remaining extensions.
778 catch ( const uno::Exception
& )
780 //Todo display the user an error
781 //see also DialogImpl::SyncPushButton::Click()
782 uno::Any
exc( ::cppu::getCaughtException() );
784 deployment::DeploymentException dpExc
;
787 if (auto e
= o3tl::tryAccess
<uno::Exception
>(dpExc
.Cause
))
789 // notify error cause only:
793 if (msg
.isEmpty()) // fallback for debugging purposes
794 msg
= ::comphelper::anyToString(exc
);
796 const SolarMutexGuard guard
;
798 m_pDialogHelper
->incBusy();
800 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(currentCmdEnv
->activeDialog(),
801 VclMessageType::Warning
, VclButtonsType::Ok
, msg
));
803 xBox
->set_title(m_pDialogHelper
->getFrameWeld()->get_title());
806 m_pDialogHelper
->decBusy();
807 //Continue with installation of the remaining extensions
810 std::scoped_lock
aGuard( m_mutex
);
816 // when leaving the while loop with break, we should set working to false, too
817 std::scoped_lock
aGuard( m_mutex
);
821 if ( !bStartProgress
)
822 currentCmdEnv
->stopProgress();
826 o3tl::safeCoUninitializeReinit(COINIT_MULTITHREADED
, nNbCallCoInitializeExForReinit
);
831 void ExtensionCmdQueue::Thread::_addExtension( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
832 const OUString
&rPackageURL
,
833 const OUString
&rRepository
,
834 const bool bWarnUser
)
836 //check if we have a string in anyTitle. For example "unopkg gui \" caused anyTitle to be void
837 //and anyTitle.get<OUString> throws as RuntimeException.
841 anyTitle
= ::ucbhelper::Content( rPackageURL
, rCmdEnv
, m_xContext
).getPropertyValue( u
"Title"_ustr
);
843 catch ( const uno::Exception
& )
849 if ( ! (anyTitle
>>= sName
) )
851 OSL_FAIL("Could not get file name for extension.");
855 rCmdEnv
->setWarnUser( bWarnUser
);
856 uno::Reference
< deployment::XExtensionManager
> xExtMgr
= m_pManager
->getExtensionManager();
857 uno::Reference
< task::XAbortChannel
> xAbortChannel( xExtMgr
->createAbortChannel() );
859 m_sAddingPackages
.replaceAll("%EXTENSION_NAME", sName
));
860 rCmdEnv
->progressSection( sTitle
, xAbortChannel
);
864 xExtMgr
->addExtension(rPackageURL
, uno::Sequence
<beans::NamedValue
>(),
865 rRepository
, xAbortChannel
, rCmdEnv
);
867 catch ( const ucb::CommandFailedException
& )
869 // When the extension is already installed we'll get a dialog asking if we want to overwrite. If we then press
870 // cancel this exception is thrown.
872 catch ( const ucb::CommandAbortedException
& )
874 // User clicked the cancel button
875 // TODO: handle cancel
877 rCmdEnv
->setWarnUser( false );
881 void ExtensionCmdQueue::Thread::_removeExtension( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
882 const uno::Reference
< deployment::XPackage
> &xPackage
)
884 uno::Reference
< deployment::XExtensionManager
> xExtMgr
= m_pManager
->getExtensionManager();
885 uno::Reference
< task::XAbortChannel
> xAbortChannel( xExtMgr
->createAbortChannel() );
887 m_sRemovingPackages
.replaceAll("%EXTENSION_NAME",
888 xPackage
->getDisplayName()));
889 rCmdEnv
->progressSection( sTitle
, xAbortChannel
);
891 OUString
id( dp_misc::getIdentifier( xPackage
) );
894 xExtMgr
->removeExtension( id
, xPackage
->getName(), xPackage
->getRepositoryName(), xAbortChannel
, rCmdEnv
);
896 catch ( const deployment::DeploymentException
& )
898 catch ( const ucb::CommandFailedException
& )
900 catch ( const ucb::CommandAbortedException
& )
903 // Check, if there are still updates to be notified via menu bar icon
904 uno::Sequence
< uno::Sequence
< OUString
> > aItemList
;
905 UpdateDialog::createNotifyJob( false, aItemList
);
909 void ExtensionCmdQueue::Thread::_checkForUpdates(
910 std::vector
<uno::Reference
<deployment::XPackage
> > && vExtensionList
)
912 const SolarMutexGuard guard
;
915 m_pDialogHelper
->incBusy();
917 std::vector
< UpdateData
> vData
;
918 UpdateDialog
aUpdateDialog(m_xContext
, m_pDialogHelper
? m_pDialogHelper
->getFrameWeld() : nullptr, std::move(vExtensionList
), &vData
);
920 aUpdateDialog
.notifyMenubar( true, false ); // prepare the checking, if there updates to be notified via menu bar icon
922 bool bOk
= aUpdateDialog
.run() == RET_OK
;
924 m_pDialogHelper
->decBusy();
926 if (bOk
&& !vData
.empty())
928 // If there is at least one directly downloadable extension then we
929 // open the install dialog.
930 std::vector
< UpdateData
> dataDownload
;
932 for (auto const& data
: vData
)
934 if ( data
.sWebsiteURL
.isEmpty() )
935 dataDownload
.push_back(data
);
938 short nDialogResult
= RET_OK
;
939 if ( !dataDownload
.empty() )
942 m_pDialogHelper
->incBusy();
943 UpdateInstallDialog
aDlg(m_pDialogHelper
? m_pDialogHelper
->getFrameWeld() : nullptr, dataDownload
, m_xContext
);
944 nDialogResult
= aDlg
.run();
946 m_pDialogHelper
->decBusy();
947 aUpdateDialog
.notifyMenubar( false, true ); // Check, if there are still pending updates to be notified via menu bar icon
950 aUpdateDialog
.notifyMenubar( false, false ); // Check, if there are pending updates to be notified via menu bar icon
952 //Now start the webbrowser and navigate to the websites where we get the updates
953 if ( RET_OK
== nDialogResult
)
955 for (auto const& data
: vData
)
957 if ( m_pDialogHelper
&& ( !data
.sWebsiteURL
.isEmpty() ) )
958 m_pDialogHelper
->openWebBrowser( data
.sWebsiteURL
, m_pDialogHelper
->getFrameWeld()->get_title() );
963 aUpdateDialog
.notifyMenubar( false, false ); // check if there updates to be notified via menu bar icon
967 void ExtensionCmdQueue::Thread::_enableExtension( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
968 const uno::Reference
< deployment::XPackage
> &xPackage
)
970 if ( !xPackage
.is() )
973 uno::Reference
< deployment::XExtensionManager
> xExtMgr
= m_pManager
->getExtensionManager();
974 uno::Reference
< task::XAbortChannel
> xAbortChannel( xExtMgr
->createAbortChannel() );
976 m_sEnablingPackages
.replaceAll("%EXTENSION_NAME",
977 xPackage
->getDisplayName()));
978 rCmdEnv
->progressSection( sTitle
, xAbortChannel
);
982 xExtMgr
->enableExtension( xPackage
, xAbortChannel
, rCmdEnv
);
983 if ( m_pDialogHelper
)
984 m_pDialogHelper
->updatePackageInfo( xPackage
);
986 catch ( const ::ucb::CommandAbortedException
& )
991 void ExtensionCmdQueue::Thread::_disableExtension( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
992 const uno::Reference
< deployment::XPackage
> &xPackage
)
994 if ( !xPackage
.is() )
997 uno::Reference
< deployment::XExtensionManager
> xExtMgr
= m_pManager
->getExtensionManager();
998 uno::Reference
< task::XAbortChannel
> xAbortChannel( xExtMgr
->createAbortChannel() );
1000 m_sDisablingPackages
.replaceAll("%EXTENSION_NAME",
1001 xPackage
->getDisplayName()));
1002 rCmdEnv
->progressSection( sTitle
, xAbortChannel
);
1006 xExtMgr
->disableExtension( xPackage
, xAbortChannel
, rCmdEnv
);
1007 if ( m_pDialogHelper
)
1008 m_pDialogHelper
->updatePackageInfo( xPackage
);
1010 catch ( const ::ucb::CommandAbortedException
& )
1015 void ExtensionCmdQueue::Thread::_acceptLicense( ::rtl::Reference
< ProgressCmdEnv
> const &rCmdEnv
,
1016 const uno::Reference
< deployment::XPackage
> &xPackage
)
1018 if ( !xPackage
.is() )
1021 uno::Reference
< deployment::XExtensionManager
> xExtMgr
= m_pManager
->getExtensionManager();
1022 uno::Reference
< task::XAbortChannel
> xAbortChannel( xExtMgr
->createAbortChannel() );
1024 m_sAcceptLicense
.replaceAll("%EXTENSION_NAME",
1025 xPackage
->getDisplayName()));
1026 rCmdEnv
->progressSection( sTitle
, xAbortChannel
);
1030 xExtMgr
->checkPrerequisitesAndEnable( xPackage
, xAbortChannel
, rCmdEnv
);
1031 if ( m_pDialogHelper
)
1032 m_pDialogHelper
->updatePackageInfo( xPackage
);
1034 catch ( const ::ucb::CommandAbortedException
& )
1038 void ExtensionCmdQueue::Thread::_insert(const TExtensionCmd
& rExtCmd
)
1040 std::scoped_lock
aGuard( m_mutex
);
1042 // If someone called stop then we do not process the command -> game over!
1046 m_queue
.push( rExtCmd
);
1048 m_wakeup
.notify_all();
1052 ExtensionCmdQueue::ExtensionCmdQueue( DialogHelper
* pDialogHelper
,
1053 TheExtensionManager
*pManager
,
1054 const uno::Reference
< uno::XComponentContext
> &rContext
)
1055 : m_thread( new Thread( pDialogHelper
, pManager
, rContext
) )
1060 ExtensionCmdQueue::~ExtensionCmdQueue() {
1065 void ExtensionCmdQueue::addExtension( const OUString
& extensionURL
,
1066 const OUString
& repository
,
1067 const bool bWarnUser
)
1069 m_thread
->addExtension( extensionURL
, repository
, bWarnUser
);
1072 void ExtensionCmdQueue::removeExtension( const uno::Reference
< deployment::XPackage
> &rPackage
)
1074 m_thread
->removeExtension( rPackage
);
1077 void ExtensionCmdQueue::enableExtension( const uno::Reference
< deployment::XPackage
> &rPackage
,
1078 const bool bEnable
)
1080 m_thread
->enableExtension( rPackage
, bEnable
);
1083 void ExtensionCmdQueue::checkForUpdates( std::vector
<uno::Reference
<deployment::XPackage
> > && vExtensionList
)
1085 m_thread
->checkForUpdates( std::move(vExtensionList
) );
1088 void ExtensionCmdQueue::acceptLicense( const uno::Reference
< deployment::XPackage
> &rPackage
)
1090 m_thread
->acceptLicense( rPackage
);
1093 void ExtensionCmdQueue::syncRepositories( const uno::Reference
< uno::XComponentContext
> &xContext
)
1095 dp_misc::syncRepositories( false, new ProgressCmdEnv( xContext
, nullptr, u
"Extension Manager"_ustr
) );
1098 bool ExtensionCmdQueue::isBusy()
1100 return m_thread
->isBusy();
1103 void handleInteractionRequest( const uno::Reference
< uno::XComponentContext
> & xContext
,
1104 const uno::Reference
< task::XInteractionRequest
> & xRequest
)
1106 ::rtl::Reference
< ProgressCmdEnv
> xCmdEnv( new ProgressCmdEnv( xContext
, nullptr, u
"Extension Manager"_ustr
) );
1107 xCmdEnv
->handle( xRequest
);
1110 } //namespace dp_gui
1112 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */