Work on issue #4

This commit is contained in:
Alex Spataru 2016-11-04 09:35:13 -06:00
parent fbb37ed225
commit c25b106280
9 changed files with 171 additions and 79 deletions

View File

@ -35,11 +35,11 @@
#include <QObject>
#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();

View File

@ -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;
}

View File

@ -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();

View File

@ -35,6 +35,10 @@ static QList<Updater*> 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);
}
@ -326,6 +347,8 @@ Updater* QSimpleUpdater::getUpdater (const QString& url) const {
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));

View File

@ -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) {
/* 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;

View File

@ -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;

View File

@ -35,6 +35,8 @@ Window::Window (QWidget* parent) : QMainWindow (parent) {
/* 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 (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: <p><pre>" +
QString::fromUtf8 (reply) +
"</pre></p><p> If you need to store more information on the "
"appcast (or use another format), just use the "
"<b>QSimpleUpdater::setCustomAppcast()</b> function. "
"It allows your application to interpret the appcast "
"using your code and not QSU's code.</p>";
m_ui->changelogText->setText (text);
}
}

View File

@ -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;

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>496</width>
<height>487</height>
<width>483</width>
<height>494</height>
</rect>
</property>
<property name="windowTitle">
@ -82,6 +82,23 @@
<string>Updater Options</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<widget class="QCheckBox" name="showAllNotifcations">
<property name="text">
<string>Show all notifications</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="installedVersion">
<property name="text">
<string>0.1</string>
</property>
<property name="placeholderText">
<string>Write a version string...</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="enableDownloader">
<property name="text">
@ -102,13 +119,6 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="showAllNotifcations">
<property name="text">
<string>Show all notifications</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
@ -116,13 +126,10 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="installedVersion">
<item row="6" column="0">
<widget class="QCheckBox" name="customAppcast">
<property name="text">
<string>0.1</string>
</property>
<property name="placeholderText">
<string>Write a version string...</string>
<string>Do not use the QSU library to read the appcast</string>
</property>
</widget>
</item>
@ -144,27 +151,14 @@
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'.Lucida Grande UI'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Click &amp;quot;Check for Updates&amp;quot; to update this field...&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'.SF NS Text'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'.Lucida Grande UI';&quot;&gt;Click &amp;quot;Check for Updates&amp;quot; to update this field...&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QFrame" name="frame">
<property name="frameShape">