From c25b10628098cdbaf4979e199d9efae9e608fe70 Mon Sep 17 00:00:00 2001 From: Alex Spataru Date: Fri, 4 Nov 2016 09:35:13 -0600 Subject: [PATCH] Work on issue #4 --- include/QSimpleUpdater.h | 17 +++++---- src/Downloader.cpp | 5 ++- src/Downloader.h | 2 +- src/QSimpleUpdater.cpp | 41 +++++++++++++++----- src/Updater.cpp | 81 ++++++++++++++++++++++++++++++---------- src/Updater.h | 14 ++++--- tutorial/src/Window.cpp | 33 ++++++++++++++-- tutorial/src/Window.h | 3 +- tutorial/src/Window.ui | 54 ++++++++++++--------------- 9 files changed, 171 insertions(+), 79 deletions(-) diff --git a/include/QSimpleUpdater.h b/include/QSimpleUpdater.h index eaa827e..22f7eaa 100644 --- a/include/QSimpleUpdater.h +++ b/include/QSimpleUpdater.h @@ -35,11 +35,11 @@ #include #if defined (QSU_SHARED) - #define QSU_DECL Q_DECL_EXPORT +#define QSU_DECL Q_DECL_EXPORT #elif defined (QSU_IMPORT) - #define QSU_DECL Q_DECL_IMPORT +#define QSU_DECL Q_DECL_IMPORT #else - #define QSU_DECL +#define QSU_DECL #endif class Updater; @@ -68,11 +68,13 @@ class QSU_DECL QSimpleUpdater : public QObject { signals: void checkingFinished (const QString& url); + void appcastDownloaded (const QString& url, const QByteArray& data); void downloadFinished (const QString& url, const QString& filepath); public: static QSimpleUpdater* getInstance(); + bool usesCustomAppcast (const QString& url) const; bool getNotifyOnUpdate (const QString& url) const; bool getNotifyOnFinish (const QString& url) const; bool getUpdateAvailable (const QString& url) const; @@ -90,12 +92,13 @@ class QSU_DECL QSimpleUpdater : public QObject { public slots: void checkForUpdates (const QString& url); void setModuleName (const QString& url, const QString& name); - void setNotifyOnUpdate (const QString& url, const bool& notify); - void setNotifyOnFinish (const QString& url, const bool& notify); + void setNotifyOnUpdate (const QString& url, const bool notify); + void setNotifyOnFinish (const QString& url, const bool notify); void setPlatformKey (const QString& url, const QString& platform); void setModuleVersion (const QString& url, const QString& version); - void setDownloaderEnabled (const QString& url, const bool& enabled); - void setUseCustomInstallProcedures (const QString& url, const bool& custom); + void setDownloaderEnabled (const QString& url, const bool enabled); + void setUseCustomAppcast (const QString& url, const bool customAppcast); + void setUseCustomInstallProcedures (const QString& url, const bool custom); protected: ~QSimpleUpdater(); diff --git a/src/Downloader.cpp b/src/Downloader.cpp index c02db2f..e5002e2 100755 --- a/src/Downloader.cpp +++ b/src/Downloader.cpp @@ -201,7 +201,8 @@ void Downloader::onDownloadFinished() { QString name = m_reply->url().toString().split ("/").last(); /* Check if we need to redirect */ - QUrl url = m_reply->attribute (QNetworkRequest::RedirectionTargetAttribute).toUrl(); + QUrl url = m_reply->attribute ( + QNetworkRequest::RedirectionTargetAttribute).toUrl(); if (!url.isEmpty()) { startDownload (url); return; @@ -326,6 +327,6 @@ qreal Downloader::round (const qreal& input) { * Use the signals fired by the \c QSimpleUpdater to implement your own install * procedures. */ -void Downloader::setUseCustomInstallProcedures (const bool& custom) { +void Downloader::setUseCustomInstallProcedures (const bool custom) { m_useCustomProcedures = custom; } diff --git a/src/Downloader.h b/src/Downloader.h index eb60ad8..bb753ae 100755 --- a/src/Downloader.h +++ b/src/Downloader.h @@ -57,7 +57,7 @@ class Downloader : public QWidget { public slots: void startDownload (const QUrl& url); - void setUseCustomInstallProcedures (const bool& custom); + void setUseCustomInstallProcedures (const bool custom); private slots: void openDownload(); diff --git a/src/QSimpleUpdater.cpp b/src/QSimpleUpdater.cpp index a54ba91..358a239 100644 --- a/src/QSimpleUpdater.cpp +++ b/src/QSimpleUpdater.cpp @@ -35,6 +35,10 @@ static QList UPDATERS; QSimpleUpdater::~QSimpleUpdater() { URLS.clear(); + + foreach (Updater* updater, UPDATERS) + updater->deleteLater(); + UPDATERS.clear(); } @@ -46,6 +50,18 @@ QSimpleUpdater* QSimpleUpdater::getInstance() { return &updater; } +/** + * Returns \c true if the \c Updater instance registered with the given \a url + * uses a custom appcast format and/or allows the application to read and + * interpret the downloaded appcast file + * + * \note If an \c Updater instance registered with the given \a url is not + * found, that \c Updater instance will be initialized automatically + */ +bool QSimpleUpdater::usesCustomAppcast (const QString& url) const { + return getUpdater (url)->customAppcast(); +} + /** * Returns \c true if the \c Updater instance registered with the given \a url * shall notify the user when an update is available. @@ -115,7 +131,7 @@ bool QSimpleUpdater::usesCustomInstallProcedures (const QString& url) const { * \note If an \c Updater instance registered with the given \a url is not * found, that \c Updater instance will be initialized automatically */ -QString QSimpleUpdater::getOpenUrl (const QString &url) const { +QString QSimpleUpdater::getOpenUrl (const QString& url) const { return getUpdater (url)->openUrl(); } @@ -230,7 +246,7 @@ void QSimpleUpdater::setModuleName (const QString& url, const QString& name) { * found, that \c Updater instance will be initialized automatically */ void QSimpleUpdater::setNotifyOnUpdate (const QString& url, - const bool& notify) { + const bool notify) { getUpdater (url)->setNotifyOnUpdate (notify); } @@ -243,7 +259,7 @@ void QSimpleUpdater::setNotifyOnUpdate (const QString& url, * found, that \c Updater instance will be initialized automatically */ void QSimpleUpdater::setNotifyOnFinish (const QString& url, - const bool& notify) { + const bool notify) { getUpdater (url)->setNotifyOnFinish (notify); } @@ -288,10 +304,15 @@ void QSimpleUpdater::setModuleVersion (const QString& url, * found, that \c Updater instance will be initialized automatically */ void QSimpleUpdater::setDownloaderEnabled (const QString& url, - const bool& enabled) { + const bool enabled) { getUpdater (url)->setDownloaderEnabled (enabled); } +void QSimpleUpdater::setUseCustomAppcast (const QString& url, + const bool customAppcast) { + getUpdater (url)->setUseCustomAppcast (customAppcast); +} + /** * If the \a custom parameter is set to \c true, the \c Updater instance * registered with the given \a url will not try to open the downloaded file. @@ -304,7 +325,7 @@ void QSimpleUpdater::setDownloaderEnabled (const QString& url, * found, that \c Updater instance will be initialized automatically */ void QSimpleUpdater::setUseCustomInstallProcedures (const QString& url, - const bool& custom) { + const bool custom) { getUpdater (url)->setUseCustomInstallProcedures (custom); } @@ -322,10 +343,12 @@ Updater* QSimpleUpdater::getUpdater (const QString& url) const { URLS.append (url); UPDATERS.append (updater); - connect (updater, SIGNAL (checkingFinished (QString)), - this, SIGNAL (checkingFinished (QString))); - connect (updater, SIGNAL (downloadFinished (QString, QString)), - this, SIGNAL (downloadFinished (QString, QString))); + connect (updater, SIGNAL (checkingFinished (QString)), + this, SIGNAL (checkingFinished (QString))); + connect (updater, SIGNAL (downloadFinished (QString, QString)), + this, SIGNAL (downloadFinished (QString, QString))); + connect (updater, SIGNAL (appcastDownloaded (QString, QByteArray)), + this, SIGNAL (appcastDownloaded (QString, QByteArray))); } return UPDATERS.at (URLS.indexOf (url)); diff --git a/src/Updater.cpp b/src/Updater.cpp index 3a0d07b..691dce4 100644 --- a/src/Updater.cpp +++ b/src/Updater.cpp @@ -43,6 +43,7 @@ Updater::Updater() { m_changelog = ""; m_downloadUrl = ""; m_latestVersion = ""; + m_customAppcast = false; m_notifyOnUpdate = true; m_notifyOnFinish = false; m_updateAvailable = false; @@ -144,6 +145,15 @@ QString Updater::moduleVersion() const { return m_moduleVersion; } +/** + * Returns \c true if the updater should NOT interpret the downloaded appcast. + * This is useful if you need to store more variables (or information) in the + * JSON file or use another appcast format (e.g. XML) + */ +bool Updater::customAppcast() const { + return m_customAppcast; +} + /** * Returns \c true if the updater should notify the user when an update is * available. @@ -218,7 +228,7 @@ void Updater::setModuleName (const QString& name) { * If \a notify is set to \c true, then the \c Updater will notify the user * when an update is available. */ -void Updater::setNotifyOnUpdate (const bool& notify) { +void Updater::setNotifyOnUpdate (const bool notify) { m_notifyOnUpdate = notify; } @@ -226,7 +236,7 @@ void Updater::setNotifyOnUpdate (const bool& notify) { * If \a notify is set to \c true, then the \c Updater will notify the user * when it has finished interpreting the update definitions file. */ -void Updater::setNotifyOnFinish (const bool& notify) { +void Updater::setNotifyOnFinish (const bool notify) { m_notifyOnFinish = notify; } @@ -244,7 +254,7 @@ void Updater::setModuleVersion (const QString& version) { * If the \a enabled parameter is set to \c true, the \c Updater will open the * integrated downloader if the user agrees to install the update (if any) */ -void Updater::setDownloaderEnabled (const bool& enabled) { +void Updater::setDownloaderEnabled (const bool enabled) { m_downloaderEnabled = enabled; } @@ -261,12 +271,22 @@ void Updater::setPlatformKey (const QString& platformKey) { m_platform = platformKey; } +/** + * If the \a customAppcast parameter is set to \c true, then the \c Updater + * will not try to read the network reply from the server, instead, it will + * emit the \c appcastDownloaded() signal, which allows the application to + * read and interpret the appcast file by itself + */ +void Updater::setUseCustomAppcast (const bool customAppcast) { + m_customAppcast = customAppcast; +} + /** * If the \a custom parameter is set to \c true, the \c Updater will not try * to open the downloaded file. Use the signals fired by the \c QSimpleUpdater * to install the update from the downloaded file by yourself. */ -void Updater::setUseCustomInstallProcedures (const bool& custom) { +void Updater::setUseCustomInstallProcedures (const bool custom) { m_downloader->setUseCustomInstallProcedures (custom); } @@ -274,23 +294,44 @@ void Updater::setUseCustomInstallProcedures (const bool& custom) { * Called when the download of the update definitions file is finished. */ void Updater::onReply (QNetworkReply* reply) { - if (reply->error() == QNetworkReply::NoError) { - QJsonDocument document = QJsonDocument::fromJson (reply->readAll()); - - if (document.isNull()) - return; - - QJsonObject updates = document.object().value ("updates").toObject(); - QJsonObject platform = updates.value (platformKey()).toObject(); - - m_openUrl = platform.value ("open-url").toString(); - m_changelog = platform.value ("changelog").toString(); - m_downloadUrl = platform.value ("download-url").toString(); - m_latestVersion = platform.value ("latest-version").toString(); - - setUpdateAvailable (compare (latestVersion(), moduleVersion())); + /* Check if we need to redirect */ + QUrl redirect = reply->attribute ( + QNetworkRequest::RedirectionTargetAttribute).toUrl(); + if (!redirect.isEmpty()) { + setUrl (redirect.toString()); + checkForUpdates(); + return; } + /* There was a network error */ + if (reply->error() != QNetworkReply::NoError) + return; + + /* The application wants to interpret the appcast by itself */ + if (customAppcast()) { + emit appcastDownloaded (url(), reply->readAll()); + return; + } + + /* Try to create a JSON document from downloaded data */ + QJsonDocument document = QJsonDocument::fromJson (reply->readAll()); + + /* JSON is invalid */ + if (document.isNull()) + return; + + /* Get the platform information */ + QJsonObject updates = document.object().value ("updates").toObject(); + QJsonObject platform = updates.value (platformKey()).toObject(); + + /* Get update information */ + m_openUrl = platform.value ("open-url").toString(); + m_changelog = platform.value ("changelog").toString(); + m_downloadUrl = platform.value ("download-url").toString(); + m_latestVersion = platform.value ("latest-version").toString(); + + /* Compare latest and current version */ + setUpdateAvailable (compare (latestVersion(), moduleVersion())); emit checkingFinished (url()); } @@ -298,7 +339,7 @@ void Updater::onReply (QNetworkReply* reply) { * Prompts the user based on the value of the \a available parameter and the * settings of this instance of the \c Updater class. */ -void Updater::setUpdateAvailable (const bool& available) { +void Updater::setUpdateAvailable (const bool available) { m_updateAvailable = available; QMessageBox box; diff --git a/src/Updater.h b/src/Updater.h index 7e7d5a8..7061d09 100644 --- a/src/Updater.h +++ b/src/Updater.h @@ -48,6 +48,7 @@ class QSU_DECL Updater : public QObject { signals: void checkingFinished (const QString& url); void downloadFinished (const QString& url, const QString& filepath); + void appcastDownloaded (const QString& url, const QByteArray& data); public: Updater(); @@ -62,6 +63,7 @@ class QSU_DECL Updater : public QObject { QString moduleVersion() const; QString latestVersion() const; + bool customAppcast() const; bool notifyOnUpdate() const; bool notifyOnFinish() const; bool updateAvailable() const; @@ -72,16 +74,17 @@ class QSU_DECL Updater : public QObject { void checkForUpdates(); void setUrl (const QString& url); void setModuleName (const QString& name); - void setNotifyOnUpdate (const bool& notify); - void setNotifyOnFinish (const bool& notify); + void setNotifyOnUpdate (const bool notify); + void setNotifyOnFinish (const bool notify); void setModuleVersion (const QString& version); - void setDownloaderEnabled (const bool& enabled); + void setDownloaderEnabled (const bool enabled); void setPlatformKey (const QString& platformKey); - void setUseCustomInstallProcedures (const bool& custom); + void setUseCustomAppcast (const bool customAppcast); + void setUseCustomInstallProcedures (const bool custom); private slots: void onReply (QNetworkReply* reply); - void setUpdateAvailable (const bool& available); + void setUpdateAvailable (const bool available); private: bool compare (const QString& x, const QString& y); @@ -89,6 +92,7 @@ class QSU_DECL Updater : public QObject { private: QString m_url; + bool m_customAppcast; bool m_notifyOnUpdate; bool m_notifyOnFinish; bool m_updateAvailable; diff --git a/tutorial/src/Window.cpp b/tutorial/src/Window.cpp index 1fa35b1..250ee21 100644 --- a/tutorial/src/Window.cpp +++ b/tutorial/src/Window.cpp @@ -33,8 +33,10 @@ Window::Window (QWidget* parent) : QMainWindow (parent) { m_updater = QSimpleUpdater::getInstance(); /* Check for updates when the "Check For Updates" button is clicked */ - connect (m_updater, SIGNAL (checkingFinished (QString)), - this, SLOT (updateChangelog (QString))); + connect (m_updater, SIGNAL (checkingFinished (QString)), + this, SLOT (updateChangelog (QString))); + connect (m_updater, SIGNAL (appcastDownloaded (QString, QByteArray)), + this, SLOT (displayAppcast (QString, QByteArray))); /* React to button clicks */ connect (m_ui->resetButton, SIGNAL (clicked()), @@ -45,7 +47,8 @@ Window::Window (QWidget* parent) : QMainWindow (parent) { this, SLOT (checkForUpdates())); /* Resize the dialog to fit */ - setFixedSize (minimumSizeHint()); + setMinimumSize (minimumSizeHint()); + resize (minimumSizeHint()); /* Reset the UI state */ resetFields(); @@ -65,6 +68,7 @@ Window::~Window() { void Window::resetFields() { m_ui->installedVersion->setText ("0.1"); + m_ui->customAppcast->setChecked (false); m_ui->enableDownloader->setChecked (true); m_ui->showAllNotifcations->setChecked (false); m_ui->showUpdateNotifications->setChecked (true); @@ -77,6 +81,7 @@ void Window::resetFields() { void Window::checkForUpdates() { /* Get settings from the UI */ QString version = m_ui->installedVersion->text(); + bool customAppcast = m_ui->customAppcast->isChecked(); bool downloaderEnabled = m_ui->enableDownloader->isChecked(); bool notifyOnFinish = m_ui->showAllNotifcations->isChecked(); bool notifyOnUpdate = m_ui->showUpdateNotifications->isChecked(); @@ -85,6 +90,7 @@ void Window::checkForUpdates() { m_updater->setModuleVersion (DEFS_URL, version); m_updater->setNotifyOnFinish (DEFS_URL, notifyOnFinish); m_updater->setNotifyOnUpdate (DEFS_URL, notifyOnUpdate); + m_updater->setUseCustomAppcast (DEFS_URL, customAppcast); m_updater->setDownloaderEnabled (DEFS_URL, downloaderEnabled); /* Check for updates */ @@ -95,7 +101,26 @@ void Window::checkForUpdates() { // Window::updateChangelog //============================================================================== -void Window::updateChangelog (QString url) { +void Window::updateChangelog (const QString& url) { if (url == DEFS_URL) m_ui->changelogText->setText (m_updater->getChangelog (url)); } + + +//============================================================================== +// Window::displayAppcast +//============================================================================== + +void Window::displayAppcast (const QString& url, const QByteArray& reply) { + if (url == DEFS_URL) { + QString text = "This is the downloaded appcast:

" +
+                       QString::fromUtf8 (reply) +
+                       "

If you need to store more information on the " + "appcast (or use another format), just use the " + "QSimpleUpdater::setCustomAppcast() function. " + "It allows your application to interpret the appcast " + "using your code and not QSU's code.

"; + + m_ui->changelogText->setText (text); + } +} diff --git a/tutorial/src/Window.h b/tutorial/src/Window.h index 1d49f50..7fa75b1 100644 --- a/tutorial/src/Window.h +++ b/tutorial/src/Window.h @@ -28,7 +28,8 @@ class Window : public QMainWindow { public slots: void resetFields(); void checkForUpdates(); - void updateChangelog (QString url); + void updateChangelog (const QString& url); + void displayAppcast (const QString& url, const QByteArray& reply); private: Ui::Window* m_ui; diff --git a/tutorial/src/Window.ui b/tutorial/src/Window.ui index 109ce9f..aca6acb 100644 --- a/tutorial/src/Window.ui +++ b/tutorial/src/Window.ui @@ -6,8 +6,8 @@ 0 0 - 496 - 487 + 483 + 494 @@ -82,6 +82,23 @@ Updater Options + + + + Show all notifications + + + + + + + 0.1 + + + Write a version string... + + + @@ -102,13 +119,6 @@ - - - - Show all notifications - - - @@ -116,13 +126,10 @@ - - + + - 0.1 - - - Write a version string... + Do not use the QSU library to read the appcast @@ -144,27 +151,14 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'.Lucida Grande UI'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click &quot;Check for Updates&quot; to update this field...</p></body></html> +</style></head><body style=" font-family:'.SF NS Text'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'.Lucida Grande UI';">Click &quot;Check for Updates&quot; to update this field...</span></p></body></html> - - - - Qt::Vertical - - - - 20 - 40 - - - -