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 #define IGNORED_UPDATES OUString("/org.openoffice.Office.ExtensionManager/ExtensionUpdateData/IgnoredUpdates")
90 #define PROPERTY_VERSION "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, OUString const & version = OUString()) 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, OUString const & 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.isEmpty())
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  uno::Sequence< OUString > aItem(2);
668 
669  UpdateDialog::Index const * p = reinterpret_cast< UpdateDialog::Index const * >(m_xUpdates->get_id(i).toInt64());
670 
671  if ( p->m_eKind == ENABLED_UPDATE )
672  {
673  dp_gui::UpdateData aUpdData = m_enabledUpdates[ p->m_nIndex ];
674  aItem[0] = dp_misc::getIdentifier( aUpdData.aInstalledPackage );
675 
676  dp_misc::DescriptionInfoset aInfoset( m_context, aUpdData.aUpdateInfo );
677  aItem[1] = aInfoset.getVersion();
678  }
679  else
680  continue;
681 
682  aItemList.realloc( nCount + 1 );
683  aItemList[ nCount ] = aItem;
684  nCount += 1;
685  }
686  }
687 
688  createNotifyJob( bPrepareOnly, aItemList );
689 }
690 
691 // *********************************************************************************
692 
693 void UpdateDialog::initDescription()
694 {
695  m_xPublisherLabel->hide();
696  m_xPublisherLink->hide();
697  m_xReleaseNotesLabel->hide();
698  m_xReleaseNotesLink->hide();
699 }
700 
701 void UpdateDialog::clearDescription()
702 {
703  m_xPublisherLabel->hide();
704  m_xPublisherLink->hide();
705  m_xPublisherLink->set_label("");
706  m_xPublisherLink->set_uri("");
707  m_xReleaseNotesLabel->hide();
708  m_xReleaseNotesLink->hide();
709  m_xReleaseNotesLink->set_uri( "" );
710  m_xDescriptions->set_text("");
711 }
712 
713 bool UpdateDialog::showDescription(uno::Reference< xml::dom::XNode > const & aUpdateInfo)
714 {
715  dp_misc::DescriptionInfoset infoset(m_context, aUpdateInfo);
716  return showDescription(infoset.getLocalizedPublisherNameAndURL(),
717  infoset.getLocalizedReleaseNotesURL());
718 }
719 
720 bool UpdateDialog::showDescription(uno::Reference< deployment::XPackage > const & aExtension)
721 {
722  OSL_ASSERT(aExtension.is());
723  beans::StringPair pubInfo = aExtension->getPublisherInfo();
724  return showDescription(std::make_pair(pubInfo.First, pubInfo.Second),
725  "");
726 }
727 
728 bool UpdateDialog::showDescription(std::pair< OUString, OUString > const & pairPublisher,
729  OUString const & sReleaseNotes)
730 {
731  OUString sPub = pairPublisher.first;
732  OUString sURL = pairPublisher.second;
733 
734  if ( sPub.isEmpty() && sURL.isEmpty() && sReleaseNotes.isEmpty() )
735  // nothing to show
736  return false;
737 
738  if ( !sPub.isEmpty() )
739  {
740  m_xPublisherLabel->show();
741  m_xPublisherLink->show();
742  m_xPublisherLink->set_label(sPub);
743  m_xPublisherLink->set_uri(sURL);
744  }
745 
746  if ( !sReleaseNotes.isEmpty() )
747  {
748  m_xReleaseNotesLabel->show();
749  m_xReleaseNotesLink->show();
750  m_xReleaseNotesLink->set_uri( sReleaseNotes );
751  }
752  return true;
753 }
754 
755 bool UpdateDialog::showDescription( const OUString& rDescription)
756 {
757  if ( rDescription.isEmpty() )
758  // nothing to show
759  return false;
760 
761  m_xDescriptions->set_text(rDescription);
762  return true;
763 }
764 
765 void UpdateDialog::getIgnoredUpdates()
766 {
767  uno::Reference< lang::XMultiServiceFactory > xConfig(
768  configuration::theDefaultProvider::get(m_context));
769  beans::NamedValue aValue( "nodepath", uno::Any( IGNORED_UPDATES ) );
770  uno::Sequence< uno::Any > args(1);
771  args[0] <<= aValue;
772 
773  uno::Reference< container::XNameAccess > xNameAccess( xConfig->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", args), uno::UNO_QUERY_THROW );
774  const uno::Sequence< OUString > aElementNames = xNameAccess->getElementNames();
775 
776  for ( OUString const & aIdentifier : aElementNames )
777  {
778  OUString aVersion;
779 
780  uno::Any aPropValue( uno::Reference< beans::XPropertySet >( xNameAccess->getByName( aIdentifier ), uno::UNO_QUERY_THROW )->getPropertyValue( PROPERTY_VERSION ) );
781  aPropValue >>= aVersion;
782  IgnoredUpdate *pData = new IgnoredUpdate( aIdentifier, aVersion );
783  m_ignoredUpdates.emplace_back( pData );
784  }
785 }
786 
787 
788 bool UpdateDialog::isIgnoredUpdate( UpdateDialog::Index * index )
789 {
790  bool bIsIgnored = false;
791 
792  if (! m_ignoredUpdates.empty() )
793  {
794  OUString aExtensionID;
795  OUString aVersion;
796 
797  if ( index->m_eKind == ENABLED_UPDATE )
798  {
799  dp_gui::UpdateData aUpdData = m_enabledUpdates[ index->m_nIndex ];
800  aExtensionID = dp_misc::getIdentifier( aUpdData.aInstalledPackage );
801  aVersion = aUpdData.updateVersion;
802  }
803  else if ( index->m_eKind == DISABLED_UPDATE )
804  {
805  DisabledUpdate &rData = m_disabledUpdates[ index->m_nIndex ];
806  dp_misc::DescriptionInfoset aInfoset( m_context, rData.aUpdateInfo );
807  ::std::optional< OUString > aID( aInfoset.getIdentifier() );
808  if ( aID )
809  aExtensionID = *aID;
810  aVersion = aInfoset.getVersion();
811  }
812 
813  for (auto const& ignoredUpdate : m_ignoredUpdates)
814  {
815  if ( ignoredUpdate->sExtensionID == aExtensionID )
816  {
817  if ( ( !ignoredUpdate->sVersion.isEmpty() ) || ( ignoredUpdate->sVersion == aVersion ) )
818  {
819  bIsIgnored = true;
820  index->m_bIgnored = true;
821  }
822  break;
823  }
824  }
825  }
826 
827  return bIsIgnored;
828 }
829 
830 
831 IMPL_LINK_NOARG(UpdateDialog, selectionHandler, weld::TreeView&, void)
832 {
833  OUStringBuffer b;
834  int nSelectedPos = m_xUpdates->get_selected_index();
835  clearDescription();
836 
837  const UpdateDialog::Index* p = nullptr;
838  if (nSelectedPos != -1)
839  p = reinterpret_cast<UpdateDialog::Index const *>(m_xUpdates->get_id(nSelectedPos).toInt64());
840  if (p != nullptr)
841  {
842  sal_uInt16 pos = p->m_nIndex;
843 
844  switch (p->m_eKind)
845  {
846  case ENABLED_UPDATE:
847  {
848  if ( m_enabledUpdates[ pos ].aUpdateSource.is() )
849  showDescription( m_enabledUpdates[ pos ].aUpdateSource );
850  else
851  showDescription( m_enabledUpdates[ pos ].aUpdateInfo );
852 
853  if ( p->m_bIgnored )
854  b.append( m_ignoredUpdate );
855 
856  break;
857  }
858  case DISABLED_UPDATE:
859  {
860  if ( !m_disabledUpdates.empty() )
861  showDescription( m_disabledUpdates[pos].aUpdateInfo );
862 
863  if ( p->m_bIgnored )
864  b.append( m_ignoredUpdate );
865 
866  if ( m_disabledUpdates.empty() )
867  break;
868 
869  UpdateDialog::DisabledUpdate & data = m_disabledUpdates[ pos ];
870  if (data.unsatisfiedDependencies.hasElements())
871  {
872  // create error string for version mismatch
873  OUString sVersion( "%VERSION" );
874  OUString sProductName( "%PRODUCTNAME" );
875  sal_Int32 nPos = m_noDependencyCurVer.indexOf( sVersion );
876  if ( nPos >= 0 )
877  {
878  m_noDependencyCurVer = m_noDependencyCurVer.replaceAt( nPos, sVersion.getLength(), utl::ConfigManager::getAboutBoxProductVersion() );
879  }
880  nPos = m_noDependencyCurVer.indexOf( sProductName );
881  if ( nPos >= 0 )
882  {
883  m_noDependencyCurVer = m_noDependencyCurVer.replaceAt( nPos, sProductName.getLength(), utl::ConfigManager::getProductName() );
884  }
885  nPos = m_noDependency.indexOf( sProductName );
886  if ( nPos >= 0 )
887  {
888  m_noDependency = m_noDependency.replaceAt( nPos, sProductName.getLength(), utl::ConfigManager::getProductName() );
889  }
890 
891  b.append(m_noInstall);
892  b.append(LF);
893  b.append(m_noDependency);
894  for (sal_Int32 i = 0;
895  i < data.unsatisfiedDependencies.getLength(); ++i)
896  {
897  b.append(LF);
898  b.append(" ");
899  // U+2003 EM SPACE would be better than two spaces,
900  // but some fonts do not contain it
901  b.append(
902  confineToParagraph(
903  data.unsatisfiedDependencies[i]));
904  }
905  b.append(LF);
906  b.append(" ");
907  b.append(m_noDependencyCurVer);
908  }
909  break;
910  }
911  case SPECIFIC_ERROR:
912  {
913  UpdateDialog::SpecificError & data = m_specificErrors[ pos ];
914  b.append(m_failure);
915  b.append(LF);
916  b.append( data.message.isEmpty() ? m_unknownError : data.message );
917  break;
918  }
919  default:
920  OSL_ASSERT(false);
921  break;
922  }
923  }
924 
925  if ( b.isEmpty() )
926  b.append( m_noDescription );
927 
928  showDescription( b.makeStringAndClear() );
929 }
930 
932 {
933  if (m_xAll->get_active())
934  {
935  m_xUpdate->set_sensitive(true);
936  m_xUpdates->set_sensitive(true);
937  m_xDescription->set_sensitive(true);
938  m_xDescriptions->set_sensitive(true);
939 
940  for (auto const& listboxEntry : m_ListboxEntries)
941  {
942  if ( listboxEntry->m_bIgnored || ( listboxEntry->m_eKind != ENABLED_UPDATE ) )
943  insertItem(listboxEntry.get(), false);
944  }
945  }
946  else
947  {
948  for (sal_uInt16 i = m_xUpdates->n_children(); i != 0 ;)
949  {
950  i -= 1;
951  UpdateDialog::Index const * p = reinterpret_cast< UpdateDialog::Index const * >( m_xUpdates->get_id(i).toInt64() );
952  if ( p->m_bIgnored || ( p->m_eKind != ENABLED_UPDATE ) )
953  {
954  m_xUpdates->remove(i);
955  }
956  }
957 
958  if (m_xUpdates->n_children() == 0)
959  {
960  clearDescription();
961  m_xUpdate->set_sensitive(false);
962  m_xUpdates->set_sensitive(false);
963  if (m_xChecking->get_visible())
964  m_xDescription->set_sensitive(false);
965  else
966  showDescription(m_noInstallable);
967  }
968  }
969 }
970 
972 {
973  //If users are going to update a shared extension then we need
974  //to warn them
975  for (auto const& enableUpdate : m_enabledUpdates)
976  {
977  OSL_ASSERT(enableUpdate.aInstalledPackage.is());
978  //If the user has no write access to the shared folder then the update
979  //for a shared extension is disable, that is it cannot be in m_enabledUpdates
980  }
981 
982 
983  for (sal_uInt16 i = 0, nCount = m_xUpdates->n_children(); i < nCount; ++i)
984  {
985  UpdateDialog::Index const * p =
986  reinterpret_cast< UpdateDialog::Index const * >(
987  m_xUpdates->get_id(i).toInt64());
988  if (p->m_eKind == ENABLED_UPDATE && m_xUpdates->get_toggle(i) == TRISTATE_TRUE) {
989  m_updateData.push_back( m_enabledUpdates[ p->m_nIndex ] );
990  }
991  }
992 
993  m_xDialog->response(RET_OK);
994 }
995 
997 {
998  m_thread->stop();
999  m_xDialog->response(RET_CANCEL);
1000 }
1001 
1002 /* 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:284
uno::Reference< uno::XComponentContext > m_context
bool office_is_running()
Definition: dp_misc.cxx:333
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)
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)
OUString getUpdateDisplayString(dp_gui::UpdateData const &data, OUString const &version=OUString()) const
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
::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
#define IGNORED_UPDATES
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2174
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:488
Reference< XDispatch > xDispatch
IgnoredUpdate(const OUString &rExtensionID, const OUString &rVersion)
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:32
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
#define PROPERTY_VERSION
OUString DpResId(const char *pId)
Definition: dp_shared.hxx:36
const char CR
Definition: dp_misc.h:31
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.