swift
updateinfocomponent.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2017 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <QDesktopServices>
7 #include <QMessageBox>
8 
9 #include "ui_updateinfocomponent.h"
10 
11 #include "config/buildconfig.h"
14 #include "gui/guiapplication.h"
16 #include "misc/logmessage.h"
18 #include "misc/stringutils.h"
19 
20 using namespace swift::config;
21 using namespace swift::core::application;
22 using namespace swift::misc;
23 using namespace swift::misc::db;
24 using namespace swift::misc::network;
25 
26 namespace swift::gui::components
27 {
28  CUpdateInfoComponent::CUpdateInfoComponent(QWidget *parent) : QFrame(parent), ui(new Ui::CUpdateInfoComponent)
29  {
30  ui->setupUi(this);
31  Q_ASSERT_X(sGui, Q_FUNC_INFO, "Need sGui");
32 
33  connect(sGui, &CGuiApplication::updateInfoAvailable, this, &CUpdateInfoComponent::changedUpdateInfo,
34  Qt::QueuedConnection);
35  connect(ui->pb_CheckForUpdates, &QPushButton::pressed, this, &CUpdateInfoComponent::requestLoadOfSetup,
36  Qt::QueuedConnection);
37  connect(ui->pb_DownloadXSwiftBus, &QPushButton::pressed, this, &CUpdateInfoComponent::downloadXSwiftBusDialog,
38  Qt::QueuedConnection);
39  connect(ui->pb_DownloadInstaller, &QPushButton::pressed, this, &CUpdateInfoComponent::downloadInstallerDialog,
40  Qt::QueuedConnection);
41 
42  // use version signal as trigger for completion
43  if (!m_updateInfo.get().isEmpty()) { this->changedUpdateInfo(); }
44  }
45 
47 
49  {
50  const CUpdateInfo info = m_updateInfo.get();
51  const CPlatform p = this->getSelectedOrDefaultPlatform();
52  const CDistribution d = this->getSelectedOrDefaultDistribution();
53  const CArtifact a =
55  return a;
56  }
57 
59  {
60  const QStringList settings = m_updateSettings.get();
61  Q_ASSERT_X(settings.size() == 2, Q_FUNC_INFO, "wrong setting");
62  const QString channel = settings.front();
63  if (channel.isEmpty()) { return false; }
64 
65  const CUpdateInfo info = m_updateInfo.get();
67  const QVersionNumber vCurrentChannelPlatform =
69  const QVersionNumber vCurrent = CBuildConfig::getVersion();
70  if (vCurrentChannelPlatform.isNull()) { return false; }
71  return (vCurrentChannelPlatform > vCurrent);
72  }
73 
75  {
76  QPointer<CUpdateInfoComponent> myself(this);
77  QTimer::singleShot(10, this, [=] {
78  if (!myself) { return; }
79  ui->pb_DownloadInstaller->click();
80  });
81  }
82 
83  void CUpdateInfoComponent::requestLoadOfSetup()
84  {
85  if (!sGui || sGui->isShuttingDown()) { return; }
87  }
88 
89  void CUpdateInfoComponent::changedUpdateInfo()
90  {
91  ui->lbl_CurrentVersionDisplay->setText(CBuildConfig::getVersionString());
92 
93  const CUpdateInfo updateInfo(m_updateInfo.get());
94  const QStringList settings = m_updateSettings.get();
95  Q_ASSERT_X(settings.size() == 2, Q_FUNC_INFO, "Settings");
96 
97  const CPlatformSet platforms = updateInfo.getArtifactsPilotClient().getPlatforms();
98  CDistributionList distributions = updateInfo.getArtifactsPilotClient().getDistributions();
99  distributions.sortByStability(Qt::DescendingOrder);
100 
101  int i = 0;
102  ui->cb_Platforms->disconnect();
103  ui->cb_Platforms->clear();
104  for (const CPlatform &platform : platforms)
105  {
106  ui->cb_Platforms->insertItem(i++, CIcon(platform.toIcon()).toPixmap(), platform.getPlatformName());
107  }
108  if (platforms.contains(settings.last())) { ui->cb_Platforms->setCurrentText(settings.last()); }
109  else if (platforms.contains(CPlatform::currentPlatform().getPlatformName()))
110  {
111  ui->cb_Platforms->setCurrentText(CPlatform::currentPlatform().getPlatformName());
112  }
113 
114  i = 0;
115  ui->cb_Channels->disconnect();
116  ui->cb_Channels->clear();
117  for (const CDistribution &distribution : distributions)
118  {
119  ui->cb_Channels->insertItem(i++, CIcon(distribution.getRestrictionIcon()).toPixmap(),
120  distribution.getChannel());
121  }
122  if (distributions.containsChannel(settings.front())) { ui->cb_Channels->setCurrentText(settings.front()); }
123 
124  this->uiSelectionChanged();
125  connect(ui->cb_Platforms, &QComboBox::currentTextChanged, this, &CUpdateInfoComponent::platformChanged,
126  Qt::QueuedConnection);
127  connect(ui->cb_Channels, &QComboBox::currentTextChanged, this, &CUpdateInfoComponent::channelChanged,
128  Qt::QueuedConnection);
129 
130  // emit via digest signal
131  m_dsDistributionAvailable.inputSignal();
132  }
133 
134  void CUpdateInfoComponent::downloadXSwiftBusDialog()
135  {
136  const QString currentXsb = ui->cb_ArtifactsXsb->currentText();
137  const QString currentSwift = ui->cb_ArtifactsPilotClient->currentText();
138 
139  if (!stringCompare(currentXsb, currentSwift, Qt::CaseInsensitive))
140  {
141  const QString msg = QStringLiteral("xswiftbus '%1' does NOT match swift version, download anyway?")
142  .arg(currentXsb, currentSwift);
143  const QMessageBox::StandardButton reply = QMessageBox::question(this, QStringLiteral("Download xswiftbus"),
144  msg, QMessageBox::Yes | QMessageBox::No);
145  if (reply != QMessageBox::Yes) { return; }
146  }
147 
148  if (!m_installXSwiftBusDialog)
149  {
150  m_installXSwiftBusDialog.reset(new CInstallXSwiftBusDialog(this));
151  m_installXSwiftBusDialog->setModal(true);
152  }
153 
154  m_installXSwiftBusDialog->setDefaultDownloadName(currentXsb);
155  m_installXSwiftBusDialog->show();
156  }
157 
158  void CUpdateInfoComponent::downloadInstallerDialog()
159  {
160  const CUpdateInfo update(m_updateInfo.get());
161  const QString currentVersion = ui->cb_ArtifactsPilotClient->currentText();
162  const QString platform = ui->cb_Platforms->currentText();
163  if (!CPlatform::isCurrentPlatform(platform))
164  {
165  const QMessageBox::StandardButton ret =
166  QMessageBox::warning(this, "Download installer",
167  QStringLiteral("The platform '%1' does not match your current platform '%2'.\n"
168  "Do you want to continue?")
169  .arg(platform, CPlatform::currentPlatform().getPlatformName()),
170  QMessageBox::Yes | QMessageBox::No);
171  if (ret != QMessageBox::Yes) { return; }
172  }
173 
174  // find artifcat
175  const CArtifact artifact =
176  update.getArtifactsPilotClient().findByMatchingPlatform(platform).findFirstByVersionOrDefault(
177  currentVersion);
178 
179  if (!m_downloadDialog)
180  {
181  m_downloadDialog.reset(new CDownloadDialog(this));
182  m_downloadDialog->setModal(true);
183  }
184 
185  const CRemoteFile rf = artifact.asRemoteFile();
186  if (rf.getUrl().isHavingHtmlSuffix()) { QDesktopServices::openUrl(rf.getUrl()); }
187  else
188  {
189  m_downloadDialog->setMode(CDownloadComponent::SwiftInstaller);
190  m_downloadDialog->setDownloadFile(artifact.asRemoteFile());
191  m_downloadDialog->showAndStartDownloading();
192  }
193  }
194 
195  void CUpdateInfoComponent::saveSettings()
196  {
197  const QString channel = this->getSelectedOrDefaultDistribution().getChannel();
198  const QString platform = this->getSelectedOrDefaultPlatform().getPlatformName();
199  const QStringList settings({ channel, platform });
200  const CStatusMessage m = m_updateSettings.setAndSave(settings);
201  if (m.isFailure()) { CLogMessage(this).preformatted(m); }
202  }
203 
204  void CUpdateInfoComponent::channelChanged() { this->uiSelectionChanged(); }
205 
206  void CUpdateInfoComponent::platformChanged() { this->uiSelectionChanged(); }
207 
208  void CUpdateInfoComponent::uiSelectionChanged()
209  {
210  const CDistribution selectedDistribution(this->getSelectedOrDefaultDistribution());
211  const CPlatform selectedPlatform(this->getSelectedOrDefaultPlatform());
212 
213  // for xswiftbus we only show public (unrestricted) ones, as the follow up dialog will only show unrestricted
214  const CUpdateInfo updateInfo(m_updateInfo.get());
215  const CArtifactList artifactsPilotClient = updateInfo.getArtifactsPilotClient().findByDistributionAndPlatform(
216  selectedDistribution, selectedPlatform, true);
217  const CArtifactList artifactsXsb =
218  updateInfo.getArtifactsXSwiftBus().findWithUnrestrictedDistributions().findByDistributionAndPlatform(
219  selectedDistribution, selectedPlatform, true);
220  const CArtifact latestPilotClient = artifactsPilotClient.getLatestArtifactOrDefault();
221 
222  const QStringList sortedPilotClientVersions = artifactsPilotClient.getSortedVersions();
223  ui->cb_ArtifactsPilotClient->clear();
224  ui->cb_ArtifactsPilotClient->insertItems(0, sortedPilotClientVersions);
225  ui->pb_DownloadInstaller->setEnabled(!artifactsPilotClient.isEmpty());
226 
227  const QStringList sortedXsbVersions = artifactsXsb.getSortedVersions();
228  ui->cb_ArtifactsXsb->clear();
229  ui->cb_ArtifactsXsb->insertItems(0, sortedXsbVersions);
230  ui->pb_DownloadXSwiftBus->setEnabled(!artifactsXsb.isEmpty());
231 
232  // save the settings as this is needed afterwards
233  this->saveSettings();
234 
236  const bool newer = this->isNewPilotClientVersionAvailable();
237  ui->lbl_StatusInfo->setText(newer ? "New version available" : "Nothing new");
238  ui->lbl_StatusInfo->setStyleSheet(newer ? "background-color: green; color: white;" :
239  "background-color: red; color: white;");
240 
241  emit this->selectionChanged();
242 
243  if (newer && latestPilotClient.isLoadedFromDb()) { emit this->newerPilotClientAvailable(latestPilotClient); }
244  }
245 
246  const CPlatform &CUpdateInfoComponent::getSelectedOrDefaultPlatform() const
247  {
248  const QStringList settings = m_updateSettings.get(); // channel / platform
249  QString p = ui->cb_Platforms->currentText();
250  if (p.isEmpty()) { p = settings.last(); }
251  if (p.isEmpty()) { p = CPlatform::currentPlatform().getPlatformName(); }
252  return CPlatform::stringToPlatformObject(p);
253  }
254 
255  CDistribution CUpdateInfoComponent::getSelectedOrDefaultDistribution() const
256  {
257  const QStringList settings = m_updateSettings.get(); // channel / platform
258  QString c = ui->cb_Channels->currentText();
259  if (c.isEmpty()) { c = settings.first(); }
260  const CUpdateInfo updateInfo(m_updateInfo.get());
261  return c.isEmpty() ? updateInfo.getDistributions().getMostStableOrDefault() :
262  updateInfo.getDistributions().findFirstByChannelOrDefault(c);
263  }
264 } // namespace swift::gui::components
void updateInfoAvailable(bool success)
Update info available (cache, web load)
bool isShuttingDown() const
Is application shutting down?
void reloadUpdateInfo()
Reload update info.
Update info (distributions, artifacts etc.)
void selectionChanged()
New platfrom or channel.
bool isNewPilotClientVersionAvailable() const
Is there a new version available?
swift::misc::db::CArtifact getLatestAvailablePilotClientArtifactForSelection() const
Is there a new version available return version, else empty string.
void newerPilotClientAvailable(const swift::misc::db::CArtifact &latestPilotClient)
A newer pilot client is available.
CStatusMessage setAndSave(const T &value, qint64 timestamp=0)
Write and save in the same step. Must be called from the thread in which the owner lives.
Definition: valuecache.h:417
T get() const
Get a copy of the current value.
Definition: valuecache.h:408
void inputSignal()
Received input signal, or manually trigger.
Value object for icons. An icon is stored in the global icon repository and identified by its index....
Definition: icon.h:39
QPixmap toPixmap() const
Corresponding pixmap.
Definition: icon.cpp:34
Class for emitting a log message.
Definition: logmessage.h:27
static void preformatted(const CStatusMessage &statusMessage)
Sends a verbatim, preformatted message to the log.
Platform (i.e.
Definition: platform.h:24
QString getPlatformName() const
Name of platform.
Definition: platform.cpp:53
Value object for a set of platforms.
Definition: platformset.h:22
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
Streamable status message, e.g.
Artifacts ("our software" products)
Definition: artifact.h:23
network::CRemoteFile asRemoteFile() const
Turn into remote file.
Definition: artifact.cpp:59
CArtifactList findByDistribution(const CDistribution &distribution, bool findMoreStableDistribution=false) const
Find by distribution.
CArtifactList findByDistributionAndPlatform(const CDistribution &distribution, const CPlatform &platform, bool findMoreStableDistributions=false) const
Find by distribution and platform.
QVersionNumber getLatestQVersion() const
Latest version.
CArtifact getLatestArtifactOrDefault() const
Latest (newest) artifact.
CArtifactList findWithUnrestrictedDistributions() const
Find artifacts with public (unrestricted) distributions.
QStringList getSortedVersions() const
All unique versions.
Distributions for channel.
Definition: distribution.h:27
const QString & getChannel() const
Version channel (Alpha, Beta, Stable ..)
Definition: distribution.h:45
Multiple distributions for different channels:
CDistribution findFirstByChannelOrDefault(const QString &channel) const
Find by channel.
void sortByStability(Qt::SortOrder order=Qt::AscendingOrder)
Stability.
Update info, i.e. artifacts and distributions.
Definition: updateinfo.h:24
const CDistributionList & getDistributions() const
Distributions (all)
Definition: updateinfo.h:64
const CArtifactList & getArtifactsPilotClient() const
Artifacts (pilot client)
Definition: updateinfo.h:44
bool isLoadedFromDb() const
Loaded from DB.
Definition: datastore.cpp:49
const CUrl & getUrl() const
Get URL.
Definition: remotefile.h:76
bool isHavingHtmlSuffix() const
Likely a HTM file?
Definition: url.cpp:170
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
High level reusable GUI components.
Definition: aboutdialog.cpp:13
Free functions in swift::misc.
SWIFT_MISC_EXPORT bool stringCompare(const QString &c1, const QString &c2, Qt::CaseSensitivity cs)
String compare.
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...
Definition: threadutils.h:30