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 static sal_Unicode const LF = 0x000A;
87 static 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  std::vector<int> aWidths;
459  aWidths.push_back(m_xUpdates->get_checkbox_column_width());
460  m_xUpdates->set_column_fixed_widths(aWidths);
461 
462  OSL_ASSERT(updateData != nullptr);
463 
464  m_xExtensionManager = deployment::ExtensionManager::get( context );
465 
466  m_xUpdates->connect_changed(LINK(this, UpdateDialog, selectionHandler));
467  m_xUpdates->connect_toggled(LINK(this, UpdateDialog, entryToggled));
468  m_xAll->connect_toggled(LINK(this, UpdateDialog, allHandler));
469  m_xOk->connect_clicked(LINK(this, UpdateDialog, okHandler));
470  m_xClose->connect_clicked(LINK(this, UpdateDialog, closeHandler));
472  m_xHelp->set_sensitive(false);
473 
474  initDescription();
475  getIgnoredUpdates();
476 }
477 
478 UpdateDialog::~UpdateDialog()
479 {
480 }
481 
482 short UpdateDialog::run() {
483  m_xThrobber->start();
484  m_thread->launch();
485  short nRet = GenericDialogController::run();
486  m_thread->stop();
487  return nRet;
488 }
489 
490 IMPL_LINK(UpdateDialog, entryToggled, const row_col&, rRowCol, void)
491 {
492  int nRow = rRowCol.first;
493 
494  // error's can't be enabled
495  const UpdateDialog::Index* p = reinterpret_cast<UpdateDialog::Index const *>(m_xUpdates->get_id(rRowCol.first).toInt64());
496  if (p->m_eKind == SPECIFIC_ERROR)
497  m_xUpdates->set_toggle(nRow, TRISTATE_FALSE, 0);
498 
499  enableOk();
500 }
501 
502 void UpdateDialog::insertItem(UpdateDialog::Index *pEntry, bool bEnabledCheckBox)
503 {
504  int nEntry = m_xUpdates->n_children();
505  m_xUpdates->append();
506  m_xUpdates->set_toggle(nEntry, bEnabledCheckBox ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
507  m_xUpdates->set_text(nEntry, pEntry->m_aName, 1);
508  m_xUpdates->set_id(nEntry, OUString::number(reinterpret_cast<sal_Int64>(pEntry)));
509 }
510 
511 void UpdateDialog::addAdditional(UpdateDialog::Index * index, bool bEnabledCheckBox)
512 {
513  m_xAll->set_sensitive(true);
514  if (m_xAll->get_active())
515  {
516  insertItem(index, bEnabledCheckBox);
517  m_xUpdate->set_sensitive(true);
518  m_xUpdates->set_sensitive(true);
519  m_xDescription->set_sensitive(true);
520  m_xDescriptions->set_sensitive(true);
521  }
522 }
523 
524 void UpdateDialog::addEnabledUpdate( OUString const & name,
525  dp_gui::UpdateData const & data )
526 {
527  sal_uInt16 nIndex = sal::static_int_cast< sal_uInt16 >( m_enabledUpdates.size() );
528  UpdateDialog::Index *pEntry = new UpdateDialog::Index( ENABLED_UPDATE, nIndex, name );
529 
530  m_enabledUpdates.push_back( data );
531  m_ListboxEntries.emplace_back( pEntry );
532 
533  if (!isIgnoredUpdate(pEntry))
534  {
535  insertItem(pEntry, true);
536  }
537  else
538  addAdditional(pEntry, false);
539 
540  m_xUpdate->set_sensitive(true);
541  m_xUpdates->set_sensitive(true);
542  m_xDescription->set_sensitive(true);
543  m_xDescriptions->set_sensitive(true);
544 }
545 
546 void UpdateDialog::addDisabledUpdate( UpdateDialog::DisabledUpdate const & data )
547 {
548  sal_uInt16 nIndex = sal::static_int_cast< sal_uInt16 >( m_disabledUpdates.size() );
549  UpdateDialog::Index *pEntry = new UpdateDialog::Index( DISABLED_UPDATE, nIndex, data.name );
550 
551  m_disabledUpdates.push_back( data );
552  m_ListboxEntries.emplace_back( pEntry );
553 
554  isIgnoredUpdate( pEntry );
555  addAdditional(pEntry, false);
556 }
557 
558 void UpdateDialog::addSpecificError( UpdateDialog::SpecificError const & data )
559 {
560  sal_uInt16 nIndex = sal::static_int_cast< sal_uInt16 >( m_specificErrors.size() );
561  UpdateDialog::Index *pEntry = new UpdateDialog::Index( SPECIFIC_ERROR, nIndex, data.name );
562 
563  m_specificErrors.push_back( data );
564  m_ListboxEntries.emplace_back( pEntry );
565 
566  addAdditional(pEntry, false);
567 }
568 
569 void UpdateDialog::checkingDone() {
570  m_xChecking->hide();
571  m_xThrobber->stop();
572  m_xThrobber->hide();
573  if (m_xUpdates->n_children() == 0)
574  {
575  clearDescription();
576  m_xDescription->set_sensitive(true);
577  m_xDescriptions->set_sensitive(true);
578 
579  if ( m_disabledUpdates.empty() && m_specificErrors.empty() && m_ignoredUpdates.empty() )
580  showDescription( m_none );
581  else
582  showDescription( m_noInstallable );
583  }
584 
585  enableOk();
586 }
587 
588 void UpdateDialog::enableOk() {
589  if (!m_xChecking->get_visible()) {
590  int nChecked = 0;
591  for (int i = 0, nCount = m_xUpdates->n_children(); i < nCount; ++i) {
592  if (m_xUpdates->get_toggle(i, 0) == TRISTATE_TRUE)
593  ++nChecked;
594  }
595  m_xOk->set_sensitive(nChecked != 0);
596  }
597 }
598 
599 // *********************************************************************************
600 void UpdateDialog::createNotifyJob( bool bPrepareOnly,
601  uno::Sequence< uno::Sequence< OUString > > const &rItemList )
602 {
604  return;
605 
606  // notify update check job
607  try
608  {
609  uno::Reference< lang::XMultiServiceFactory > xConfigProvider(
610  configuration::theDefaultProvider::get(
612 
613  beans::PropertyValue aProperty;
614  aProperty.Name = "nodepath";
615  aProperty.Value <<= OUString("org.openoffice.Office.Addons/AddonUI/OfficeHelp/UpdateCheckJob");
616 
617  uno::Sequence< uno::Any > aArgumentList( 1 );
618  aArgumentList[0] <<= aProperty;
619 
620  uno::Reference< container::XNameAccess > xNameAccess(
621  xConfigProvider->createInstanceWithArguments(
622  "com.sun.star.configuration.ConfigurationAccess", aArgumentList ),
623  uno::UNO_QUERY_THROW );
624 
625  util::URL aURL;
626  xNameAccess->getByName("URL") >>= aURL.Complete;
627 
628  uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
629  uno::Reference < util::XURLTransformer > xTransformer = util::URLTransformer::create(xContext);
630 
631  xTransformer->parseStrict(aURL);
632 
633  uno::Reference < frame::XDesktop2 > xDesktop = frame::Desktop::create( xContext );
634  uno::Reference< frame::XDispatchProvider > xDispatchProvider( xDesktop->getCurrentFrame(),
635  uno::UNO_QUERY_THROW );
636  uno::Reference< frame::XDispatch > xDispatch = xDispatchProvider->queryDispatch(aURL, OUString(), 0);
637 
638  if( xDispatch.is() )
639  {
640  uno::Sequence< beans::PropertyValue > aPropList(2);
641  aProperty.Name = "updateList";
642  aProperty.Value <<= rItemList;
643  aPropList[0] = aProperty;
644  aProperty.Name = "prepareOnly";
645  aProperty.Value <<= bPrepareOnly;
646  aPropList[1] = aProperty;
647 
648  xDispatch->dispatch(aURL, aPropList );
649  }
650  }
651  catch( const uno::Exception& e )
652  {
653  dp_misc::TRACE( "Caught exception: "
654  + e.Message + "\n thread terminated.\n\n");
655  }
656 }
657 
658 // *********************************************************************************
659 void UpdateDialog::notifyMenubar( bool bPrepareOnly, bool bRecheckOnly )
660 {
662  return;
663 
664  uno::Sequence< uno::Sequence< OUString > > aItemList;
665 
666  if ( ! bRecheckOnly )
667  {
668  sal_Int32 nCount = 0;
669  for (sal_uInt16 i = 0, nItemCount = m_xUpdates->n_children(); i < nItemCount; ++i)
670  {
671  uno::Sequence< OUString > aItem(2);
672 
673  UpdateDialog::Index const * p = reinterpret_cast< UpdateDialog::Index const * >(m_xUpdates->get_id(i).toInt64());
674 
675  if ( p->m_eKind == ENABLED_UPDATE )
676  {
677  dp_gui::UpdateData aUpdData = m_enabledUpdates[ p->m_nIndex ];
678  aItem[0] = dp_misc::getIdentifier( aUpdData.aInstalledPackage );
679 
680  dp_misc::DescriptionInfoset aInfoset( m_context, aUpdData.aUpdateInfo );
681  aItem[1] = aInfoset.getVersion();
682  }
683  else
684  continue;
685 
686  aItemList.realloc( nCount + 1 );
687  aItemList[ nCount ] = aItem;
688  nCount += 1;
689  }
690  }
691 
692  createNotifyJob( bPrepareOnly, aItemList );
693 }
694 
695 // *********************************************************************************
696 
697 void UpdateDialog::initDescription()
698 {
699  m_xPublisherLabel->hide();
700  m_xPublisherLink->hide();
701  m_xReleaseNotesLabel->hide();
702  m_xReleaseNotesLink->hide();
703 }
704 
705 void UpdateDialog::clearDescription()
706 {
707  m_xPublisherLabel->hide();
708  m_xPublisherLink->hide();
709  m_xPublisherLink->set_label("");
710  m_xPublisherLink->set_uri("");
711  m_xReleaseNotesLabel->hide();
712  m_xReleaseNotesLink->hide();
713  m_xReleaseNotesLink->set_uri( "" );
714  m_xDescriptions->set_text("");
715 }
716 
717 bool UpdateDialog::showDescription(uno::Reference< xml::dom::XNode > const & aUpdateInfo)
718 {
719  dp_misc::DescriptionInfoset infoset(m_context, aUpdateInfo);
720  return showDescription(infoset.getLocalizedPublisherNameAndURL(),
721  infoset.getLocalizedReleaseNotesURL());
722 }
723 
724 bool UpdateDialog::showDescription(uno::Reference< deployment::XPackage > const & aExtension)
725 {
726  OSL_ASSERT(aExtension.is());
727  beans::StringPair pubInfo = aExtension->getPublisherInfo();
728  return showDescription(std::make_pair(pubInfo.First, pubInfo.Second),
729  "");
730 }
731 
732 bool UpdateDialog::showDescription(std::pair< OUString, OUString > const & pairPublisher,
733  OUString const & sReleaseNotes)
734 {
735  OUString sPub = pairPublisher.first;
736  OUString sURL = pairPublisher.second;
737 
738  if ( sPub.isEmpty() && sURL.isEmpty() && sReleaseNotes.isEmpty() )
739  // nothing to show
740  return false;
741 
742  if ( !sPub.isEmpty() )
743  {
744  m_xPublisherLabel->show();
745  m_xPublisherLink->show();
746  m_xPublisherLink->set_label(sPub);
747  m_xPublisherLink->set_uri(sURL);
748  }
749 
750  if ( !sReleaseNotes.isEmpty() )
751  {
752  m_xReleaseNotesLabel->show();
753  m_xReleaseNotesLink->show();
754  m_xReleaseNotesLink->set_uri( sReleaseNotes );
755  }
756  return true;
757 }
758 
759 bool UpdateDialog::showDescription( const OUString& rDescription)
760 {
761  if ( rDescription.isEmpty() )
762  // nothing to show
763  return false;
764 
765  m_xDescriptions->set_text(rDescription);
766  return true;
767 }
768 
769 void UpdateDialog::getIgnoredUpdates()
770 {
771  uno::Reference< lang::XMultiServiceFactory > xConfig(
772  configuration::theDefaultProvider::get(m_context));
773  beans::NamedValue aValue( "nodepath", uno::Any( IGNORED_UPDATES ) );
774  uno::Sequence< uno::Any > args(1);
775  args[0] <<= aValue;
776 
777  uno::Reference< container::XNameAccess > xNameAccess( xConfig->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", args), uno::UNO_QUERY_THROW );
778  uno::Sequence< OUString > aElementNames = xNameAccess->getElementNames();
779 
780  for ( sal_Int32 i = 0; i < aElementNames.getLength(); i++ )
781  {
782  OUString aIdentifier = aElementNames[i];
783  OUString aVersion;
784 
785  uno::Any aPropValue( uno::Reference< beans::XPropertySet >( xNameAccess->getByName( aIdentifier ), uno::UNO_QUERY_THROW )->getPropertyValue( PROPERTY_VERSION ) );
786  aPropValue >>= aVersion;
787  IgnoredUpdate *pData = new IgnoredUpdate( aIdentifier, aVersion );
788  m_ignoredUpdates.emplace_back( pData );
789  }
790 }
791 
792 
793 bool UpdateDialog::isIgnoredUpdate( UpdateDialog::Index * index )
794 {
795  bool bIsIgnored = false;
796 
797  if (! m_ignoredUpdates.empty() )
798  {
799  OUString aExtensionID;
800  OUString aVersion;
801 
802  if ( index->m_eKind == ENABLED_UPDATE )
803  {
804  dp_gui::UpdateData aUpdData = m_enabledUpdates[ index->m_nIndex ];
805  aExtensionID = dp_misc::getIdentifier( aUpdData.aInstalledPackage );
806  aVersion = aUpdData.updateVersion;
807  }
808  else if ( index->m_eKind == DISABLED_UPDATE )
809  {
810  DisabledUpdate &rData = m_disabledUpdates[ index->m_nIndex ];
811  dp_misc::DescriptionInfoset aInfoset( m_context, rData.aUpdateInfo );
812  ::std::optional< OUString > aID( aInfoset.getIdentifier() );
813  if ( aID )
814  aExtensionID = *aID;
815  aVersion = aInfoset.getVersion();
816  }
817 
818  for (auto const& ignoredUpdate : m_ignoredUpdates)
819  {
820  if ( ignoredUpdate->sExtensionID == aExtensionID )
821  {
822  if ( ( !ignoredUpdate->sVersion.isEmpty() ) || ( ignoredUpdate->sVersion == aVersion ) )
823  {
824  bIsIgnored = true;
825  index->m_bIgnored = true;
826  }
827  break;
828  }
829  }
830  }
831 
832  return bIsIgnored;
833 }
834 
835 
836 IMPL_LINK_NOARG(UpdateDialog, selectionHandler, weld::TreeView&, void)
837 {
838  OUStringBuffer b;
839  int nSelectedPos = m_xUpdates->get_selected_index();
840  clearDescription();
841 
842  const UpdateDialog::Index* p = nullptr;
843  if (nSelectedPos != -1)
844  p = reinterpret_cast<UpdateDialog::Index const *>(m_xUpdates->get_id(nSelectedPos).toInt64());
845  if (p != nullptr)
846  {
847  sal_uInt16 pos = p->m_nIndex;
848 
849  switch (p->m_eKind)
850  {
851  case ENABLED_UPDATE:
852  {
853  if ( m_enabledUpdates[ pos ].aUpdateSource.is() )
854  showDescription( m_enabledUpdates[ pos ].aUpdateSource );
855  else
856  showDescription( m_enabledUpdates[ pos ].aUpdateInfo );
857 
858  if ( p->m_bIgnored )
859  b.append( m_ignoredUpdate );
860 
861  break;
862  }
863  case DISABLED_UPDATE:
864  {
865  if ( !m_disabledUpdates.empty() )
866  showDescription( m_disabledUpdates[pos].aUpdateInfo );
867 
868  if ( p->m_bIgnored )
869  b.append( m_ignoredUpdate );
870 
871  if ( m_disabledUpdates.empty() )
872  break;
873 
874  UpdateDialog::DisabledUpdate & data = m_disabledUpdates[ pos ];
875  if (data.unsatisfiedDependencies.hasElements())
876  {
877  // create error string for version mismatch
878  OUString sVersion( "%VERSION" );
879  OUString sProductName( "%PRODUCTNAME" );
880  sal_Int32 nPos = m_noDependencyCurVer.indexOf( sVersion );
881  if ( nPos >= 0 )
882  {
883  m_noDependencyCurVer = m_noDependencyCurVer.replaceAt( nPos, sVersion.getLength(), utl::ConfigManager::getAboutBoxProductVersion() );
884  }
885  nPos = m_noDependencyCurVer.indexOf( sProductName );
886  if ( nPos >= 0 )
887  {
888  m_noDependencyCurVer = m_noDependencyCurVer.replaceAt( nPos, sProductName.getLength(), utl::ConfigManager::getProductName() );
889  }
890  nPos = m_noDependency.indexOf( sProductName );
891  if ( nPos >= 0 )
892  {
893  m_noDependency = m_noDependency.replaceAt( nPos, sProductName.getLength(), utl::ConfigManager::getProductName() );
894  }
895 
896  b.append(m_noInstall);
897  b.append(LF);
898  b.append(m_noDependency);
899  for (sal_Int32 i = 0;
900  i < data.unsatisfiedDependencies.getLength(); ++i)
901  {
902  b.append(LF);
903  b.append(" ");
904  // U+2003 EM SPACE would be better than two spaces,
905  // but some fonts do not contain it
906  b.append(
907  confineToParagraph(
908  data.unsatisfiedDependencies[i]));
909  }
910  b.append(LF);
911  b.append(" ");
912  b.append(m_noDependencyCurVer);
913  }
914  break;
915  }
916  case SPECIFIC_ERROR:
917  {
918  UpdateDialog::SpecificError & data = m_specificErrors[ pos ];
919  b.append(m_failure);
920  b.append(LF);
921  b.append( data.message.isEmpty() ? m_unknownError : data.message );
922  break;
923  }
924  default:
925  OSL_ASSERT(false);
926  break;
927  }
928  }
929 
930  if ( b.isEmpty() )
931  b.append( m_noDescription );
932 
933  showDescription( b.makeStringAndClear() );
934 }
935 
937 {
938  if (m_xAll->get_active())
939  {
940  m_xUpdate->set_sensitive(true);
941  m_xUpdates->set_sensitive(true);
942  m_xDescription->set_sensitive(true);
943  m_xDescriptions->set_sensitive(true);
944 
945  for (auto const& listboxEntry : m_ListboxEntries)
946  {
947  if ( listboxEntry->m_bIgnored || ( listboxEntry->m_eKind != ENABLED_UPDATE ) )
948  insertItem(listboxEntry.get(), false);
949  }
950  }
951  else
952  {
953  for (sal_uInt16 i = m_xUpdates->n_children(); i != 0 ;)
954  {
955  i -= 1;
956  UpdateDialog::Index const * p = reinterpret_cast< UpdateDialog::Index const * >( m_xUpdates->get_id(i).toInt64() );
957  if ( p->m_bIgnored || ( p->m_eKind != ENABLED_UPDATE ) )
958  {
959  m_xUpdates->remove(i);
960  }
961  }
962 
963  if (m_xUpdates->n_children() == 0)
964  {
965  clearDescription();
966  m_xUpdate->set_sensitive(false);
967  m_xUpdates->set_sensitive(false);
968  if (m_xChecking->get_visible())
969  m_xDescription->set_sensitive(false);
970  else
971  showDescription(m_noInstallable);
972  }
973  }
974 }
975 
977 {
978  //If users are going to update a shared extension then we need
979  //to warn them
980  for (auto const& enableUpdate : m_enabledUpdates)
981  {
982  OSL_ASSERT(enableUpdate.aInstalledPackage.is());
983  //If the user has no write access to the shared folder then the update
984  //for a shared extension is disable, that is it cannot be in m_enabledUpdates
985  }
986 
987 
988  for (sal_uInt16 i = 0, nCount = m_xUpdates->n_children(); i < nCount; ++i)
989  {
990  UpdateDialog::Index const * p =
991  reinterpret_cast< UpdateDialog::Index const * >(
992  m_xUpdates->get_id(i).toInt64());
993  if (p->m_eKind == ENABLED_UPDATE && m_xUpdates->get_toggle(i, 0) == TRISTATE_TRUE) {
994  m_updateData.push_back( m_enabledUpdates[ p->m_nIndex ] );
995  }
996  }
997 
998  m_xDialog->response(RET_OK);
999 }
1000 
1002 {
1003  m_thread->stop();
1004  m_xDialog->response(RET_CANCEL);
1005 }
1006 
1007 /* 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:101
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
type_info_ info
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
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
IMPL_LINK(UpdateDialog, entryToggled, const row_col &, rRowCol, void)
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:98
The modal “Check for Updates” dialog.
static OUString getAboutBoxProductVersion()
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:2095
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:95
RET_OK
const char LF
Definition: dp_misc.h:33
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:37
const char CR
Definition: dp_misc.h:32
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.