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/conditn.hxx>
50 #include <osl/diagnose.h>
51 #include <osl/mutex.hxx>
52 #include <rtl/ref.hxx>
53 #include <rtl/ustring.hxx>
54 #include <sal/types.h>
55 #include <salhelper/thread.hxx>
56 #include <ucbhelper/content.hxx>
57 #include <cppuhelper/exc_hlp.hxx>
58 #include <cppuhelper/implbase.hxx>
60 #include <vcl/svapp.hxx>
61 #include <vcl/weld.hxx>
62 
65 #include "dp_gui_dialog2.hxx"
66 #include <dp_shared.hxx>
67 #include <strings.hrc>
68 #include "dp_gui_theextmgr.hxx"
69 #include "dp_gui_updatedialog.hxx"
71 #include <dp_dependencies.hxx>
72 #include <dp_misc.h>
73 #include <dp_identifier.hxx>
74 #include <dp_version.hxx>
75 
76 #include <queue>
77 #include <memory>
78 
79 #ifdef _WIN32
80 #if !defined WIN32_LEAN_AND_MEAN
81 # define WIN32_LEAN_AND_MEAN
82 #endif
83 #include <windows.h>
84 #include <objbase.h>
85 #endif
86 
87 
88 using namespace ::com::sun::star;
89 
90 namespace {
91 
92 OUString getVersion( OUString const & sVersion )
93 {
94  return ( sVersion.isEmpty() ) ? OUString( "0" ) : sVersion;
95 }
96 
97 OUString getVersion( const uno::Reference< deployment::XPackage > &rPackage )
98 {
99  return getVersion( rPackage->getVersion());
100 }
101 }
102 
103 
104 namespace dp_gui {
105 
106 namespace {
107 
108 class ProgressCmdEnv
109  : public ::cppu::WeakImplHelper< ucb::XCommandEnvironment,
110  task::XInteractionHandler,
111  ucb::XProgressHandler >
112 {
113  uno::Reference< task::XInteractionHandler2> m_xHandler;
114  uno::Reference< uno::XComponentContext > m_xContext;
115 
116  DialogHelper* m_pDialogHelper;
117  OUString m_sTitle;
120 
121  void updateProgress();
122 
124  void update_( uno::Any const & Status );
125 
126 public:
134  ProgressCmdEnv( const uno::Reference< uno::XComponentContext >& rContext,
135  DialogHelper* pDialogHelper,
136  const OUString& rTitle )
137  : m_xContext( rContext )
138  , m_pDialogHelper( pDialogHelper )
139  , m_sTitle( rTitle )
140  , m_bWarnUser( false )
141  , m_nCurrentProgress(0)
142  {}
143 
144  weld::Window* activeDialog() { return m_pDialogHelper ? m_pDialogHelper->getFrameWeld() : nullptr; }
145 
146  void startProgress();
147  void stopProgress();
148  void progressSection( const OUString &rText,
149  const uno::Reference< task::XAbortChannel > &xAbortChannel );
150  void setWarnUser( bool bNewVal ) { m_bWarnUser = bNewVal; }
151 
152  // XCommandEnvironment
153  virtual uno::Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler() override;
154  virtual uno::Reference< ucb::XProgressHandler > SAL_CALL getProgressHandler() override;
155 
156  // XInteractionHandler
157  virtual void SAL_CALL handle( uno::Reference< task::XInteractionRequest > const & xRequest ) override;
158 
159  // XProgressHandler
160  virtual void SAL_CALL push( uno::Any const & Status ) override;
161  virtual void SAL_CALL update( uno::Any const & Status ) override;
162  virtual void SAL_CALL pop() override;
163 };
164 
165 
166 struct ExtensionCmd
167 {
168  enum E_CMD_TYPE { ADD, ENABLE, DISABLE, REMOVE, CHECK_FOR_UPDATES, ACCEPT_LICENSE };
169 
170  E_CMD_TYPE m_eCmdType;
171  bool m_bWarnUser;
172  OUString m_sExtensionURL;
173  OUString m_sRepository;
174  uno::Reference< deployment::XPackage > m_xPackage;
175  std::vector< uno::Reference< deployment::XPackage > > m_vExtensionList;
176 
177  ExtensionCmd( const E_CMD_TYPE eCommand,
178  const OUString &rExtensionURL,
179  const OUString &rRepository,
180  const bool bWarnUser )
181  : m_eCmdType( eCommand ),
182  m_bWarnUser( bWarnUser ),
183  m_sExtensionURL( rExtensionURL ),
184  m_sRepository( rRepository ) {};
185  ExtensionCmd( const E_CMD_TYPE eCommand,
186  const uno::Reference< deployment::XPackage > &rPackage )
187  : m_eCmdType( eCommand ),
188  m_bWarnUser( false ),
189  m_xPackage( rPackage ) {};
190  ExtensionCmd( const E_CMD_TYPE eCommand,
191  const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
192  : m_eCmdType( eCommand ),
193  m_bWarnUser( false ),
194  m_vExtensionList( vExtensionList ) {};
195 };
196 
197 }
198 
199 typedef std::shared_ptr< ExtensionCmd > TExtensionCmd;
200 
201 
203 {
204 public:
205  Thread( DialogHelper *pDialogHelper,
206  TheExtensionManager *pManager,
207  const uno::Reference< uno::XComponentContext > & rContext );
208 
209  void addExtension( const OUString &rExtensionURL,
210  const OUString &rRepository,
211  const bool bWarnUser );
212  void removeExtension( const uno::Reference< deployment::XPackage > &rPackage );
213  void enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
214  const bool bEnable );
215  void checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList );
216  void acceptLicense( const uno::Reference< deployment::XPackage > &rPackage );
217  void stop();
218  bool isBusy();
219 
220 private:
221  virtual ~Thread() override;
222 
223  virtual void execute() override;
224 
225  void _insert(const TExtensionCmd& rExtCmd);
226 
227  void _addExtension( ::rtl::Reference< ProgressCmdEnv > const &rCmdEnv,
228  const OUString &rPackageURL,
229  const OUString &rRepository,
230  const bool bWarnUser );
231  void _removeExtension( ::rtl::Reference< ProgressCmdEnv > const &rCmdEnv,
232  const uno::Reference< deployment::XPackage > &xPackage );
233  void _enableExtension( ::rtl::Reference< ProgressCmdEnv > const &rCmdEnv,
234  const uno::Reference< deployment::XPackage > &xPackage );
236  const uno::Reference< deployment::XPackage > &xPackage );
237  void _checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList );
238  void _acceptLicense( ::rtl::Reference< ProgressCmdEnv > const &rCmdEnv,
239  const uno::Reference< deployment::XPackage > &xPackage );
240 
241  enum Input { NONE, START, STOP };
242 
243  uno::Reference< uno::XComponentContext > m_xContext;
244  std::queue< TExtensionCmd > m_queue;
245 
248 
249  const OUString m_sEnablingPackages;
250  const OUString m_sDisablingPackages;
251  const OUString m_sAddingPackages;
252  const OUString m_sRemovingPackages;
253  const OUString m_sDefaultCmd;
254  const OUString m_sAcceptLicense;
255  osl::Condition m_wakeup;
256  osl::Mutex m_mutex;
260 };
261 
262 
263 void ProgressCmdEnv::startProgress()
264 {
265  m_nCurrentProgress = 0;
266 
267  if ( m_pDialogHelper )
268  m_pDialogHelper->showProgress( true );
269 }
270 
271 
272 void ProgressCmdEnv::stopProgress()
273 {
274  if ( m_pDialogHelper )
275  m_pDialogHelper->showProgress( false );
276 }
277 
278 
279 void ProgressCmdEnv::progressSection( const OUString &rText,
280  const uno::Reference< task::XAbortChannel > &xAbortChannel )
281 {
282  m_nCurrentProgress = 0;
283  if ( m_pDialogHelper )
284  {
285  m_pDialogHelper->updateProgress( rText, xAbortChannel );
287  }
288 }
289 
290 
291 void ProgressCmdEnv::updateProgress()
292 {
293  long nProgress = ((m_nCurrentProgress*5) % 100) + 5;
294  if ( m_pDialogHelper )
295  m_pDialogHelper->updateProgress( nProgress );
296 }
297 
298 // XCommandEnvironment
299 
300 uno::Reference< task::XInteractionHandler > ProgressCmdEnv::getInteractionHandler()
301 {
302  return this;
303 }
304 
305 
306 uno::Reference< ucb::XProgressHandler > ProgressCmdEnv::getProgressHandler()
307 {
308  return this;
309 }
310 
311 
312 // XInteractionHandler
313 
314 void ProgressCmdEnv::handle( uno::Reference< task::XInteractionRequest > const & xRequest )
315 {
316  uno::Any request( xRequest->getRequest() );
317  OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION );
318  dp_misc::TRACE( "[dp_gui_cmdenv.cxx] incoming request:\n"
319  + ::comphelper::anyToString(request) + "\n");
320 
321  lang::WrappedTargetException wtExc;
322  deployment::DependencyException depExc;
323  deployment::LicenseException licExc;
324  deployment::VersionException verExc;
325  deployment::InstallException instExc;
326  deployment::PlatformException platExc;
327 
328  // selections:
329  bool approve = false;
330  bool abort = false;
331 
332  if (request >>= wtExc) {
333  // handable deployment error signalled, e.g.
334  // bundle item registration failed, notify cause only:
335  uno::Any cause;
336  deployment::DeploymentException dpExc;
337  if (wtExc.TargetException >>= dpExc)
338  cause = dpExc.Cause;
339  else {
340  ucb::CommandFailedException cfExc;
341  if (wtExc.TargetException >>= cfExc)
342  cause = cfExc.Reason;
343  else
344  cause = wtExc.TargetException;
345  }
346  update_( cause );
347 
348  // ignore intermediate errors of legacy packages, i.e.
349  // former pkgchk behaviour:
350  const uno::Reference< deployment::XPackage > xPackage( wtExc.Context, uno::UNO_QUERY );
351  OSL_ASSERT( xPackage.is() );
352  if ( xPackage.is() )
353  {
354  const uno::Reference< deployment::XPackageTypeInfo > xPackageType( xPackage->getPackageType() );
355  OSL_ASSERT( xPackageType.is() );
356  if (xPackageType.is())
357  {
358  approve = ( xPackage->isBundle() &&
359  xPackageType->getMediaType().match(
360  "application/vnd.sun.star.legacy-package-bundle" ));
361  }
362  }
363  abort = !approve;
364  }
365  else if (request >>= depExc)
366  {
367  std::vector< OUString > deps;
368  deps.reserve(depExc.UnsatisfiedDependencies.getLength());
369  for (sal_Int32 i = 0; i < depExc.UnsatisfiedDependencies.getLength(); ++i)
370  {
371  deps.push_back(
372  dp_misc::Dependencies::getErrorText( depExc.UnsatisfiedDependencies[i]) );
373  }
374  {
375  SolarMutexGuard guard;
376  if (m_pDialogHelper)
378  DependencyDialog aDlg(activeDialog(), deps);
379  short n = aDlg.run();
380  if (m_pDialogHelper)
382  // Distinguish between closing the dialog and programmatically
383  // canceling the dialog (headless VCL):
384  approve = n == RET_OK
386  }
387  }
388  else if (request >>= licExc)
389  {
390  SolarMutexGuard guard;
391 
392  weld::Window *pTopLevel = activeDialog();
393  if (m_pDialogHelper)
395  uno::Reference< ui::dialogs::XExecutableDialog > xDialog(
397  m_xContext, pTopLevel ? pTopLevel->GetXWindow() : nullptr,
398  licExc.ExtensionName, licExc.Text ) );
399  sal_Int16 res = xDialog->execute();
400  if (m_pDialogHelper)
402  if ( res == ui::dialogs::ExecutableDialogResults::CANCEL )
403  abort = true;
404  else if ( res == ui::dialogs::ExecutableDialogResults::OK )
405  approve = true;
406  else
407  {
408  OSL_ASSERT(false);
409  }
410  }
411  else if (request >>= verExc)
412  {
413  const char* id;
414  switch (dp_misc::compareVersions(
415  verExc.NewVersion, verExc.Deployed->getVersion() ))
416  {
417  case dp_misc::LESS:
418  id = RID_STR_WARNING_VERSION_LESS;
419  break;
420  case dp_misc::EQUAL:
421  id = RID_STR_WARNING_VERSION_EQUAL;
422  break;
423  default: // dp_misc::GREATER
424  id = RID_STR_WARNING_VERSION_GREATER;
425  break;
426  }
427  OSL_ASSERT( verExc.Deployed.is() );
428  bool bEqualNames = verExc.NewDisplayName ==
429  verExc.Deployed->getDisplayName();
430  {
431  SolarMutexGuard guard;
432 
433  if (m_pDialogHelper)
435 
436  std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(activeDialog(),
437  VclMessageType::Warning, VclButtonsType::OkCancel, DpResId(id)));
438  OUString s;
439  if (bEqualNames)
440  {
441  s = xBox->get_primary_text();
442  }
443  else if (!strcmp(id, RID_STR_WARNING_VERSION_EQUAL))
444  {
445  //hypothetical: requires two instances of an extension with the same
446  //version to have different display names. Probably the developer forgot
447  //to change the version.
448  s = DpResId(RID_STR_WARNINGBOX_VERSION_EQUAL_DIFFERENT_NAMES);
449  }
450  else if (!strcmp(id, RID_STR_WARNING_VERSION_LESS))
451  {
452  s = DpResId(RID_STR_WARNINGBOX_VERSION_LESS_DIFFERENT_NAMES);
453  }
454  else if (!strcmp(id, RID_STR_WARNING_VERSION_GREATER))
455  {
456  s = DpResId(RID_STR_WARNINGBOX_VERSION_GREATER_DIFFERENT_NAMES);
457  }
458  s = s.replaceAll("$NAME", verExc.NewDisplayName);
459  s = s.replaceAll("$OLDNAME", verExc.Deployed->getDisplayName());
460  s = s.replaceAll("$NEW", getVersion(verExc.NewVersion));
461  s = s.replaceAll("$DEPLOYED", getVersion(verExc.Deployed));
462  xBox->set_primary_text(s);
463  approve = xBox->run() == RET_OK;
464  if (m_pDialogHelper)
466  abort = !approve;
467  }
468  }
469  else if (request >>= instExc)
470  {
471  if ( ! m_bWarnUser )
472  {
473  approve = true;
474  }
475  else
476  {
477  if ( m_pDialogHelper )
478  {
479  SolarMutexGuard guard;
480 
481  approve = m_pDialogHelper->installExtensionWarn( instExc.displayName );
482  }
483  else
484  approve = false;
485  abort = !approve;
486  }
487  }
488  else if (request >>= platExc)
489  {
490  SolarMutexGuard guard;
491  OUString sMsg(DpResId(RID_STR_UNSUPPORTED_PLATFORM));
492  sMsg = sMsg.replaceAll("%Name", platExc.package->getDisplayName());
493  if (m_pDialogHelper)
495  std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(activeDialog(),
496  VclMessageType::Warning, VclButtonsType::Ok, sMsg));
497  xBox->run();
498  if (m_pDialogHelper)
500  approve = true;
501  }
502 
503  if (!approve && !abort)
504  {
505  // forward to UUI handler:
506  if (! m_xHandler.is()) {
507  // late init:
508  m_xHandler = task::InteractionHandler::createWithParentAndContext(m_xContext, nullptr, m_sTitle);
509  }
510  m_xHandler->handle( xRequest );
511  }
512  else
513  {
514  // select:
515  uno::Sequence< uno::Reference< task::XInteractionContinuation > > conts(
516  xRequest->getContinuations() );
517  uno::Reference< task::XInteractionContinuation > const * pConts = conts.getConstArray();
518  sal_Int32 len = conts.getLength();
519  for ( sal_Int32 pos = 0; pos < len; ++pos )
520  {
521  if (approve) {
522  uno::Reference< task::XInteractionApprove > xInteractionApprove( pConts[ pos ], uno::UNO_QUERY );
523  if (xInteractionApprove.is()) {
524  xInteractionApprove->select();
525  // don't query again for ongoing continuations:
526  approve = false;
527  }
528  }
529  else if (abort) {
530  uno::Reference< task::XInteractionAbort > xInteractionAbort( pConts[ pos ], uno::UNO_QUERY );
531  if (xInteractionAbort.is()) {
532  xInteractionAbort->select();
533  // don't query again for ongoing continuations:
534  abort = false;
535  }
536  }
537  }
538  }
539 }
540 
541 
542 // XProgressHandler
543 
544 void ProgressCmdEnv::push( uno::Any const & rStatus )
545 {
546  update_( rStatus );
547 }
548 
549 
550 void ProgressCmdEnv::update_( uno::Any const & rStatus )
551 {
552  OUString text;
553  if ( rStatus.hasValue() && !( rStatus >>= text) )
554  {
555  if ( auto e = o3tl::tryAccess<uno::Exception>(rStatus) )
556  text = e->Message;
557  if ( text.isEmpty() )
558  text = ::comphelper::anyToString( rStatus ); // fallback
559 
560  const SolarMutexGuard aGuard;
561  if (m_pDialogHelper)
563  std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(activeDialog(),
564  VclMessageType::Warning, VclButtonsType::Ok, text));
565  xBox->run();
566  if (m_pDialogHelper)
568  }
570  updateProgress();
571 }
572 
573 
574 void ProgressCmdEnv::update( uno::Any const & rStatus )
575 {
576  update_( rStatus );
577 }
578 
579 
580 void ProgressCmdEnv::pop()
581 {
582  update_( uno::Any() ); // no message
583 }
584 
585 
587  TheExtensionManager *pManager,
588  const uno::Reference< uno::XComponentContext > & rContext ) :
589  salhelper::Thread( "dp_gui_extensioncmdqueue" ),
590  m_xContext( rContext ),
591  m_pDialogHelper( pDialogHelper ),
592  m_pManager( pManager ),
593  m_sEnablingPackages( DpResId( RID_STR_ENABLING_PACKAGES ) ),
594  m_sDisablingPackages( DpResId( RID_STR_DISABLING_PACKAGES ) ),
595  m_sAddingPackages( DpResId( RID_STR_ADDING_PACKAGES ) ),
596  m_sRemovingPackages( DpResId( RID_STR_REMOVING_PACKAGES ) ),
597  m_sDefaultCmd( DpResId( RID_STR_ADD_PACKAGES ) ),
598  m_sAcceptLicense( DpResId( RID_STR_ACCEPT_LICENSE ) ),
599  m_eInput( NONE ),
600  m_bStopped( false ),
601  m_bWorking( false )
602 {
603  OSL_ASSERT( pDialogHelper );
604 }
605 
606 
607 void ExtensionCmdQueue::Thread::addExtension( const OUString &rExtensionURL,
608  const OUString &rRepository,
609  const bool bWarnUser )
610 {
611  if ( !rExtensionURL.isEmpty() )
612  {
613  TExtensionCmd pEntry = std::make_shared<ExtensionCmd>( ExtensionCmd::ADD, rExtensionURL, rRepository, bWarnUser );
614  _insert( pEntry );
615  }
616 }
617 
618 
619 void ExtensionCmdQueue::Thread::removeExtension( const uno::Reference< deployment::XPackage > &rPackage )
620 {
621  if ( rPackage.is() )
622  {
623  TExtensionCmd pEntry = std::make_shared<ExtensionCmd>( ExtensionCmd::REMOVE, rPackage );
624  _insert( pEntry );
625  }
626 }
627 
628 
629 void ExtensionCmdQueue::Thread::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage )
630 {
631  if ( rPackage.is() )
632  {
633  TExtensionCmd pEntry = std::make_shared<ExtensionCmd>( ExtensionCmd::ACCEPT_LICENSE, rPackage );
634  _insert( pEntry );
635  }
636 }
637 
638 
639 void ExtensionCmdQueue::Thread::enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
640  const bool bEnable )
641 {
642  if ( rPackage.is() )
643  {
644  TExtensionCmd pEntry = std::make_shared<ExtensionCmd>( bEnable ? ExtensionCmd::ENABLE :
645  ExtensionCmd::DISABLE,
646  rPackage );
647  _insert( pEntry );
648  }
649 }
650 
651 
653  const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
654 {
655  TExtensionCmd pEntry = std::make_shared<ExtensionCmd>( ExtensionCmd::CHECK_FOR_UPDATES, vExtensionList );
656  _insert( pEntry );
657 }
658 
659 
660 //Stopping this thread will not abort the installation of extensions.
662 {
663  osl::MutexGuard aGuard( m_mutex );
664  m_bStopped = true;
665  m_eInput = STOP;
666  m_wakeup.set();
667 }
668 
669 
671 {
672  osl::MutexGuard aGuard( m_mutex );
673  return m_bWorking;
674 }
675 
676 
678 
679 
681 {
682 #ifdef _WIN32
683  //Needed for use of the service "com.sun.star.system.SystemShellExecute" in
684  //DialogHelper::openWebBrowser
685  CoUninitialize();
686  (void) CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
687 #endif
688  for (;;)
689  {
690  if ( m_wakeup.wait() != osl::Condition::result_ok )
691  {
692  dp_misc::TRACE( "dp_gui::ExtensionCmdQueue::Thread::run: ignored "
693  "osl::Condition::wait failure\n" );
694  }
695  m_wakeup.reset();
696 
697  int nSize;
698  Input eInput;
699  {
700  osl::MutexGuard aGuard( m_mutex );
701  eInput = m_eInput;
702  m_eInput = NONE;
703  nSize = m_queue.size();
704  m_bWorking = false;
705  }
706 
707  // If this thread has been woken up by anything else except start, stop
708  // then input is NONE and we wait again.
709  // We only install the extension which are currently in the queue.
710  // The progressbar will be set to show the progress of the current number
711  // of extensions. If we allowed to add extensions now then the progressbar may
712  // have reached the end while we still install newly added extensions.
713  if ( ( eInput == NONE ) || ( nSize == 0 ) )
714  continue;
715  if ( eInput == STOP )
716  break;
717 
718  ::rtl::Reference< ProgressCmdEnv > currentCmdEnv( new ProgressCmdEnv( m_xContext, m_pDialogHelper, m_sDefaultCmd ) );
719 
720  // Do not lock the following part with addExtension. addExtension may be called in the main thread.
721  // If the message box "Do you want to install the extension (or similar)" is shown and then
722  // addExtension is called, which then blocks the main thread, then we deadlock.
723  bool bStartProgress = true;
724 
725  while ( --nSize >= 0 )
726  {
727  {
728  osl::MutexGuard aGuard( m_mutex );
729  m_bWorking = true;
730  }
731 
732  try
733  {
734  TExtensionCmd pEntry;
735  {
736  ::osl::MutexGuard queueGuard( m_mutex );
737  pEntry = m_queue.front();
738  m_queue.pop();
739  }
740 
741  if ( bStartProgress && ( pEntry->m_eCmdType != ExtensionCmd::CHECK_FOR_UPDATES ) )
742  {
743  currentCmdEnv->startProgress();
744  bStartProgress = false;
745  }
746 
747  switch ( pEntry->m_eCmdType ) {
748  case ExtensionCmd::ADD :
749  _addExtension( currentCmdEnv, pEntry->m_sExtensionURL, pEntry->m_sRepository, pEntry->m_bWarnUser );
750  break;
751  case ExtensionCmd::REMOVE :
752  _removeExtension( currentCmdEnv, pEntry->m_xPackage );
753  break;
754  case ExtensionCmd::ENABLE :
755  _enableExtension( currentCmdEnv, pEntry->m_xPackage );
756  break;
757  case ExtensionCmd::DISABLE :
758  _disableExtension( currentCmdEnv, pEntry->m_xPackage );
759  break;
760  case ExtensionCmd::CHECK_FOR_UPDATES :
761  _checkForUpdates( pEntry->m_vExtensionList );
762  break;
763  case ExtensionCmd::ACCEPT_LICENSE :
764  _acceptLicense( currentCmdEnv, pEntry->m_xPackage );
765  break;
766  }
767  }
768  catch ( const ucb::CommandAbortedException & )
769  {
770  //This exception is thrown when the user clicks cancel on the progressbar.
771  //Then we cancel the installation of all extensions and remove them from
772  //the queue.
773  {
774  ::osl::MutexGuard queueGuard2(m_mutex);
775  while ( --nSize >= 0 )
776  m_queue.pop();
777  }
778  break;
779  }
780  catch ( const ucb::CommandFailedException & )
781  {
782  //This exception is thrown when a user clicked cancel in the messagebox which was
783  //started by the interaction handler. For example the user will be asked if he/she
784  //really wants to install the extension.
785  //These interactions run for exactly one extension at a time. Therefore we continue
786  //with installing the remaining extensions.
787  continue;
788  }
789  catch ( const uno::Exception & )
790  {
791  //Todo display the user an error
792  //see also DialogImpl::SyncPushButton::Click()
794  OUString msg;
795  deployment::DeploymentException dpExc;
796  if (exc >>= dpExc)
797  {
798  if (auto e = o3tl::tryAccess<uno::Exception>(dpExc.Cause))
799  {
800  // notify error cause only:
801  msg = e->Message;
802  }
803  }
804  if (msg.isEmpty()) // fallback for debugging purposes
805  msg = ::comphelper::anyToString(exc);
806 
807  const SolarMutexGuard guard;
808  if (m_pDialogHelper)
809  m_pDialogHelper->incBusy();
810 
811  std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(currentCmdEnv->activeDialog(),
812  VclMessageType::Warning, VclButtonsType::Ok, msg));
813  if (m_pDialogHelper)
814  xBox->set_title(m_pDialogHelper->getFrameWeld()->get_title());
815  xBox->run();
816  if (m_pDialogHelper)
817  m_pDialogHelper->decBusy();
818  //Continue with installation of the remaining extensions
819  }
820  {
821  osl::MutexGuard aGuard( m_mutex );
822  m_bWorking = false;
823  }
824  }
825 
826  {
827  // when leaving the while loop with break, we should set working to false, too
828  osl::MutexGuard aGuard( m_mutex );
829  m_bWorking = false;
830  }
831 
832  if ( !bStartProgress )
833  currentCmdEnv->stopProgress();
834  }
835  //end for
836 #ifdef _WIN32
837  CoUninitialize();
838 #endif
839 }
840 
841 
843  const OUString &rPackageURL,
844  const OUString &rRepository,
845  const bool bWarnUser )
846 {
847  //check if we have a string in anyTitle. For example "unopkg gui \" caused anyTitle to be void
848  //and anyTitle.get<OUString> throws as RuntimeException.
849  uno::Any anyTitle;
850  try
851  {
852  anyTitle = ::ucbhelper::Content( rPackageURL, rCmdEnv.get(), m_xContext ).getPropertyValue( "Title" );
853  }
854  catch ( const uno::Exception & )
855  {
856  return;
857  }
858 
859  OUString sName;
860  if ( ! (anyTitle >>= sName) )
861  {
862  OSL_FAIL("Could not get file name for extension.");
863  return;
864  }
865 
866  rCmdEnv->setWarnUser( bWarnUser );
867  uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
868  uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
869  OUString sTitle(
870  m_sAddingPackages.replaceAll("%EXTENSION_NAME", sName));
871  rCmdEnv->progressSection( sTitle, xAbortChannel );
872 
873  try
874  {
875  xExtMgr->addExtension(rPackageURL, uno::Sequence<beans::NamedValue>(),
876  rRepository, xAbortChannel, rCmdEnv.get() );
877  }
878  catch ( const ucb::CommandFailedException & )
879  {
880  // When the extension is already installed we'll get a dialog asking if we want to overwrite. If we then press
881  // cancel this exception is thrown.
882  }
883  catch ( const ucb::CommandAbortedException & )
884  {
885  // User clicked the cancel button
886  // TODO: handle cancel
887  }
888  rCmdEnv->setWarnUser( false );
889 }
890 
891 
893  const uno::Reference< deployment::XPackage > &xPackage )
894 {
895  uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
896  uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
897  OUString sTitle(
898  m_sRemovingPackages.replaceAll("%EXTENSION_NAME",
899  xPackage->getDisplayName()));
900  rCmdEnv->progressSection( sTitle, xAbortChannel );
901 
902  OUString id( dp_misc::getIdentifier( xPackage ) );
903  try
904  {
905  xExtMgr->removeExtension( id, xPackage->getName(), xPackage->getRepositoryName(), xAbortChannel, rCmdEnv.get() );
906  }
907  catch ( const deployment::DeploymentException & )
908  {}
909  catch ( const ucb::CommandFailedException & )
910  {}
911  catch ( const ucb::CommandAbortedException & )
912  {}
913 
914  // Check, if there are still updates to be notified via menu bar icon
915  uno::Sequence< uno::Sequence< OUString > > aItemList;
916  UpdateDialog::createNotifyJob( false, aItemList );
917 }
918 
919 
921  const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
922 {
923  const SolarMutexGuard guard;
924 
925  if (m_pDialogHelper)
926  m_pDialogHelper->incBusy();
927 
928  std::vector< UpdateData > vData;
929  UpdateDialog aUpdateDialog(m_xContext, m_pDialogHelper ? m_pDialogHelper->getFrameWeld() : nullptr, vExtensionList, &vData);
930 
931  aUpdateDialog.notifyMenubar( true, false ); // prepare the checking, if there updates to be notified via menu bar icon
932 
933  bool bOk = aUpdateDialog.run() == RET_OK;
934  if (m_pDialogHelper)
935  m_pDialogHelper->decBusy();
936 
937  if (bOk && !vData.empty())
938  {
939  // If there is at least one directly downloadable extension then we
940  // open the install dialog.
941  std::vector< UpdateData > dataDownload;
942 
943  for (auto const& data : vData)
944  {
945  if ( data.sWebsiteURL.isEmpty() )
946  dataDownload.push_back(data);
947  }
948 
949  short nDialogResult = RET_OK;
950  if ( !dataDownload.empty() )
951  {
952  if (m_pDialogHelper)
953  m_pDialogHelper->incBusy();
954  UpdateInstallDialog aDlg(m_pDialogHelper ? m_pDialogHelper->getFrameWeld() : nullptr, dataDownload, m_xContext);
955  nDialogResult = aDlg.run();
956  if (m_pDialogHelper)
957  m_pDialogHelper->decBusy();
958  aUpdateDialog.notifyMenubar( false, true ); // Check, if there are still pending updates to be notified via menu bar icon
959  }
960  else
961  aUpdateDialog.notifyMenubar( false, false ); // Check, if there are pending updates to be notified via menu bar icon
962 
963  //Now start the webbrowser and navigate to the websites where we get the updates
964  if ( RET_OK == nDialogResult )
965  {
966  for (auto const& data : vData)
967  {
968  if ( m_pDialogHelper && ( !data.sWebsiteURL.isEmpty() ) )
969  m_pDialogHelper->openWebBrowser( data.sWebsiteURL, m_pDialogHelper->getFrameWeld()->get_title() );
970  }
971  }
972  }
973  else
974  aUpdateDialog.notifyMenubar( false, false ); // check if there updates to be notified via menu bar icon
975 }
976 
977 
979  const uno::Reference< deployment::XPackage > &xPackage )
980 {
981  if ( !xPackage.is() )
982  return;
983 
984  uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
985  uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
986  OUString sTitle(
987  m_sEnablingPackages.replaceAll("%EXTENSION_NAME",
988  xPackage->getDisplayName()));
989  rCmdEnv->progressSection( sTitle, xAbortChannel );
990 
991  try
992  {
993  xExtMgr->enableExtension( xPackage, xAbortChannel, rCmdEnv.get() );
994  if ( m_pDialogHelper )
995  m_pDialogHelper->updatePackageInfo( xPackage );
996  }
997  catch ( const ::ucb::CommandAbortedException & )
998  {}
999 }
1000 
1001 
1003  const uno::Reference< deployment::XPackage > &xPackage )
1004 {
1005  if ( !xPackage.is() )
1006  return;
1007 
1008  uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
1009  uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
1010  OUString sTitle(
1011  m_sDisablingPackages.replaceAll("%EXTENSION_NAME",
1012  xPackage->getDisplayName()));
1013  rCmdEnv->progressSection( sTitle, xAbortChannel );
1014 
1015  try
1016  {
1017  xExtMgr->disableExtension( xPackage, xAbortChannel, rCmdEnv.get() );
1018  if ( m_pDialogHelper )
1019  m_pDialogHelper->updatePackageInfo( xPackage );
1020  }
1021  catch ( const ::ucb::CommandAbortedException & )
1022  {}
1023 }
1024 
1025 
1027  const uno::Reference< deployment::XPackage > &xPackage )
1028 {
1029  if ( !xPackage.is() )
1030  return;
1031 
1032  uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
1033  uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
1034  OUString sTitle(
1035  m_sAcceptLicense.replaceAll("%EXTENSION_NAME",
1036  xPackage->getDisplayName()));
1037  rCmdEnv->progressSection( sTitle, xAbortChannel );
1038 
1039  try
1040  {
1041  xExtMgr->checkPrerequisitesAndEnable( xPackage, xAbortChannel, rCmdEnv.get() );
1042  if ( m_pDialogHelper )
1043  m_pDialogHelper->updatePackageInfo( xPackage );
1044  }
1045  catch ( const ::ucb::CommandAbortedException & )
1046  {}
1047 }
1048 
1049 void ExtensionCmdQueue::Thread::_insert(const TExtensionCmd& rExtCmd)
1050 {
1051  ::osl::MutexGuard aGuard( m_mutex );
1052 
1053  // If someone called stop then we do not process the command -> game over!
1054  if ( m_bStopped )
1055  return;
1056 
1057  m_queue.push( rExtCmd );
1058  m_eInput = START;
1059  m_wakeup.set();
1060 }
1061 
1062 
1064  TheExtensionManager *pManager,
1065  const uno::Reference< uno::XComponentContext > &rContext )
1066  : m_thread( new Thread( pDialogHelper, pManager, rContext ) )
1067 {
1068  m_thread->launch();
1069 }
1070 
1072  stop();
1073 }
1074 
1075 void ExtensionCmdQueue::addExtension( const OUString & extensionURL,
1076  const OUString & repository,
1077  const bool bWarnUser )
1078 {
1079  m_thread->addExtension( extensionURL, repository, bWarnUser );
1080 }
1081 
1082 void ExtensionCmdQueue::removeExtension( const uno::Reference< deployment::XPackage > &rPackage )
1083 {
1084  m_thread->removeExtension( rPackage );
1085 }
1086 
1087 void ExtensionCmdQueue::enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
1088  const bool bEnable )
1089 {
1090  m_thread->enableExtension( rPackage, bEnable );
1091 }
1092 
1093 void ExtensionCmdQueue::checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
1094 {
1095  m_thread->checkForUpdates( vExtensionList );
1096 }
1097 
1098 void ExtensionCmdQueue::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage )
1099 {
1100  m_thread->acceptLicense( rPackage );
1101 }
1102 
1103 void ExtensionCmdQueue::syncRepositories( const uno::Reference< uno::XComponentContext > &xContext )
1104 {
1105  dp_misc::syncRepositories( false, new ProgressCmdEnv( xContext, nullptr, "Extension Manager" ) );
1106 }
1107 
1109 {
1110  m_thread->stop();
1111 }
1112 
1114 {
1115  return m_thread->isBusy();
1116 }
1117 
1118 void handleInteractionRequest( const uno::Reference< uno::XComponentContext > & xContext,
1119  const uno::Reference< task::XInteractionRequest > & xRequest )
1120 {
1121  ::rtl::Reference< ProgressCmdEnv > xCmdEnv( new ProgressCmdEnv( xContext, nullptr, "Extension Manager" ) );
1122  xCmdEnv->handle( xRequest );
1123 }
1124 
1125 } //namespace dp_gui
1126 
1127 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
The modal “Download and Installation” dialog.
virtual void updateProgress(const OUString &rText, const css::uno::Reference< css::task::XAbortChannel > &xAbortChannel)=0
bool hasValue()
OUString m_sExtensionURL
void _removeExtension(::rtl::Reference< ProgressCmdEnv > const &rCmdEnv, const uno::Reference< deployment::XPackage > &xPackage)
virtual css::uno::Reference< css::awt::XWindow > GetXWindow()=0
bool installExtensionWarn(const OUString &rExtensionURL)
Thread(DialogHelper *pDialogHelper, TheExtensionManager *pManager, const uno::Reference< uno::XComponentContext > &rContext)
bool update()
Definition: updater.cxx:284
sal_Int64 n
OUString m_sTitle
void checkForUpdates(const std::vector< uno::Reference< deployment::XPackage > > &vExtensionList)
void notifyMenubar(bool bPrepareOnly, bool bRecheckOnly)
void syncRepositories(bool force, Reference< ucb::XCommandEnvironment > const &xCmdEnv)
Definition: dp_misc.cxx:493
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC Order compareVersions(OUString const &version1, OUString const &version2)
Definition: dp_version.cxx:41
static void createNotifyJob(bool bPrepareOnly, css::uno::Sequence< css::uno::Sequence< OUString > > const &rItemList)
void _checkForUpdates(const std::vector< uno::Reference< deployment::XPackage > > &vExtensionList)
RET_CANCEL
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)
E_CMD_TYPE m_eCmdType
NONE
virtual void showProgress(bool bStart)=0
Any SAL_CALL getCaughtException()
size_t pos
std::vector< uno::Reference< deployment::XPackage > > m_vExtensionList
bool getPropertyValue(ValueType &rValue, css::uno::Reference< css::beans::XPropertySet > const &xPropSet, OUString const &propName)
void removeExtension(const uno::Reference< deployment::XPackage > &rPackage)
uno::Reference< task::XInteractionHandler2 > m_xHandler
STOP
sal_Int32 m_nCurrentProgress
void removeExtension(const css::uno::Reference< css::deployment::XPackage > &rPackage)
std::shared_ptr< ExtensionCmd > TExtensionCmd
if(nullptr==pCandidateA||nullptr==pCandidateB)
const char * sName
static bool IsDialogCancelEnabled()
void _acceptLicense(::rtl::Reference< ProgressCmdEnv > const &rCmdEnv, const uno::Reference< deployment::XPackage > &xPackage)
void addExtension(const OUString &rExtensionURL, const OUString &rRepository, const bool bWarnUser)
void checkForUpdates(const std::vector< css::uno::Reference< css::deployment::XPackage > > &vList)
void _enableExtension(::rtl::Reference< ProgressCmdEnv > const &rCmdEnv, const uno::Reference< deployment::XPackage > &xPackage)
int i
The modal “Check for Updates” dialog.
void acceptLicense(const uno::Reference< deployment::XPackage > &rPackage)
rtl::Reference< Thread > m_thread
void _disableExtension(::rtl::Reference< ProgressCmdEnv > const &rCmdEnv, const uno::Reference< deployment::XPackage > &xPackage)
void _insert(const TExtensionCmd &rExtCmd)
Mutex m_mutex
static void syncRepositories(const css::uno::Reference< css::uno::XComponentContext > &xContext)
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2093
void handleInteractionRequest(const uno::Reference< uno::XComponentContext > &xContext, const uno::Reference< task::XInteractionRequest > &xRequest)
ExtensionCmdQueue(DialogHelper *pDialogHelper, TheExtensionManager *pManager, const css::uno::Reference< css::uno::XComponentContext > &rContext)
Create an instance.
void stop()
This call does not block.
void acceptLicense(const css::uno::Reference< css::deployment::XPackage > &rPackage)
void TRACE(OUString const &sText)
print the text to the console in a debug build.
Definition: dp_misc.cxx:488
void enableExtension(const css::uno::Reference< css::deployment::XPackage > &rPackage, const bool bEnable)
RET_OK
uno::Reference< deployment::XPackage > m_xPackage
void enableExtension(const uno::Reference< deployment::XPackage > &rPackage, const bool bEnable)
void addExtension(const OUString &rExtensionURL, const OUString &rRepository, const bool bWarnUser)
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage)
def text(shape, st)
OUString DpResId(const char *pId)
Definition: dp_shared.hxx:37
Definition: dp_gui.h:23
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC OUString getErrorText(css::uno::Reference< css::xml::dom::XElement > const &dependency)
Obtain the (human-readable) error message of a failed dependency.
OUString m_sRepository
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC OUString getIdentifier(css::uno::Reference< css::deployment::XPackage > const &package)
Gets the identifier of a package.
DialogHelper * m_pDialogHelper
void _addExtension(::rtl::Reference< ProgressCmdEnv > const &rCmdEnv, const OUString &rPackageURL, const OUString &rRepository, const bool bWarnUser)
uno::Reference< uno::XComponentContext > m_xContext
uno::Reference< uno::XComponentContext > m_xContext
OUString anyToString(uno::Any const &value)
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo