From 6d193e28c4f620c85c533872b4c5cac451be68ca Mon Sep 17 00:00:00 2001 From: skyjake Date: Sat, 26 May 2012 11:46:59 +0300 Subject: [PATCH] Refactor|Updater: Separated VersionInfo, UpdaterSettings Also added UpdateAvailableDialog that will be shown after checking for available updates. --- doomsday/engine/engine.pro | 7 +- doomsday/engine/portable/src/updater.cpp | 137 ++---------------- .../src/updater/updateavailabledialog.cpp | 58 ++++++++ .../src/updater/updateavailabledialog.h | 19 +++ .../portable/src/updater/updatersettings.cpp | 92 ++++++++++++ .../portable/src/updater/updatersettings.h | 43 ++++++ .../engine/portable/src/updater/versioninfo.h | 90 ++++++++++++ 7 files changed, 318 insertions(+), 128 deletions(-) create mode 100644 doomsday/engine/portable/src/updater/updateavailabledialog.cpp create mode 100644 doomsday/engine/portable/src/updater/updateavailabledialog.h create mode 100644 doomsday/engine/portable/src/updater/updatersettings.cpp create mode 100644 doomsday/engine/portable/src/updater/updatersettings.h create mode 100644 doomsday/engine/portable/src/updater/versioninfo.h diff --git a/doomsday/engine/engine.pro b/doomsday/engine/engine.pro index 735ea09cf6..082e1e6176 100644 --- a/doomsday/engine/engine.pro +++ b/doomsday/engine/engine.pro @@ -363,7 +363,10 @@ DENG_HEADERS += \ portable/include/vertex.h \ portable/include/wadfile.h \ portable/include/window.h \ - portable/include/zipfile.h + portable/include/zipfile.h \ + portable/src/updater/updateavailabledialog.h \ + portable/src/updater/updatersettings.h \ + portable/src/updater/versioninfo.h INCLUDEPATH += \ $$DENG_INCLUDE_DIR \ @@ -640,6 +643,8 @@ SOURCES += \ portable/src/ui_mpi.c \ portable/src/ui_panel.c \ portable/src/updater.cpp \ + portable/src/updater/updateavailabledialog.cpp \ + portable/src/updater/updatersettings.cpp \ portable/src/uri.c \ portable/src/vertex.cpp \ portable/src/wadfile.c \ diff --git a/doomsday/engine/portable/src/updater.cpp b/doomsday/engine/portable/src/updater.cpp index fa35e296c8..2501c1e317 100644 --- a/doomsday/engine/portable/src/updater.cpp +++ b/doomsday/engine/portable/src/updater.cpp @@ -24,6 +24,9 @@ #include "dd_version.h" #include "dd_types.h" #include "json.h" +#include "updater/updateavailabledialog.h" +#include "updater/updatersettings.h" +#include "updater/versioninfo.h" #include #include #include @@ -35,13 +38,6 @@ static Updater* updater = 0; -#define STK_FREQUENCY "updater/frequency" -#define STK_CHANNEL "updater/channel" -#define STK_LAST_CHECKED "updater/lastChecked" -#define STK_ONLY_MANUAL "updater/onlyManually" -#define STK_DELETE "updater/delete" -#define STK_DOWNLOAD_PATH "updater/downloadPath" - /// @todo The platform ID should come from the Builder. #if defined(WIN32) # define PLATFORM_ID "win-x86" @@ -63,145 +59,28 @@ static Updater* updater = 0; struct Updater::Instance { - enum Frequency - { - Daily = 0, - Biweekly = 1, // 3.5 days - Weekly = 2, // 7 days - Monthly = 3 // 30 days - }; - enum Channel - { - Stable = 0, - Unstable = 1 - }; - - struct VersionInfo - { - int major; - int minor; - int revision; - int patch; - int build; - - /** - * Version information. - * @todo Could be useful as a generic utility class. - */ - VersionInfo() : patch(0), build(de::Time().asBuildNumber()) - { - parseVersionString(DOOMSDAY_VERSION_BASE); -#ifdef DOOMSDAY_BUILD_TEXT - build = de::String(DOOMSDAY_BUILD_TEXT).toInt(); -#endif - } - - VersionInfo(const de::String& version, int buildNumber) : build(buildNumber) - { - parseVersionString(version); - } - - QString asText() const - { - if(patch > 0) - { - return QString("%1.%2.%3-%4 Build %5").arg(major).arg(minor).arg(revision).arg(patch).arg(build); - } - return QString("%1.%2.%3 Build %4").arg(major).arg(minor).arg(revision).arg(build); - } - - void parseVersionString(const de::String& version) - { - QStringList parts = version.split('.'); - major = parts[0].toInt(); - minor = parts[1].toInt(); - if(parts[2].contains('-')) - { - QStringList rev = parts[2].split('-'); - revision = rev[0].toInt(); - patch = rev[1].toInt(); - } - else - { - revision = parts[2].toInt(); - patch = 0; - } - } - - bool operator < (const VersionInfo& other) const - { - if(major == other.major) - { - if(minor == other.minor) - { - if(revision == other.revision) - { - return build < other.build; - } - return revision < other.revision; - } - return minor < other.minor; - } - return major < other.major; - } - - bool operator == (const VersionInfo& other) const - { - return major == other.major && minor == other.minor && - revision == other.revision && build == other.build; - } - - bool operator > (const VersionInfo& other) const - { - return !(*this < other || *this == other); - } - }; - Updater* self; QNetworkAccessManager* network; - Frequency checkFrequency; - Channel channel; ///< What kind of updates to check for. - QDateTime lastCheckTime;///< Time of last check (automatic or manual). - bool onlyCheckManually; ///< Should only check when manually requested. - bool deleteAfterUpdate; ///< Downloaded file is deleted afterwards. - QString downloadPath; ///< Path where the downloaded file is saved. VersionInfo latestVersion; QString latestPackageUri; QString latestLogUri; Instance(Updater* up) : self(up) { - // Fetch the current settings. - QSettings st; - checkFrequency = Frequency(st.value(STK_FREQUENCY, Weekly).toInt()); - channel = Channel(st.value(STK_CHANNEL, QString(DOOMSDAY_RELEASE_TYPE) == "Stable"? Stable : Unstable).toInt()); - lastCheckTime = st.value(STK_LAST_CHECKED).toDateTime(); - onlyCheckManually = st.value(STK_ONLY_MANUAL, false).toBool(); - deleteAfterUpdate = st.value(STK_DELETE, true).toBool(); - downloadPath = st.value(STK_DOWNLOAD_PATH, - QDesktopServices::storageLocation(QDesktopServices::TempLocation)).toString(); - network = new QNetworkAccessManager(self); } ~Instance() { - // Save settings. - QSettings st; - st.setValue(STK_FREQUENCY, int(checkFrequency)); - st.setValue(STK_CHANNEL, int(channel)); - st.setValue(STK_LAST_CHECKED, lastCheckTime); - st.setValue(STK_ONLY_MANUAL, onlyCheckManually); - st.setValue(STK_DELETE, deleteAfterUpdate); - st.setValue(STK_DOWNLOAD_PATH, downloadPath); } QString composeCheckUri() { + UpdaterSettings st; QString uri = QString(DOOMSDAY_HOMEURL) + "/latestbuild?"; uri += QString("platform=") + PLATFORM_ID; - uri += (channel == Stable? "&stable" : "&unstable"); + uri += (st.channel() == UpdaterSettings::Stable? "&stable" : "&unstable"); uri += "&graph"; LOG_DEBUG("Check URI: ") << uri; @@ -210,7 +89,7 @@ struct Updater::Instance void queryLatestVersion() { - lastCheckTime = QDateTime::currentDateTime(); + UpdaterSettings().setLastCheckTime(de::Time()); network->get(QNetworkRequest(composeCheckUri())); } @@ -236,7 +115,11 @@ struct Updater::Instance << latestPackageUri << latestLogUri; // Is this newer than what we're running? + UpdateAvailableDialog* dlg = new UpdateAvailableDialog; + + dlg->exec(); + delete dlg; } }; diff --git a/doomsday/engine/portable/src/updater/updateavailabledialog.cpp b/doomsday/engine/portable/src/updater/updateavailabledialog.cpp new file mode 100644 index 0000000000..25fa186fee --- /dev/null +++ b/doomsday/engine/portable/src/updater/updateavailabledialog.cpp @@ -0,0 +1,58 @@ +#include "updateavailabledialog.h" +#include "versioninfo.h" +#include +#include +#include +#include +#include +#include +#include + +struct UpdateAvailableDialog::Instance +{ + UpdateAvailableDialog* self; + + QLabel* info; + + Instance(UpdateAvailableDialog* d) : self(d) + { + QVBoxLayout* mainLayout = new QVBoxLayout(self); + self->setLayout(mainLayout); + //mainLayout->setMargin(12); + + info = new QLabel; + info->setTextFormat(Qt::RichText); + info->setText(QString("You are up to date." + "

The installed version %2 is the latest available stable build.") + .arg(int(self->font().pointSize() * 1.2)) + .arg(VersionInfo().asText())); + + QCheckBox* neverCheck = new QCheckBox("Never check for updates automatically"); + + QDialogButtonBox* bbox = new QDialogButtonBox; + + QPushButton* ok = bbox->addButton("Ok", QDialogButtonBox::AcceptRole); + ok->setDefault(true); + + QPushButton* cfg = bbox->addButton("Settings...", QDialogButtonBox::ActionRole); + cfg->setAutoDefault(false); + cfg->setDefault(false); + + //QPushButton* whatsNew = bbox->addButton("What's new?", QDialogButtonBox::HelpRole); + + mainLayout->addWidget(info); + mainLayout->addWidget(neverCheck); + mainLayout->addWidget(bbox); + } +}; + +UpdateAvailableDialog::UpdateAvailableDialog(QWidget *parent) + : QDialog(parent) +{ + d = new Instance(this); +} + +UpdateAvailableDialog::~UpdateAvailableDialog() +{ + delete d; +} diff --git a/doomsday/engine/portable/src/updater/updateavailabledialog.h b/doomsday/engine/portable/src/updater/updateavailabledialog.h new file mode 100644 index 0000000000..060bcd77d7 --- /dev/null +++ b/doomsday/engine/portable/src/updater/updateavailabledialog.h @@ -0,0 +1,19 @@ +#ifndef LIBDENG_UPDATEAVAILABLEDIALOG_H +#define LIBDENG_UPDATEAVAILABLEDIALOG_H + +#include + +class UpdateAvailableDialog : public QDialog +{ + Q_OBJECT + +public: + explicit UpdateAvailableDialog(QWidget *parent = 0); + ~UpdateAvailableDialog(); + +private: + struct Instance; + Instance* d; +}; + +#endif // LIBDENG_UPDATEAVAILABLEDIALOG_H diff --git a/doomsday/engine/portable/src/updater/updatersettings.cpp b/doomsday/engine/portable/src/updater/updatersettings.cpp new file mode 100644 index 0000000000..14f71fe279 --- /dev/null +++ b/doomsday/engine/portable/src/updater/updatersettings.cpp @@ -0,0 +1,92 @@ +#include "updatersettings.h" +#include "versioninfo.h" +#include +#include +#include + +#define STK_FREQUENCY "updater/frequency" +#define STK_CHANNEL "updater/channel" +#define STK_LAST_CHECKED "updater/lastChecked" +#define STK_ONLY_MANUAL "updater/onlyManually" +#define STK_DELETE "updater/delete" +#define STK_DOWNLOAD_PATH "updater/downloadPath" + +static de::String defaultDownloadPath() +{ + return QDesktopServices::storageLocation(QDesktopServices::TempLocation); +} + +UpdaterSettings::UpdaterSettings() +{} + +UpdaterSettings::Frequency UpdaterSettings::frequency() const +{ + return Frequency(QSettings().value(STK_FREQUENCY, Weekly).toInt()); +} + +UpdaterSettings::Channel UpdaterSettings::channel() const +{ + return Channel(QSettings().value(STK_CHANNEL, + QString(DOOMSDAY_RELEASE_TYPE) == "Stable"? Stable : Unstable).toInt()); +} + +de::Time UpdaterSettings::lastCheckTime() const +{ + return QSettings().value(STK_LAST_CHECKED).toDateTime(); +} + +bool UpdaterSettings::onlyCheckManually() const +{ + return QSettings().value(STK_ONLY_MANUAL, false).toBool(); +} + +bool UpdaterSettings::deleteAfterUpdate() const +{ + return QSettings().value(STK_DELETE, true).toBool(); +} + +bool UpdaterSettings::isDefaultDownloadPath() const +{ + de::String path = downloadPath(); + return path == defaultDownloadPath(); +} + +de::String UpdaterSettings::downloadPath() const +{ + return QSettings().value(STK_DOWNLOAD_PATH, defaultDownloadPath()).toString(); +} + +void UpdaterSettings::setFrequency(UpdaterSettings::Frequency freq) +{ + QSettings().setValue(STK_FREQUENCY, int(freq)); +} + +void UpdaterSettings::channel(UpdaterSettings::Channel channel) +{ + QSettings().setValue(STK_CHANNEL, int(channel)); +} + +void UpdaterSettings::setLastCheckTime(const de::Time &time) +{ + QSettings().setValue(STK_LAST_CHECKED, time.asDateTime()); +} + +void UpdaterSettings::setOnlyCheckManually(bool onlyManually) +{ + QSettings().setValue(STK_ONLY_MANUAL, onlyManually); +} + +void UpdaterSettings::setDeleteAfterUpdate(bool deleteAfter) +{ + QSettings().setValue(STK_DELETE, deleteAfter); +} + +void UpdaterSettings::setDownloadPath(de::String downloadPath) +{ + QSettings().setValue(STK_DOWNLOAD_PATH, downloadPath); +} + +void UpdaterSettings::useDefaultDownloadPath() +{ + setDownloadPath(defaultDownloadPath()); +} diff --git a/doomsday/engine/portable/src/updater/updatersettings.h b/doomsday/engine/portable/src/updater/updatersettings.h new file mode 100644 index 0000000000..70edb73cce --- /dev/null +++ b/doomsday/engine/portable/src/updater/updatersettings.h @@ -0,0 +1,43 @@ +#ifndef LIBDENG_UPDATERSETTINGS_H +#define LIBDENG_UPDATERSETTINGS_H + +#include +#include + +class UpdaterSettings +{ +public: + enum Frequency + { + Daily = 0, + Biweekly = 1, // 3.5 days + Weekly = 2, // 7 days + Monthly = 3 // 30 days + }; + enum Channel + { + Stable = 0, + Unstable = 1 + }; + +public: + UpdaterSettings(); + + Frequency frequency() const; + Channel channel() const; + de::Time lastCheckTime() const; + bool onlyCheckManually() const; + bool deleteAfterUpdate() const; + bool isDefaultDownloadPath() const; + de::String downloadPath() const; + + void setFrequency(Frequency freq); + void channel(Channel channel); + void setLastCheckTime(const de::Time& time); + void setOnlyCheckManually(bool onlyManually); + void setDeleteAfterUpdate(bool deleteAfter); + void setDownloadPath(de::String downloadPath); + void useDefaultDownloadPath(); +}; + +#endif // LIBDENG_UPDATERSETTINGS_H diff --git a/doomsday/engine/portable/src/updater/versioninfo.h b/doomsday/engine/portable/src/updater/versioninfo.h new file mode 100644 index 0000000000..292d146782 --- /dev/null +++ b/doomsday/engine/portable/src/updater/versioninfo.h @@ -0,0 +1,90 @@ +#ifndef LIBDENG_VERSIOINFO_H +#define LIBDENG_VERSIOINFO_H + +#include +#include +#include +#include "dd_version.h" + +struct VersionInfo +{ + int major; + int minor; + int revision; + int patch; + int build; + + /** + * Version information. + */ + VersionInfo() : patch(0), build(de::Time().asBuildNumber()) + { + parseVersionString(DOOMSDAY_VERSION_BASE); +#ifdef DOOMSDAY_BUILD_TEXT + build = de::String(DOOMSDAY_BUILD_TEXT).toInt(); +#endif + } + + VersionInfo(const de::String& version, int buildNumber) : build(buildNumber) + { + parseVersionString(version); + } + + QString asText() const + { + if(patch > 0) + { + return QString("%1.%2.%3-%4 Build %5") + .arg(major).arg(minor).arg(revision).arg(patch).arg(build); + } + return QString("%1.%2.%3 Build %4").arg(major).arg(minor).arg(revision).arg(build); + } + + void parseVersionString(const de::String& version) + { + QStringList parts = version.split('.'); + major = parts[0].toInt(); + minor = parts[1].toInt(); + if(parts[2].contains('-')) + { + QStringList rev = parts[2].split('-'); + revision = rev[0].toInt(); + patch = rev[1].toInt(); + } + else + { + revision = parts[2].toInt(); + patch = 0; + } + } + + bool operator < (const VersionInfo& other) const + { + if(major == other.major) + { + if(minor == other.minor) + { + if(revision == other.revision) + { + return build < other.build; + } + return revision < other.revision; + } + return minor < other.minor; + } + return major < other.major; + } + + bool operator == (const VersionInfo& other) const + { + return major == other.major && minor == other.minor && + revision == other.revision && build == other.build; + } + + bool operator > (const VersionInfo& other) const + { + return !(*this < other || *this == other); + } +}; + +#endif // LIBDENG_VERSIOINFO_H