Implemented a "download and install" dialog

This commit is contained in:
Alex Spataru 2014-11-06 18:59:09 -06:00
parent 48b8195655
commit d88c4955eb
9 changed files with 475 additions and 82 deletions

View File

@ -63,6 +63,9 @@ void Example::checkForUpdates() {
updater->setReferenceUrl("https://raw.githubusercontent.com/alex-97/"
"QSimpleUpdater/Files-for-example-project/current_version.txt");
// Tell the updater where to download the update, its recommended to use direct links
updater->setDownloadUrl("https://github.com/alex-97/QSimpleUpdater/archive/master.zip");
// Finally, check for updates...
updater->checkForUpdates();
}
@ -81,6 +84,7 @@ void Example::onCheckingFinished() {
QMessageBox::information(this, tr("Update available"),
tr("There's a newer version available! The latest version is ") +
updater->latestVersion());
updater->downloadLatestVersion();
}
// The installed version is equal or greater to the "official" latest version,

View File

@ -8,8 +8,10 @@
QT += network
HEADERS += $$PWD/src/qsimpleupdater.h
SOURCES += $$PWD/src/qsimpleupdater.cpp
HEADERS += $$PWD/src/qsimpleupdater.h \
$$PWD/src/dialogs/download_dialog.h
SOURCES += $$PWD/src/qsimpleupdater.cpp \
$$PWD/src/dialogs/download_dialog.cpp
OTHER_FILES += $$PWD/src/QSimpleUpdater
INCLUDEPATH += $$PWD/src
@ -22,3 +24,9 @@ win32* {
CONFIG += openssl-linked
LIBS += -L$$PWD/dependencies/win32/ -llibeay32
}
RESOURCES += \
$$PWD/res/res.qrc
FORMS += \
$$PWD/src/dialogs/download_dialog.ui

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/icons">
<file>internet_icon.png</file>
</qresource>
</RCC>

View File

@ -0,0 +1,188 @@
//
// This file is part of QSimpleUpdater
//
// Copyright (c) 2014 Alex Spataru <alex_spataru@gmail.com>
//
// Please check the license.txt file for more information.
//
#include "download_dialog.h"
#include "ui_download_dialog.h"
DownloadDialog::DownloadDialog(QWidget *parent) :
QWidget(parent),
ui(new Ui::DownloadDialog)
{
// Setup the UI
ui->setupUi(this);
ui->installButton->setEnabled(false);
// Connect SIGNALS/SLOTS
connect(ui->installButton, SIGNAL(clicked()), this, SLOT(openDownload()));
connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(cancelDownload()));
// Initialize the network access manager
m_manager = new QNetworkAccessManager(this);
// Avoid SSL issues
connect(m_manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
this, SLOT(ignoreSslErrors(QNetworkReply*,QList<QSslError>)));
}
DownloadDialog::~DownloadDialog()
{
delete ui;
}
void DownloadDialog::beginDownload(const QUrl &url)
{
// Reset the UI
ui->progressBar->setValue(0);
ui->installButton->setEnabled(false);
ui->downloadLabel->setText(tr("Downloading update..."));
// Begin the download
m_reply = m_manager->get(QNetworkRequest(url));
// Update the progress bar value automatically
connect(m_reply, SIGNAL(downloadProgress(qint64,qint64)),
this, SLOT(updateProgress(qint64,qint64)));
// Write the file to the hard disk once the download is finished
connect(m_reply, SIGNAL(finished()), this, SLOT(downloadFinished()));
// Show the dialog
showNormal();
}
void DownloadDialog::openDownload()
{
if (!m_path.isEmpty()) {
QString url = m_path;
// Build a correct URL to open local files
if (url.startsWith("/"))
url = "file://" + url;
else
url = "file:///" + url;
// Let the system open the downloaded file
QDesktopServices::openUrl(url);
}
else {
qWarning() << "QSimpleUpdater: cannot open downloaded file!";
}
}
void DownloadDialog::cancelDownload()
{
// Cancel download
m_reply->abort();
// Close the dialog
close();
}
void DownloadDialog::downloadFinished()
{
// Setup the UI
ui->installButton->setEnabled(true);
// Write the file
QByteArray data = m_reply->readAll();
if (!data.isEmpty()) {
// Create a QFile with the name of the downloaded file
QStringList list = m_reply->url().toString().split("/");
QFile file(QDir::tempPath() + "/" + list.at(list.count() - 1));
// Write download data to the opened file
if (file.open(QIODevice::WriteOnly)) {
file.write(data);
m_path = file.fileName();
}
// Show a warning if we cannot open the file for writting
else {
qWarning() << "QSimpleUpdater: cannot write downloaded data!";
}
// Close the file
file.close();
}
else {
qWarning() << "QSimpleUpdater: invalid download data!";
}
}
void DownloadDialog::updateProgress(qint64 received, qint64 total)
{
// We know the size of the download, so we can calculate the progress....
if (total > 0) {
ui->progressBar->setMinimum(0);
ui->progressBar->setMaximum(100);
// Calculate and show download progress
int _progress = (int) ((received * 100) / total);
ui->progressBar->setValue(_progress);
ui->downloadLabel->setText(tr("Downloading update (%1%)...").arg(_progress));
// Get size information
QString _total_string;
QString _received_string;
float _total = total;
float _received = received;
// Calculate the lenght unit for
// the total size of the download
if (_total < 1024) {
_total_string = tr("%1 bytes").arg(_total);
} else if (_total < 1024 * 1024) {
_total = roundNumber(_total / 1024);
_total_string = tr("%1 KB").arg(_total);
} else {
_total = roundNumber(_total / (1024 * 1024));
_total_string = tr("%1 MB").arg(_total);
}
// Calculate the lenght unit for
// the received data of the download
if (_received < 1024) {
_received_string = tr("%1 bytes").arg(_received);
} else if (received < 1024 * 1024) {
_received = roundNumber(_received / 1024);
_received_string = tr("%1 KB").arg(_received);
} else {
_received = roundNumber(_received / (1024 * 1024));
_received_string = tr("%1 MB").arg(_received);
}
// Update the progress label
ui->progressLabel->setText(_received_string + " " + tr("of") + " " + _total_string);
}
// We do not know the size of the download, so we improvise...
else {
// Enable a marquee animation
ui->progressBar->setValue(-1);
ui->progressBar->setMinimum(0);
ui->progressBar->setMaximum(0);
ui->downloadLabel->setText(tr("Downloading update..."));
}
}
void DownloadDialog::ignoreSslErrors (QNetworkReply *reply, const QList<QSslError> &error)
{
reply->ignoreSslErrors (error);
}
float DownloadDialog::roundNumber(const float &input)
{
// Round the input number to two decimal places
return roundf(input * 100) / 100;
}

View File

@ -0,0 +1,44 @@
#ifndef DOWNLOAD_DIALOG_H
#define DOWNLOAD_DIALOG_H
#include <QDir>
#include <QWidget>
#include <QNetworkReply>
#include <QDesktopServices>
#include <QNetworkAccessManager>
#include <math.h>
namespace Ui {
class DownloadDialog;
}
class DownloadDialog : public QWidget
{
Q_OBJECT
public:
explicit DownloadDialog(QWidget *parent = 0);
~DownloadDialog();
void beginDownload(const QUrl &url);
private slots:
void openDownload();
void cancelDownload();
void downloadFinished();
void updateProgress(qint64 received, qint64 total);
void ignoreSslErrors(QNetworkReply *reply, const QList<QSslError> &error);
private:
Ui::DownloadDialog *ui;
QString m_path;
QNetworkReply *m_reply;
QNetworkAccessManager *m_manager;
float roundNumber(const float &input);
};
#endif

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DownloadDialog</class>
<widget class="QWidget" name="DownloadDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>385</width>
<height>168</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="windowTitle">
<string>Updater</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="downloadIcon">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../../res/res.qrc">:/icons/internet_icon.png</pixmap>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_2" native="true">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QWidget" name="progressFrame" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="downloadLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Downloading update...</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>0</number>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="progressLabel">
<property name="text">
<string>0 kb / 0 kb</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="buttonFrame" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="buttonSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="cancelButton">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="installButton">
<property name="text">
<string>Install</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../res/res.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -8,25 +8,23 @@
#include "qsimpleupdater.h"
QSimpleUpdater::QSimpleUpdater(QObject *parent) : QObject(parent)
QSimpleUpdater::QSimpleUpdater(QObject *parent)
: QObject(parent)
, m_changelog_downloaded(false)
, m_version_check_finished(false)
, m_new_version_available(false)
{
m_new_version_available = false;
m_downloadDialog = new DownloadDialog();
}
QString QSimpleUpdater::changeLog() {
// Return the contents of the downloaded changelog
if (!m_changelog.isEmpty()) {
return m_changelog;
}
// If the changelog is empty, we issue a warning message in
// the console and return an empty string
else {
QString QSimpleUpdater::changeLog() const {
if (m_changelog.isEmpty()) {
qWarning() << "QSimpleUpdater: change log is empty,"
<< "did you call setChangelogUrl() and checkForUpdates()?";
return NULL;
}
return m_changelog;
}
void QSimpleUpdater::checkForUpdates() {
@ -56,38 +54,7 @@ void QSimpleUpdater::checkForUpdates() {
}
}
QString QSimpleUpdater::latestVersion() {
// Return the application version referenced by the string
// that we downloaded
if (!m_latest_version.isEmpty()) {
return m_latest_version;
}
// Issue a warning message in the case that the downloaded
// application version string is empty
else {
qWarning() << "QSimpleUpdater: latest version is empty,"
<< "did you call checkForUpdates() and setReferenceUrl()?";
return NULL;
}
}
QString QSimpleUpdater::installedVersion() {
// Return the string issued by the user in the setApplicationVersion() function
if (!m_installed_version.isEmpty()) {
return m_installed_version;
}
// Issue a warning message in the case that the installed application
// version is empty
else {
qWarning() << "QSimpleUpdater: installed version is empty,"
<< "did you call setApplicationVersion()?";
return NULL;
}
}
void QSimpleUpdater::downloadLatestVersion() {
void QSimpleUpdater::openDownloadLink() {
// Open the download URL in a web browser
if (!m_download_url.isEmpty()) {
QDesktopServices::openUrl(m_download_url);
@ -100,59 +67,87 @@ void QSimpleUpdater::downloadLatestVersion() {
}
}
bool QSimpleUpdater::newerVersionAvailable() {
// Return the application version referenced by the string
// that we downloaded
QString QSimpleUpdater::latestVersion() const {
if (m_latest_version.isEmpty()) {
qWarning() << "QSimpleUpdater: latest version is empty,"
<< "did you call checkForUpdates() and setReferenceUrl()?";
}
return m_latest_version;
}
// Return the string issued by the user in the setApplicationVersion() function
QString QSimpleUpdater::installedVersion() const {
if (m_installed_version.isEmpty()) {
qWarning() << "QSimpleUpdater: installed version is empty,"
<< "did you call setApplicationVersion()?";
}
return m_installed_version;
}
void QSimpleUpdater::downloadLatestVersion() {
// Show the download dialog
if (!m_download_url.isEmpty()) {
m_downloadDialog->beginDownload(m_download_url);
}
// The m_download_url is empty, so we issue another warning message
else {
qWarning() << "QSimpleUpdater: cannot download latest version,"
<< "did you call setDownloadUrl() and checkForUpdates()?";
}
}
bool QSimpleUpdater::newerVersionAvailable() const {
return m_new_version_available;
}
void QSimpleUpdater::setDownloadUrl(const QString url) {
// Change the download URL if the issued URL is valid
void QSimpleUpdater::setDownloadUrl(const QString &url) {
Q_ASSERT(!url.isEmpty());
if (!url.isEmpty()) {
m_download_url.setUrl(url);
}
// The issued URL is ilegal, so we warn the user
else {
} else {
qWarning() << "QSimpleUpdater: input URL cannot be empty!";
}
}
void QSimpleUpdater::setReferenceUrl(const QString url) {
// Change the reference URL if the issued URL is valid
void QSimpleUpdater::setReferenceUrl(const QString &url) {
Q_ASSERT(!url.isEmpty());
if (!url.isEmpty()) {
m_reference_url.setUrl(url);
}
// The issued URL is ilegal, so we warn the user
else {
} else {
qWarning() << "QSimpleUpdater: input URL cannot be empty!";
}
}
void QSimpleUpdater::setChangelogUrl(const QString url) {
// Change the changelog URL if the issued URL is valid
void QSimpleUpdater::setChangelogUrl(const QString &url) {
Q_ASSERT(!url.isEmpty());
if (!url.isEmpty()) {
m_changelog_url.setUrl(url);
}
// The issued URL is ilegal, so we warn the user
else {
} else {
qWarning() << "QSimpleUpdater: input URL cannot be empty!";
}
}
void QSimpleUpdater::setApplicationVersion(const QString version) {
// Change the installed application version if the issued string is valid
void QSimpleUpdater::setApplicationVersion(const QString &version) {
Q_ASSERT(!version.isEmpty());
if (!version.isEmpty()) {
m_installed_version = version;
}
// The application version cannot be empty, so we warn the user
else {
} else {
qWarning() << "QSimpleUpdater: input string cannot be empty!";
}
}
void QSimpleUpdater::checkDownloadedVersion(QNetworkReply *reply) {
bool _new_update = false;
@ -261,6 +256,6 @@ void QSimpleUpdater::processDownloadedChangelog(QNetworkReply *reply) {
emit checkingFinished();
}
void QSimpleUpdater::ignoreSslErrors (QNetworkReply *reply, QList<QSslError> error) {
void QSimpleUpdater::ignoreSslErrors (QNetworkReply *reply, const QList<QSslError> &error) {
reply->ignoreSslErrors (error);
}

View File

@ -13,29 +13,32 @@
#include <QSslConfiguration>
#include <QNetworkAccessManager>
#include "dialogs/download_dialog.h"
class QSimpleUpdater : public QObject {
Q_OBJECT
public:
QSimpleUpdater(QObject *parent = 0);
QString changeLog();
QString changeLog() const;
void checkForUpdates();
QString latestVersion();
QString installedVersion();
void openDownloadLink();
QString latestVersion() const;
QString installedVersion() const;
void downloadLatestVersion();
bool newerVersionAvailable();
bool newerVersionAvailable() const;
public slots:
void setDownloadUrl(const QString url);
void setReferenceUrl(const QString url);
void setChangelogUrl(const QString url);
void setApplicationVersion(const QString version);
void setDownloadUrl(const QString &url);
void setReferenceUrl(const QString &url);
void setChangelogUrl(const QString &url);
void setApplicationVersion(const QString &version);
private slots:
void checkDownloadedVersion(QNetworkReply *reply);
void processDownloadedChangelog(QNetworkReply *reply);
void ignoreSslErrors(QNetworkReply *reply, QList<QSslError> error);
void ignoreSslErrors(QNetworkReply *reply, const QList<QSslError> &error);
signals:
void checkingFinished();
@ -55,6 +58,8 @@ private:
bool m_version_check_finished;
bool m_new_version_available;
DownloadDialog *m_downloadDialog;
};
#endif