ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
Updater.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include <QJsonValue>
9 #include <QJsonObject>
10 #include <QMessageBox>
11 #include <QApplication>
12 #include <QJsonDocument>
13 #include <QDesktopServices>
14 
15 #include <CVLog.h>
16 
19 
21 {
22  m_url = "";
23  m_openUrl = "";
24  m_changelog = "";
25  m_downloadUrl = "";
26  m_latestVersion = "";
27  m_customAppcast = false;
28  m_notifyOnUpdate = true;
29  m_notifyOnFinish = false;
30  m_updateAvailable = false;
31  m_downloaderEnabled = true;
32  m_moduleName = qApp->applicationName();
33  m_moduleVersion = qApp->applicationVersion();
34  m_mandatoryUpdate = false;
35 
36  m_downloader = new Downloader();
37  m_manager = new QNetworkAccessManager();
38 
39 #if defined Q_OS_WIN
40  m_platform = "windows";
41 #elif defined Q_OS_MAC
42  m_platform = "osx";
43 #elif defined Q_OS_LINUX
44  m_platform = "linux";
45 #elif defined Q_OS_ANDROID
46  m_platform = "android";
47 #elif defined Q_OS_IOS
48  m_platform = "ios";
49 #endif
50 
51  setUserAgentString(QString("%1/%2 (Qt; QSimpleUpdater)").arg(qApp->applicationName(), qApp->applicationVersion()));
52 
53  connect(m_downloader, SIGNAL(downloadFinished(QString, QString)), this, SIGNAL(downloadFinished(QString, QString)));
54  connect(m_manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onReply(QNetworkReply *)));
55 }
56 
58 {
59  delete m_downloader;
60 }
61 
65 QString Updater::url() const
66 {
67  return m_url;
68 }
69 
76 QString Updater::openUrl() const
77 {
78  return m_openUrl;
79 }
80 
85 QString Updater::changelog() const
86 {
87  return m_changelog;
88 }
89 
93 QString Updater::moduleName() const
94 {
95  return m_moduleName;
96 }
97 
108 QString Updater::platformKey() const
109 {
110  return m_platform;
111 }
112 
117 QString Updater::downloadUrl() const
118 {
119  return m_downloadUrl;
120 }
121 
126 QString Updater::latestVersion() const
127 {
128  return m_latestVersion;
129 }
130 
136 {
137  return m_userAgentString;
138 }
139 
143 QString Updater::moduleVersion() const
144 {
145  return m_moduleVersion;
146 }
147 
154 {
155  return m_customAppcast;
156 }
157 
163 {
164  return m_notifyOnUpdate;
165 }
166 
175 {
176  return m_notifyOnFinish;
177 }
178 
184 {
185  return m_mandatoryUpdate;
186 }
187 
193 {
194  return m_updateAvailable;
195 }
196 
203 {
204  return m_downloaderEnabled;
205 }
206 
213 {
214  return m_downloader->useCustomInstallProcedures();
215 }
216 
222 {
223  QNetworkRequest request(url());
224  if (!userAgentString().isEmpty())
225  request.setRawHeader("User-Agent", userAgentString().toUtf8());
226 
227  m_manager->get(request);
228 }
229 
234 void Updater::setUrl(const QString &url)
235 {
236  m_url = url;
237 }
238 
244 void Updater::setModuleName(const QString &name)
245 {
246  m_moduleName = name;
247 }
248 
253 void Updater::setNotifyOnUpdate(const bool notify)
254 {
255  m_notifyOnUpdate = notify;
256 }
257 
262 void Updater::setNotifyOnFinish(const bool notify)
263 {
264  m_notifyOnFinish = notify;
265 }
266 
273 void Updater::setUserAgentString(const QString &agent)
274 {
275  m_userAgentString = agent;
276  m_downloader->setUserAgentString(agent);
277 }
278 
285 void Updater::setModuleVersion(const QString &version)
286 {
287  m_moduleVersion = version;
288 }
289 
294 void Updater::setDownloaderEnabled(const bool enabled)
295 {
296  m_downloaderEnabled = enabled;
297 }
298 
308 void Updater::setPlatformKey(const QString &platformKey)
309 {
310  m_platform = platformKey;
311 }
312 
319 void Updater::setUseCustomAppcast(const bool customAppcast)
320 {
321  m_customAppcast = customAppcast;
322 }
323 
330 {
331  m_downloader->setUseCustomInstallProcedures(custom);
332 }
333 
338 void Updater::setMandatoryUpdate(const bool mandatory_update)
339 {
340  m_mandatoryUpdate = mandatory_update;
341 }
345 void Updater::onReply(QNetworkReply *reply)
346 {
347  /* Check if we need to redirect */
348  QUrl redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
349  if (!redirect.isEmpty())
350  {
351  setUrl(redirect.toString());
352  checkForUpdates();
353  return;
354  }
355 
356  /* There was a network error */
357  if (reply->error() != QNetworkReply::NoError)
358  {
359  setUpdateAvailable(false);
360  emit checkingFinished(url());
361  return;
362  }
363 
364  /* The application wants to interpret the appcast by itself */
365  if (customAppcast())
366  {
367  emit appcastDownloaded(url(), reply->readAll());
368  emit checkingFinished(url());
369  return;
370  }
371 
372  /* Try to create a JSON document from downloaded data */
373  QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
374 
375  /* JSON is invalid */
376  if (document.isNull())
377  {
378  setUpdateAvailable(false);
379  emit checkingFinished(url());
380  return;
381  }
382 
383  /* Get the platform information */
384  QJsonObject updates = document.object().value("updates").toObject();
385  QJsonObject platform = updates.value(platformKey()).toObject();
386 
387  /* Get update information */
388  m_openUrl = platform.value("open-url").toString();
389  m_changelog = platform.value("changelog").toString();
390  m_downloadUrl = platform.value("download-url").toString();
391  m_latestVersion = platform.value("latest-version").toString();
392  if (platform.contains("mandatory"))
393  m_mandatoryUpdate = platform.value("mandatory").toBool();
394 
395  /* Compare latest and current version */
396  setUpdateAvailable(compare(latestVersion(), moduleVersion()));
397  emit checkingFinished(url());
398 }
399 
404 void Updater::setUpdateAvailable(const bool available)
405 {
406  m_updateAvailable = available;
407 
408  QMessageBox box;
409  box.setTextFormat(Qt::RichText);
410  box.setIcon(QMessageBox::Information);
411 
413  {
414  QString text = tr("Would you like to download the update now?");
415  if (m_mandatoryUpdate)
416  {
417  text = tr("Would you like to download the update now? This is a mandatory update, "
418  "you should install this version after exiting application!");
419  }
420 
421  QString title
422  = "<h3>" + tr("Version %1 of %2 has been released!").arg(latestVersion()).arg(moduleName()) + "</h3>";
423 
424  box.setText(title);
425  box.setInformativeText(text);
426  box.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
427  box.setDefaultButton(QMessageBox::Yes);
428 
429  if (box.exec() == QMessageBox::Yes)
430  {
431  if (!openUrl().isEmpty())
432  {
433  QDesktopServices::openUrl(QUrl(openUrl()));
434  }
435  else if (downloaderEnabled())
436  {
437  m_downloader->setUrlId(url());
438  QString fileName = downloadUrl().split("/").last();
439  m_downloader->setFileName(fileName.split("?").first());
440  m_downloader->setMandatoryUpdate(m_mandatoryUpdate);
441  m_downloader->startDownload(QUrl(downloadUrl()));
442  }
443  else
444  {
445  QDesktopServices::openUrl(QUrl(downloadUrl()));
446  }
447  }
448  else
449  {
450  // do nothing
451  CVLog::Print(tr("You can download latest application from %1 mannually").arg(downloadUrl()));
452  return;
453  }
454  }
455 
456  else if (notifyOnFinish())
457  {
458  box.setStandardButtons(QMessageBox::Close);
459  box.setInformativeText(tr("No updates are available for the moment"));
460  box.setText("<h3>"
461  + tr("Congratulations! You are running the "
462  "latest version of %1")
463  .arg(moduleName())
464  + "</h3>");
465 
466  box.exec();
467  }
468 }
469 
476 bool Updater::compare(const QString &x, const QString &y)
477 {
478  QStringList versionsX = x.split(".");
479  QStringList versionsY = y.split(".");
480 
481  int count = qMin(versionsX.count(), versionsY.count());
482 
483  for (int i = 0; i < count; ++i)
484  {
485  int a = QString(versionsX.at(i)).toInt();
486  int b = QString(versionsY.at(i)).toInt();
487 
488  if (a > b)
489  return true;
490 
491  else if (b > a)
492  return false;
493  }
494 
495  return versionsY.count() < versionsX.count();
496 }
std::string version
std::string name
int count
static bool Print(const char *format,...)
Prints out a formatted message in console.
Definition: CVLog.cpp:113
Implements an integrated file downloader with a nice UI.
Definition: Downloader.h:26
void setUserAgentString(const QString &agent)
Definition: Downloader.cpp:135
bool useCustomInstallProcedures() const
Definition: Downloader.cpp:68
void startDownload(const QUrl &url)
Definition: Downloader.cpp:88
void setFileName(const QString &file)
Definition: Downloader.cpp:124
void setMandatoryUpdate(const bool mandatory_update)
Definition: Downloader.cpp:426
void setUseCustomInstallProcedures(const bool custom)
Definition: Downloader.cpp:438
void setUrlId(const QString &url)
Definition: Downloader.cpp:80
QString changelog() const
Definition: Updater.cpp:85
QString url() const
Definition: Updater.cpp:65
void setNotifyOnFinish(const bool notify)
Definition: Updater.cpp:262
void setUrl(const QString &url)
Definition: Updater.cpp:234
QString openUrl() const
Definition: Updater.cpp:76
void setDownloaderEnabled(const bool enabled)
Definition: Updater.cpp:294
bool useCustomInstallProcedures() const
Definition: Updater.cpp:212
bool notifyOnFinish() const
Definition: Updater.cpp:174
void downloadFinished(const QString &url, const QString &filepath)
~Updater()
Definition: Updater.cpp:57
void setUseCustomInstallProcedures(const bool custom)
Definition: Updater.cpp:329
QString moduleName() const
Definition: Updater.cpp:93
QString latestVersion() const
Definition: Updater.cpp:126
void checkForUpdates()
Definition: Updater.cpp:221
bool mandatoryUpdate() const
Definition: Updater.cpp:183
void setModuleName(const QString &name)
Definition: Updater.cpp:244
QString downloadUrl() const
Definition: Updater.cpp:117
void checkingFinished(const QString &url)
void setPlatformKey(const QString &platformKey)
Definition: Updater.cpp:308
bool customAppcast() const
Definition: Updater.cpp:153
void setModuleVersion(const QString &version)
Definition: Updater.cpp:285
void setMandatoryUpdate(const bool mandatory_update)
Definition: Updater.cpp:338
bool downloaderEnabled() const
Definition: Updater.cpp:202
bool notifyOnUpdate() const
Definition: Updater.cpp:162
QString platformKey() const
Definition: Updater.cpp:108
void setUseCustomAppcast(const bool customAppcast)
Definition: Updater.cpp:319
bool updateAvailable() const
Definition: Updater.cpp:192
void appcastDownloaded(const QString &url, const QByteArray &data)
void setNotifyOnUpdate(const bool notify)
Definition: Updater.cpp:253
Updater()
Definition: Updater.cpp:20
QString userAgentString() const
Definition: Updater.cpp:135
QString moduleVersion() const
Definition: Updater.cpp:143
void setUserAgentString(const QString &agent)
Definition: Updater.cpp:273