Rewrite library to allow multiple updaters & JSON appcasts

- The update definitions are now stored in the JSON format
- The QSimpleUpdater now allows updating separate “modules” of the
application, this can be useful if you are using a large application
with several updatable plugins
- You can now implement your own procedures to install the downloaded
updates
This commit is contained in:
Alex Spataru 2016-05-22 21:36:53 -05:00
parent 365bb632ea
commit 47c6909259
39 changed files with 2276 additions and 1992 deletions

27
COPYING.md Normal file
View File

@ -0,0 +1,27 @@
# DON'T BE A DICK PUBLIC LICENSE
> Version 1, December 2009
> Copyright (C) 2009 Philip Sturgeon <me@philsturgeon.uk>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
> DON'T BE A DICK PUBLIC LICENSE
> TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
1. Do whatever you like with the original work, just don't be a dick.
Being a dick includes - but is not limited to - the following instances:
1a. Outright copyright infringement - Don't just copy this and change the name.
1b. Selling the unmodified original with no work done what-so-ever, that's REALLY being a dick.
1c. Modifying the original work to contain hidden harmful content. That would make you a PROPER dick.
2. If you become rich through modifications, related works/services, or supporting the original work,
share the love. Only a dick would make loads off this work and not buy the original work's
creator(s) a pint.
3. Code is provided with no warranty. Using somebody else's code and bitching when it goes wrong makes
you a DONKEY dick. Fix the problem yourself. A non-dick would submit the fix back.

View File

@ -1,89 +0,0 @@
#include "example.h"
#include "ui_example.h"
int main (int argc, char *argv[])
{
QApplication app (argc, argv);
app.setApplicationName ("QSimpleUpdater Example");
// Create the dialog and show it
Example example;
example.show();
// Run the app
return app.exec();
}
Example::Example (QWidget *parent) : QDialog (parent), ui (new Ui::Example)
{
// Create and configure the user interface
ui->setupUi (this);
ui->versionLineEdit->setText ("0.1");
ui->versionLineEdit->setPlaceholderText ("0.1");
ui->changelogTextEdit->setPlainText ("Click the \"Check for updates\" button to download the change log");
// Close the dialog when the close button is clicked
connect (ui->closeButton, SIGNAL (clicked()), this, SLOT (close()));
// Check for updates when the updates button is clicked
connect (ui->updatesButton, SIGNAL (clicked()), this, SLOT (checkForUpdates()));
// Initialize the updater
updater = new QSimpleUpdater (this);
// When the updater finishes checking for updates, show a message box
// and show the change log of the latest version
connect (updater, SIGNAL (checkingFinished()), this, SLOT (onCheckingFinished()));
}
Example::~Example()
{
delete ui;
}
void Example::checkForUpdates()
{
// Disable the check for updates button while the updater
// is checking for updates
ui->updatesButton->setEnabled (false);
ui->updatesButton->setText ("Checking for updates...");
// If the user changed the text of the versionLineEdit, then change the
// application version in the updater too
if (!ui->versionLineEdit->text().isEmpty())
updater->setApplicationVersion (ui->versionLineEdit->text());
// If the versionLineEdit is empty, then set the application version
// to "0.1"
else
updater->setApplicationVersion ("0.1");
// Tell the updater where we should download the changelog, note that
// the changelog can be any file you want,
// such as an HTML page or (as in this example), a text file
updater->setChangelogUrl ("https://raw.githubusercontent.com/alex-97/"
"QSimpleUpdater/Files-for-example-project/changelog.txt");
// Tell the updater where we can find the file that tells us the latest version
// of the application
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://codeload.github.com/alex-97/QSimpleUpdater/zip/master");
// Show the progress dialog and show messages when checking is finished
updater->setSilent (false);
updater->setShowNewestVersionMessage (true);
// Finally, check for updates...
updater->checkForUpdates();
}
void Example::onCheckingFinished()
{
// Enable the updatesButton and change its text to let the user know
// that he/she can check for updates again
ui->updatesButton->setEnabled (true);
ui->updatesButton->setText ("Check for updates");
}

View File

@ -1,32 +0,0 @@
#ifndef EXAMPLE_H
#define EXAMPLE_H
#include <QDialog>
#include <QMessageBox>
#include <QSimpleUpdater>
namespace Ui
{
class Example;
}
class Example : public QDialog
{
Q_OBJECT
public:
explicit Example (QWidget *parent = 0);
~Example();
public slots:
void checkForUpdates();
void onCheckingFinished();
private:
Ui::Example *ui;
QString m_installed_version;
QSimpleUpdater *updater;
};
#endif

22
Example/example.pro Executable file → Normal file
View File

@ -1,10 +1,16 @@
# Include the QSimpleUpdater files #
include($$PWD/../QSimpleUpdater/QSimpleUpdater.pri) # Copyright (c) 2014-2016 Alex Spataru <alex_spataru@outlook.com>
#
# This work is free. You can redistribute it and/or modify it under the
# terms of the Do What The Fuck You Want To Public License, Version 2,
# as published by Sam Hocevar. See the COPYING file for more details.
#
# Include the QtWidgets module TEMPLATE = app
QT += widgets
# Define the source code FORMS += $$PWD/src/Window.ui
FORMS += example.ui HEADERS += $$PWD/src/Window.h
HEADERS += example.h SOURCES += $$PWD/src/Window.cpp \
SOURCES += example.cpp $$PWD/src/main.cpp
include ($$PWD/../QSimpleUpdater.pri)

View File

@ -1,84 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Example</class>
<widget class="QDialog" name="Example">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>QSimpleUpdater Example</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="versionLabel">
<property name="text">
<string>Set installed version (latest version is 1.0)</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="versionLineEdit">
<property name="placeholderText">
<string>0.1 (default)</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="changelogLabel">
<property name="text">
<string>Changelog of latest version</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="changelogTextEdit">
<property name="font">
<font>
<family>Courier</family>
<pointsize>11</pointsize>
</font>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="backgroundVisible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="closeButton">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="updatesButton">
<property name="text">
<string>Check for updates</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

95
Example/src/Window.cpp Normal file
View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2014-2016 Alex Spataru <alex_spataru@outlook.com>
*
* This work is free. You can redistribute it and/or modify it under the
* terms of the Do What The Fuck You Want To Public License, Version 2,
* as published by Sam Hocevar. See the COPYING file for more details.
*/
#include "Window.h"
#include "ui_Window.h"
#include <QSimpleUpdater.h>
//==============================================================================
// Define the URL of the Update Definitions file
//==============================================================================
static const QString DEFS_URL = "http://pastebin.com/raw/FGs1sTs0";
//==============================================================================
// Window::Window
//==============================================================================
Window::Window (QWidget* parent) : QMainWindow (parent) {
m_ui = new Ui::Window;
m_ui->setupUi (this);
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)));
/* React to button clicks */
connect (m_ui->resetButton, SIGNAL (clicked()),
this, SLOT (resetFields()));
connect (m_ui->closeButton, SIGNAL (clicked()),
this, SLOT (close()));
connect (m_ui->checkButton, SIGNAL (clicked()),
this, SLOT (checkForUpdates()));
/* Resize the dialog to fit */
setFixedSize (minimumSizeHint());
/* Reset the UI state */
resetFields();
}
//==============================================================================
// Window::~Window
//==============================================================================
Window::~Window() {
delete m_ui;
}
//==============================================================================
// Window::checkForUpdates
//==============================================================================
void Window::resetFields() {
m_ui->installedVersion->setText ("0.1");
m_ui->enableDownloader->setChecked (true);
m_ui->showAllNotifcations->setChecked (false);
m_ui->showUpdateNotifications->setChecked (true);
}
//==============================================================================
// Window::checkForUpdates
//==============================================================================
void Window::checkForUpdates() {
/* Get settings from the UI */
QString version = m_ui->installedVersion->text();
bool downloaderEnabled = m_ui->enableDownloader->isChecked();
bool notifyOnFinish = m_ui->showAllNotifcations->isChecked();
bool notifyOnUpdate = m_ui->showUpdateNotifications->isChecked();
/* Apply the settings */
m_updater->setModuleVersion (DEFS_URL, version);
m_updater->setNotifyOnFinish (DEFS_URL, notifyOnFinish);
m_updater->setNotifyOnUpdate (DEFS_URL, notifyOnUpdate);
m_updater->setDownloaderEnabled (DEFS_URL, downloaderEnabled);
/* Check for updates */
m_updater->checkForUpdates (DEFS_URL);
}
//==============================================================================
// Window::updateChangelog
//==============================================================================
void Window::updateChangelog (QString url) {
m_ui->changelogText->setText (m_updater->getChangelog (url));
}

38
Example/src/Window.h Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2014-2016 Alex Spataru <alex_spataru@outlook.com>
*
* This work is free. You can redistribute it and/or modify it under the
* terms of the Do What The Fuck You Want To Public License, Version 2,
* as published by Sam Hocevar. See the COPYING file for more details.
*/
#ifndef _WINDOW_H
#define _WINDOW_H
#include <QMainWindow>
#include <QApplication>
namespace Ui {
class Window;
}
class QSimpleUpdater;
class Window : public QMainWindow {
Q_OBJECT
public:
explicit Window (QWidget* parent = 0);
~Window();
public slots:
void resetFields();
void checkForUpdates();
void updateChangelog (QString url);
private:
Ui::Window* m_ui;
QSimpleUpdater* m_updater;
};
#endif

221
Example/src/Window.ui Normal file
View File

@ -0,0 +1,221 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Window</class>
<widget class="QMainWindow" name="Window">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>496</width>
<height>487</height>
</rect>
</property>
<property name="windowTitle">
<string>QSimpleUpdater Example</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../../etc/resources/qsimpleupdater.qrc">:/icons/update.png</pixmap>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_3">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>&lt;h1&gt;&lt;i&gt;QSimpleUpdater&lt;/i&gt;&lt;/h1&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>&lt;i&gt;A simpler way to update your Qt applications...&lt;/i&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Updater Options</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="5" column="0">
<widget class="QCheckBox" name="enableDownloader">
<property name="text">
<string>Enable integrated downloader</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="showUpdateNotifications">
<property name="text">
<string>Notify me when an update is available</string>
</property>
<property name="checked">
<bool>true</bool>
</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">
<string>Set installed version (latest version is 1.0)</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>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Changelog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTextBrowser" name="changelogText">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="html">
<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>
</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">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="resetButton">
<property name="text">
<string>Reset Fields</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<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="closeButton">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="checkButton">
<property name="text">
<string>Check for Updates</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
<resources>
<include location="../../etc/resources/qsimpleupdater.qrc"/>
</resources>
<connections/>
</ui>

20
Example/src/main.cpp Normal file
View File

@ -0,0 +1,20 @@
/*
* Copyright (c) 2014-2016 Alex Spataru <alex_spataru@outlook.com>
*
* This work is free. You can redistribute it and/or modify it under the
* terms of the Do What The Fuck You Want To Public License, Version 2,
* as published by Sam Hocevar. See the COPYING file for more details.
*/
#include "Window.h"
int main (int argc, char** argv) {
QApplication app (argc, argv);
app.setApplicationVersion ("1.0");
app.setApplicationName ("Application");
Window window;
window.show();
return app.exec();
}

47
QSimpleUpdater.pri Normal file
View File

@ -0,0 +1,47 @@
#
# Copyright (c) 2014-2016 Alex Spataru <alex_spataru@outlook.com>
#
# This file is part of the QSimpleUpdater library, which is released under
# the DBAD license, you can read a copy of it below:
#
# DON'T BE A DICK PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION
# AND MODIFICATION:
#
# Do whatever you like with the original work, just don't be a dick.
# Being a dick includes - but is not limited to - the following instances:
#
# 1a. Outright copyright infringement - Don't just copy this and change the
# name.
# 1b. Selling the unmodified original with no work done what-so-ever, that's
# REALLY being a dick.
# 1c. Modifying the original work to contain hidden harmful content.
# That would make you a PROPER dick.
#
# If you become rich through modifications, related works/services, or
# supporting the original work, share the love.
# Only a dick would make loads off this work and not buy the original works
# creator(s) a pint.
#
# Code is provided with no warranty. Using somebody else's code and bitching
# when it goes wrong makes you a DONKEY dick.
# Fix the problem yourself. A non-dick would submit the fix back.
QT += gui
QT += core
QT += network
QT += widgets
INCLUDEPATH += $$PWD/include
SOURCES += \
$$PWD/src/Updater.cpp \
$$PWD/src/Downloader.cpp \
$$PWD/src/QSimpleUpdater.cpp
HEADERS += \
$$PWD/include/QSimpleUpdater.h \
$$PWD/src/Updater.h \
$$PWD/src/Downloader.h
FORMS += $$PWD/src/Downloader.ui
RESOURCES += $$PWD/etc/resources/qsimpleupdater.qrc

31
QSimpleUpdater.pro Normal file
View File

@ -0,0 +1,31 @@
#
# Copyright (c) 2014-2016 Alex Spataru <alex_spataru@outlook.com>
#
# This file is part of the QSimpleUpdater library, which is released under
# the DBAD license, you can read a copy of it below:
#
# DON'T BE A DICK PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION
# AND MODIFICATION:
#
# Do whatever you like with the original work, just don't be a dick.
# Being a dick includes - but is not limited to - the following instances:
#
# 1a. Outright copyright infringement - Don't just copy this and change the
# name.
# 1b. Selling the unmodified original with no work done what-so-ever, that's
# REALLY being a dick.
# 1c. Modifying the original work to contain hidden harmful content.
# That would make you a PROPER dick.
#
# If you become rich through modifications, related works/services, or
# supporting the original work, share the love.
# Only a dick would make loads off this work and not buy the original works
# creator(s) a pint.
#
# Code is provided with no warranty. Using somebody else's code and bitching
# when it goes wrong makes you a DONKEY dick.
# Fix the problem yourself. A non-dick would submit the fix back.
TEMPLATE = lib
DEFINES += QSU_SHARED
include ($$PWD/QSimpleUpdater.pri)

View File

@ -1,14 +0,0 @@
# Project info
project = QSimpleUpdater
url = http://qsimpleupdater.sf.net/doc
description = A simple auto-updating system for Qt projects
# Import sources and headers
headerdirs = ../src
sourcedirs = ../src
sources.fileextensions = "*.cpp *.qdoc *.mm *.qml"
headers.fileextensions = "*.h *.ch *.h++ *.hh *.hpp *.hxx"
# Output as HTML
outputdir = doc-html
outputformats = HTML

View File

@ -1,165 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View File

@ -1,36 +0,0 @@
#
# This file is part of QSimpleUpdater
#
# Copyright (c) 2014 Alex Spataru <alex_spataru@outlook.com>
#
# Please check the license.txt file for more information.
#
QT += gui
QT += widgets
QT += network
HEADERS += $$PWD/src/qsimpleupdater.h \
$$PWD/src/dialogs/download_dialog.h \
$$PWD/src/dialogs/progress_dialog.h
SOURCES += $$PWD/src/qsimpleupdater.cpp \
$$PWD/src/dialogs/download_dialog.cpp \
$$PWD/src/dialogs/progress_dialog.cpp
OTHER_FILES += $$PWD/src/QSimpleUpdater
INCLUDEPATH += $$PWD/src
unix:!android {
LIBS += -lcrypto -lssl
}
win32* {
LIBS += -LC:/OpenSSL-Win32/lib -llibeay32
}
RESOURCES += $$PWD/res/qsu_resources.qrc
FORMS += $$PWD/src/dialogs/download_dialog.ui \
$$PWD/src/dialogs/progress_dialog.ui

View File

@ -1 +0,0 @@
#include "qsimpleupdater.h"

View File

@ -1,271 +0,0 @@
/*
* (C) Copyright 2014 Alex Spataru
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/
#include "download_dialog.h"
#include "ui_download_dialog.h"
#include <QMutex>
DownloadDialog::DownloadDialog (QWidget *parent)
: QWidget (parent)
, ui (new Ui::DownloadDialog)
{
// Setup the UI
ui->setupUi (this);
// Make the window look like a dialog
QIcon _blank;
setWindowIcon (_blank);
setWindowModality (Qt::WindowModal);
setWindowFlags (Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
// Connect SIGNALS/SLOTS
connect (ui->stopButton, SIGNAL (clicked()), this, SLOT (cancelDownload()));
connect (ui->openButton, SIGNAL (clicked()), this, SLOT (installUpdate()));
// Configure open button
ui->openButton->setEnabled (false);
ui->openButton->setVisible (false);
// 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 (void)
{
delete ui;
}
void DownloadDialog::beginDownload (const QUrl& url)
{
Q_ASSERT (!url.isEmpty());
// Reset the UI
ui->progressBar->setValue (0);
ui->stopButton->setText (tr ("Stop"));
ui->downloadLabel->setText (tr ("Downloading updates"));
ui->timeLabel->setText (tr ("Time remaining") + ": " + tr ("unknown"));
// Begin the download
m_reply = m_manager->get (QNetworkRequest (url));
m_start_time = QDateTime::currentDateTime().toTime_t();
// 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::installUpdate (void)
{
QMessageBox msg;
msg.setIcon (QMessageBox::Question);
msg.setText ("<b>" +
tr ("To apply the update(s), you must first quit %1")
.arg (qApp->applicationName()) +
"</b>");
msg.setInformativeText (tr ("Do you want to quit %1 now?").arg (qApp->applicationName()));
msg.setStandardButtons (QMessageBox::Yes | QMessageBox::No);
if (msg.exec() == QMessageBox::Yes)
{
openDownload();
qApp->closeAllWindows();
}
else
{
ui->openButton->setEnabled (true);
ui->openButton->setVisible (true);
ui->timeLabel->setText (tr ("Click the \"Open\" button to apply the update"));
}
}
void DownloadDialog::openDownload (void)
{
if (!m_path.isEmpty())
{
QString url = m_path;
if (url.startsWith ("/"))
url = "file://" + url;
else
url = "file:///" + url;
QDesktopServices::openUrl (url);
}
}
void DownloadDialog::cancelDownload (void)
{
if (!m_reply->isFinished())
{
QMessageBox _message;
_message.setWindowTitle (tr ("Updater"));
_message.setIcon (QMessageBox::Question);
_message.setStandardButtons (QMessageBox::Yes | QMessageBox::No);
_message.setText (tr ("Are you sure you want to cancel the download?"));
if (_message.exec() == QMessageBox::Yes)
{
hide();
m_reply->abort();
}
}
else
hide();
}
void DownloadDialog::downloadFinished (void)
{
ui->stopButton->setText (tr ("Close"));
ui->downloadLabel->setText (tr ("Download complete!"));
ui->timeLabel->setText (tr ("The installer will open in a separate window..."));
QByteArray data = m_reply->readAll();
if (!data.isEmpty())
{
QStringList list = m_reply->url().toString().split ("/");
QFile file (QDir::tempPath() + "/" + list.at (list.count() - 1));
QMutex _mutex;
if (file.open (QIODevice::WriteOnly))
{
_mutex.lock();
file.write (data);
m_path = file.fileName();
file.close();
_mutex.unlock();
}
installUpdate();
}
}
void DownloadDialog::updateProgress (qint64 received, qint64 total)
{
// We know the size of the download, so we can calculate the progress....
if (total > 0 && received > 0)
{
ui->progressBar->setMinimum (0);
ui->progressBar->setMaximum (100);
int _progress = (int) ((received * 100) / total);
ui->progressBar->setValue (_progress);
QString _total_string;
QString _received_string;
float _total = total;
float _received = received;
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);
}
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);
}
ui->downloadLabel->setText (tr ("Downloading updates") + " (" + _received_string + " " + tr ("of") + " " + _total_string + ")");
uint _diff = QDateTime::currentDateTime().toTime_t() - m_start_time;
if (_diff > 0)
{
QString _time_string;
float _time_remaining = total / (received / _diff);
if (_time_remaining > 7200)
{
_time_remaining /= 3600;
_time_string = tr ("About %1 hours").arg (int (_time_remaining + 0.5));
}
else if (_time_remaining > 60)
{
_time_remaining /= 60;
_time_string = tr ("About %1 minutes").arg (int (_time_remaining + 0.5));
}
else if (_time_remaining <= 60)
_time_string = tr ("%1 seconds").arg (int (_time_remaining + 0.5));
ui->timeLabel->setText (tr ("Time remaining") + ": " + _time_string);
}
}
// We do not know the size of the download, so we avoid scaring the shit out
// of the user
else
{
ui->progressBar->setValue (-1);
ui->progressBar->setMinimum (0);
ui->progressBar->setMaximum (0);
ui->downloadLabel->setText (tr ("Downloading updates"));
ui->timeLabel->setText (tr ("Time remaining") + ": " + tr ("Unknown"));
}
}
void DownloadDialog::ignoreSslErrors (QNetworkReply *reply,
const QList<QSslError>& error)
{
#ifndef Q_OS_IOS
reply->ignoreSslErrors (error);
#else
Q_UNUSED (reply);
Q_UNUSED (error);
#endif
}
float DownloadDialog::roundNumber (const float& input)
{
return roundf (input * 100) / 100;
}

View File

@ -1,66 +0,0 @@
/*
* (C) Copyright 2014 Alex Spataru
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/
#ifndef DOWNLOAD_DIALOG_H
#define DOWNLOAD_DIALOG_H
#include <QDir>
#include <QIcon>
#include <QDateTime>
#include <QMessageBox>
#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);
void beginDownload (const QUrl& url);
private slots:
void openDownload (void);
void installUpdate (void);
void cancelDownload (void);
void downloadFinished (void);
void updateProgress (qint64 received, qint64 total);
void ignoreSslErrors (QNetworkReply *reply, const QList<QSslError>& error);
private:
Ui::DownloadDialog *ui;
QString m_path;
bool m_download_paused;
QNetworkReply *m_reply;
QNetworkAccessManager *m_manager;
uint m_start_time;
float roundNumber (const float& input);
};
#endif

File diff suppressed because one or more lines are too long

View File

@ -1,42 +0,0 @@
/*
* (C) Copyright 2014 Alex Spataru
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "progress_dialog.h"
#include "ui_progress_dialog.h"
ProgressDialog::ProgressDialog (QWidget *parent) : QDialog (parent), ui (new Ui::ProgressDialog)
{
// Create and configure UI
ui->setupUi (this);
// Make the window look like a dialog
QIcon _blank;
setWindowIcon (_blank);
setWindowModality (Qt::WindowModal);
setWindowFlags (Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
// Close dialog when cancel button is clicked
connect (ui->ui_cancel_button, SIGNAL (clicked()), this, SLOT (cancel()));
}
ProgressDialog::~ProgressDialog()
{
delete ui;
}
void ProgressDialog::cancel (void)
{
hide();
emit cancelClicked();
}

View File

@ -1,43 +0,0 @@
/*
* (C) Copyright 2014 Alex Spataru
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef PROGRESS_DIALOG_H
#define PROGRESS_DIALOG_H
#include <QDialog>
namespace Ui
{
class ProgressDialog;
}
class ProgressDialog : public QDialog
{
Q_OBJECT
public:
explicit ProgressDialog (QWidget *parent = 0);
~ProgressDialog();
signals:
void cancelClicked();
private slots:
void cancel (void);
private:
Ui::ProgressDialog *ui;
};
#endif // PROGRESS_DIALOG_H

View File

@ -1,121 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ProgressDialog</class>
<widget class="QDialog" name="ProgressDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>410</width>
<height>152</height>
</rect>
</property>
<property name="windowTitle">
<string>Software Updater</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<widget class="QLabel" name="ui_icon">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../../res/qsu_resources.qrc">:/icons/update.png</pixmap>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</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="ui_progress_bar">
<property name="text">
<string>Checking for updates...</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="minimumSize">
<size>
<width>250</width>
<height>0</height>
</size>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="value">
<number>-1</number>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="button_widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer">
<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="ui_cancel_button">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../res/qsu_resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -1,520 +0,0 @@
/*
* (C) Copyright 2014 Alex Spataru
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
/*! \class QSimpleUpdater
* \brief A simple auto-updater system for Qt
*
* QSimpleUpdater is an implementation of an auto-updating system to be used with Qt projects.
* Aside from notifying you if there's a newer version, it allows you to download the change log in any
* format (such as HTML or RTF) and download the updates directly from your application using a dialog.
* QSimpleUpdater is free and open source LGPL software,
* which means that you can use it for both open source and proprietary applications.
*
* \chapter Installation
*
* \list
* \o Copy the QSimpleUpdater folder in your "3rd-party" folder.
* \o Include the QSimpleUpdater project include (pri) file using the include() function.
* \o That's all! Check the example project as a reference for your project.
* \endlist
*
* \chapter Running the example project
*
* \list
* \o Navigate to the Example folder and open example.pro with Qt Creator.
* \o Compile the project and play with it :)
* \endlist
*
* \chapter Warnings
* Many websites today use the HTTP Secure protocol, which means that you will need SSL
* in order to communicate with them.
* If your project needs to access such a webiste (for example GitHub),
* you will need to carefully read the following information in order to ensure that
* QSimpleUpdater works with those websites (both in your machine and in the final users' machine).
*
* This section is extremely important for any developers wishing to deploy their applications under
* the Windows platform, because the application will depend on the OpenSSL libaries in order to work.
*
* \bold {Linux}
*
* Make sure that you have installed the following libraries in your system:
*
* \list
* \o lssl
* \o lcrypto
* \endlist
*
* \bold {Mac OS X}
*
* The libraries required by QSimpleUpdater are the same as Linux, however, these libraries
* are installed by default in most Mac OS X installations.
*
* \bold {Microsoft Windows}
*
* QSimpleUpdater makes use of the OpenSSL-Win32 project, make sure that have it installed
* and that the project knows where to find them (the default location is C:/OpenSSL-Win32).
* Finally, deploy the following libraries with your compiled project:
*
* \list
* \o libeay32.dll
* \o ssleay32.dll
* \endlist
*/
/*! \fn QSimpleUpdater::checkingFinished (void)
* This signal is triggered when the updater system finishes downloading
* and proccessing the version data and changelog data.
*/
#include "qsimpleupdater.h"
/*! \internal
* Initializes and configures the class.
*/
QSimpleUpdater::QSimpleUpdater (QObject *parent)
: QObject (parent)
, m_silent (false)
, m_show_newest_version (true)
, m_show_update_available (true)
, m_new_version_available (false)
{
m_progressDialog = new ProgressDialog();
m_downloadDialog = new DownloadDialog();
m_manager = new QNetworkAccessManager (this);
connect (m_manager, SIGNAL (finished (QNetworkReply *)), this,
SLOT (checkDownloadedVersion (QNetworkReply *)));
connect (m_manager, SIGNAL (sslErrors (QNetworkReply *, QList<QSslError>)),
this, SLOT (ignoreSslErrors (QNetworkReply *, QList<QSslError>)));
connect (m_progressDialog, SIGNAL (cancelClicked()), this, SLOT (cancel()));
connect (this, SIGNAL (checkingFinished()), this, SLOT (onCheckingFinished()));
setApplicationVersion (qApp->applicationVersion());
}
/*!
* Returns the downloaded change log as a \c QString.
*
* \sa setChangelogUrl()
*/
QString QSimpleUpdater::changeLog() const
{
return m_changelog;
}
/*!
* Checks for updates and calls the appropiate functions
* when finished.
*
* \sa setDownloadUrl(), setReferenceUrl()
*/
void QSimpleUpdater::checkForUpdates (void)
{
if (!m_reference_url.isEmpty())
{
m_manager->get (QNetworkRequest (m_reference_url));
if (!silent())
m_progressDialog->show();
}
else
qDebug() << "QSimpleUpdater: Invalid reference URL";
}
/*!
* Opens the download link in a web browser.
*
* \sa setDownloadUrl()
*/
void QSimpleUpdater::openDownloadLink (void)
{
if (!m_download_url.isEmpty())
QDesktopServices::openUrl (m_download_url);
}
/*!
* Returns the latest version as a \c QString.
*
* \sa setReferenceUrl(), checkForUpdates()
*/
QString QSimpleUpdater::latestVersion() const
{
return m_latest_version;
}
/*!
* Returns the local version of the application.
*
* \sa setApplicationVersion()
*/
QString QSimpleUpdater::installedVersion() const
{
return m_installed_version;
}
/*!
* Downloads the latest version of the application
* and displays download info in a dialog.
*
* \sa setDownloadUrl(), checkForUpdates()
*/
void QSimpleUpdater::downloadLatestVersion (void)
{
if (!m_download_url.isEmpty())
m_downloadDialog->beginDownload (m_download_url);
}
/*!
* Returns \c true if the system detected that there is
* a newer version of the application available online.
*
* \sa setReferenceUrl(), checkForUpdates()
*/
bool QSimpleUpdater::newerVersionAvailable() const
{
return m_new_version_available;
}
/*!
* Returns \c true if the system is set to
* hide the progress dialog.
*
* \sa setSilent()
*/
bool QSimpleUpdater::silent() const
{
return m_silent;
}
/*!
* Tells the system from where to download the update packages
* with the \a url parameter.
*
* Its recommended to use fixed URLs if you
* want to automatically download and install your updates using
* the bundled download dialog.
*
* \sa downloadLatestVersion(), openDownloadLink()
*/
void QSimpleUpdater::setDownloadUrl (const QString& url)
{
Q_ASSERT (!url.isEmpty());
m_download_url.setUrl (url);
}
/*!
* Tells the updater system from where to download the file
* that indicates the latest version using the \a url parameter.
*
* The reference file should contain \bold {ONLY} the latest version
* in a plain text format. For example:
*
* \list
* \o 1
* \o 0.1
* \o 1.0.1
* \o 2.2.12
* \o etc
* \endlist
*
* \sa latestVersion()
*/
void QSimpleUpdater::setReferenceUrl (const QString& url)
{
Q_ASSERT (!url.isEmpty());
m_reference_url.setUrl (url);
}
/*!
* Tells the updater system from where to download the
* change log using the \a url parameter.
* The change log can be any file you like, however,
* its recommended to write it in plain text,
* such as TXT, HTML and RTF files.
*
* \sa changeLog()
*/
void QSimpleUpdater::setChangelogUrl (const QString& url)
{
Q_ASSERT (!url.isEmpty());
m_changelog_url.setUrl (url);
}
/*!
* Tells the updater the version of the installed
* copy of your application using the \a version parameter.
*
* Calling this function is optional, as the default
* values are loaded from QApplication class.
*
* \sa installedVersion(), checkForUpdates()
*/
void QSimpleUpdater::setApplicationVersion (const QString& version)
{
Q_ASSERT (!version.isEmpty());
m_installed_version = version;
}
/*!
*
* \list
* \o If \a silent is set to \c true, no dialogs will be shown while checking
* for updates or when a newer version of the application is found.
* \o If \a silent is set to \c false, a dialog will be shown while checking for
* updates or when a newer version of the application is found.
* \endlist
*
* \sa silent()
*/
void QSimpleUpdater::setSilent (bool silent)
{
m_silent = silent;
if (m_silent)
setShowNewestVersionMessage (false);
}
/*!
* If the \a show parameter is set to \c true, the updater system will show a
* message box notifying the user when there's an update available.
*
* \sa checkForUpdates()
*/
void QSimpleUpdater::setShowUpdateAvailableMessage (bool show)
{
m_show_update_available = show;
}
/*!
* If the \a show parameter is set to \c true, the updater system will show a
* message box notifying the user when the latest version is already installed.
*
* For example, this configuration is useful when the user manually calls this function.
* \i {Eg:} when he or she clicks the "Check for updates" menu item.
*
* \sa checkForUpdates()
*/
void QSimpleUpdater::setShowNewestVersionMessage (bool show)
{
m_show_newest_version = show;
}
/*! \internal
* Disconnects the network access manager when the user
* clicks on the "cancel" button in the progress dialog.
*/
void QSimpleUpdater::cancel (void)
{
m_manager->disconnect();
}
/*! \internal
* Alerts the user when the download of version information
* data is corrupted.
*
* \sa checkDownloadedVersion()
*/
void QSimpleUpdater::showErrorMessage (void)
{
if (!silent())
{
m_progressDialog->hide();
QMessageBox::warning (NULL, tr ("Software Updater"),
tr ("An unknown error occured while checking for updates"));
}
}
/*! \internal
* Informs the user if there's a newer version available for download
* or if he or she is running the latest version of the application.
*
* \sa checkDownloadedVersion()
*/
void QSimpleUpdater::onCheckingFinished (void)
{
// Hide the progress dialog
m_progressDialog->hide();
// Get the application icon as a pixmap
QPixmap _icon = qApp->windowIcon().pixmap (
qApp->windowIcon().actualSize (QSize (96, 96)));
// If the icon is invalid, use default icon
if (_icon.isNull())
_icon = QPixmap (":/icons/update.png");
QMessageBox _message;
_message.setIconPixmap (_icon);
// Ask user if he/she wants to download newer version
if (newerVersionAvailable() && m_show_update_available)
{
_message.setDetailedText (changeLog());
_message.setStandardButtons (QMessageBox::Yes | QMessageBox::No);
_message.setText ("<b>" + tr ("A new version of %1 is available!").arg (qApp->applicationName()) + "</b>");
_message.setInformativeText (tr ("%1 %2 is available - you have %3. Would you like to download it now?")
.arg (qApp->applicationName())
.arg (latestVersion())
.arg (installedVersion()));
if (_message.exec() == QMessageBox::Yes)
downloadLatestVersion();
}
// Tell user that he/she is up to date (only if necessary)
else if (!silent() && m_show_newest_version && !m_latest_version.isEmpty())
{
_message.setStandardButtons (QMessageBox::Ok);
_message.setText ("<b>" + tr ("You're up-to-date!") +
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</b>");
_message.setInformativeText (
tr ("%1 %2 is currently the newest version available")
.arg (qApp->applicationName())
.arg (installedVersion()));
_message.exec();
}
}
/*! \internal
* Compares downloaded version information with local version information
* and decides if there's a newer version available.
*
* Finally, the function downloads the changelog if there's a newer version
* available online.
*
* \sa checkForUpdates()
*/
void QSimpleUpdater::checkDownloadedVersion (QNetworkReply *reply)
{
bool _new_update = false;
QString _reply = QString::fromUtf8 (reply->readAll());
_reply.replace (" ", "");
_reply.replace ("\n", "");
if (!_reply.isEmpty())
{
m_latest_version = _reply;
QStringList _download = m_latest_version.split (".");
QStringList _installed = m_installed_version.split (".");
for (int i = 0; i <= _download.count() - 1; ++i)
{
if (_download.count() - 1 >= i && _installed.count() - 1 >= i)
{
if (_download.at (i) > _installed.at (i))
{
_new_update = true;
break;
}
}
else
{
if (_installed.count() < _download.count())
{
if (_installed.at (i - 1) == _download.at (i - 1))
break;
else
{
_new_update = true;
break;
}
}
}
}
}
else
showErrorMessage();
m_new_version_available = _new_update;
if (!m_changelog_url.isEmpty() && newerVersionAvailable())
{
QNetworkAccessManager *_manager = new QNetworkAccessManager (this);
connect (_manager, SIGNAL (finished (QNetworkReply *)), this,
SLOT (processDownloadedChangelog (QNetworkReply *)));
connect (_manager, SIGNAL (sslErrors (QNetworkReply *, QList<QSslError>)),
this, SLOT (ignoreSslErrors (QNetworkReply *, QList<QSslError>)));
_manager->get (QNetworkRequest (m_changelog_url));
}
else
emit checkingFinished();
}
/*! \internal
* Reads the downloaded changelog data and transforms it into a QString.
*
* \sa setChangelogUrl(), changeLog()
*/
void QSimpleUpdater::processDownloadedChangelog (QNetworkReply *reply)
{
QString _reply = QString::fromUtf8 (reply->readAll());
if (!_reply.isEmpty())
m_changelog = _reply;
emit checkingFinished();
}
/*! \internal
* Allows the download process to continue even if there are SSL errors.
*
* \sa checkForUpdates()
*/
void QSimpleUpdater::ignoreSslErrors (QNetworkReply *reply,
const QList<QSslError>& error)
{
#if SUPPORTS_SSL
reply->ignoreSslErrors (error);
#else
Q_UNUSED (reply);
Q_UNUSED (error);
#endif
}

View File

@ -1,97 +0,0 @@
/*
* (C) Copyright 2014 Alex Spataru
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/
#ifndef Q_SIMPLE_UPDATER_H
#define Q_SIMPLE_UPDATER_H
#define SUPPORTS_SSL !defined(Q_OS_IOS)
#include <QUrl>
#include <QIcon>
#include <QPixmap>
#include <QMessageBox>
#include <QApplication>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QDesktopServices>
#include <QNetworkAccessManager>
#if SUPPORTS_SSL
#include <QSsl>
#include <QSslError>
#include <QSslConfiguration>
#endif
#include "dialogs/download_dialog.h"
#include "dialogs/progress_dialog.h"
class QSimpleUpdater : public QObject
{
Q_OBJECT
public:
QSimpleUpdater (QObject *parent = 0);
QString changeLog() const;
QString latestVersion() const;
QString installedVersion() const;
bool silent() const;
bool newerVersionAvailable() const;
void checkForUpdates (void);
void openDownloadLink (void);
void downloadLatestVersion (void);
public slots:
void setSilent (bool silent);
void setDownloadUrl (const QString& url);
void setReferenceUrl (const QString& url);
void setChangelogUrl (const QString& url);
void setShowNewestVersionMessage (bool show);
void setShowUpdateAvailableMessage (bool show);
void setApplicationVersion (const QString& version);
signals:
void checkingFinished (void);
private slots:
void cancel (void);
void showErrorMessage (void);
void onCheckingFinished (void);
void checkDownloadedVersion (QNetworkReply *reply);
void processDownloadedChangelog (QNetworkReply *reply);
void ignoreSslErrors (QNetworkReply *reply, const QList<QSslError>& error);
private:
QString m_changelog;
QString m_latest_version;
QString m_installed_version;
QNetworkAccessManager *m_manager;
QUrl m_download_url;
QUrl m_reference_url;
QUrl m_changelog_url;
bool m_silent;
bool m_show_newest_version;
bool m_show_update_available;
bool m_new_version_available;
DownloadDialog *m_downloadDialog;
ProgressDialog *m_progressDialog;
};
#endif

69
Readme.md Executable file → Normal file
View File

@ -1,59 +1,10 @@
## QSimpleUpdater # QSimpleUpdater
QSimpleUpdater is an implementation of an auto-updating system to be used with Qt projects.
[![OpenHub](https://www.openhub.net/p/qsimpleupdater/widgets/project_thin_badge.gif)](http://openhub.net/p/qsimpleupdater)
## Integrating QSimpleUpdater with your projects
QSimpleUpdater is an implementation of an auto-updating system to be used with Qt projects. 1. Copy the QSimpleUpdater folder in your "3rd-party" folder.
2. Include the QSimpleUpdater project include (*pri*) file using the include() function.
QSimpleUpdater is **free and open source [LGPL software](https://www.gnu.org/licenses/lgpl.html)**, which means that you can use it for both open source and proprietary applications. 3. That's all! Check the example project as a reference for your project.
## Developer Documentation ## License
QSimpleUpdater is free and open-source software, it is released under the [DBAD](COPYING.md) license.
You can find the developer documentation for QSimpleUpdater [here](http://qsimpleupdater.sourceforge.net/doc/).
## Using QSimpleUpdater
1. Copy the *QSimpleUpdater* folder in your "3rd-party" folder.
2. Include the QSimpleUpdater project include (pri) file using the include() function.
3. That's all! Check the example project as a reference for your project.
## Running the example project
1. Navigate to the *Example* folder and open *example.pro* with [Qt Creator](http://qt-project.org/wiki/Category:Tools::QtCreator).
2. Compile the project and play with it *:)*
## Warnings
Many websites today use the [HTTP Secure](http://en.wikipedia.org/wiki/HTTP_Secure) protocol, which means that you will need [SSL](https://www.globalsign.com/en/ssl-information-center/what-ssl/) in order to communicate with them. If your project needs to access such a webiste (for example GitHub), you will need to carefully read the following information in order to ensure that QSimpleUpdater works with those websites (both in your machine and in the final users' machine).
This section is extremely important for any developer wishing to deploy his or her applications under the Windows platform, because the application will depend on the libraries provided by QSimpleUpdater.
### Linux
Make sure that you have installed the following libraries in your system:
+ lssl
+ lcrypto
### Mac OS X
The libraries required by QSimpleUpdater are the same as Linux, however, these libraries are installed by default in most Mac OS X installations.
### Windows
QSimpleUpdater makes use of the OpenSSL-Win32 project, make sure that have it installed and that the project knows where to find them (the default location is C:/OpenSSL-Win32) and that you deploy the following libraries with your compiled project:
+ libeay32.dll
+ ssleay32.dll
## Donate
Donate [Bitcoins](http://bitcoin.org) to the project to keep it going!
> 1FFz9TZCPGgiCD97yEqnFaauYYvZUE7f51
## Useful Links
+ [Project website](http://qsimpleupdater.sourceforge.net)
+ [OpenHub Project](http://openhub.net/p/qsimpleupdater)
+ [GitHub repository](http://github.com/alex-97/qsimpleupdater)
+ [Contact developer](mailto:alex.racotta@gmail.com)

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,20 @@
:: Description: This script changes the style format of
:: all the source code of the project.
:: Setup the command line
@echo off
title Code Formatter
:: Go to the directory where the script is run
cd /d %~dp0
:: Style and format the source code recursively
astyle --pad-oper --pad-first-paren-out --align-pointer=type --remove-brackets --convert-tabs --max-code-length=80 --style=google --lineend=windows --suffix=none --recursive ../../*.h ../../*.cpp ../../*.c
:: Notify the user that we have finished
echo.
echo Code styling complete!
echo.
:: Let the user see the output
pause

View File

@ -0,0 +1,2 @@
# Style and format recursively
astyle --pad-oper --pad-first-paren-out --align-pointer=type --remove-brackets --convert-tabs --max-code-length=80 --style=google --lineend=windows --suffix=none --recursive ../../*.h ../../*.cpp ../../*.c

13
example/COPYING Normal file
View File

@ -0,0 +1,13 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

View File

@ -0,0 +1,12 @@
# What is this?
The [updates.json](updates.json) file is the update definitions file. In other words, it lists the latest versions, changelogs and download URLs for each platform.
The example project downloads the [updates.json](updates.json) file and analyzes in order to:
- Compare the local (user set) version and the remote version (specified in [updates.json](updates.json))
- Download the change log for the current platform
- Obtain the download URLs
- Obtain the URL to open (if specified)
Check the article on this article on the [wiki](#) for more information.

View File

@ -0,0 +1,34 @@
{
"updates": {
"windows": {
"open-url": "",
"latest-version": "1.0",
"download-url": "https://github.com/alex-spataru/QSimpleUpdater/archive/master.zip",
"changelog": "This is an example changelog for Windows. Go on..."
},
"osx": {
"open-url": "",
"latest-version": "1.0",
"download-url": "https://github.com/alex-spataru/QSimpleUpdater/archive/master.zip",
"changelog": "This is an example changelog for Mac OS X. Go on..."
},
"linux": {
"open-url": "",
"latest-version": "1.0",
"download-url": "https://github.com/alex-spataru/QSimpleUpdater/archive/master.zip",
"changelog": "This is an example changelog for Linux. Go on..."
},
"ios": {
"open-url": "",
"latest-version": "1.0",
"download-url": "https://github.com/alex-spataru/QSimpleUpdater/archive/master.zip",
"changelog": "This is an example changelog for iOS. Go on..."
},
"android": {
"open-url": "",
"latest-version": "1.0",
"download-url": "https://github.com/alex-spataru/QSimpleUpdater/archive/master.zip",
"changelog": "This is an example changelog for Android. Go on..."
}
}
}

273
include/QSimpleUpdater.h Normal file
View File

@ -0,0 +1,273 @@
/*
* Copyright (c) 2014-2016 Alex Spataru <alex_spataru@outlook.com>
*
* This file is part of the QSimpleUpdater library, which is released under
* the DBAD license, you can read a copy of it below:
*
* DON'T BE A DICK PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING,
* DISTRIBUTION AND MODIFICATION:
*
* Do whatever you like with the original work, just don't be a dick.
* Being a dick includes - but is not limited to - the following instances:
*
* 1a. Outright copyright infringement - Don't just copy this and change the
* name.
* 1b. Selling the unmodified original with no work done what-so-ever, that's
* REALLY being a dick.
* 1c. Modifying the original work to contain hidden harmful content.
* That would make you a PROPER dick.
*
* If you become rich through modifications, related works/services, or
* supporting the original work, share the love.
* Only a dick would make loads off this work and not buy the original works
* creator(s) a pint.
*
* Code is provided with no warranty. Using somebody else's code and bitching
* when it goes wrong makes you a DONKEY dick.
* Fix the problem yourself. A non-dick would submit the fix back.
*/
#ifndef _QSIMPLEUPDATER_MAIN_H
#define _QSIMPLEUPDATER_MAIN_H
#include <QUrl>
#include <QList>
#include <QObject>
#if defined (QSU_SHARED)
# define QSU_DECL Q_DECL_EXPORT
#elif defined (QSU_IMPORT)
# define QSU_DECL Q_DECL_IMPORT
#else
# define QSU_DECL
#endif
class Updater;
///
/// Project homepage: http://qsimpleupdater.sf.net/
/// Code repository: http://github.com/alex-spataru/qsimpleupdater
///
/// The \c QSimpleUpdater class manages the updater system and allows for
/// parallel application modules to check for updates and download them.
///
/// The behavior of each updater can be regulated by specifying the update
/// definitions URL (from where we download the individual update definitions)
/// and defining the desired options by calling the individual "setter"
/// functions (e.g. \c setNotifyOnUpdate()).
///
/// The \c QSimpleUpdater also implements an integrated downloader.
/// If you need to use a custom install procedure/code, just create a function
/// that is called when the \c downloadFinished() signal is emitted to
/// implement your own install procedures.
///
/// By default, the downloader will try to open the file as if you opened it
/// from a file manager or a web browser (with the "file:///" url).
///
class QSU_DECL QSimpleUpdater : public QObject {
Q_OBJECT
public:
///
/// Returns the only instance of the class
///
static QSimpleUpdater* getInstance();
///
/// Returns \c true if the updater registered with the given \a url is set
/// to notify the user when it finds an available update.
///
bool getNotifyOnUpdate (const QString& url) const;
///
/// Returns \c true if the updater registered with the given \a url is set
/// to notify the user when it finishes checking for updates
///
bool getNotifyOnFinish (const QString& url) const;
///
/// Returns \c true if the updater registered with the given \a url has an
/// update available.
///
/// \note you should call \c checkForUpdates() for this URL first in order
/// for this function to regurn a valid value
///
bool getUpdateAvailable (const QString& url) const;
///
/// Returns \c true if the downloader is enabled for the updater registered
/// with the given \a c url
///
bool getDownloaderEnabled (const QString& url) const;
///
/// Returns the changelog of the updater instance with the given \c url.
///
QString getChangelog (const QString& url) const;
///
/// Returns the URL from where we can download the update
///
QString getDownloadUrl (const QString& url) const;
///
/// Returns the latest version online
///
QString getLatestVersion (const QString& url) const;
///
/// Returns the platform of the updater with the given \c url.
///
QString getPlatformKey (const QString& url) const;
///
/// Returns the application name registered for the given \c url.
///
QString getModuleName (const QString& url) const;
///
/// Returns the application version registered for the given \c url
///
QString getModuleVersion (const QString& url) const;
///
/// Returns \c true if the downloader will not attempt to install the
/// downloaded file.
///
/// This can be useful if you want to use the \c downloadFinished() signal
/// to implement your own install procedures.
///
bool usesCustomInstallProcedures (const QString& url) const;
public slots:
///
/// Checks for updates by downloading the update definitions file at the
/// given \a url.
///
/// You can have more than one updater running at the same time while the
/// \a url is different. Every updater instance will have its own set of
/// settings.
///
/// This can be used - for example - when having multiple shared modules
/// (e.g. plugins) that can be updated separately.
///
void checkForUpdates (const QString& url);
///
/// Changes the platform key which we use to get version data and download
/// link in the appcast in the given \c url.
///
/// \note By default, the updater will use the name of the current operating
/// system as its platform key.
///
void setPlatformKey (const QString& url, const QString& platform);
///
/// Changes the application name to display in the notification messages
/// for the given appcast \a url.
///
/// This can be used - for example - when having multiple shared modules
/// (e.g. plugins) that can be updated separately.
///
/// \note By default, the updater will use the name given to the
/// \c QApplication during initialization of your application.
///
void setModuleName (const QString& url, const QString& name);
///
/// Changes the application version to use when comparing the local and
/// remote application versions.
///
/// This can be used - for example - when having multiple shared modules
/// (e.g. plugins) that can be updated separately.
///
/// \note By default, the updater will use the version given to the
/// \c QApplication during initialization of your application.
///
void setModuleVersion (const QString& url, const QString& version);
///
/// If \c notify is set to true, the \c QSimpleUpdater will notify the user
/// when an update is available.
///
/// If \c notify is set to false, the \c QSimpleUpdater will not notify the
/// user when an update is available.
///
/// \note this feature is enabled by default
/// \note you should disable this feature if you are implementing your own
/// notification methods or update procedures in your application.
/// \note this function only changes the behavior for the updater registered
/// with the given \a url.
///
void setNotifyOnUpdate (const QString& url, const bool& notify);
///
/// If set to \c true, the updater will notify the user when it finishes
/// checking for updates (even where there are no updates available).
///
/// If set to \c false (default), the updater will only notify the user
/// when there is an update available (if setNotifyOnUpdate() is \c true).
///
/// You can enable this feature when the user triggers manually the updater
/// (e.g. by clicking on the "Check for Updates..." action on the menu).
///
/// \note this feature is disabled by default
/// \note you should disable this feature if you are implementing your own
/// notification methods or update procedures in your application.
/// \note this function only changes the behavior for the updater registered
/// with the given \a url.
///
void setNotifyOnFinish (const QString& url, const bool& notify);
///
/// If set to true, the updater will allow the user to choose whenever to
/// download the update directly from the application (instead of opening
/// the given download link through a browser).
///
/// \note this feature is enabled by default
/// \note you should disable this if you are implementing your own update
/// procedures in your application.
/// \note this function only changes the behavior for the updater registered
/// with the given \a url.
///
void setDownloaderEnabled (const QString& url, const bool& enabled);
///
/// If \c custom is set to true, then the Downloader will not attempt to
/// open or install the downloaded updates. This can be useful if you want
/// to implement your own install procedures using the \c downloadFinished()
/// signal.
///
void setUseCustomInstallProcedures (const QString& url, const bool& custom);
signals:
///
/// Emitted when the check for updates process finishes.
/// You can use this function if you are implementing your own notification
/// methods or download procedures.
///
/// \note use of this signal is not obligatory if you don't want
/// to show a custom notification or create your own downloader.
///
void checkingFinished (const QString& url);
///
/// Emitted when the download has finished.
/// You can use this to implement your own procedures to install the
/// downloaded updates.
///
void downloadFinished (const QString& url, const QString& filepath);
protected:
~QSimpleUpdater();
private:
///
/// Returns the updater object registered with the given \a url.
/// If an updater object with the given \a url is not found, then this
/// function will create it and configure it.
///
Updater* getUpdater (const QString& url) const;
};
#endif

165
lgpl3.txt
View File

@ -1,165 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

314
src/Downloader.cpp Executable file
View File

@ -0,0 +1,314 @@
/*
* (C) Copyright 2014 Alex Spataru
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/
//==============================================================================
// Class includes
//==============================================================================
#include "Downloader.h"
//==============================================================================
// System includes
//==============================================================================
#include <math.h>
#include <QDir>
#include <QFile>
#include <QProcess>
#include <QMessageBox>
#include <QNetworkReply>
#include <QDesktopServices>
#include <QNetworkAccessManager>
//==============================================================================
// Downloader::Downloader
//==============================================================================
Downloader::Downloader (QWidget* parent) : QWidget (parent) {
m_ui = new Ui::Downloader;
m_ui->setupUi (this);
/* Initialize private members */
m_manager = new QNetworkAccessManager();
/* Initialize internal values */
m_filePath = "";
m_startTime = 0;
m_useCustomProcedures = false;
/* Make the window look like a modal dialog */
setWindowIcon (QIcon ());
setWindowFlags (Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
/* Configure the appearance and behavior of the buttons */
m_ui->openButton->setEnabled (false);
m_ui->openButton->setVisible (false);
connect (m_ui->stopButton, SIGNAL (clicked()),
this, SLOT (cancelDownload()));
connect (m_ui->openButton, SIGNAL (clicked()),
this, SLOT (installUpdate()));
/* Resize to fit */
setFixedSize (minimumSizeHint());
}
//==============================================================================
// Downloader::~Downloader
//==============================================================================
Downloader::~Downloader() {
delete m_ui;
delete m_reply;
delete m_manager;
}
//==============================================================================
// Downloader::useCustomInstallProcedures
//==============================================================================
bool Downloader::useCustomInstallProcedures() const {
return m_useCustomProcedures;
}
//==============================================================================
// Downloader::startDownload
//==============================================================================
void Downloader::startDownload (const QUrl& url) {
/* Reset UI */
m_ui->progressBar->setValue (0);
m_ui->stopButton->setText (tr ("Stop"));
m_ui->downloadLabel->setText (tr ("Downloading updates"));
m_ui->timeLabel->setText (tr ("Time remaining") + ": " + tr ("unknown"));
/* Start download */
m_startTime = QDateTime::currentDateTime().toTime_t();
m_reply = m_manager->get (QNetworkRequest (url));
/* Update UI when download progress changes or download finishes */
connect (m_reply, SIGNAL (downloadProgress (qint64, qint64)),
this, SLOT (updateProgress (qint64, qint64)));
connect (m_reply, SIGNAL (finished()),
this, SLOT (onDownloadFinished()));
showNormal();
}
//==============================================================================
// Downloader::openDownload
//==============================================================================
void Downloader::openDownload() {
if (!m_filePath.isEmpty()) {
QString url = m_filePath;
if (url.startsWith ("/"))
url = "file://" + url;
else
url = "file:///" + url;
hide();
QDesktopServices::openUrl (url);
}
else {
QMessageBox::critical (this,
tr ("Error"),
tr ("Cannot find downloaded update!"),
QMessageBox::Close);
}
}
//==============================================================================
// Downloader::installUpdate
//==============================================================================
void Downloader::installUpdate() {
if (useCustomInstallProcedures())
return;
QMessageBox box;
box.setIcon (QMessageBox::Question);
box.setDefaultButton (QMessageBox::Ok);
box.setStandardButtons (QMessageBox::Ok | QMessageBox::Cancel);
box.setInformativeText (tr ("Click \"OK\" to begin installing the update"));
box.setText ("<h3>" +
tr ("In order to install the update, you may need to "
"quit the application.")
+ "</h3>");
if (box.exec() == QMessageBox::Ok) {
if (!useCustomInstallProcedures())
openDownload();
}
else {
m_ui->openButton->setEnabled (true);
m_ui->openButton->setVisible (true);
m_ui->timeLabel->setText (tr ("Click the \"Open\" button to "
"apply the update"));
}
}
//==============================================================================
// Downloader::cancelDownload
//==============================================================================
void Downloader::cancelDownload() {
if (!m_reply->isFinished()) {
QMessageBox box;
box.setWindowTitle (tr ("Updater"));
box.setIcon (QMessageBox::Question);
box.setStandardButtons (QMessageBox::Yes | QMessageBox::No);
box.setText (tr ("Are you sure you want to cancel the download?"));
if (box.exec() == QMessageBox::Yes) {
hide();
m_reply->abort();
}
}
else
hide();
}
//==============================================================================
// Downloader::onDownloadFinished
//==============================================================================
void Downloader::onDownloadFinished() {
m_ui->stopButton->setText (tr ("Close"));
m_ui->downloadLabel->setText (tr ("Download complete!"));
m_ui->timeLabel->setText (tr ("The installer will open separately")
+ "...");
QByteArray data = m_reply->readAll();
if (!data.isEmpty()) {
QStringList list = m_reply->url().toString().split ("/");
QFile file (QDir::tempPath() + "/" + list.at (list.count() - 1));
if (file.open (QIODevice::WriteOnly)) {
file.write (data);
file.close();
m_filePath = file.fileName();
emit downloadFinished (m_reply->url().toString(), m_filePath);
}
installUpdate();
}
}
//==============================================================================
// Downloader::calculateSizes
//==============================================================================
void Downloader::calculateSizes (qint64 received, qint64 total) {
QString totalSize;
QString receivedSize;
if (total < 1024)
totalSize = tr ("%1 bytes").arg (total);
else if (total < 1048576)
totalSize = tr ("%1 KB").arg (round (total / 1024));
else
totalSize = tr ("%1 MB").arg (round (total / 1048576));
if (received < 1024)
receivedSize = tr ("%1 bytes").arg (received);
else if (received < 1048576)
receivedSize = tr ("%1 KB").arg (received / 1024);
else
receivedSize = tr ("%1 MB").arg (received / 1048576);
m_ui->downloadLabel->setText (tr ("Downloading updates")
+ " (" + receivedSize + " " + tr ("of")
+ " " + totalSize + ")");
}
//==============================================================================
// Downloader::updateProgress
//==============================================================================
void Downloader::updateProgress (qint64 received, qint64 total) {
if (total > 0) {
m_ui->progressBar->setMinimum (0);
m_ui->progressBar->setMaximum (100);
m_ui->progressBar->setValue ((received * 100) / total);
calculateSizes (received, total);
calculateTimeRemaining (received, total);
}
else {
m_ui->progressBar->setMinimum (0);
m_ui->progressBar->setMaximum (0);
m_ui->progressBar->setValue (-1);
m_ui->downloadLabel->setText (tr ("Downloading Updates") + "...");
m_ui->timeLabel->setText (QString ("%1: %2")
.arg (tr ("Time Remaining"))
.arg (tr ("Unknown")));
}
}
//==============================================================================
// Downloader::calculateTimeRemaining
//==============================================================================
void Downloader::calculateTimeRemaining (qint64 received, qint64 total) {
uint difference = QDateTime::currentDateTime().toTime_t() - m_startTime;
if (difference > 0) {
QString timeString;
float timeRemaining = total / (received / difference);
if (timeRemaining > 7200) {
timeRemaining /= 3600;
timeString = tr ("About %1 hours").arg (int (timeRemaining + 0.5));
}
else if (timeRemaining > 60) {
timeRemaining /= 60;
timeString = tr ("About %1 minutes").arg (int (timeRemaining + 0.5));
}
else if (timeRemaining <= 60)
timeString = tr ("%1 seconds").arg (int (timeRemaining + 0.5));
m_ui->timeLabel->setText (tr ("Time remaining") + ": " + timeString);
}
}
//==============================================================================
// Downloader::round
//==============================================================================
float Downloader::round (const float& input) {
return roundf (input * 100) / 100;
}
//==============================================================================
// Downloader::setUseCustomInstallProcedures
//==============================================================================
void Downloader::setUseCustomInstallProcedures (const bool& custom) {
m_useCustomProcedures = custom;
}

91
src/Downloader.h Executable file
View File

@ -0,0 +1,91 @@
/*
* (C) Copyright 2014 Alex Spataru
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/
#ifndef DOWNLOAD_DIALOG_H
#define DOWNLOAD_DIALOG_H
#include <QDialog>
#include <ui_Downloader.h>
namespace Ui {
class Downloader;
}
class QNetworkReply;
class QNetworkAccessManager;
class Downloader : public QWidget {
Q_OBJECT
public:
explicit Downloader (QWidget* parent = 0);
~Downloader();
///
/// Returns \c true if the downloader will not attempt to install the
/// downloaded file.
///
/// This can be useful if you want to use the \c downloadFinished() signal
/// to implement your own install procedures.
///
bool useCustomInstallProcedures() const;
public slots:
///
/// Begins downloading the update
///
void startDownload (const QUrl& url);
///
/// If \c custom is set to true, then the Downloader will not attempt to
/// open or install the downloaded updates. This can be useful if you want
/// to implement your own install procedures using the \c downloadFinished()
/// signal.
///
void setUseCustomInstallProcedures (const bool& custom);
private slots:
void openDownload();
void installUpdate();
void cancelDownload();
void onDownloadFinished();
void calculateSizes (qint64 received, qint64 total);
void updateProgress (qint64 received, qint64 total);
void calculateTimeRemaining (qint64 received, qint64 total);
private:
///
/// Rounds the \a input to the nearest integer
///
float round (const float& input);
signals:
///
/// Emitted when the download has finished.
/// You can use this to implement your own procedures to install the
/// downloaded updates.
///
void downloadFinished (const QString& url, const QString& filepath);
private:
uint m_startTime;
QString m_filePath;
Ui::Downloader* m_ui;
QNetworkReply* m_reply;
bool m_useCustomProcedures;
QNetworkAccessManager* m_manager;
};
#endif

171
src/Downloader.ui Executable file
View File

@ -0,0 +1,171 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Downloader</class>
<widget class="QWidget" name="Downloader">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>464</width>
<height>164</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Updater</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>12</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>12</number>
</property>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</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="updater_icon">
<property name="minimumSize">
<size>
<width>96</width>
<height>96</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../etc/resources/qsimpleupdater.qrc">:/icons/update.png</pixmap>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="progressFrame" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="downloadLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Downloading updates</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="minimumSize">
<size>
<width>320</width>
<height>0</height>
</size>
</property>
<property name="value">
<number>0</number>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="timeLabel">
<property name="text">
<string>Time remaining: 0 minutes</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="buttonFrame" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>12</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>12</number>
</property>
<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="openButton">
<property name="text">
<string>Open</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="stopButton">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../etc/resources/qsimpleupdater.qrc"/>
</resources>
<connections/>
</ui>

239
src/QSimpleUpdater.cpp Normal file
View File

@ -0,0 +1,239 @@
/*
* Copyright (c) 2014-2016 Alex Spataru <alex_spataru@outlook.com>
*
* This file is part of the QSimpleUpdater library, which is released under
* the DBAD license, you can read a copy of it below:
*
* DON'T BE A DICK PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING,
* DISTRIBUTION AND MODIFICATION:
*
* Do whatever you like with the original work, just don't be a dick.
* Being a dick includes - but is not limited to - the following instances:
*
* 1a. Outright copyright infringement - Don't just copy this and change the
* name.
* 1b. Selling the unmodified original with no work done what-so-ever, that's
* REALLY being a dick.
* 1c. Modifying the original work to contain hidden harmful content.
* That would make you a PROPER dick.
*
* If you become rich through modifications, related works/services, or
* supporting the original work, share the love.
* Only a dick would make loads off this work and not buy the original works
* creator(s) a pint.
*
* Code is provided with no warranty. Using somebody else's code and bitching
* when it goes wrong makes you a DONKEY dick.
* Fix the problem yourself. A non-dick would submit the fix back.
*/
//==============================================================================
// Class Includes
//==============================================================================
#include "Updater.h"
#include "QSimpleUpdater.h"
//==============================================================================
// Implementation hacks
//==============================================================================
static QList<QString> URLS;
static QList<Updater*> UPDATERS;
//==============================================================================
// QSimpleUpdater::~QSimpleUpdater
//==============================================================================
QSimpleUpdater::~QSimpleUpdater() {
URLS.clear();
UPDATERS.clear();
}
//==============================================================================
// QSimpleUpdater::getInstance
//==============================================================================
QSimpleUpdater* QSimpleUpdater::getInstance() {
static QSimpleUpdater updater;
return &updater;
}
//==============================================================================
// QSimpleUpdater::getNotifyOnUpdate
//==============================================================================
bool QSimpleUpdater::getNotifyOnUpdate (const QString& url) const {
return getUpdater (url)->notifyOnUpdate();
}
//==============================================================================
// QSimpleUpdater::getNotifyOnFinish
//==============================================================================
bool QSimpleUpdater::getNotifyOnFinish (const QString& url) const {
return getUpdater (url)->notifyOnFinish();
}
//==============================================================================
// QSimpleUpdater::getUpdateAvailable
//==============================================================================
bool QSimpleUpdater::getUpdateAvailable (const QString& url) const {
return getUpdater (url)->updateAvailable();
}
//==============================================================================
// QSimpleUpdater::getDownloaderEnabled
//==============================================================================
bool QSimpleUpdater::getDownloaderEnabled (const QString& url) const {
return getUpdater (url)->downloaderEnabled();
}
//==============================================================================
// QSimpleUpdater::getChangelog
//==============================================================================
QString QSimpleUpdater::getChangelog (const QString& url) const {
return getUpdater (url)->changelog();
}
//==============================================================================
// QSimpleUpdater::getDownloadUrl
//==============================================================================
QString QSimpleUpdater::getDownloadUrl (const QString& url) const {
return getUpdater (url)->downloadUrl();
}
//==============================================================================
// QSimpleUpdater::getLatestVersion
//==============================================================================
QString QSimpleUpdater::getLatestVersion (const QString& url) const {
return getUpdater (url)->latestVersion();
}
//==============================================================================
// QSimpleUpdater::getPlatformKey
//==============================================================================
QString QSimpleUpdater::getPlatformKey (const QString& url) const {
return getUpdater (url)->platformKey();
}
//==============================================================================
// QSimpleUpdater::getModuleName
//==============================================================================
QString QSimpleUpdater::getModuleName (const QString& url) const {
return getUpdater (url)->moduleName();
}
//==============================================================================
// QSimpleUpdater::getModuleVersion
//==============================================================================
QString QSimpleUpdater::getModuleVersion (const QString& url) const {
return getUpdater (url)->moduleVersion();
}
//==============================================================================
// QSimpleUpdater::usesCustomInstallProcedures
//==============================================================================
bool QSimpleUpdater::usesCustomInstallProcedures (const QString& url) const {
return getUpdater (url)->useCustomInstallProcedures();
}
//==============================================================================
// QSimpleUpdater::checkForUpdates
//==============================================================================
void QSimpleUpdater::checkForUpdates (const QString& url) {
getUpdater (url)->checkForUpdates();
}
//==============================================================================
// QSimpleUpdater::setPlatformKey
//==============================================================================
void QSimpleUpdater::setPlatformKey (const QString& url,
const QString& platform) {
getUpdater (url)->setPlatformKey (platform);
}
//==============================================================================
// QSimpleUpdater::setModuleName
//==============================================================================
void QSimpleUpdater::setModuleName (const QString& url, const QString& name) {
getUpdater (url)->setModuleName (name);
}
//==============================================================================
// QSimpleUpdater::setModuleVersion
//==============================================================================
void QSimpleUpdater::setModuleVersion (const QString& url,
const QString& version) {
getUpdater (url)->setModuleVersion (version);
}
//==============================================================================
// QSimpleUpdater::setNotifyOnUpdate
//==============================================================================
void QSimpleUpdater::setNotifyOnUpdate (const QString& url,
const bool& notify) {
getUpdater (url)->setNotifyOnUpdate (notify);
}
//==============================================================================
// QSimpleUpdater::setNotifyOnFinish
//==============================================================================
void QSimpleUpdater::setNotifyOnFinish (const QString& url,
const bool& notify) {
getUpdater (url)->setNotifyOnFinish (notify);
}
//==============================================================================
// QSimpleUpdater::setDownloaderEnabled
//==============================================================================
void QSimpleUpdater::setDownloaderEnabled (const QString& url,
const bool& enabled) {
getUpdater (url)->setDownloaderEnabled (enabled);
}
//==============================================================================
// QSimpleUpdater::setUseCustomInstallProcedures
//==============================================================================
void QSimpleUpdater::setUseCustomInstallProcedures (const QString& url,
const bool& custom) {
getUpdater (url)->setUseCustomInstallProcedures (custom);
}
//==============================================================================
// QSimpleUpdater::getUpdater
//==============================================================================
Updater* QSimpleUpdater::getUpdater (const QString& url) const {
if (!URLS.contains (url)) {
Updater* updater = new Updater;
updater->setUrl (url);
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)));
}
return UPDATERS.at (URLS.indexOf (url));
}

356
src/Updater.cpp Normal file
View File

@ -0,0 +1,356 @@
/*
* Copyright (c) 2014-2016 Alex Spataru <alex_spataru@outlook.com>
*
* This file is part of the QSimpleUpdater library, which is released under
* the DBAD license, you can read a copy of it below:
*
* DON'T BE A DICK PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING,
* DISTRIBUTION AND MODIFICATION:
*
* Do whatever you like with the original work, just don't be a dick.
* Being a dick includes - but is not limited to - the following instances:
*
* 1a. Outright copyright infringement - Don't just copy this and change the
* name.
* 1b. Selling the unmodified original with no work done what-so-ever, that's
* REALLY being a dick.
* 1c. Modifying the original work to contain hidden harmful content.
* That would make you a PROPER dick.
*
* If you become rich through modifications, related works/services, or
* supporting the original work, share the love.
* Only a dick would make loads off this work and not buy the original works
* creator(s) a pint.
*
* Code is provided with no warranty. Using somebody else's code and bitching
* when it goes wrong makes you a DONKEY dick.
* Fix the problem yourself. A non-dick would submit the fix back.
*/
//==============================================================================
// Class includes
//==============================================================================
#include "Updater.h"
#include "Downloader.h"
//==============================================================================
// System includes
//==============================================================================
#include <QJsonValue>
#include <QJsonObject>
#include <QMessageBox>
#include <QApplication>
#include <QJsonDocument>
#include <QDesktopServices>
//==============================================================================
// Updater::Updater
//==============================================================================
Updater::Updater() {
m_url = "";
m_openUrl = "";
m_changelog = "";
m_downloadUrl = "";
m_latestVersion = "";
m_notifyOnUpdate = true;
m_notifyOnFinish = false;
m_updateAvailable = false;
m_downloaderEnabled = true;
m_moduleName = qApp->applicationName();
m_moduleVersion = qApp->applicationVersion();
m_downloader = new Downloader();
m_manager = new QNetworkAccessManager();
#if defined Q_OS_WIN
m_platform = "windows";
#elif defined Q_OS_MAC
m_platform = "osx";
#elif defined Q_OS_LINUX
m_platform = "linux";
#elif defined Q_OS_ANDROID
m_platform = "android";
#elif defined Q_OS_IOS
m_platform = "ios";
#endif
connect (m_downloader, SIGNAL (downloadFinished (QString, QString)),
this, SIGNAL (downloadFinished (QString, QString)));
connect (m_manager, SIGNAL (finished (QNetworkReply*)),
this, SLOT (onReply (QNetworkReply*)));
}
//==============================================================================
// Updater::~Updater
//==============================================================================
Updater::~Updater() {
delete m_downloader;
}
//==============================================================================
// Updater::url
//==============================================================================
QString Updater::url() const {
return m_url;
}
//==============================================================================
// Updater::platformKey
//==============================================================================
QString Updater::platformKey() const {
return m_platform;
}
//==============================================================================
// Updater::notifyOnUpdate
//==============================================================================
bool Updater::notifyOnUpdate() const {
return m_notifyOnUpdate;
}
//==============================================================================
// Updater::notifyOnFinish
//==============================================================================
bool Updater::notifyOnFinish() const {
return m_notifyOnFinish;
}
//==============================================================================
// Updater::updateAvailable
//==============================================================================
bool Updater::updateAvailable() const {
return m_updateAvailable;
}
//==============================================================================
// Updater::downloaderEnabled
//==============================================================================
bool Updater::downloaderEnabled() const {
return m_downloaderEnabled;
}
//==============================================================================
// Updater::m_changelog
//==============================================================================
QString Updater::changelog() const {
return m_changelog;
}
//==============================================================================
// Updater::downloadUrl
//==============================================================================
QString Updater::downloadUrl() const {
return m_downloadUrl;
}
//==============================================================================
// Updater::latestVersion
//==============================================================================
QString Updater::latestVersion() const {
return m_latestVersion;
}
//==============================================================================
// Updater::moduleName
//==============================================================================
QString Updater::moduleName() const {
return m_moduleName;
}
//==============================================================================
// Updater::moduleVersion
//==============================================================================
QString Updater::moduleVersion() const {
return m_moduleVersion;
}
//==============================================================================
// Updater::useCustomInstallProcedures
//==============================================================================
bool Updater::useCustomInstallProcedures() const {
return m_downloader->useCustomInstallProcedures();
}
//==============================================================================
// Updater::checkForUpdates
//==============================================================================
void Updater::checkForUpdates() {
m_manager->get (QNetworkRequest (url()));
}
//==============================================================================
// Updater::setUrl
//==============================================================================
void Updater::setUrl (const QString& url) {
m_url = url;
}
//==============================================================================
// Updater::setNotifyOnUpdate
//==============================================================================
void Updater::setNotifyOnUpdate (const bool& notify) {
m_notifyOnUpdate = notify;
}
//==============================================================================
// Updater::setNotifyOnFinish
//==============================================================================
void Updater::setNotifyOnFinish (const bool& notify) {
m_notifyOnFinish = notify;
}
//==============================================================================
// Updater::setPlatformKey
//==============================================================================
void Updater::setPlatformKey (const QString& platformKey) {
m_platform = platformKey;
}
//==============================================================================
// Updater::setModuleName
//==============================================================================
void Updater::setModuleName (const QString& name) {
m_moduleName = name;
}
//==============================================================================
// Updater::setDownloaderEnabled
//==============================================================================
void Updater::setDownloaderEnabled (const bool& enabled) {
m_downloaderEnabled = enabled;
}
//==============================================================================
// Updater::setUseCustomInstallProcedures
//==============================================================================
void Updater::setUseCustomInstallProcedures (const bool& custom) {
m_downloader->setUseCustomInstallProcedures (custom);
}
//==============================================================================
// Updater::setModuleVersion
//==============================================================================
void Updater::setModuleVersion (const QString& version) {
m_moduleVersion = version;
}
//==============================================================================
// Updater::onReply
//==============================================================================
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()));
}
emit checkingFinished (url());
}
//==============================================================================
// Updater::setUpdateAvailable
//==============================================================================
void Updater::setUpdateAvailable (const bool& available) {
m_updateAvailable = available;
QMessageBox box;
box.setTextFormat (Qt::RichText);
box.setIcon (QMessageBox::Information);
if (updateAvailable() && (notifyOnUpdate() || notifyOnFinish())) {
QString text = tr ("Would you like to download the update now?");
QString title = "<h3>"
+ tr ("Version %1 of %2 has been released!")
.arg (latestVersion()).arg (moduleName())
+ "</h3>";
box.setText (title);
box.setInformativeText (text);
box.setStandardButtons (QMessageBox::No | QMessageBox::Yes);
box.setDefaultButton (QMessageBox::Yes);
if (box.exec() == QMessageBox::Yes) {
if (!m_openUrl.isEmpty())
QDesktopServices::openUrl (QUrl (m_openUrl));
else if (downloaderEnabled())
m_downloader->startDownload (downloadUrl());
else
QDesktopServices::openUrl (QUrl (downloadUrl()));
}
}
else if (notifyOnFinish()) {
box.setStandardButtons (QMessageBox::Close);
box.setInformativeText (tr ("No updates are available for the moment"));
box.setText ("<h3>"
+ tr ("Congratulations! You are running the "
"latest version of %1").arg (moduleName())
+ "</h3>");
box.exec();
}
}
//==============================================================================
// Updater::compare
//==============================================================================
bool Updater::compare (const QString& x, const QString& y) {
QStringList versionsX = x.split (".");
QStringList versionsY = y.split (".");
int count = qMin (versionsX.count(), versionsY.count());
for (int i = 0; i < count; ++i) {
int a = QString (versionsX.at (i)).toInt();
int b = QString (versionsY.at (i)).toInt();
if (a > b)
return true;
else if (b > a)
return false;
}
return versionsY.count() < versionsX.count();
}

248
src/Updater.h Normal file
View File

@ -0,0 +1,248 @@
/*
* Copyright (c) 2014-2016 Alex Spataru <alex_spataru@outlook.com>
*
* This file is part of the QSimpleUpdater library, which is released under
* the DBAD license, you can read a copy of it below:
*
* DON'T BE A DICK PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING,
* DISTRIBUTION AND MODIFICATION:
*
* Do whatever you like with the original work, just don't be a dick.
* Being a dick includes - but is not limited to - the following instances:
*
* 1a. Outright copyright infringement - Don't just copy this and change the
* name.
* 1b. Selling the unmodified original with no work done what-so-ever, that's
* REALLY being a dick.
* 1c. Modifying the original work to contain hidden harmful content.
* That would make you a PROPER dick.
*
* If you become rich through modifications, related works/services, or
* supporting the original work, share the love.
* Only a dick would make loads off this work and not buy the original works
* creator(s) a pint.
*
* Code is provided with no warranty. Using somebody else's code and bitching
* when it goes wrong makes you a DONKEY dick.
* Fix the problem yourself. A non-dick would submit the fix back.
*/
#ifndef _QSIMPLEUPDATER_UPDATER_H
#define _QSIMPLEUPDATER_UPDATER_H
#include <QUrl>
#include <QObject>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QSimpleUpdater.h>
class Downloader;
///
/// The Updater class is in charge of downloading and analyzing
/// the appcast and "reacting" based on the options given by the
/// user/developer/application.
///
class QSU_DECL Updater : public QObject {
Q_OBJECT
public:
Updater();
~Updater();
///
/// Returns the AppCast URL (from which we extract the update definitions)
///
QString url() const;
///
/// Returns the current platform key, which is used to differentiate the
/// different download links (and download versions) based on the current
/// operating system.
///
/// You can modify this value with the \c setPlatformKey() function
///
QString platformKey() const;
///
/// Returns \c true if the class is set to notify the user when an update
/// is found online. By default this value is set to \c true.
///
bool notifyOnUpdate() const;
///
/// Returns \c true if the class is set to notify the user when it finishes
/// checking for updates (even if there are no updates available).
/// By default this value is set to \c false.
///
bool notifyOnFinish() const;
///
/// Returns \c true if the updater found an updated version of the
/// application/module online.
///
bool updateAvailable() const;
///
/// Returns \c if the updater allows the integrated downloader to download
/// and install the update (if aplicable).
///
bool downloaderEnabled() const;
///
/// Returns the latest changelog
///
QString changelog() const;
///
/// Returns the URL from where we can download the update
///
QString downloadUrl() const;
///
/// Returns the latest version online
///
QString latestVersion() const;
///
/// Returns the application name, which can be set manually or
/// automatically using the \c qApp->applicationName() function.
///
QString moduleName() const;
///
/// Returns the application version, which can be set manually or
/// automatically using the \c qApp->applicationVersion() function.
///
QString moduleVersion() const;
///
/// Returns \c true if the downloader will not attempt to install the
/// downloaded file.
///
/// This can be useful if you want to use the \c downloadFinished() signal
/// to implement your own install procedures.
///
bool useCustomInstallProcedures() const;
public slots:
///
/// Downloads the update definitions file and analyzes it to determine the
/// latest version and the download links
///
void checkForUpdates();
///
/// Changes the \a url from where we download the update definitions
///
void setUrl (const QString& url);
///
/// If \c notify is set to true, the \c QSimpleUpdater will notify the user
/// when an update is available.
///
/// If \c notify is set to false, the \c QSimpleUpdater will not notify the
/// user when an update is available.
///
void setNotifyOnUpdate (const bool& notify);
///
/// If set to \c true, the updater will notify the user when it finishes
/// checking for updates (even where there are no updates available).
///
/// If set to \c false (default), the updater will only notify the user
/// when there is an update available (if setNotifyOnUpdate() is \c true).
///
void setNotifyOnFinish (const bool& notify);
///
/// Changes the name of the module, this can be useful in large applications
/// that only need to update certain components of them (e.g. plugins).
///
void setModuleName (const QString& name);
///
/// Changes the version of the module, this can be useful in large
/// applications that only need to update certain components of them
/// (e.g. plugins).
///
void setModuleVersion (const QString& version);
///
/// If \a enabled is set to true, then the user will be able to download
/// and install updates directly from the application, without the need
/// of opening the download URL from a browser and manually installing
/// the update.
///
void setDownloaderEnabled (const bool& enabled);
///
/// Changes the platform key/id. This can be useful if the update depends
/// on more than the underlying operating system on which the application
/// runs.
///
void setPlatformKey (const QString& platformKey);
///
/// If \c custom is set to true, then the Downloader will not attempt to
/// open or install the downloaded updates. This can be useful if you want
/// to implement your own install procedures using the \c downloadFinished()
/// signal.
///
void setUseCustomInstallProcedures (const bool& custom);
signals:
///
/// Emitted when the download definitions have been downloaded and analyzed.
///
void checkingFinished (const QString& url);
///
/// Emitted when the download has finished.
/// You can use this to implement your own procedures to install the
/// downloaded updates.
///
void downloadFinished (const QString& url, const QString& filepath);
private slots:
///
/// Reads and analyzes the downloaded update definition.
///
void onReply (QNetworkReply* reply);
///
/// Changes the appropiate internal values, shows notifications (if allowed)
/// and (if allowed) initializes the internal downloader.
///
void setUpdateAvailable (const bool& available);
private:
///
/// Returns \c true if version \a x is greater than version \a y.
/// This is used to determine if the online version is greater than the
/// installed version of the module.
///
bool compare (const QString& x, const QString& y);
private:
QString m_url;
bool m_notifyOnUpdate;
bool m_notifyOnFinish;
bool m_updateAvailable;
bool m_downloaderEnabled;
QString m_openUrl;
QString m_platform;
QString m_changelog;
QString m_moduleName;
QString m_downloadUrl;
QString m_moduleVersion;
QString m_latestVersion;
Downloader* m_downloader;
QNetworkAccessManager* m_manager;
};
#endif