LibreOffice Module desktop (master)  1
dp_gui_updatedialog.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 
21 #include <sal/config.h>
22 
23 #include <utility>
24 #include <vector>
25 
26 
27 #include <optional>
28 #include <com/sun/star/beans/NamedValue.hpp>
29 #include <com/sun/star/beans/XPropertySet.hpp>
30 #include <com/sun/star/configuration/theDefaultProvider.hpp>
31 #include <com/sun/star/container/XNameAccess.hpp>
32 #include <com/sun/star/deployment/UpdateInformationProvider.hpp>
33 #include <com/sun/star/deployment/ExtensionManager.hpp>
34 #include <com/sun/star/deployment/XUpdateInformationProvider.hpp>
35 #include <com/sun/star/frame/Desktop.hpp>
36 #include <com/sun/star/frame/XDispatch.hpp>
37 #include <com/sun/star/frame/XDispatchProvider.hpp>
38 #include <com/sun/star/lang/IllegalArgumentException.hpp>
39 #include <com/sun/star/task/InteractionHandler.hpp>
40 #include <com/sun/star/ucb/CommandFailedException.hpp>
41 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
42 #include <com/sun/star/uno/Any.hxx>
43 #include <com/sun/star/uno/Exception.hpp>
44 #include <com/sun/star/uno/Reference.hxx>
45 #include <com/sun/star/uno/Sequence.hxx>
46 #include <com/sun/star/util/URL.hpp>
47 #include <com/sun/star/util/URLTransformer.hpp>
48 #include <com/sun/star/util/XURLTransformer.hpp>
49 #include <com/sun/star/xml/dom/XElement.hpp>
50 #include <osl/diagnose.h>
51 #include <rtl/ref.hxx>
52 #include <rtl/ustrbuf.hxx>
53 #include <rtl/ustring.hxx>
54 #include <sal/types.h>
55 #include <salhelper/thread.hxx>
56 #include <tools/gen.hxx>
57 #include <tools/link.hxx>
58 #include <unotools/configmgr.hxx>
59 #include <vcl/svapp.hxx>
60 
63 
64 #include <dp_dependencies.hxx>
66 #include <dp_identifier.hxx>
67 #include <dp_misc.h>
68 #include <dp_update.hxx>
69 
70 #include <strings.hrc>
71 #include "dp_gui_updatedata.hxx"
72 #include "dp_gui_updatedialog.hxx"
73 #include <dp_shared.hxx>
74 
75 class KeyEvent;
76 class MouseEvent;
77 namespace com::sun::star::uno {
78  class XComponentContext;
79 }
80 
81 using namespace ::com::sun::star;
83 
84 namespace {
85 
86 sal_Unicode const LF = 0x000A;
87 sal_Unicode const CR = 0x000D;
88 
89 constexpr OUStringLiteral IGNORED_UPDATES = u"/org.openoffice.Office.ExtensionManager/ExtensionUpdateData/IgnoredUpdates";
90 constexpr OUStringLiteral PROPERTY_VERSION = u"Version";
91 
92 enum Kind { ENABLED_UPDATE, DISABLED_UPDATE, SPECIFIC_ERROR };
93 
94 OUString confineToParagraph(OUString const & text) {
95  // Confine arbitrary text to a single paragraph in a VclMultiLineEdit
96  // This assumes that U+000A and U+000D are the only paragraph separators in
97  // a VclMultiLineEdit, and that replacing them with a single space
98  // each is acceptable:
99  return text.replace(LF, ' ').replace(CR, ' ');
100 }
101 }
102 
104  OUString name;
105  uno::Sequence< OUString > unsatisfiedDependencies;
106  // We also want to show release notes and publisher for disabled updates
107  css::uno::Reference< css::xml::dom::XNode > aUpdateInfo;
108 };
109 
111  OUString name;
112  OUString message;
113 };
114 
115 
117  OUString sExtensionID;
118  OUString sVersion;
119 
120  IgnoredUpdate( const OUString &rExtensionID, const OUString &rVersion );
121 };
122 
123 
124 UpdateDialog::IgnoredUpdate::IgnoredUpdate( const OUString &rExtensionID, const OUString &rVersion ):
125  sExtensionID( rExtensionID ),
126  sVersion( rVersion )
127 {}
128 
129 
131 {
134  sal_uInt16 m_nIndex;
135  OUString m_aName;
136 
137  Index( Kind theKind, sal_uInt16 nIndex, const OUString &rName ) :
138  m_eKind( theKind ),
139  m_bIgnored( false ),
140  m_nIndex( nIndex ),
141  m_aName( rName ) {}
142 };
143 
144 
146 public:
147  Thread(
148  uno::Reference< uno::XComponentContext > const & context,
149  UpdateDialog & dialog,
150  std::vector< uno::Reference< deployment::XPackage > > && vExtensionList);
151 
152  void stop();
153 
154 private:
155  virtual ~Thread() override;
156 
157  virtual void execute() override;
158 
159  void handleSpecificError(
160  uno::Reference< deployment::XPackage > const & package,
161  uno::Any const & exception) const;
162 
163  OUString getUpdateDisplayString(
164  dp_gui::UpdateData const & data, std::u16string_view version = std::u16string_view()) const;
165 
166  void prepareUpdateData(
167  css::uno::Reference< css::xml::dom::XNode > const & updateInfo,
169  dp_gui::UpdateData & out_data) const;
170 
171  bool update(
172  UpdateDialog::DisabledUpdate const & du,
173  dp_gui::UpdateData const & data) const;
174 
175  uno::Reference< uno::XComponentContext > m_context;
177  std::vector< uno::Reference< deployment::XPackage > > m_vExtensionList;
178  uno::Reference< deployment::XUpdateInformationProvider > m_updateInformation;
179  uno::Reference< task::XInteractionHandler > m_xInteractionHdl;
180 
181  // guarded by Application::GetSolarMutex():
182  bool m_stop;
183 };
184 
186  uno::Reference< uno::XComponentContext > const & context,
187  UpdateDialog & dialog,
188  std::vector< uno::Reference< deployment::XPackage > >&& vExtensionList):
189  salhelper::Thread("dp_gui_updatedialog"),
190  m_context(context),
191  m_dialog(dialog),
192  m_vExtensionList(std::move(vExtensionList)),
193  m_updateInformation(
194  deployment::UpdateInformationProvider::create(context)),
195  m_stop(false)
196 {
197  if( m_context.is() )
198  {
200  task::InteractionHandler::createWithParent(m_context, dialog.getDialog()->GetXWindow());
201  m_updateInformation->setInteractionHandler( m_xInteractionHdl );
202  }
203 }
204 
206  {
207  SolarMutexGuard g;
208  m_stop = true;
209  }
210  m_updateInformation->cancel();
211 }
212 
214 {
215  if ( m_xInteractionHdl.is() )
216  m_updateInformation->setInteractionHandler( uno::Reference< task::XInteractionHandler > () );
217 }
218 
220 {
221  {
222  SolarMutexGuard g;
223  if ( m_stop ) {
224  return;
225  }
226  }
227  uno::Reference<deployment::XExtensionManager> extMgr =
228  deployment::ExtensionManager::get(m_context);
229 
230  std::vector<std::pair<uno::Reference<deployment::XPackage>, uno::Any > > errors;
231 
233  m_context, extMgr, m_updateInformation, &m_vExtensionList, errors);
234 
235  for (auto const& elem : errors)
236  handleSpecificError(elem.first, elem.second);
237 
238  for (auto const& updateInfo : updateInfoMap)
239  {
240  dp_misc::UpdateInfo const & info = updateInfo.second;
241  UpdateData updateData(info.extension);
242  DisabledUpdate disableUpdate;
243  //determine if online updates meet the requirements
244  prepareUpdateData(info.info, disableUpdate, updateData);
245 
246  //determine if the update is installed in the user or shared repository
247  OUString sOnlineVersion;
248  if (info.info.is())
249  sOnlineVersion = info.version;
250  OUString sVersionUser;
251  OUString sVersionShared;
252  OUString sVersionBundled;
253  uno::Sequence< uno::Reference< deployment::XPackage> > extensions;
254  try {
255  extensions = extMgr->getExtensionsWithSameIdentifier(
256  dp_misc::getIdentifier(info.extension), info.extension->getName(),
257  uno::Reference<ucb::XCommandEnvironment>());
258  } catch ( const lang::IllegalArgumentException& ) {
259  OSL_ASSERT(false);
260  continue;
261  } catch ( const css::ucb::CommandFailedException& ) {
262  OSL_ASSERT(false);
263  continue;
264  }
265  OSL_ASSERT(extensions.getLength() == 3);
266  if (extensions[0].is() )
267  sVersionUser = extensions[0]->getVersion();
268  if (extensions[1].is() )
269  sVersionShared = extensions[1]->getVersion();
270  if (extensions[2].is() )
271  sVersionBundled = extensions[2]->getVersion();
272 
273  bool bSharedReadOnly = extMgr->isReadOnlyRepository("shared");
274 
276  bSharedReadOnly, sVersionUser, sVersionShared, sVersionBundled, sOnlineVersion);
278  bSharedReadOnly, sVersionShared, sVersionBundled, sOnlineVersion);
279 
280  if (sourceUser != dp_misc::UPDATE_SOURCE_NONE)
281  {
282  if (sourceUser == dp_misc::UPDATE_SOURCE_SHARED)
283  {
284  updateData.aUpdateSource = extensions[1];
285  updateData.updateVersion = extensions[1]->getVersion();
286  }
287  else if (sourceUser == dp_misc::UPDATE_SOURCE_BUNDLED)
288  {
289  updateData.aUpdateSource = extensions[2];
290  updateData.updateVersion = extensions[2]->getVersion();
291  }
292  if (!update(disableUpdate, updateData))
293  return;
294  }
295 
296  if (sourceShared != dp_misc::UPDATE_SOURCE_NONE)
297  {
298  if (sourceShared == dp_misc::UPDATE_SOURCE_BUNDLED)
299  {
300  updateData.aUpdateSource = extensions[2];
301  updateData.updateVersion = extensions[2]->getVersion();
302  }
303  updateData.bIsShared = true;
304  if (!update(disableUpdate, updateData))
305  return;
306  }
307  }
308 
309 
310  SolarMutexGuard g;
311  if (!m_stop) {
312  m_dialog.checkingDone();
313  }
314 }
315 
316 //Parameter package can be null
318  uno::Reference< deployment::XPackage > const & package,
319  uno::Any const & exception) const
320 {
322  if (package.is())
323  data.name = package->getDisplayName();
324  uno::Exception e;
325  if (exception >>= e) {
326  data.message = e.Message;
327  }
328  SolarMutexGuard g;
329  if (!m_stop) {
330  m_dialog.addSpecificError(data);
331  }
332 }
333 
335  dp_gui::UpdateData const & data, std::u16string_view version) const
336 {
337  OSL_ASSERT(data.aInstalledPackage.is());
338  OUStringBuffer b(data.aInstalledPackage->getDisplayName());
339  b.append(' ');
340  {
341  SolarMutexGuard g;
342  if(!m_stop)
343  b.append(m_dialog.m_version);
344  }
345  b.append(' ');
346  if (!version.empty())
347  b.append(version);
348  else
349  b.append(data.updateVersion);
350 
351  if (!data.sWebsiteURL.isEmpty())
352  {
353  b.append(' ');
354  {
355  SolarMutexGuard g;
356  if(!m_stop)
357  b.append(m_dialog.m_browserbased);
358  }
359  }
360  return b.makeStringAndClear();
361 }
362 
366  uno::Reference< xml::dom::XNode > const & updateInfo,
368  dp_gui::UpdateData & out_data) const
369 {
370  if (!updateInfo.is())
371  return;
372  dp_misc::DescriptionInfoset infoset(m_context, updateInfo);
373  OSL_ASSERT(!infoset.getVersion().isEmpty());
374  uno::Sequence< uno::Reference< xml::dom::XElement > > ds(
376 
377  out_du.aUpdateInfo = updateInfo;
378  out_du.unsatisfiedDependencies.realloc(ds.getLength());
379  auto p_unsatisfiedDependencies = out_du.unsatisfiedDependencies.getArray();
380  for (sal_Int32 i = 0; i < ds.getLength(); ++i) {
381  p_unsatisfiedDependencies[i] = dp_misc::Dependencies::getErrorText(ds[i]);
382  }
383 
384  const ::std::optional< OUString> updateWebsiteURL(infoset.getLocalizedUpdateWebsiteURL());
385 
386  out_du.name = getUpdateDisplayString(out_data, infoset.getVersion());
387 
388  if (!out_du.unsatisfiedDependencies.hasElements())
389  {
390  out_data.aUpdateInfo = updateInfo;
391  out_data.updateVersion = infoset.getVersion();
392  if (updateWebsiteURL)
393  out_data.sWebsiteURL = *updateWebsiteURL;
394  }
395 }
396 
398  UpdateDialog::DisabledUpdate const & du,
399  dp_gui::UpdateData const & data) const
400 {
401  bool ret = false;
402  if (!du.unsatisfiedDependencies.hasElements())
403  {
404  SolarMutexGuard g;
405  if (!m_stop) {
406  m_dialog.addEnabledUpdate(getUpdateDisplayString(data), data);
407  }
408  ret = !m_stop;
409  } else {
410  SolarMutexGuard g;
411  if (!m_stop) {
412  m_dialog.addDisabledUpdate(du);
413  }
414  ret = !m_stop;
415  }
416  return ret;
417 }
418 
419 // UpdateDialog ----------------------------------------------------------
420 UpdateDialog::UpdateDialog(
421  uno::Reference< uno::XComponentContext > const & context,
422  weld::Window * parent, std::vector<uno::Reference< deployment::XPackage > > && vExtensionList,
423  std::vector< dp_gui::UpdateData > * updateData)
424  : GenericDialogController(parent, "desktop/ui/updatedialog.ui", "UpdateDialog")
425  , m_context(context)
426  , m_none(DpResId(RID_DLG_UPDATE_NONE))
427  , m_noInstallable(DpResId(RID_DLG_UPDATE_NOINSTALLABLE))
428  , m_failure(DpResId(RID_DLG_UPDATE_FAILURE))
429  , m_unknownError(DpResId(RID_DLG_UPDATE_UNKNOWNERROR))
430  , m_noDescription(DpResId(RID_DLG_UPDATE_NODESCRIPTION))
431  , m_noInstall(DpResId(RID_DLG_UPDATE_NOINSTALL))
432  , m_noDependency(DpResId(RID_DLG_UPDATE_NODEPENDENCY))
433  , m_noDependencyCurVer(DpResId(RID_DLG_UPDATE_NODEPENDENCY_CUR_VER))
434  , m_browserbased(DpResId(RID_DLG_UPDATE_BROWSERBASED))
435  , m_version(DpResId(RID_DLG_UPDATE_VERSION))
436  , m_ignoredUpdate(DpResId(RID_DLG_UPDATE_IGNORED_UPDATE))
437  , m_updateData(*updateData)
438  , m_thread(new UpdateDialog::Thread(context, *this, std::move(vExtensionList)))
439  , m_xChecking(m_xBuilder->weld_label("UPDATE_CHECKING"))
440  , m_xThrobber(m_xBuilder->weld_spinner("THROBBER"))
441  , m_xUpdate(m_xBuilder->weld_label("UPDATE_LABEL"))
442  , m_xUpdates(m_xBuilder->weld_tree_view("checklist"))
443  , m_xAll(m_xBuilder->weld_check_button("UPDATE_ALL"))
444  , m_xDescription(m_xBuilder->weld_label("DESCRIPTION_LABEL"))
445  , m_xPublisherLabel(m_xBuilder->weld_label("PUBLISHER_LABEL"))
446  , m_xPublisherLink(m_xBuilder->weld_link_button("PUBLISHER_LINK"))
447  , m_xReleaseNotesLabel(m_xBuilder->weld_label("RELEASE_NOTES_LABEL"))
448  , m_xReleaseNotesLink(m_xBuilder->weld_link_button("RELEASE_NOTES_LINK"))
449  , m_xDescriptions(m_xBuilder->weld_text_view("DESCRIPTIONS"))
450  , m_xOk(m_xBuilder->weld_button("ok"))
451  , m_xClose(m_xBuilder->weld_button("close"))
452  , m_xHelp(m_xBuilder->weld_button("help"))
453 {
454  auto nWidth = m_xDescriptions->get_approximate_digit_width() * 62;
455  auto nHeight = m_xDescriptions->get_height_rows(8);
456  m_xDescriptions->set_size_request(nWidth, nHeight);
457  m_xUpdates->set_size_request(nWidth, nHeight);
458 
459  m_xUpdates->enable_toggle_buttons(weld::ColumnToggleType::Check);
460 
461  OSL_ASSERT(updateData != nullptr);
462 
463  m_xExtensionManager = deployment::ExtensionManager::get( context );
464 
465  m_xUpdates->connect_changed(LINK(this, UpdateDialog, selectionHandler));
466  m_xUpdates->connect_toggled(LINK(this, UpdateDialog, entryToggled));
467  m_xAll->connect_toggled(LINK(this, UpdateDialog, allHandler));
468  m_xOk->connect_clicked(LINK(this, UpdateDialog, okHandler));
469  m_xClose->connect_clicked(LINK(this, UpdateDialog, closeHandler));
471  m_xHelp->set_sensitive(false);
472 
473  initDescription();
474  getIgnoredUpdates();
475 }
476 
477 UpdateDialog::~UpdateDialog()
478 {
479 }
480 
481 short UpdateDialog::run() {
482  m_xThrobber->start();
483  m_thread->launch();
484  short nRet = GenericDialogController::run();
485  m_thread->stop();
486  return nRet;
487 }
488 
489 IMPL_LINK(UpdateDialog, entryToggled, const weld::TreeView::iter_col&, rRowCol, void)
490 {
491  // error's can't be enabled
492  const UpdateDialog::Index* p = weld::fromId<UpdateDialog::Index const *>(m_xUpdates->get_id(rRowCol.first));
493  if (p->m_eKind == SPECIFIC_ERROR)
494  m_xUpdates->set_toggle(rRowCol.first, TRISTATE_FALSE);
495 
496  enableOk();
497 }
498 
499 void UpdateDialog::insertItem(const UpdateDialog::Index *pEntry, bool bEnabledCheckBox)
500 {
501  int nEntry = m_xUpdates->n_children();
502  m_xUpdates->append();
503  m_xUpdates->set_toggle(nEntry, bEnabledCheckBox ? TRISTATE_TRUE : TRISTATE_FALSE);
504  m_xUpdates->set_text(nEntry, pEntry->m_aName, 0);
505  m_xUpdates->set_id(nEntry, weld::toId(pEntry));
506 }
507 
508 void UpdateDialog::addAdditional(const UpdateDialog::Index * index, bool bEnabledCheckBox)
509 {
510  m_xAll->set_sensitive(true);
511  if (m_xAll->get_active())
512  {
513  insertItem(index, bEnabledCheckBox);
514  m_xUpdate->set_sensitive(true);
515  m_xUpdates->set_sensitive(true);
516  m_xDescription->set_sensitive(true);
517  m_xDescriptions->set_sensitive(true);
518  }
519 }
520 
521 void UpdateDialog::addEnabledUpdate( OUString const & name,
522  dp_gui::UpdateData const & data )
523 {
524  sal_uInt16 nIndex = sal::static_int_cast< sal_uInt16 >( m_enabledUpdates.size() );
525  UpdateDialog::Index *pEntry = new UpdateDialog::Index( ENABLED_UPDATE, nIndex, name );
526 
527  m_enabledUpdates.push_back( data );
528  m_ListboxEntries.emplace_back( pEntry );
529 
530  if (!isIgnoredUpdate(pEntry))
531  {
532  insertItem(pEntry, true);
533  }
534  else
535  addAdditional(pEntry, false);
536 
537  m_xUpdate->set_sensitive(true);
538  m_xUpdates->set_sensitive(true);
539  m_xDescription->set_sensitive(true);
540  m_xDescriptions->set_sensitive(true);
541 }
542 
543 void UpdateDialog::addDisabledUpdate( UpdateDialog::DisabledUpdate const & data )
544 {
545  sal_uInt16 nIndex = sal::static_int_cast< sal_uInt16 >( m_disabledUpdates.size() );
546  UpdateDialog::Index *pEntry = new UpdateDialog::Index( DISABLED_UPDATE, nIndex, data.name );
547 
548  m_disabledUpdates.push_back( data );
549  m_ListboxEntries.emplace_back( pEntry );
550 
551  isIgnoredUpdate( pEntry );
552  addAdditional(pEntry, false);
553 }
554 
555 void UpdateDialog::addSpecificError( UpdateDialog::SpecificError const & data )
556 {
557  sal_uInt16 nIndex = sal::static_int_cast< sal_uInt16 >( m_specificErrors.size() );
558  UpdateDialog::Index *pEntry = new UpdateDialog::Index( SPECIFIC_ERROR, nIndex, data.name );
559 
560  m_specificErrors.push_back( data );
561  m_ListboxEntries.emplace_back( pEntry );
562 
563  addAdditional(pEntry, false);
564 }
565 
566 void UpdateDialog::checkingDone() {
567  m_xChecking->hide();
568  m_xThrobber->stop();
569  m_xThrobber->hide();
570  if (m_xUpdates->n_children() == 0)
571  {
572  clearDescription();
573  m_xDescription->set_sensitive(true);
574  m_xDescriptions->set_sensitive(true);
575 
576  if ( m_disabledUpdates.empty() && m_specificErrors.empty() && m_ignoredUpdates.empty() )
577  showDescription( m_none );
578  else
579  showDescription( m_noInstallable );
580  }
581 
582  enableOk();
583 }
584 
585 void UpdateDialog::enableOk() {
586  if (!m_xChecking->get_visible()) {
587  int nChecked = 0;
588  for (int i = 0, nCount = m_xUpdates->n_children(); i < nCount; ++i) {
589  if (m_xUpdates->get_toggle(i) == TRISTATE_TRUE)
590  ++nChecked;
591  }
592  m_xOk->set_sensitive(nChecked != 0);
593  }
594 }
595 
596 // *********************************************************************************
597 void UpdateDialog::createNotifyJob( bool bPrepareOnly,
598  uno::Sequence< uno::Sequence< OUString > > const &rItemList )
599 {
601  return;
602 
603  // notify update check job
604  try
605  {
606  uno::Reference< lang::XMultiServiceFactory > xConfigProvider(
607  configuration::theDefaultProvider::get(
609 
610  uno::Sequence< uno::Any > aArgumentList{ uno::Any(comphelper::makePropertyValue(
611  "nodepath",
612  OUString("org.openoffice.Office.Addons/AddonUI/OfficeHelp/UpdateCheckJob"))) };
613 
614  uno::Reference< container::XNameAccess > xNameAccess(
615  xConfigProvider->createInstanceWithArguments(
616  "com.sun.star.configuration.ConfigurationAccess", aArgumentList ),
617  uno::UNO_QUERY_THROW );
618 
619  util::URL aURL;
620  xNameAccess->getByName("URL") >>= aURL.Complete;
621 
622  uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
623  uno::Reference < util::XURLTransformer > xTransformer = util::URLTransformer::create(xContext);
624 
625  xTransformer->parseStrict(aURL);
626 
627  uno::Reference < frame::XDesktop2 > xDesktop = frame::Desktop::create( xContext );
628  uno::Reference< frame::XDispatchProvider > xDispatchProvider( xDesktop->getCurrentFrame(),
629  uno::UNO_QUERY_THROW );
630  uno::Reference< frame::XDispatch > xDispatch = xDispatchProvider->queryDispatch(aURL, OUString(), 0);
631 
632  if( xDispatch.is() )
633  {
634  uno::Sequence aPropList{ comphelper::makePropertyValue("updateList", rItemList),
635  comphelper::makePropertyValue("prepareOnly", bPrepareOnly) };
636 
637  xDispatch->dispatch(aURL, aPropList );
638  }
639  }
640  catch( const uno::Exception& e )
641  {
642  dp_misc::TRACE( "Caught exception: "
643  + e.Message + "\n thread terminated.\n\n");
644  }
645 }
646 
647 // *********************************************************************************
648 void UpdateDialog::notifyMenubar( bool bPrepareOnly, bool bRecheckOnly )
649 {
651  return;
652 
653  uno::Sequence< uno::Sequence< OUString > > aItemList;
654 
655  if ( ! bRecheckOnly )
656  {
657  sal_Int32 nCount = 0;
658  for (sal_uInt16 i = 0, nItemCount = m_xUpdates->n_children(); i < nItemCount; ++i)
659  {
660 
661  UpdateDialog::Index const * p = weld::fromId<UpdateDialog::Index const*>(m_xUpdates->get_id(i));
662 
663  if ( p->m_eKind == ENABLED_UPDATE )
664  {
665  dp_gui::UpdateData aUpdData = m_enabledUpdates[ p->m_nIndex ];
666 
667  dp_misc::DescriptionInfoset aInfoset( m_context, aUpdData.aUpdateInfo );
668  uno::Sequence< OUString > aItem
669  {
671  aInfoset.getVersion()
672  };
673  aItemList.realloc( nCount + 1 );
674  aItemList.getArray()[ nCount ] = aItem;
675  nCount += 1;
676  }
677  else
678  continue;
679  }
680  }
681 
682  createNotifyJob( bPrepareOnly, aItemList );
683 }
684 
685 // *********************************************************************************
686 
687 void UpdateDialog::initDescription()
688 {
689  m_xPublisherLabel->hide();
690  m_xPublisherLink->hide();
691  m_xReleaseNotesLabel->hide();
692  m_xReleaseNotesLink->hide();
693 }
694 
695 void UpdateDialog::clearDescription()
696 {
697  m_xPublisherLabel->hide();
698  m_xPublisherLink->hide();
699  m_xPublisherLink->set_label("");
700  m_xPublisherLink->set_uri("");
701  m_xReleaseNotesLabel->hide();
702  m_xReleaseNotesLink->hide();
703  m_xReleaseNotesLink->set_uri( "" );
704  m_xDescriptions->set_text("");
705 }
706 
707 bool UpdateDialog::showDescription(uno::Reference< xml::dom::XNode > const & aUpdateInfo)
708 {
709  dp_misc::DescriptionInfoset infoset(m_context, aUpdateInfo);
710  return showDescription(infoset.getLocalizedPublisherNameAndURL(),
711  infoset.getLocalizedReleaseNotesURL());
712 }
713 
714 bool UpdateDialog::showDescription(uno::Reference< deployment::XPackage > const & aExtension)
715 {
716  OSL_ASSERT(aExtension.is());
717  beans::StringPair pubInfo = aExtension->getPublisherInfo();
718  return showDescription(std::make_pair(pubInfo.First, pubInfo.Second),
719  "");
720 }
721 
722 bool UpdateDialog::showDescription(std::pair< OUString, OUString > const & pairPublisher,
723  OUString const & sReleaseNotes)
724 {
725  OUString sPub = pairPublisher.first;
726  OUString sURL = pairPublisher.second;
727 
728  if ( sPub.isEmpty() && sURL.isEmpty() && sReleaseNotes.isEmpty() )
729  // nothing to show
730  return false;
731 
732  if ( !sPub.isEmpty() )
733  {
734  m_xPublisherLabel->show();
735  m_xPublisherLink->show();
736  m_xPublisherLink->set_label(sPub);
737  m_xPublisherLink->set_uri(sURL);
738  }
739 
740  if ( !sReleaseNotes.isEmpty() )
741  {
742  m_xReleaseNotesLabel->show();
743  m_xReleaseNotesLink->show();
744  m_xReleaseNotesLink->set_uri( sReleaseNotes );
745  }
746  return true;
747 }
748 
749 bool UpdateDialog::showDescription( const OUString& rDescription)
750 {
751  if ( rDescription.isEmpty() )
752  // nothing to show
753  return false;
754 
755  m_xDescriptions->set_text(rDescription);
756  return true;
757 }
758 
759 void UpdateDialog::getIgnoredUpdates()
760 {
761  uno::Reference< lang::XMultiServiceFactory > xConfig(
762  configuration::theDefaultProvider::get(m_context));
763  beans::NamedValue aValue( "nodepath", uno::Any( OUString(IGNORED_UPDATES) ) );
764  uno::Sequence< uno::Any > args{ uno::Any(aValue) };
765 
766  uno::Reference< container::XNameAccess > xNameAccess( xConfig->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", args), uno::UNO_QUERY_THROW );
767  const uno::Sequence< OUString > aElementNames = xNameAccess->getElementNames();
768 
769  for ( OUString const & aIdentifier : aElementNames )
770  {
771  OUString aVersion;
772 
773  uno::Any aPropValue( uno::Reference< beans::XPropertySet >( xNameAccess->getByName( aIdentifier ), uno::UNO_QUERY_THROW )->getPropertyValue( PROPERTY_VERSION ) );
774  aPropValue >>= aVersion;
775  IgnoredUpdate *pData = new IgnoredUpdate( aIdentifier, aVersion );
776  m_ignoredUpdates.emplace_back( pData );
777  }
778 }
779 
780 
781 bool UpdateDialog::isIgnoredUpdate( UpdateDialog::Index * index )
782 {
783  bool bIsIgnored = false;
784 
785  if (! m_ignoredUpdates.empty() )
786  {
787  OUString aExtensionID;
788  OUString aVersion;
789 
790  if ( index->m_eKind == ENABLED_UPDATE )
791  {
792  dp_gui::UpdateData aUpdData = m_enabledUpdates[ index->m_nIndex ];
793  aExtensionID = dp_misc::getIdentifier( aUpdData.aInstalledPackage );
794  aVersion = aUpdData.updateVersion;
795  }
796  else if ( index->m_eKind == DISABLED_UPDATE )
797  {
798  DisabledUpdate &rData = m_disabledUpdates[ index->m_nIndex ];
799  dp_misc::DescriptionInfoset aInfoset( m_context, rData.aUpdateInfo );
800  ::std::optional< OUString > aID( aInfoset.getIdentifier() );
801  if ( aID )
802  aExtensionID = *aID;
803  aVersion = aInfoset.getVersion();
804  }
805 
806  for (auto const& ignoredUpdate : m_ignoredUpdates)
807  {
808  if ( ignoredUpdate->sExtensionID == aExtensionID )
809  {
810  if ( ( !ignoredUpdate->sVersion.isEmpty() ) || ( ignoredUpdate->sVersion == aVersion ) )
811  {
812  bIsIgnored = true;
813  index->m_bIgnored = true;
814  }
815  break;
816  }
817  }
818  }
819 
820  return bIsIgnored;
821 }
822 
823 
824 IMPL_LINK_NOARG(UpdateDialog, selectionHandler, weld::TreeView&, void)
825 {
826  OUStringBuffer b;
827  int nSelectedPos = m_xUpdates->get_selected_index();
828  clearDescription();
829 
830  const UpdateDialog::Index* p = nullptr;
831  if (nSelectedPos != -1)
832  p = weld::fromId<UpdateDialog::Index const*>(m_xUpdates->get_id(nSelectedPos));
833  if (p != nullptr)
834  {
835  sal_uInt16 pos = p->m_nIndex;
836 
837  switch (p->m_eKind)
838  {
839  case ENABLED_UPDATE:
840  {
841  if ( m_enabledUpdates[ pos ].aUpdateSource.is() )
842  showDescription( m_enabledUpdates[ pos ].aUpdateSource );
843  else
844  showDescription( m_enabledUpdates[ pos ].aUpdateInfo );
845 
846  if ( p->m_bIgnored )
847  b.append( m_ignoredUpdate );
848 
849  break;
850  }
851  case DISABLED_UPDATE:
852  {
853  if ( !m_disabledUpdates.empty() )
854  showDescription( m_disabledUpdates[pos].aUpdateInfo );
855 
856  if ( p->m_bIgnored )
857  b.append( m_ignoredUpdate );
858 
859  if ( m_disabledUpdates.empty() )
860  break;
861 
862  UpdateDialog::DisabledUpdate & data = m_disabledUpdates[ pos ];
863  if (data.unsatisfiedDependencies.hasElements())
864  {
865  // create error string for version mismatch
866  OUString sVersion( "%VERSION" );
867  OUString sProductName( "%PRODUCTNAME" );
868  sal_Int32 nPos = m_noDependencyCurVer.indexOf( sVersion );
869  if ( nPos >= 0 )
870  {
871  m_noDependencyCurVer = m_noDependencyCurVer.replaceAt( nPos, sVersion.getLength(), utl::ConfigManager::getAboutBoxProductVersion() );
872  }
873  nPos = m_noDependencyCurVer.indexOf( sProductName );
874  if ( nPos >= 0 )
875  {
876  m_noDependencyCurVer = m_noDependencyCurVer.replaceAt( nPos, sProductName.getLength(), utl::ConfigManager::getProductName() );
877  }
878  nPos = m_noDependency.indexOf( sProductName );
879  if ( nPos >= 0 )
880  {
881  m_noDependency = m_noDependency.replaceAt( nPos, sProductName.getLength(), utl::ConfigManager::getProductName() );
882  }
883 
884  b.append(m_noInstall);
885  b.append(LF);
886  b.append(m_noDependency);
887  for (sal_Int32 i = 0;
888  i < data.unsatisfiedDependencies.getLength(); ++i)
889  {
890  b.append(LF);
891  b.append(" ");
892  // U+2003 EM SPACE would be better than two spaces,
893  // but some fonts do not contain it
894  b.append(
895  confineToParagraph(
896  data.unsatisfiedDependencies[i]));
897  }
898  b.append(LF);
899  b.append(" ");
900  b.append(m_noDependencyCurVer);
901  }
902  break;
903  }
904  case SPECIFIC_ERROR:
905  {
906  UpdateDialog::SpecificError & data = m_specificErrors[ pos ];
907  b.append(m_failure);
908  b.append(LF);
909  b.append( data.message.isEmpty() ? m_unknownError : data.message );
910  break;
911  }
912  default:
913  OSL_ASSERT(false);
914  break;
915  }
916  }
917 
918  if ( b.isEmpty() )
919  b.append( m_noDescription );
920 
921  showDescription( b.makeStringAndClear() );
922 }
923 
925 {
926  if (m_xAll->get_active())
927  {
928  m_xUpdate->set_sensitive(true);
929  m_xUpdates->set_sensitive(true);
930  m_xDescription->set_sensitive(true);
931  m_xDescriptions->set_sensitive(true);
932 
933  for (auto const& listboxEntry : m_ListboxEntries)
934  {
935  if ( listboxEntry->m_bIgnored || ( listboxEntry->m_eKind != ENABLED_UPDATE ) )
936  insertItem(listboxEntry.get(), false);
937  }
938  }
939  else
940  {
941  for (sal_uInt16 i = m_xUpdates->n_children(); i != 0 ;)
942  {
943  i -= 1;
944  UpdateDialog::Index const * p = weld::fromId<UpdateDialog::Index const*>(m_xUpdates->get_id(i));
945  if ( p->m_bIgnored || ( p->m_eKind != ENABLED_UPDATE ) )
946  {
947  m_xUpdates->remove(i);
948  }
949  }
950 
951  if (m_xUpdates->n_children() == 0)
952  {
953  clearDescription();
954  m_xUpdate->set_sensitive(false);
955  m_xUpdates->set_sensitive(false);
956  if (m_xChecking->get_visible())
957  m_xDescription->set_sensitive(false);
958  else
959  showDescription(m_noInstallable);
960  }
961  }
962 }
963 
965 {
966  //If users are going to update a shared extension then we need
967  //to warn them
968  for (auto const& enableUpdate : m_enabledUpdates)
969  {
970  OSL_ASSERT(enableUpdate.aInstalledPackage.is());
971  //If the user has no write access to the shared folder then the update
972  //for a shared extension is disable, that is it cannot be in m_enabledUpdates
973  }
974 
975 
976  for (sal_uInt16 i = 0, nCount = m_xUpdates->n_children(); i < nCount; ++i)
977  {
978  UpdateDialog::Index const * p =
979  weld::fromId<UpdateDialog::Index const*>(m_xUpdates->get_id(i));
980  if (p->m_eKind == ENABLED_UPDATE && m_xUpdates->get_toggle(i) == TRISTATE_TRUE) {
981  m_updateData.push_back( m_enabledUpdates[ p->m_nIndex ] );
982  }
983  }
984 
985  m_xDialog->response(RET_OK);
986 }
987 
989 {
990  m_thread->stop();
991  m_xDialog->response(RET_CANCEL);
992 }
993 
994 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
uno::Reference< task::XInteractionHandler > m_xInteractionHdl
css::uno::Reference< css::deployment::XPackage > aInstalledPackage
css::uno::Reference< css::xml::dom::XNode > aUpdateInfo
std::map< OUString, UpdateInfo > UpdateInfoMap
Definition: dp_update.hxx:100
URL aURL
sal_Int32 nIndex
virtual css::uno::Reference< css::awt::XWindow > GetXWindow()=0
void prepareUpdateData(css::uno::Reference< css::xml::dom::XNode > const &updateInfo, UpdateDialog::DisabledUpdate &out_du, dp_gui::UpdateData &out_data) const
out_data will only be filled if all dependencies are ok.
uno::Reference< deployment::XUpdateInformationProvider > m_updateInformation
css::uno::Reference< css::xml::dom::XNode > aUpdateInfo
bool update()
Definition: updater.cxx:286
std::unique_ptr< sal_Int32[]> pData
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
uno::Reference< uno::XComponentContext > m_context
bool office_is_running()
Definition: dp_misc.cxx:332
tuple args
const ContentProperties & rData
virtual Dialog * getDialog() override
TRISTATE_TRUE
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)
OUString getVersion() const
Return the textual version representation.
sal_uInt16 sal_Unicode
IMPL_LINK_NOARG(UpdateDialog, selectionHandler, weld::TreeView &, void)
OUString getUpdateDisplayString(dp_gui::UpdateData const &data, std::u16string_view version=std::u16string_view()) const
size_t pos
std::vector< uno::Reference< deployment::XPackage > > m_vExtensionList
std::pair< const TreeIter &, int > iter_col
bool getPropertyValue(ValueType &rValue, css::uno::Reference< css::beans::XPropertySet > const &xPropSet, OUString const &propName)
int nCount
std::vector< uno::Reference< deployment::XPackage > > m_vExtensionList
void handleSpecificError(uno::Reference< deployment::XPackage > const &package, uno::Any const &exception) const
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC UPDATE_SOURCE isUpdateSharedExtension(bool bReadOnlyShared, OUString const &sharedVersion, OUString const &bundledVersion, OUString const &onlineVersion)
Definition: dp_update.cxx:284
int i
static OUString getProductName()
TRISTATE_FALSE
float u
::std::optional< OUString > getIdentifier() const
Return the identifier.
css::uno::Reference< css::xml::dom::XNode > info
Definition: dp_update.hxx:97
The modal “Check for Updates” dialog.
static OUString getAboutBoxProductVersion()
exports com.sun.star.chart2. data
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC UPDATE_SOURCE isUpdateUserExtension(bool bReadOnlyShared, OUString const &userVersion, OUString const &sharedVersion, OUString const &bundledVersion, OUString const &onlineVersion)
Definition: dp_update.cxx:234
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2429
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC UpdateInfoMap getOnlineUpdateInfos(css::uno::Reference< css::uno::XComponentContext > const &xContext, css::uno::Reference< css::deployment::XExtensionManager > const &xExtMgr, css::uno::Reference< css::deployment::XUpdateInformationProvider > const &updateInformation, std::vector< css::uno::Reference< css::deployment::XPackage > > const *extensionList, std::vector< std::pair< css::uno::Reference< css::deployment::XPackage >, css::uno::Any > > &out_errors)
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC css::uno::Sequence< css::uno::Reference< css::xml::dom::XElement > > check(dp_misc::DescriptionInfoset const &infoset)
Check for unsatisfied dependencies.
OUString toId(const void *pValue)
void TRACE(OUString const &sText)
print the text to the console in a debug build.
Definition: dp_misc.cxx:487
Thread(uno::Reference< uno::XComponentContext > const &context, UpdateDialog &dialog, std::vector< uno::Reference< deployment::XPackage > > &&vExtensionList)
Reference< XDispatch > xDispatch
IgnoredUpdate(const OUString &rExtensionID, const OUString &rVersion)
#define PROPERTY_VERSION
css::uno::Reference< css::deployment::XPackage > extension
Definition: dp_update.hxx:94
RET_OK
IMPL_LINK(UpdateDialog, entryToggled, const weld::TreeView::iter_col &, rRowCol, void)
const char LF
Definition: dp_misc.h:35
Reference< XExecutableDialog > m_xDialog
void * p
Reference< XComponentContext > getProcessComponentContext()
virtual void execute() override
bool update(UpdateDialog::DisabledUpdate const &du, dp_gui::UpdateData const &data) const
const char CR
Definition: dp_misc.h:34
OUString DpResId(TranslateId aId)
Definition: dp_misc.cxx:554
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC OUString getErrorText(css::uno::Reference< css::xml::dom::XElement > const &dependency)
Obtain the (human-readable) error message of a failed dependency.
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC OUString getIdentifier(css::uno::Reference< css::deployment::XPackage > const &package)
Gets the identifier of a package.
Index(Kind theKind, sal_uInt16 nIndex, const OUString &rName)
uno::Sequence< OUString > unsatisfiedDependencies
sal_uInt16 nPos
::std::optional< OUString > getLocalizedUpdateWebsiteURL() const
returns the download website URL from the update information.
bool m_bDetectedRangeSegmentation false
Access to the content of an XML description element.