LibreOffice Module desktop (master) 1
dp_gui_extensioncmdqueue.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 <sal/config.h>
21
22#include <com/sun/star/beans/NamedValue.hpp>
23
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>
29
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>
33
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>
38
39#include <com/sun/star/ucb/CommandAbortedException.hpp>
40#include <com/sun/star/ucb/CommandFailedException.hpp>
41#include <com/sun/star/ucb/XCommandEnvironment.hpp>
42
43#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
44
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>
58#include <utility>
59#include <vcl/svapp.hxx>
60#include <vcl/weld.hxx>
61
64#include "dp_gui_dialog2.hxx"
65#include <dp_shared.hxx>
66#include <strings.hrc>
67#include "dp_gui_theextmgr.hxx"
70#include <dp_dependencies.hxx>
71#include <dp_misc.h>
72#include <dp_identifier.hxx>
73#include <dp_version.hxx>
74
75#include <condition_variable>
76#include <queue>
77#include <memory>
78#include <mutex>
79
80#ifdef _WIN32
82#endif
83
84
85using namespace ::com::sun::star;
86
87namespace {
88
89OUString getVersion( OUString const & sVersion )
90{
91 return ( sVersion.isEmpty() ) ? OUString( "0" ) : sVersion;
92}
93
94OUString getVersion( const uno::Reference< deployment::XPackage > &rPackage )
95{
96 return getVersion( rPackage->getVersion());
97}
98}
99
100
101namespace dp_gui {
102
103namespace {
104
105class ProgressCmdEnv
106 : public ::cppu::WeakImplHelper< ucb::XCommandEnvironment,
107 task::XInteractionHandler,
108 ucb::XProgressHandler >
109{
112
113 DialogHelper* m_pDialogHelper;
114 OUString m_sTitle;
117
118 void updateProgress();
119
121 void update_( uno::Any const & Status );
122
123public:
132 DialogHelper* pDialogHelper,
133 OUString aTitle )
134 : m_xContext(std::move( xContext ))
135 , m_pDialogHelper( pDialogHelper )
136 , m_sTitle(std::move( aTitle ))
137 , m_bWarnUser( false )
139 {}
140
141 weld::Window* activeDialog() { return m_pDialogHelper ? m_pDialogHelper->getFrameWeld() : nullptr; }
142
143 void startProgress();
144 void stopProgress();
145 void progressSection( const OUString &rText,
146 const uno::Reference< task::XAbortChannel > &xAbortChannel );
147 void setWarnUser( bool bNewVal ) { m_bWarnUser = bNewVal; }
148
149 // XCommandEnvironment
150 virtual uno::Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler() override;
151 virtual uno::Reference< ucb::XProgressHandler > SAL_CALL getProgressHandler() override;
152
153 // XInteractionHandler
154 virtual void SAL_CALL handle( uno::Reference< task::XInteractionRequest > const & xRequest ) override;
155
156 // XProgressHandler
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;
160};
161
162
163struct ExtensionCmd
164{
165 enum E_CMD_TYPE { ADD, ENABLE, DISABLE, REMOVE, CHECK_FOR_UPDATES, ACCEPT_LICENSE };
166
167 E_CMD_TYPE m_eCmdType;
168 bool m_bWarnUser;
172 std::vector< uno::Reference< deployment::XPackage > > m_vExtensionList;
173
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,
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) ) {};
192};
193
194}
195
196typedef std::shared_ptr< ExtensionCmd > TExtensionCmd;
197
198
200{
201public:
202 Thread( DialogHelper *pDialogHelper,
203 TheExtensionManager *pManager,
205
206 void addExtension( const OUString &rExtensionURL,
207 const OUString &rRepository,
208 const bool bWarnUser );
211 const bool bEnable );
212 void checkForUpdates( std::vector<uno::Reference<deployment::XPackage > > && vExtensionList );
214 void stop();
215 bool isBusy();
216
217private:
218 virtual ~Thread() override;
219
220 virtual void execute() override;
221
222 void _insert(const TExtensionCmd& rExtCmd);
223
225 const OUString &rPackageURL,
226 const OUString &rRepository,
227 const bool bWarnUser );
234 void _checkForUpdates( std::vector<uno::Reference<deployment::XPackage > > &&vExtensionList );
237
238 enum Input { NONE, START, STOP };
239
241 std::queue< TExtensionCmd > m_queue;
242
245
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;
253 std::mutex m_mutex;
257};
258
259
260void ProgressCmdEnv::startProgress()
261{
263
264 if ( m_pDialogHelper )
266}
267
268
269void ProgressCmdEnv::stopProgress()
270{
271 if ( m_pDialogHelper )
273}
274
275
276void ProgressCmdEnv::progressSection( const OUString &rText,
277 const uno::Reference< task::XAbortChannel > &xAbortChannel )
278{
280 if ( m_pDialogHelper )
281 {
282 m_pDialogHelper->updateProgress( rText, xAbortChannel );
284 }
285}
286
287
288void ProgressCmdEnv::updateProgress()
289{
290 tools::Long nProgress = ((m_nCurrentProgress*5) % 100) + 5;
291 if ( m_pDialogHelper )
292 m_pDialogHelper->updateProgress( nProgress );
293}
294
295// XCommandEnvironment
296
297uno::Reference< task::XInteractionHandler > ProgressCmdEnv::getInteractionHandler()
298{
299 return this;
300}
301
302
303uno::Reference< ucb::XProgressHandler > ProgressCmdEnv::getProgressHandler()
304{
305 return this;
306}
307
308
309// XInteractionHandler
310
311void ProgressCmdEnv::handle( uno::Reference< task::XInteractionRequest > const & xRequest )
312{
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");
317
318 lang::WrappedTargetException wtExc;
319 deployment::DependencyException depExc;
320 deployment::LicenseException licExc;
321 deployment::VersionException verExc;
322 deployment::InstallException instExc;
323 deployment::PlatformException platExc;
324
325 // selections:
326 bool approve = false;
327 bool abort = false;
328
329 if (request >>= wtExc) {
330 // handable deployment error signalled, e.g.
331 // bundle item registration failed, notify cause only:
332 uno::Any cause;
333 deployment::DeploymentException dpExc;
334 if (wtExc.TargetException >>= dpExc)
335 cause = dpExc.Cause;
336 else {
337 ucb::CommandFailedException cfExc;
338 if (wtExc.TargetException >>= cfExc)
339 cause = cfExc.Reason;
340 else
341 cause = wtExc.TargetException;
342 }
343 update_( cause );
344
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() );
349 if ( xPackage.is() )
350 {
351 const uno::Reference< deployment::XPackageTypeInfo > xPackageType( xPackage->getPackageType() );
352 OSL_ASSERT( xPackageType.is() );
353 if (xPackageType.is())
354 {
355 approve = ( xPackage->isBundle() &&
356 xPackageType->getMediaType().match(
357 "application/vnd.sun.star.legacy-package-bundle" ));
358 }
359 }
360 abort = !approve;
361 }
362 else if (request >>= depExc)
363 {
364 std::vector< OUString > deps;
365 deps.reserve(depExc.UnsatisfiedDependencies.getLength());
366 for (auto const & i : std::as_const(depExc.UnsatisfiedDependencies))
367 {
368 deps.push_back( dp_misc::Dependencies::getErrorText(i) );
369 }
370 {
371 SolarMutexGuard guard;
372 if (m_pDialogHelper)
374 DependencyDialog aDlg(activeDialog(), deps);
375 short n = aDlg.run();
376 if (m_pDialogHelper)
378 // Distinguish between closing the dialog and programmatically
379 // canceling the dialog (headless VCL):
380 approve = n == RET_OK
382 }
383 }
384 else if (request >>= licExc)
385 {
386 SolarMutexGuard guard;
387
388 weld::Window *pTopLevel = activeDialog();
389 if (m_pDialogHelper)
393 m_xContext, pTopLevel ? pTopLevel->GetXWindow() : nullptr,
394 licExc.ExtensionName, licExc.Text ) );
395 sal_Int16 res = xDialog->execute();
396 if (m_pDialogHelper)
398 if ( res == ui::dialogs::ExecutableDialogResults::CANCEL )
399 abort = true;
400 else if ( res == ui::dialogs::ExecutableDialogResults::OK )
401 approve = true;
402 else
403 {
404 OSL_ASSERT(false);
405 }
406 }
407 else if (request >>= verExc)
408 {
409 TranslateId id;
411 verExc.NewVersion, verExc.Deployed->getVersion() ))
412 {
413 case dp_misc::LESS:
414 id = RID_STR_WARNING_VERSION_LESS;
415 break;
416 case dp_misc::EQUAL:
417 id = RID_STR_WARNING_VERSION_EQUAL;
418 break;
419 default: // dp_misc::GREATER
420 id = RID_STR_WARNING_VERSION_GREATER;
421 break;
422 }
423 OSL_ASSERT( verExc.Deployed.is() );
424 bool bEqualNames = verExc.NewDisplayName ==
425 verExc.Deployed->getDisplayName();
426 {
427 SolarMutexGuard guard;
428
429 if (m_pDialogHelper)
431
432 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(activeDialog(),
433 VclMessageType::Warning, VclButtonsType::OkCancel, DpResId(id)));
434 OUString s;
435 if (bEqualNames)
436 {
437 s = xBox->get_primary_text();
438 }
439 else if (id != RID_STR_WARNING_VERSION_EQUAL)
440 {
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);
445 }
446 else if (id != RID_STR_WARNING_VERSION_LESS)
447 {
448 s = DpResId(RID_STR_WARNINGBOX_VERSION_LESS_DIFFERENT_NAMES);
449 }
450 else if (id != RID_STR_WARNING_VERSION_GREATER)
451 {
452 s = DpResId(RID_STR_WARNINGBOX_VERSION_GREATER_DIFFERENT_NAMES);
453 }
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;
460 if (m_pDialogHelper)
462 abort = !approve;
463 }
464 }
465 else if (request >>= instExc)
466 {
467 if ( ! m_bWarnUser )
468 {
469 approve = true;
470 }
471 else
472 {
473 if ( m_pDialogHelper )
474 {
475 SolarMutexGuard guard;
476
477 approve = m_pDialogHelper->installExtensionWarn( instExc.displayName );
478 }
479 else
480 approve = false;
481 abort = !approve;
482 }
483 }
484 else if (request >>= platExc)
485 {
486 SolarMutexGuard guard;
487 OUString sMsg(DpResId(RID_STR_UNSUPPORTED_PLATFORM));
488 sMsg = sMsg.replaceAll("%Name", platExc.package->getDisplayName());
489 if (m_pDialogHelper)
491 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(activeDialog(),
492 VclMessageType::Warning, VclButtonsType::Ok, sMsg));
493 xBox->run();
494 if (m_pDialogHelper)
496 approve = true;
497 }
498
499 if (!approve && !abort)
500 {
501 // forward to UUI handler:
502 if (! m_xHandler.is()) {
503 // late init:
504 m_xHandler = task::InteractionHandler::createWithParentAndContext(m_xContext, nullptr, m_sTitle);
505 }
506 m_xHandler->handle( xRequest );
507 }
508 else
509 {
510 // select:
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 )
516 {
517 if (approve) {
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:
522 approve = false;
523 }
524 }
525 else if (abort) {
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:
530 abort = false;
531 }
532 }
533 }
534 }
535}
536
537
538// XProgressHandler
539
540void ProgressCmdEnv::push( uno::Any const & rStatus )
541{
542 update_( rStatus );
543}
544
545
546void ProgressCmdEnv::update_( uno::Any const & rStatus )
547{
548 OUString text;
549 if ( rStatus.hasValue() && !( rStatus >>= text) )
550 {
551 if ( auto e = o3tl::tryAccess<uno::Exception>(rStatus) )
552 text = e->Message;
553 if ( text.isEmpty() )
554 text = ::comphelper::anyToString( rStatus ); // fallback
555
556 const SolarMutexGuard aGuard;
557 if (m_pDialogHelper)
559 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(activeDialog(),
560 VclMessageType::Warning, VclButtonsType::Ok, text));
561 xBox->run();
562 if (m_pDialogHelper)
564 }
566 updateProgress();
567}
568
569
570void ProgressCmdEnv::update( uno::Any const & rStatus )
571{
572 update_( rStatus );
573}
574
575
576void ProgressCmdEnv::pop()
577{
578 update_( uno::Any() ); // no message
579}
580
581
583 TheExtensionManager *pManager,
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 ) ),
595 m_eInput( NONE ),
596 m_bStopped( false ),
597 m_bWorking( false )
598{
599 OSL_ASSERT( pDialogHelper );
600}
601
602
603void ExtensionCmdQueue::Thread::addExtension( const OUString &rExtensionURL,
604 const OUString &rRepository,
605 const bool bWarnUser )
606{
607 if ( !rExtensionURL.isEmpty() )
608 {
609 TExtensionCmd pEntry = std::make_shared<ExtensionCmd>( ExtensionCmd::ADD, rExtensionURL, rRepository, bWarnUser );
610 _insert( pEntry );
611 }
612}
613
614
616{
617 if ( rPackage.is() )
618 {
619 TExtensionCmd pEntry = std::make_shared<ExtensionCmd>( ExtensionCmd::REMOVE, rPackage );
620 _insert( pEntry );
621 }
622}
623
624
626{
627 if ( rPackage.is() )
628 {
629 TExtensionCmd pEntry = std::make_shared<ExtensionCmd>( ExtensionCmd::ACCEPT_LICENSE, rPackage );
630 _insert( pEntry );
631 }
632}
633
634
636 const bool bEnable )
637{
638 if ( rPackage.is() )
639 {
640 TExtensionCmd pEntry = std::make_shared<ExtensionCmd>( bEnable ? ExtensionCmd::ENABLE :
641 ExtensionCmd::DISABLE,
642 rPackage );
643 _insert( pEntry );
644 }
645}
646
647
649 std::vector<uno::Reference<deployment::XPackage > > && vExtensionList )
650{
651 TExtensionCmd pEntry = std::make_shared<ExtensionCmd>( ExtensionCmd::CHECK_FOR_UPDATES, std::move(vExtensionList) );
652 _insert( pEntry );
653}
654
655
656//Stopping this thread will not abort the installation of extensions.
658{
659 std::scoped_lock aGuard( m_mutex );
660 m_bStopped = true;
661 m_eInput = STOP;
662 m_wakeup.notify_all();
663}
664
665
667{
668 std::scoped_lock aGuard( m_mutex );
669 return m_bWorking;
670}
671
672
674
675
677{
678#ifdef _WIN32
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);
683#endif
684 for (;;)
685 {
686 int nSize;
687 Input eInput;
688 {
689 std::unique_lock aGuard( m_mutex );
690 while (m_eInput == NONE) {
691 m_wakeup.wait(aGuard);
692 }
693 eInput = m_eInput;
694 m_eInput = NONE;
695 nSize = m_queue.size();
696 // coverity[missing_lock: FALSE] - maybe due to (by-design) unique_lock vs. scoped_lock?
697 m_bWorking = false;
698 }
699
700 if ( eInput == STOP )
701 break;
702
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.
707 if ( nSize == 0 )
708 continue;
709
710 ::rtl::Reference< ProgressCmdEnv > currentCmdEnv( new ProgressCmdEnv( m_xContext, m_pDialogHelper, m_sDefaultCmd ) );
711
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;
716
717 while ( --nSize >= 0 )
718 {
719 {
720 std::scoped_lock aGuard( m_mutex );
721 m_bWorking = true;
722 }
723
724 try
725 {
726 TExtensionCmd pEntry;
727 {
728 std::scoped_lock queueGuard( m_mutex );
729 pEntry = m_queue.front();
730 m_queue.pop();
731 }
732
733 if ( bStartProgress && ( pEntry->m_eCmdType != ExtensionCmd::CHECK_FOR_UPDATES ) )
734 {
735 currentCmdEnv->startProgress();
736 bStartProgress = false;
737 }
738
739 switch ( pEntry->m_eCmdType ) {
740 case ExtensionCmd::ADD :
741 _addExtension( currentCmdEnv, pEntry->m_sExtensionURL, pEntry->m_sRepository, pEntry->m_bWarnUser );
742 break;
743 case ExtensionCmd::REMOVE :
744 _removeExtension( currentCmdEnv, pEntry->m_xPackage );
745 break;
746 case ExtensionCmd::ENABLE :
747 _enableExtension( currentCmdEnv, pEntry->m_xPackage );
748 break;
749 case ExtensionCmd::DISABLE :
750 _disableExtension( currentCmdEnv, pEntry->m_xPackage );
751 break;
752 case ExtensionCmd::CHECK_FOR_UPDATES :
753 _checkForUpdates( std::vector(pEntry->m_vExtensionList) );
754 break;
755 case ExtensionCmd::ACCEPT_LICENSE :
756 _acceptLicense( currentCmdEnv, pEntry->m_xPackage );
757 break;
758 }
759 }
760 catch ( const ucb::CommandAbortedException & )
761 {
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
764 //the queue.
765 {
766 std::scoped_lock queueGuard2(m_mutex);
767 while ( --nSize >= 0 )
768 m_queue.pop();
769 }
770 break;
771 }
772 catch ( const ucb::CommandFailedException & )
773 {
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.
779 continue;
780 }
781 catch ( const uno::Exception & )
782 {
783 //Todo display the user an error
784 //see also DialogImpl::SyncPushButton::Click()
785 uno::Any exc( ::cppu::getCaughtException() );
786 OUString msg;
787 deployment::DeploymentException dpExc;
788 if (exc >>= dpExc)
789 {
790 if (auto e = o3tl::tryAccess<uno::Exception>(dpExc.Cause))
791 {
792 // notify error cause only:
793 msg = e->Message;
794 }
795 }
796 if (msg.isEmpty()) // fallback for debugging purposes
797 msg = ::comphelper::anyToString(exc);
798
799 const SolarMutexGuard guard;
800 if (m_pDialogHelper)
801 m_pDialogHelper->incBusy();
802
803 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(currentCmdEnv->activeDialog(),
804 VclMessageType::Warning, VclButtonsType::Ok, msg));
805 if (m_pDialogHelper)
806 xBox->set_title(m_pDialogHelper->getFrameWeld()->get_title());
807 xBox->run();
808 if (m_pDialogHelper)
809 m_pDialogHelper->decBusy();
810 //Continue with installation of the remaining extensions
811 }
812 {
813 std::scoped_lock aGuard( m_mutex );
814 m_bWorking = false;
815 }
816 }
817
818 {
819 // when leaving the while loop with break, we should set working to false, too
820 std::scoped_lock aGuard( m_mutex );
821 m_bWorking = false;
822 }
823
824 if ( !bStartProgress )
825 currentCmdEnv->stopProgress();
826 }
827 //end for
828#ifdef _WIN32
829 o3tl::safeCoUninitializeReinit(COINIT_MULTITHREADED, nNbCallCoInitializeExForReinit);
830#endif
831}
832
833
835 const OUString &rPackageURL,
836 const OUString &rRepository,
837 const bool bWarnUser )
838{
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.
841 uno::Any anyTitle;
842 try
843 {
844 anyTitle = ::ucbhelper::Content( rPackageURL, rCmdEnv, m_xContext ).getPropertyValue( "Title" );
845 }
846 catch ( const uno::Exception & )
847 {
848 return;
849 }
850
851 OUString sName;
852 if ( ! (anyTitle >>= sName) )
853 {
854 OSL_FAIL("Could not get file name for extension.");
855 return;
856 }
857
858 rCmdEnv->setWarnUser( bWarnUser );
859 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
860 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
861 OUString sTitle(
862 m_sAddingPackages.replaceAll("%EXTENSION_NAME", sName));
863 rCmdEnv->progressSection( sTitle, xAbortChannel );
864
865 try
866 {
867 xExtMgr->addExtension(rPackageURL, uno::Sequence<beans::NamedValue>(),
868 rRepository, xAbortChannel, rCmdEnv );
869 }
870 catch ( const ucb::CommandFailedException & )
871 {
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.
874 }
875 catch ( const ucb::CommandAbortedException & )
876 {
877 // User clicked the cancel button
878 // TODO: handle cancel
879 }
880 rCmdEnv->setWarnUser( false );
881}
882
883
886{
887 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
888 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
889 OUString sTitle(
890 m_sRemovingPackages.replaceAll("%EXTENSION_NAME",
891 xPackage->getDisplayName()));
892 rCmdEnv->progressSection( sTitle, xAbortChannel );
893
894 OUString id( dp_misc::getIdentifier( xPackage ) );
895 try
896 {
897 xExtMgr->removeExtension( id, xPackage->getName(), xPackage->getRepositoryName(), xAbortChannel, rCmdEnv );
898 }
899 catch ( const deployment::DeploymentException & )
900 {}
901 catch ( const ucb::CommandFailedException & )
902 {}
903 catch ( const ucb::CommandAbortedException & )
904 {}
905
906 // Check, if there are still updates to be notified via menu bar icon
908 UpdateDialog::createNotifyJob( false, aItemList );
909}
910
911
913 std::vector<uno::Reference<deployment::XPackage > > && vExtensionList )
914{
915 const SolarMutexGuard guard;
916
917 if (m_pDialogHelper)
918 m_pDialogHelper->incBusy();
919
920 std::vector< UpdateData > vData;
921 UpdateDialog aUpdateDialog(m_xContext, m_pDialogHelper ? m_pDialogHelper->getFrameWeld() : nullptr, std::move(vExtensionList), &vData);
922
923 aUpdateDialog.notifyMenubar( true, false ); // prepare the checking, if there updates to be notified via menu bar icon
924
925 bool bOk = aUpdateDialog.run() == RET_OK;
926 if (m_pDialogHelper)
927 m_pDialogHelper->decBusy();
928
929 if (bOk && !vData.empty())
930 {
931 // If there is at least one directly downloadable extension then we
932 // open the install dialog.
933 std::vector< UpdateData > dataDownload;
934
935 for (auto const& data : vData)
936 {
937 if ( data.sWebsiteURL.isEmpty() )
938 dataDownload.push_back(data);
939 }
940
941 short nDialogResult = RET_OK;
942 if ( !dataDownload.empty() )
943 {
944 if (m_pDialogHelper)
945 m_pDialogHelper->incBusy();
946 UpdateInstallDialog aDlg(m_pDialogHelper ? m_pDialogHelper->getFrameWeld() : nullptr, dataDownload, m_xContext);
947 nDialogResult = aDlg.run();
948 if (m_pDialogHelper)
949 m_pDialogHelper->decBusy();
950 aUpdateDialog.notifyMenubar( false, true ); // Check, if there are still pending updates to be notified via menu bar icon
951 }
952 else
953 aUpdateDialog.notifyMenubar( false, false ); // Check, if there are pending updates to be notified via menu bar icon
954
955 //Now start the webbrowser and navigate to the websites where we get the updates
956 if ( RET_OK == nDialogResult )
957 {
958 for (auto const& data : vData)
959 {
960 if ( m_pDialogHelper && ( !data.sWebsiteURL.isEmpty() ) )
961 m_pDialogHelper->openWebBrowser( data.sWebsiteURL, m_pDialogHelper->getFrameWeld()->get_title() );
962 }
963 }
964 }
965 else
966 aUpdateDialog.notifyMenubar( false, false ); // check if there updates to be notified via menu bar icon
967}
968
969
972{
973 if ( !xPackage.is() )
974 return;
975
976 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
977 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
978 OUString sTitle(
979 m_sEnablingPackages.replaceAll("%EXTENSION_NAME",
980 xPackage->getDisplayName()));
981 rCmdEnv->progressSection( sTitle, xAbortChannel );
982
983 try
984 {
985 xExtMgr->enableExtension( xPackage, xAbortChannel, rCmdEnv );
986 if ( m_pDialogHelper )
987 m_pDialogHelper->updatePackageInfo( xPackage );
988 }
989 catch ( const ::ucb::CommandAbortedException & )
990 {}
991}
992
993
996{
997 if ( !xPackage.is() )
998 return;
999
1000 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
1001 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
1002 OUString sTitle(
1003 m_sDisablingPackages.replaceAll("%EXTENSION_NAME",
1004 xPackage->getDisplayName()));
1005 rCmdEnv->progressSection( sTitle, xAbortChannel );
1006
1007 try
1008 {
1009 xExtMgr->disableExtension( xPackage, xAbortChannel, rCmdEnv );
1010 if ( m_pDialogHelper )
1011 m_pDialogHelper->updatePackageInfo( xPackage );
1012 }
1013 catch ( const ::ucb::CommandAbortedException & )
1014 {}
1015}
1016
1017
1020{
1021 if ( !xPackage.is() )
1022 return;
1023
1024 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
1025 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
1026 OUString sTitle(
1027 m_sAcceptLicense.replaceAll("%EXTENSION_NAME",
1028 xPackage->getDisplayName()));
1029 rCmdEnv->progressSection( sTitle, xAbortChannel );
1030
1031 try
1032 {
1033 xExtMgr->checkPrerequisitesAndEnable( xPackage, xAbortChannel, rCmdEnv );
1034 if ( m_pDialogHelper )
1035 m_pDialogHelper->updatePackageInfo( xPackage );
1036 }
1037 catch ( const ::ucb::CommandAbortedException & )
1038 {}
1039}
1040
1042{
1043 std::scoped_lock aGuard( m_mutex );
1044
1045 // If someone called stop then we do not process the command -> game over!
1046 if ( m_bStopped )
1047 return;
1048
1049 m_queue.push( rExtCmd );
1050 m_eInput = START;
1051 m_wakeup.notify_all();
1052}
1053
1054
1056 TheExtensionManager *pManager,
1058 : m_thread( new Thread( pDialogHelper, pManager, rContext ) )
1059{
1060 m_thread->launch();
1061}
1062
1064 m_thread->stop();
1065 m_thread->join();
1066}
1067
1068void ExtensionCmdQueue::addExtension( const OUString & extensionURL,
1069 const OUString & repository,
1070 const bool bWarnUser )
1071{
1072 m_thread->addExtension( extensionURL, repository, bWarnUser );
1073}
1074
1076{
1077 m_thread->removeExtension( rPackage );
1078}
1079
1081 const bool bEnable )
1082{
1083 m_thread->enableExtension( rPackage, bEnable );
1084}
1085
1087{
1088 m_thread->checkForUpdates( std::move(vExtensionList) );
1089}
1090
1092{
1093 m_thread->acceptLicense( rPackage );
1094}
1095
1097{
1098 dp_misc::syncRepositories( false, new ProgressCmdEnv( xContext, nullptr, "Extension Manager" ) );
1099}
1100
1102{
1103 return m_thread->isBusy();
1104}
1105
1108{
1109 ::rtl::Reference< ProgressCmdEnv > xCmdEnv( new ProgressCmdEnv( xContext, nullptr, "Extension Manager" ) );
1110 xCmdEnv->handle( xRequest );
1111}
1112
1113} //namespace dp_gui
1114
1115/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static bool IsDialogCancelEnabled()
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, const ILibreOfficeKitNotifier *pNotifier=nullptr)
virtual void updateProgress(const OUString &rText, const css::uno::Reference< css::task::XAbortChannel > &xAbortChannel)=0
virtual void showProgress(bool bStart)=0
bool installExtensionWarn(std::u16string_view rExtensionURL)
void _removeExtension(::rtl::Reference< ProgressCmdEnv > const &rCmdEnv, const uno::Reference< deployment::XPackage > &xPackage)
void removeExtension(const uno::Reference< deployment::XPackage > &rPackage)
Thread(DialogHelper *pDialogHelper, TheExtensionManager *pManager, uno::Reference< uno::XComponentContext > xContext)
void _addExtension(::rtl::Reference< ProgressCmdEnv > const &rCmdEnv, const OUString &rPackageURL, const OUString &rRepository, const bool bWarnUser)
void _enableExtension(::rtl::Reference< ProgressCmdEnv > const &rCmdEnv, const uno::Reference< deployment::XPackage > &xPackage)
void enableExtension(const uno::Reference< deployment::XPackage > &rPackage, const bool bEnable)
void _acceptLicense(::rtl::Reference< ProgressCmdEnv > const &rCmdEnv, const uno::Reference< deployment::XPackage > &xPackage)
void acceptLicense(const uno::Reference< deployment::XPackage > &rPackage)
void _insert(const TExtensionCmd &rExtCmd)
void _checkForUpdates(std::vector< uno::Reference< deployment::XPackage > > &&vExtensionList)
uno::Reference< uno::XComponentContext > m_xContext
void _disableExtension(::rtl::Reference< ProgressCmdEnv > const &rCmdEnv, const uno::Reference< deployment::XPackage > &xPackage)
void checkForUpdates(std::vector< uno::Reference< deployment::XPackage > > &&vExtensionList)
void addExtension(const OUString &rExtensionURL, const OUString &rRepository, const bool bWarnUser)
static void syncRepositories(const css::uno::Reference< css::uno::XComponentContext > &xContext)
void enableExtension(const css::uno::Reference< css::deployment::XPackage > &rPackage, const bool bEnable)
void acceptLicense(const css::uno::Reference< css::deployment::XPackage > &rPackage)
void addExtension(const OUString &rExtensionURL, const OUString &rRepository, const bool bWarnUser)
void checkForUpdates(std::vector< css::uno::Reference< css::deployment::XPackage > > &&vList)
ExtensionCmdQueue(DialogHelper *pDialogHelper, TheExtensionManager *pManager, const css::uno::Reference< css::uno::XComponentContext > &rContext)
Create an instance.
rtl::Reference< Thread > m_thread
void removeExtension(const css::uno::Reference< css::deployment::XPackage > &rPackage)
The modal “Check for Updates” dialog.
void notifyMenubar(bool bPrepareOnly, bool bRecheckOnly)
static void createNotifyJob(bool bPrepareOnly, css::uno::Sequence< css::uno::Sequence< OUString > > const &rItemList)
virtual short run() override
The modal “Download and Installation” dialog.
css::uno::Any getPropertyValue(const OUString &rPropertyName)
virtual css::uno::Reference< css::awt::XWindow > GetXWindow()=0
uno::Reference< task::XInteractionHandler2 > m_xHandler
OUString m_sExtensionURL
DialogHelper * m_pDialogHelper
uno::Reference< uno::XComponentContext > m_xContext
OUString m_sRepository
sal_Int32 m_nCurrentProgress
E_CMD_TYPE m_eCmdType
OUString m_sTitle
uno::Reference< deployment::XPackage > m_xPackage
std::vector< uno::Reference< deployment::XPackage > > m_vExtensionList
OUString DpResId(TranslateId aId)
Definition: dp_misc.cxx:555
OUString sName
Mutex m_mutex
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2642
sal_Int64 n
def text(shape, orig_st)
NONE
Definition: dp_gui.h:22
void handleInteractionRequest(const uno::Reference< uno::XComponentContext > &xContext, const uno::Reference< task::XInteractionRequest > &xRequest)
std::shared_ptr< ExtensionCmd > TExtensionCmd
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC OUString getErrorText(css::uno::Reference< css::xml::dom::XElement > const &dependency)
Obtain the (human-readable) error message of a failed dependency.
void syncRepositories(bool force, Reference< ucb::XCommandEnvironment > const &xCmdEnv)
Definition: dp_misc.cxx:491
void TRACE(OUString const &sText)
print the text to the console in a debug build.
Definition: dp_misc.cxx:486
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC Order compareVersions(std::u16string_view version1, std::u16string_view version2)
Definition: dp_version.cxx:42
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC OUString getIdentifier(css::uno::Reference< css::deployment::XPackage > const &package)
Gets the identifier of a package.
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)
long Long
START
bool hasValue()
STOP
ToolBarManager * m_pManager
bool update()
Definition: updater.cxx:286
RET_OK
RET_CANCEL
size_t pos