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