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/PropertyValue.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/configuration/theDefaultProvider.hpp>
32 #include <com/sun/star/container/XNameAccess.hpp>
33 #include <com/sun/star/deployment/UpdateInformationProvider.hpp>
34 #include <com/sun/star/deployment/ExtensionManager.hpp>
35 #include <com/sun/star/deployment/XUpdateInformationProvider.hpp>
36 #include <com/sun/star/frame/Desktop.hpp>
37 #include <com/sun/star/frame/XDispatch.hpp>
38 #include <com/sun/star/frame/XDispatchProvider.hpp>
39 #include <com/sun/star/lang/IllegalArgumentException.hpp>
40 #include <com/sun/star/task/InteractionHandler.hpp>
41 #include <com/sun/star/ucb/CommandFailedException.hpp>
42 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
43 #include <com/sun/star/uno/Any.hxx>
44 #include <com/sun/star/uno/Exception.hpp>
45 #include <com/sun/star/uno/Reference.hxx>
46 #include <com/sun/star/uno/Sequence.hxx>
47 #include <com/sun/star/util/URL.hpp>
48 #include <com/sun/star/util/URLTransformer.hpp>
49 #include <com/sun/star/util/XURLTransformer.hpp>
50 #include <com/sun/star/xml/dom/XElement.hpp>
51 #include <osl/diagnose.h>
52 #include <rtl/ref.hxx>
53 #include <rtl/ustrbuf.hxx>
54 #include <rtl/ustring.hxx>
55 #include <sal/types.h>
56 #include <salhelper/thread.hxx>
57 #include <tools/gen.hxx>
58 #include <tools/link.hxx>
59 #include <unotools/configmgr.hxx>
60 #include <vcl/svapp.hxx>
61 
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  const 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  const std::vector< uno::Reference< deployment::XPackage > > &vExtensionList):
189  salhelper::Thread("dp_gui_updatedialog"),
190  m_context(context),
191  m_dialog(dialog),
192  m_vExtensionList(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  for (sal_Int32 i = 0; i < ds.getLength(); ++i) {
381  }
382 
383  const ::std::optional< OUString> updateWebsiteURL(infoset.getLocalizedUpdateWebsiteURL());
384 
385  out_du.name = getUpdateDisplayString(out_data, infoset.getVersion());
386 
387  if (!out_du.unsatisfiedDependencies.hasElements())
388  {
389  out_data.aUpdateInfo = updateInfo;
390  out_data.updateVersion = infoset.getVersion();
391  if (updateWebsiteURL)
392  out_data.sWebsiteURL = *updateWebsiteURL;
393  }
394 }
395 
397  UpdateDialog::DisabledUpdate const & du,
398  dp_gui::UpdateData const & data) const
399 {
400  bool ret = false;
401  if (!du.unsatisfiedDependencies.hasElements())
402  {
403  SolarMutexGuard g;
404  if (!m_stop) {
405  m_dialog.addEnabledUpdate(getUpdateDisplayString(data), data);
406  }
407  ret = !m_stop;
408  } else {
409  SolarMutexGuard g;
410  if (!m_stop) {
411  m_dialog.addDisabledUpdate(du);
412  }
413  ret = !m_stop;
414  }
415  return ret;
416 }
417 
418 // UpdateDialog ----------------------------------------------------------
419 UpdateDialog::UpdateDialog(
420  uno::Reference< uno::XComponentContext > const & context,
421  weld::Window * parent, const std::vector<uno::Reference< deployment::XPackage > > &vExtensionList,
422  std::vector< dp_gui::UpdateData > * updateData)
423  : GenericDialogController(parent, "desktop/ui/updatedialog.ui", "UpdateDialog")
424  , m_context(context)
425  , m_none(DpResId(RID_DLG_UPDATE_NONE))
426  , m_noInstallable(DpResId(RID_DLG_UPDATE_NOINSTALLABLE))
427  , m_failure(DpResId(RID_DLG_UPDATE_FAILURE))
428  , m_unknownError(DpResId(RID_DLG_UPDATE_UNKNOWNERROR))
429  , m_noDescription(DpResId(RID_DLG_UPDATE_NODESCRIPTION))
430  , m_noInstall(DpResId(RID_DLG_UPDATE_NOINSTALL))
431  , m_noDependency(DpResId(RID_DLG_UPDATE_NODEPENDENCY))
432  , m_noDependencyCurVer(DpResId(RID_DLG_UPDATE_NODEPENDENCY_CUR_VER))
433  , m_browserbased(DpResId(RID_DLG_UPDATE_BROWSERBASED))
434  , m_version(DpResId(RID_DLG_UPDATE_VERSION))
435  , m_ignoredUpdate(DpResId(RID_DLG_UPDATE_IGNORED_UPDATE))
436  , m_updateData(*updateData)
437  , m_thread(new UpdateDialog::Thread(context, *this, vExtensionList))
438  , m_xChecking(m_xBuilder->weld_label("UPDATE_CHECKING"))
439  , m_xThrobber(m_xBuilder->weld_spinner("THROBBER"))
440  , m_xUpdate(m_xBuilder->weld_label("UPDATE_LABEL"))
441  , m_xUpdates(m_xBuilder->weld_tree_view("checklist"))
442  , m_xAll(m_xBuilder->weld_check_button("UPDATE_ALL"))
443  , m_xDescription(m_xBuilder->weld_label("DESCRIPTION_LABEL"))
444  , m_xPublisherLabel(m_xBuilder->weld_label("PUBLISHER_LABEL"))
445  , m_xPublisherLink(m_xBuilder->weld_link_button("PUBLISHER_LINK"))
446  , m_xReleaseNotesLabel(m_xBuilder->weld_label("RELEASE_NOTES_LABEL"))
447  , m_xReleaseNotesLink(m_xBuilder->weld_link_button("RELEASE_NOTES_LINK"))
448  , m_xDescriptions(m_xBuilder->weld_text_view("DESCRIPTIONS"))
449  , m_xOk(m_xBuilder->weld_button("ok"))
450  , m_xClose(m_xBuilder->weld_button("close"))
451  , m_xHelp(m_xBuilder->weld_button("help"))
452 {
453  auto nWidth = m_xDescriptions->get_approximate_digit_width() * 62;
454  auto nHeight = m_xDescriptions->get_height_rows(8);
455  m_xDescriptions->set_size_request(nWidth, nHeight);
456  m_xUpdates->set_size_request(nWidth, nHeight);
457 
458  m_xUpdates->enable_toggle_buttons(weld::ColumnToggleType::Check);
459 
460  OSL_ASSERT(updateData != nullptr);
461 
462  m_xExtensionManager = deployment::ExtensionManager::get( context );
463 
464  m_xUpdates->connect_changed(LINK(this, UpdateDialog, selectionHandler));
465  m_xUpdates->connect_toggled(LINK(this, UpdateDialog, entryToggled));
466  m_xAll->connect_toggled(LINK(this, UpdateDialog, allHandler));
467  m_xOk->connect_clicked(LINK(this, UpdateDialog, okHandler));
468  m_xClose->connect_clicked(LINK(this, UpdateDialog, closeHandler));
470  m_xHelp->set_sensitive(false);
471 
472  initDescription();
473  getIgnoredUpdates();
474 }
475 
476 UpdateDialog::~UpdateDialog()
477 {
478 }
479 
480 short UpdateDialog::run() {
481  m_xThrobber->start();
482  m_thread->launch();
483  short nRet = GenericDialogController::run();
484  m_thread->stop();
485  return nRet;
486 }
487 
488 IMPL_LINK(UpdateDialog, entryToggled, const weld::TreeView::iter_col&, rRowCol, void)
489 {
490  // error's can't be enabled
491  const UpdateDialog::Index* p = reinterpret_cast<UpdateDialog::Index const *>(m_xUpdates->get_id(rRowCol.first).toInt64());
492  if (p->m_eKind == SPECIFIC_ERROR)
493  m_xUpdates->set_toggle(rRowCol.first, TRISTATE_FALSE);
494 
495  enableOk();
496 }
497 
498 void UpdateDialog::insertItem(UpdateDialog::Index *pEntry, bool bEnabledCheckBox)
499 {
500  int nEntry = m_xUpdates->n_children();
501  m_xUpdates->append();
502  m_xUpdates->set_toggle(nEntry, bEnabledCheckBox ? TRISTATE_TRUE : TRISTATE_FALSE);
503  m_xUpdates->set_text(nEntry, pEntry->m_aName, 0);
504  m_xUpdates->set_id(nEntry, OUString::number(reinterpret_cast<sal_Int64>(pEntry)));
505 }
506 
507 void UpdateDialog::addAdditional(UpdateDialog::Index * index, bool bEnabledCheckBox)
508 {
509  m_xAll->set_sensitive(true);
510  if (m_xAll->get_active())
511  {
512  insertItem(index, bEnabledCheckBox);
513  m_xUpdate->set_sensitive(true);
514  m_xUpdates->set_sensitive(true);
515  m_xDescription->set_sensitive(true);
516  m_xDescriptions->set_sensitive(true);
517  }
518 }
519 
520 void UpdateDialog::addEnabledUpdate( OUString const & name,
521  dp_gui::UpdateData const & data )
522 {
523  sal_uInt16 nIndex = sal::static_int_cast< sal_uInt16 >( m_enabledUpdates.size() );
524  UpdateDialog::Index *pEntry = new UpdateDialog::Index( ENABLED_UPDATE, nIndex, name );
525 
526  m_enabledUpdates.push_back( data );
527  m_ListboxEntries.emplace_back( pEntry );
528 
529  if (!isIgnoredUpdate(pEntry))
530  {
531  insertItem(pEntry, true);
532  }
533  else
534  addAdditional(pEntry, false);
535 
536  m_xUpdate->set_sensitive(true);
537  m_xUpdates->set_sensitive(true);
538  m_xDescription->set_sensitive(true);
539  m_xDescriptions->set_sensitive(true);
540 }
541 
542 void UpdateDialog::addDisabledUpdate( UpdateDialog::DisabledUpdate const & data )
543 {
544  sal_uInt16 nIndex = sal::static_int_cast< sal_uInt16 >( m_disabledUpdates.size() );
545  UpdateDialog::Index *pEntry = new UpdateDialog::Index( DISABLED_UPDATE, nIndex, data.name );
546 
547  m_disabledUpdates.push_back( data );
548  m_ListboxEntries.emplace_back( pEntry );
549 
550  isIgnoredUpdate( pEntry );
551  addAdditional(pEntry, false);
552 }
553 
554 void UpdateDialog::addSpecificError( UpdateDialog::SpecificError const & data )
555 {
556  sal_uInt16 nIndex = sal::static_int_cast< sal_uInt16 >( m_specificErrors.size() );
557  UpdateDialog::Index *pEntry = new UpdateDialog::Index( SPECIFIC_ERROR, nIndex, data.name );
558 
559  m_specificErrors.push_back( data );
560  m_ListboxEntries.emplace_back( pEntry );
561 
562  addAdditional(pEntry, false);
563 }
564 
565 void UpdateDialog::checkingDone() {
566  m_xChecking->hide();
567  m_xThrobber->stop();
568  m_xThrobber->hide();
569  if (m_xUpdates->n_children() == 0)
570  {
571  clearDescription();
572  m_xDescription->set_sensitive(true);
573  m_xDescriptions->set_sensitive(true);
574 
575  if ( m_disabledUpdates.empty() && m_specificErrors.empty() && m_ignoredUpdates.empty() )
576  showDescription( m_none );
577  else
578  showDescription( m_noInstallable );
579  }
580 
581  enableOk();
582 }
583 
584 void UpdateDialog::enableOk() {
585  if (!m_xChecking->get_visible()) {
586  int nChecked = 0;
587  for (int i = 0, nCount = m_xUpdates->n_children(); i < nCount; ++i) {
588  if (m_xUpdates->get_toggle(i) == TRISTATE_TRUE)
589  ++nChecked;
590  }
591  m_xOk->set_sensitive(nChecked != 0);
592  }
593 }
594 
595 // *********************************************************************************
596 void UpdateDialog::createNotifyJob( bool bPrepareOnly,
597  uno::Sequence< uno::Sequence< OUString > > const &rItemList )
598 {
600  return;
601 
602  // notify update check job
603  try
604  {
605  uno::Reference< lang::XMultiServiceFactory > xConfigProvider(
606  configuration::theDefaultProvider::get(
608 
609  beans::PropertyValue aProperty;
610  aProperty.Name = "nodepath";
611  aProperty.Value <<= OUString("org.openoffice.Office.Addons/AddonUI/OfficeHelp/UpdateCheckJob");
612 
613  uno::Sequence< uno::Any > aArgumentList( 1 );
614  aArgumentList[0] <<= aProperty;
615 
616  uno::Reference< container::XNameAccess > xNameAccess(
617  xConfigProvider->createInstanceWithArguments(
618  "com.sun.star.configuration.ConfigurationAccess", aArgumentList ),
619  uno::UNO_QUERY_THROW );
620 
621  util::URL aURL;
622  xNameAccess->getByName("URL") >>= aURL.Complete;
623 
624  uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
625  uno::Reference < util::XURLTransformer > xTransformer = util::URLTransformer::create(xContext);
626 
627  xTransformer->parseStrict(aURL);
628 
629  uno::Reference < frame::XDesktop2 > xDesktop = frame::Desktop::create( xContext );
630  uno::Reference< frame::XDispatchProvider > xDispatchProvider( xDesktop->getCurrentFrame(),
631  uno::UNO_QUERY_THROW );
632  uno::Reference< frame::XDispatch > xDispatch = xDispatchProvider->queryDispatch(aURL, OUString(), 0);
633 
634  if( xDispatch.is() )
635  {
636  uno::Sequence< beans::PropertyValue > aPropList(2);
637  aProperty.Name = "updateList";
638  aProperty.Value <<= rItemList;
639  aPropList[0] = aProperty;
640  aProperty.Name = "prepareOnly";
641  aProperty.Value <<= bPrepareOnly;
642  aPropList[1] = aProperty;
643 
644  xDispatch->dispatch(aURL, aPropList );
645  }
646  }
647  catch( const uno::Exception& e )
648  {
649  dp_misc::TRACE( "Caught exception: "
650  + e.Message + "\n thread terminated.\n\n");
651  }
652 }
653 
654 // *********************************************************************************
655 void UpdateDialog::notifyMenubar( bool bPrepareOnly, bool bRecheckOnly )
656 {
658  return;
659 
660  uno::Sequence< uno::Sequence< OUString > > aItemList;
661 
662  if ( ! bRecheckOnly )
663  {
664  sal_Int32 nCount = 0;
665  for (sal_uInt16 i = 0, nItemCount = m_xUpdates->n_children(); i < nItemCount; ++i)
666  {
667 
668  UpdateDialog::Index const * p = reinterpret_cast< UpdateDialog::Index const * >(m_xUpdates->get_id(i).toInt64());
669 
670  if ( p->m_eKind == ENABLED_UPDATE )
671  {
672  dp_gui::UpdateData aUpdData = m_enabledUpdates[ p->m_nIndex ];
673 
674  dp_misc::DescriptionInfoset aInfoset( m_context, aUpdData.aUpdateInfo );
675  uno::Sequence< OUString > aItem
676  {
678  aInfoset.getVersion()
679  };
680  aItemList.realloc( nCount + 1 );
681  aItemList[ nCount ] = aItem;
682  nCount += 1;
683  }
684  else
685  continue;
686  }
687  }
688 
689  createNotifyJob( bPrepareOnly, aItemList );
690 }
691 
692 // *********************************************************************************
693 
694 void UpdateDialog::initDescription()
695 {
696  m_xPublisherLabel->hide();
697  m_xPublisherLink->hide();
698  m_xReleaseNotesLabel->hide();
699  m_xReleaseNotesLink->hide();
700 }
701 
702 void UpdateDialog::clearDescription()
703 {
704  m_xPublisherLabel->hide();
705  m_xPublisherLink->hide();
706  m_xPublisherLink->set_label("");
707  m_xPublisherLink->set_uri("");
708  m_xReleaseNotesLabel->hide();
709  m_xReleaseNotesLink->hide();
710  m_xReleaseNotesLink->set_uri( "" );
711  m_xDescriptions->set_text("");
712 }
713 
714 bool UpdateDialog::showDescription(uno::Reference< xml::dom::XNode > const & aUpdateInfo)
715 {
716  dp_misc::DescriptionInfoset infoset(m_context, aUpdateInfo);
717  return showDescription(infoset.getLocalizedPublisherNameAndURL(),
718  infoset.getLocalizedReleaseNotesURL());
719 }
720 
721 bool UpdateDialog::showDescription(uno::Reference< deployment::XPackage > const & aExtension)
722 {
723  OSL_ASSERT(aExtension.is());
724  beans::StringPair pubInfo = aExtension->getPublisherInfo();
725  return showDescription(std::make_pair(pubInfo.First, pubInfo.Second),
726  "");
727 }
728 
729 bool UpdateDialog::showDescription(std::pair< OUString, OUString > const & pairPublisher,
730  OUString const & sReleaseNotes)
731 {
732  OUString sPub = pairPublisher.first;
733  OUString sURL = pairPublisher.second;
734 
735  if ( sPub.isEmpty() && sURL.isEmpty() && sReleaseNotes.isEmpty() )
736  // nothing to show
737  return false;
738 
739  if ( !sPub.isEmpty() )
740  {
741  m_xPublisherLabel->show();
742  m_xPublisherLink->show();
743  m_xPublisherLink->set_label(sPub);
744  m_xPublisherLink->set_uri(sURL);
745  }
746 
747  if ( !sReleaseNotes.isEmpty() )
748  {
749  m_xReleaseNotesLabel->show();
750  m_xReleaseNotesLink->show();
751  m_xReleaseNotesLink->set_uri( sReleaseNotes );
752  }
753  return true;
754 }
755 
756 bool UpdateDialog::showDescription( const OUString& rDescription)
757 {
758  if ( rDescription.isEmpty() )
759  // nothing to show
760  return false;
761 
762  m_xDescriptions->set_text(rDescription);
763  return true;
764 }
765 
766 void UpdateDialog::getIgnoredUpdates()
767 {
768  uno::Reference< lang::XMultiServiceFactory > xConfig(
769  configuration::theDefaultProvider::get(m_context));
770  beans::NamedValue aValue( "nodepath", uno::Any( OUString(IGNORED_UPDATES) ) );
771  uno::Sequence< uno::Any > args(1);
772  args[0] <<= aValue;
773 
774  uno::Reference< container::XNameAccess > xNameAccess( xConfig->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", args), uno::UNO_QUERY_THROW );
775  const uno::Sequence< OUString > aElementNames = xNameAccess->getElementNames();
776 
777  for ( OUString const & aIdentifier : aElementNames )
778  {
779  OUString aVersion;
780 
781  uno::Any aPropValue( uno::Reference< beans::XPropertySet >( xNameAccess->getByName( aIdentifier ), uno::UNO_QUERY_THROW )->getPropertyValue( PROPERTY_VERSION ) );
782  aPropValue >>= aVersion;
783  IgnoredUpdate *pData = new IgnoredUpdate( aIdentifier, aVersion );
784  m_ignoredUpdates.emplace_back( pData );
785  }
786 }
787 
788 
789 bool UpdateDialog::isIgnoredUpdate( UpdateDialog::Index * index )
790 {
791  bool bIsIgnored = false;
792 
793  if (! m_ignoredUpdates.empty() )
794  {
795  OUString aExtensionID;
796  OUString aVersion;
797 
798  if ( index->m_eKind == ENABLED_UPDATE )
799  {
800  dp_gui::UpdateData aUpdData = m_enabledUpdates[ index->m_nIndex ];
801  aExtensionID = dp_misc::getIdentifier( aUpdData.aInstalledPackage );
802  aVersion = aUpdData.updateVersion;
803  }
804  else if ( index->m_eKind == DISABLED_UPDATE )
805  {
806  DisabledUpdate &rData = m_disabledUpdates[ index->m_nIndex ];
807  dp_misc::DescriptionInfoset aInfoset( m_context, rData.aUpdateInfo );
808  ::std::optional< OUString > aID( aInfoset.getIdentifier() );
809  if ( aID )
810  aExtensionID = *aID;
811  aVersion = aInfoset.getVersion();
812  }
813 
814  for (auto const& ignoredUpdate : m_ignoredUpdates)
815  {
816  if ( ignoredUpdate->sExtensionID == aExtensionID )
817  {
818  if ( ( !ignoredUpdate->sVersion.isEmpty() ) || ( ignoredUpdate->sVersion == aVersion ) )
819  {
820  bIsIgnored = true;
821  index->m_bIgnored = true;
822  }
823  break;
824  }
825  }
826  }
827 
828  return bIsIgnored;
829 }
830 
831 
832 IMPL_LINK_NOARG(UpdateDialog, selectionHandler, weld::TreeView&, void)
833 {
834  OUStringBuffer b;
835  int nSelectedPos = m_xUpdates->get_selected_index();
836  clearDescription();
837 
838  const UpdateDialog::Index* p = nullptr;
839  if (nSelectedPos != -1)
840  p = reinterpret_cast<UpdateDialog::Index const *>(m_xUpdates->get_id(nSelectedPos).toInt64());
841  if (p != nullptr)
842  {
843  sal_uInt16 pos = p->m_nIndex;
844 
845  switch (p->m_eKind)
846  {
847  case ENABLED_UPDATE:
848  {
849  if ( m_enabledUpdates[ pos ].aUpdateSource.is() )
850  showDescription( m_enabledUpdates[ pos ].aUpdateSource );
851  else
852  showDescription( m_enabledUpdates[ pos ].aUpdateInfo );
853 
854  if ( p->m_bIgnored )
855  b.append( m_ignoredUpdate );
856 
857  break;
858  }
859  case DISABLED_UPDATE:
860  {
861  if ( !m_disabledUpdates.empty() )
862  showDescription( m_disabledUpdates[pos].aUpdateInfo );
863 
864  if ( p->m_bIgnored )
865  b.append( m_ignoredUpdate );
866 
867  if ( m_disabledUpdates.empty() )
868  break;
869 
870  UpdateDialog::DisabledUpdate & data = m_disabledUpdates[ pos ];
871  if (data.unsatisfiedDependencies.hasElements())
872  {
873  // create error string for version mismatch
874  OUString sVersion( "%VERSION" );
875  OUString sProductName( "%PRODUCTNAME" );
876  sal_Int32 nPos = m_noDependencyCurVer.indexOf( sVersion );
877  if ( nPos >= 0 )
878  {
879  m_noDependencyCurVer = m_noDependencyCurVer.replaceAt( nPos, sVersion.getLength(), utl::ConfigManager::getAboutBoxProductVersion() );
880  }
881  nPos = m_noDependencyCurVer.indexOf( sProductName );
882  if ( nPos >= 0 )
883  {
884  m_noDependencyCurVer = m_noDependencyCurVer.replaceAt( nPos, sProductName.getLength(), utl::ConfigManager::getProductName() );
885  }
886  nPos = m_noDependency.indexOf( sProductName );
887  if ( nPos >= 0 )
888  {
889  m_noDependency = m_noDependency.replaceAt( nPos, sProductName.getLength(), utl::ConfigManager::getProductName() );
890  }
891 
892  b.append(m_noInstall);
893  b.append(LF);
894  b.append(m_noDependency);
895  for (sal_Int32 i = 0;
896  i < data.unsatisfiedDependencies.getLength(); ++i)
897  {
898  b.append(LF);
899  b.append(" ");
900  // U+2003 EM SPACE would be better than two spaces,
901  // but some fonts do not contain it
902  b.append(
903  confineToParagraph(
904  data.unsatisfiedDependencies[i]));
905  }
906  b.append(LF);
907  b.append(" ");
908  b.append(m_noDependencyCurVer);
909  }
910  break;
911  }
912  case SPECIFIC_ERROR:
913  {
914  UpdateDialog::SpecificError & data = m_specificErrors[ pos ];
915  b.append(m_failure);
916  b.append(LF);
917  b.append( data.message.isEmpty() ? m_unknownError : data.message );
918  break;
919  }
920  default:
921  OSL_ASSERT(false);
922  break;
923  }
924  }
925 
926  if ( b.isEmpty() )
927  b.append( m_noDescription );
928 
929  showDescription( b.makeStringAndClear() );
930 }
931 
933 {
934  if (m_xAll->get_active())
935  {
936  m_xUpdate->set_sensitive(true);
937  m_xUpdates->set_sensitive(true);
938  m_xDescription->set_sensitive(true);
939  m_xDescriptions->set_sensitive(true);
940 
941  for (auto const& listboxEntry : m_ListboxEntries)
942  {
943  if ( listboxEntry->m_bIgnored || ( listboxEntry->m_eKind != ENABLED_UPDATE ) )
944  insertItem(listboxEntry.get(), false);
945  }
946  }
947  else
948  {
949  for (sal_uInt16 i = m_xUpdates->n_children(); i != 0 ;)
950  {
951  i -= 1;
952  UpdateDialog::Index const * p = reinterpret_cast< UpdateDialog::Index const * >( m_xUpdates->get_id(i).toInt64() );
953  if ( p->m_bIgnored || ( p->m_eKind != ENABLED_UPDATE ) )
954  {
955  m_xUpdates->remove(i);
956  }
957  }
958 
959  if (m_xUpdates->n_children() == 0)
960  {
961  clearDescription();
962  m_xUpdate->set_sensitive(false);
963  m_xUpdates->set_sensitive(false);
964  if (m_xChecking->get_visible())
965  m_xDescription->set_sensitive(false);
966  else
967  showDescription(m_noInstallable);
968  }
969  }
970 }
971 
973 {
974  //If users are going to update a shared extension then we need
975  //to warn them
976  for (auto const& enableUpdate : m_enabledUpdates)
977  {
978  OSL_ASSERT(enableUpdate.aInstalledPackage.is());
979  //If the user has no write access to the shared folder then the update
980  //for a shared extension is disable, that is it cannot be in m_enabledUpdates
981  }
982 
983 
984  for (sal_uInt16 i = 0, nCount = m_xUpdates->n_children(); i < nCount; ++i)
985  {
986  UpdateDialog::Index const * p =
987  reinterpret_cast< UpdateDialog::Index const * >(
988  m_xUpdates->get_id(i).toInt64());
989  if (p->m_eKind == ENABLED_UPDATE && m_xUpdates->get_toggle(i) == TRISTATE_TRUE) {
990  m_updateData.push_back( m_enabledUpdates[ p->m_nIndex ] );
991  }
992  }
993 
994  m_xDialog->response(RET_OK);
995 }
996 
998 {
999  m_thread->stop();
1000  m_xDialog->response(RET_CANCEL);
1001 }
1002 
1003 /* 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
std::unique_ptr< ContentProperties > pData
bool update()
Definition: updater.cxx:286
uno::Reference< uno::XComponentContext > m_context
bool office_is_running()
Definition: dp_misc.cxx:331
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)
Thread(uno::Reference< uno::XComponentContext > const &context, UpdateDialog &dialog, const std::vector< uno::Reference< deployment::XPackage > > &vExtensionList)
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:2261
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.
void TRACE(OUString const &sText)
print the text to the console in a debug build.
Definition: dp_misc.cxx:486
Reference< XDispatch > xDispatch
IgnoredUpdate(const OUString &rExtensionID, const OUString &rVersion)
#define PROPERTY_VERSION
OUString DpResId(TranslateId aId)
Definition: dp_shared.hxx:36
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:36
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:35
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.
Access to the content of an XML description element.