diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f8f649e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: cpp + +before_install: + - sudo apt-get install build-essential libqt4-core libqt4-dev libqt4-gui qt4-dev-tools libssl-dev + +script: + - cd sample + - qmake + - make + - sudo make install diff --git a/Fervor.pri b/Fervor.pri index 6249172..1cd2079 100644 --- a/Fervor.pri +++ b/Fervor.pri @@ -34,7 +34,7 @@ SOURCES += \ $$PWD/fvplatform.cpp \ $$PWD/fvignoredversions.cpp \ $$PWD/fvavailableupdate.cpp \ - $$PWD/fvupdateconfirmdialog.cpp + $$PWD/fvdownloaddialog.cpp HEADERS += \ $$PWD/fvupdatewindow.h \ @@ -43,10 +43,12 @@ HEADERS += \ $$PWD/fvplatform.h \ $$PWD/fvignoredversions.h \ $$PWD/fvavailableupdate.h \ - $$PWD/fvupdateconfirmdialog.h + $$PWD/fvdownloaddialog.h FORMS += $$PWD/fvupdatewindow.ui \ - $$PWD/fvupdateconfirmdialog.ui + $$PWD/fvdownloaddialog.ui TRANSLATIONS += $$PWD/fervor_lt.ts CODECFORTR = UTF-8 + +RESOURCES += $$PWD/fv_resources.qrc diff --git a/README.mdown b/README.mdown index dc33579..6a4a943 100644 --- a/README.mdown +++ b/README.mdown @@ -1,11 +1,10 @@ -Check out the [`autoupdate` branch](fervor/tree/autoupdate) by Torben Dannhauer too! - ----- +## Fervor -Fervor is a simple, multiplatform ([Qt](http://qt.nokia.com/)-based) application update tool, inspired by [Sparkle](http://sparkle.andymatuschak.org/). +![Build status](https://travis-ci.org/alex-97/fervor.svg) +Check out the [`autoupdate` branch](fervor/tree/autoupdate) by Torben Dannhauer too! -# Description +--- Fervor is a software library that you include into your own [Qt](http://qt.nokia.com/)-based application in order to enable the application to automatically check for updates and suggest to install them. @@ -13,8 +12,7 @@ When installed and enabled, Fervor downloads a "flavoured" RSS feed (dubbed "app When a newer version of the application is found in the "appcast" (e.g. the user is using 1.0, and 1.1 is available), a dialog is presented to the user (see below for example) that allows the user to choose whether he/she wants to install the update, be reminded about the update later, or skip a particular proposed version altogether. A dialog also shows some release notes about the proposed update that help the user to choose whether or not to install an update. -At the moment, Fervor is not as cool as [Sparkle](http://sparkle.andymatuschak.org/) -- it is not able to install the actual update automatically (the user is given an option to download and install the update manually). Pull requests with unattended install modules for `.dmg`, `.pkg` (Mac OS X), `.msi` (Windows), `.rpm`, `.deb` (Linux) are welcome! - +Fervor also supports downloading and installing the updates directly from the application using an integrated dowload dialog. # Features @@ -30,9 +28,6 @@ At the moment, Fervor is not as cool as [Sparkle](http://sparkle.andymatuschak.o ![](http://pypt.github.com/fervor/screenshot-1.png "Update is available") -![](http://pypt.github.com/fervor/screenshot-2.png "Download the update") - - # Installation and Usage (This is a description of the sample application located in `sample/`.) diff --git a/bin/autostyle.cmd b/bin/autostyle.cmd new file mode 100755 index 0000000..afcfdc4 --- /dev/null +++ b/bin/autostyle.cmd @@ -0,0 +1,21 @@ +:: Description: This script changes the style format of +:: all the source code of the project. + +:: Setup the command line +@echo off +title Autostyle + +:: Go to the directory where the script is run +cd /d %~dp0 + +:: Style and format the source code recursively +astyle --style=allman -C -S -xG -Y -XW -w -f -F -p -xd -k3 -y -xj -c -K -L --suffix=none --recursive ../*.cpp ../*.h ../*.hxx ../*.cxx + +:: Notify the user that we have finished +echo. +echo Code styling complete! +echo. + +:: Let the user see the output +pause + diff --git a/bin/autostyle.sh b/bin/autostyle.sh new file mode 100755 index 0000000..c6d83f9 --- /dev/null +++ b/bin/autostyle.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Description: This script changes the style format of +# all the source code of the project. + +# Run only on the directory of the script +cd "$(dirname ${BASH_SOURCE[0]})" + +# Style and format recursively +astyle --style=allman -C -S -xG -Y -XW -w -f -F -p -xd -k3 -y -xj -c -K -L --suffix=none --recursive ../*.cpp ../*.h ../*.hxx ../*.cxx + +# Notify the user that we are done +echo +echo "Code styling complete!" +echo + +# Let the user see the output +read -n1 -r -p "Press any key to continue..." key +clear diff --git a/bin/readme.txt b/bin/readme.txt new file mode 100755 index 0000000..b8cd6bf --- /dev/null +++ b/bin/readme.txt @@ -0,0 +1 @@ +The scripts contained in this folder will require you to install the [astyle](http://astyle.sf.net) source code styler. \ No newline at end of file diff --git a/fv_resources.qrc b/fv_resources.qrc new file mode 100755 index 0000000..ac0c9e0 --- /dev/null +++ b/fv_resources.qrc @@ -0,0 +1,5 @@ + + + update.png + + diff --git a/fvdownloaddialog.cpp b/fvdownloaddialog.cpp new file mode 100755 index 0000000..36b31bb --- /dev/null +++ b/fvdownloaddialog.cpp @@ -0,0 +1,293 @@ +/* + * (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 "fvdownloaddialog.h" +#include "ui_fvdownloaddialog.h" + +#include "fvupdater.h" +#include "fvavailableupdate.h" + +#include +#include + +FvDownloadDialog::FvDownloadDialog (QWidget *parent) + : QWidget (parent) + , ui (new Ui::FvDownloadDialog) +{ + + // Setup the UI + ui->setupUi (this); + setAttribute(Qt::WA_DeleteOnClose); + + // 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)), this, + SLOT (ignoreSslErrors (QNetworkReply *, QList))); +} + +FvDownloadDialog::~FvDownloadDialog (void) +{ + delete ui; +} + +void FvDownloadDialog::beginDownload () +{ + FvAvailableUpdate* proposedUpdate = FvUpdater::sharedUpdater()->GetProposedUpdate(); + + if (! proposedUpdate) { + qDebug() << "Cannot get download URL!"; + return; + } + + // Know from where to download the updates + QUrl url = QUrl(proposedUpdate->GetEnclosureUrl().toString()); + + // 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 FvDownloadDialog::installUpdate (void) +{ + QMessageBox msg; + msg.setIcon (QMessageBox::Question); + msg.setText ("" + + tr ("To apply the update(s), you must first quit %1") + .arg (qApp->applicationName()) + + ""); + 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 FvDownloadDialog::openDownload (void) +{ + if (!m_path.isEmpty()) + { + QString url = m_path; + + if (url.startsWith ("/")) + url = "file://" + url; + + else + url = "file:///" + url; + + QDesktopServices::openUrl (url); + } +} + +void FvDownloadDialog::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 FvDownloadDialog::downloadFinished (void) +{ + QByteArray data = m_reply->readAll(); + + // File is invalid, alert the user and cancel operation + if (data.isEmpty()) { + QMessageBox::warning(this, tr("Software Updater"), + tr("Downloaded data is empty!")); + + close(); + return; + } + + ui->stopButton->setText (tr ("Close")); + ui->downloadLabel->setText (tr ("Download complete!")); + ui->timeLabel->setText (tr ("The installer will open in a separate window...")); + + 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 FvDownloadDialog::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 FvDownloadDialog::ignoreSslErrors (QNetworkReply *reply, + const QList& error) +{ +#ifndef Q_OS_IOS + reply->ignoreSslErrors (error); +#else + Q_UNUSED (reply); + Q_UNUSED (error); +#endif +} + +float FvDownloadDialog::roundNumber (const float& input) +{ + return roundf (input * 100) / 100; +} diff --git a/fvdownloaddialog.h b/fvdownloaddialog.h new file mode 100755 index 0000000..4f2e9c8 --- /dev/null +++ b/fvdownloaddialog.h @@ -0,0 +1,51 @@ +#ifndef FV_DOWNLOAD_DIALOG_H +#define FV_DOWNLOAD_DIALOG_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace Ui +{ +class FvDownloadDialog; +} + +class FvDownloadDialog : public QWidget +{ + Q_OBJECT + + public: + explicit FvDownloadDialog (QWidget *parent = 0); + ~FvDownloadDialog (void); + + void beginDownload (); + + 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& error); + + private: + Ui::FvDownloadDialog *ui; + + QString m_path; + bool m_download_paused; + + QNetworkReply *m_reply; + QNetworkAccessManager *m_manager; + + uint m_start_time; + + float roundNumber (const float& input); +}; + +#endif diff --git a/fvdownloaddialog.ui b/fvdownloaddialog.ui new file mode 100755 index 0000000..e12fc29 --- /dev/null +++ b/fvdownloaddialog.ui @@ -0,0 +1,179 @@ + + + FvDownloadDialog + + + + 0 + 0 + 464 + 164 + + + + + 0 + 0 + + + + Software Updater + + + + 0 + + + 12 + + + 12 + + + 12 + + + 12 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 72 + 72 + + + + div.image { + width: 72px; + height: 72px; + background-image: url('data:image/png;base64,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'); +} + + + + + + + :/icons/update.png + + + + + + + + 0 + + + + + + 75 + true + + + + Downloading updates + + + + + + + + 320 + 0 + + + + 0 + + + false + + + + + + + Time remaining: 0 minutes + + + + + + + + + + + + + + 12 + + + 12 + + + 12 + + + 12 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Open + + + + + + + Stop + + + + + + + + + + + + + diff --git a/fvupdateconfirmdialog.cpp b/fvupdateconfirmdialog.cpp deleted file mode 100644 index 33afeb0..0000000 --- a/fvupdateconfirmdialog.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "fvupdateconfirmdialog.h" -#include "fvavailableupdate.h" -#include "fvupdater.h" -#include "ui_fvupdateconfirmdialog.h" -#include - - -FvUpdateConfirmDialog::FvUpdateConfirmDialog(QWidget *parent) : - QDialog(parent), - m_ui(new Ui::FvUpdateConfirmDialog) -{ - m_ui->setupUi(this); - - // Delete on close - setAttribute(Qt::WA_DeleteOnClose, true); - - // Set the "close app, then reopen" string - QString closeReopenString = m_ui->downloadThisUpdateLabel->text().arg(QString::fromUtf8(FV_APP_NAME)); - m_ui->downloadThisUpdateLabel->setText(closeReopenString); - - // Connect buttons - connect(m_ui->confirmButtonBox, SIGNAL(accepted()), - FvUpdater::sharedUpdater(), SLOT(UpdateInstallationConfirmed())); - connect(m_ui->confirmButtonBox, SIGNAL(rejected()), - FvUpdater::sharedUpdater(), SLOT(UpdateInstallationNotConfirmed())); -} - -FvUpdateConfirmDialog::~FvUpdateConfirmDialog() -{ - delete m_ui; -} - -bool FvUpdateConfirmDialog::UpdateWindowWithCurrentProposedUpdate() -{ - FvAvailableUpdate* proposedUpdate = FvUpdater::sharedUpdater()->GetProposedUpdate(); - if (! proposedUpdate) { - return false; - } - - QString downloadLinkString = m_ui->updateFileLinkLabel->text() - .arg(proposedUpdate->GetEnclosureUrl().toString()); - m_ui->updateFileLinkLabel->setText(downloadLinkString); - - return true; -} - -void FvUpdateConfirmDialog::closeEvent(QCloseEvent* event) -{ - FvUpdater::sharedUpdater()->updateConfirmationDialogWasClosed(); - event->accept(); -} diff --git a/fvupdateconfirmdialog.h b/fvupdateconfirmdialog.h deleted file mode 100644 index 19db4ad..0000000 --- a/fvupdateconfirmdialog.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef FVUPDATECONFIRMDIALOG_H -#define FVUPDATECONFIRMDIALOG_H - -#include - -namespace Ui { -class FvUpdateConfirmDialog; -} - -class FvUpdateConfirmDialog : public QDialog -{ - Q_OBJECT - -public: - explicit FvUpdateConfirmDialog(QWidget *parent = 0); - ~FvUpdateConfirmDialog(); - - // Update the current update proposal from FvUpdater - bool UpdateWindowWithCurrentProposedUpdate(); - - void closeEvent(QCloseEvent* event); - -private: - Ui::FvUpdateConfirmDialog* m_ui; -}; - -#endif // FVUPDATECONFIRMDIALOG_H diff --git a/fvupdateconfirmdialog.ui b/fvupdateconfirmdialog.ui deleted file mode 100644 index a7aa039..0000000 --- a/fvupdateconfirmdialog.ui +++ /dev/null @@ -1,65 +0,0 @@ - - - FvUpdateConfirmDialog - - - - 0 - 0 - 480 - 160 - - - - Software Update - - - - - - The update file is located at: - - - - - - - <a href="%1">%1</a> - - - true - - - Qt::TextBrowserInteraction - - - - - - - Download this update, close "%1", install it, and then reopen "%1". - - - - - - - When you click "OK", this link will be opened in your browser. - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - diff --git a/fvupdater.cpp b/fvupdater.cpp index d82c0b4..fc75ec7 100644 --- a/fvupdater.cpp +++ b/fvupdater.cpp @@ -1,6 +1,6 @@ #include "fvupdater.h" #include "fvupdatewindow.h" -#include "fvupdateconfirmdialog.h" +#include "fvdownloaddialog.h" #include "fvplatform.h" #include "fvignoredversions.h" #include "fvavailableupdate.h" @@ -19,7 +19,7 @@ #ifdef FV_DEBUG - // Unit tests +// Unit tests # include "fvversioncomparatortest.h" #endif @@ -29,384 +29,391 @@ FvUpdater* FvUpdater::m_Instance = 0; FvUpdater* FvUpdater::sharedUpdater() { - static QMutex mutex; - if (! m_Instance) { - mutex.lock(); + static QMutex mutex; + if (! m_Instance) { + mutex.lock(); - if (! m_Instance) { - m_Instance = new FvUpdater; - } + if (! m_Instance) { + m_Instance = new FvUpdater; + } - mutex.unlock(); - } + mutex.unlock(); + } - return m_Instance; + return m_Instance; } void FvUpdater::drop() { - static QMutex mutex; - mutex.lock(); - delete m_Instance; - m_Instance = 0; - mutex.unlock(); + static QMutex mutex; + mutex.lock(); + delete m_Instance; + m_Instance = 0; + mutex.unlock(); } FvUpdater::FvUpdater() : QObject(0) { - m_reply = 0; - m_updaterWindow = 0; - m_updateConfirmationDialog = 0; - m_proposedUpdate = 0; + m_reply = 0; + m_updaterWindow = 0; + m_download_dialog = 0; + m_proposedUpdate = 0; - // Translation mechanism - installTranslator(); + // Translation mechanism + installTranslator(); #ifdef FV_DEBUG - // Unit tests - FvVersionComparatorTest* test = new FvVersionComparatorTest(); - test->runAll(); - delete test; + // Unit tests + FvVersionComparatorTest* test = new FvVersionComparatorTest(); + test->runAll(); + delete test; #endif } FvUpdater::~FvUpdater() { - if (m_proposedUpdate) { - delete m_proposedUpdate; - m_proposedUpdate = 0; - } + if (m_proposedUpdate) { + delete m_proposedUpdate; + m_proposedUpdate = 0; + } - hideUpdateConfirmationDialog(); - hideUpdaterWindow(); + hideDownloadDialog(); + hideUpdaterWindow(); } void FvUpdater::installTranslator() { - QTranslator translator; - QString locale = QLocale::system().name(); - translator.load(QString("fervor_") + locale); + QTranslator translator; + QString locale = QLocale::system().name(); + translator.load(QString("fervor_") + locale); //QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8")); - qApp->installTranslator(&translator); + qApp->installTranslator(&translator); } void FvUpdater::showUpdaterWindowUpdatedWithCurrentUpdateProposal() { - // Destroy window if already exists - hideUpdaterWindow(); + // Destroy window if already exists + hideUpdaterWindow(); - // Create a new window - m_updaterWindow = new FvUpdateWindow(); - m_updaterWindow->UpdateWindowWithCurrentProposedUpdate(); - m_updaterWindow->show(); + // Create a new window + m_updaterWindow = new FvUpdateWindow(); + m_updaterWindow->UpdateWindowWithCurrentProposedUpdate(); + m_updaterWindow->show(); } void FvUpdater::hideUpdaterWindow() { - if (m_updaterWindow) { - if (! m_updaterWindow->close()) { - qWarning() << "Update window didn't close, leaking memory from now on"; - } + if (m_updaterWindow) { + if (! m_updaterWindow->close()) { + qWarning() << "Update window didn't close, leaking memory from now on"; + } - // not deleting because of Qt::WA_DeleteOnClose + // not deleting because of Qt::WA_DeleteOnClose - m_updaterWindow = 0; - } + m_updaterWindow = 0; + } } void FvUpdater::updaterWindowWasClosed() { - // (Re-)nullify a pointer to a destroyed QWidget or you're going to have a bad time. - m_updaterWindow = 0; + // (Re-)nullify a pointer to a destroyed QWidget or you're going to have a bad time. + m_updaterWindow = 0; } - -void FvUpdater::showUpdateConfirmationDialogUpdatedWithCurrentUpdateProposal() -{ - // Destroy dialog if already exists - hideUpdateConfirmationDialog(); - - // Create a new window - m_updateConfirmationDialog = new FvUpdateConfirmDialog(); - m_updateConfirmationDialog->UpdateWindowWithCurrentProposedUpdate(); - m_updateConfirmationDialog->show(); -} - -void FvUpdater::hideUpdateConfirmationDialog() +void FvUpdater::hideDownloadDialog() { - if (m_updateConfirmationDialog) { - if (! m_updateConfirmationDialog->close()) { - qWarning() << "Update confirmation dialog didn't close, leaking memory from now on"; - } + if (m_download_dialog) { + if (! m_download_dialog->close()) { + qWarning() << "Update confirmation dialog didn't close, leaking memory from now on"; + } - // not deleting because of Qt::WA_DeleteOnClose + // not deleting because of Qt::WA_DeleteOnClose - m_updateConfirmationDialog = 0; - } + m_download_dialog = 0; + } } -void FvUpdater::updateConfirmationDialogWasClosed() +void FvUpdater::downloadDialogWasClosed() { - // (Re-)nullify a pointer to a destroyed QWidget or you're going to have a bad time. - m_updateConfirmationDialog = 0; + // (Re-)nullify a pointer to a destroyed QWidget or you're going to have a bad time. + m_download_dialog = 0; } void FvUpdater::SetFeedURL(QUrl feedURL) { - m_feedURL = feedURL; + m_feedURL = feedURL; } void FvUpdater::SetFeedURL(QString feedURL) { - SetFeedURL(QUrl(feedURL)); + SetFeedURL(QUrl(feedURL)); } QString FvUpdater::GetFeedURL() { - return m_feedURL.toString(); + return m_feedURL.toString(); } FvAvailableUpdate* FvUpdater::GetProposedUpdate() { - return m_proposedUpdate; + return m_proposedUpdate; } void FvUpdater::InstallUpdate() { - qDebug() << "Install update"; + qDebug() << "Install update"; + + // Destroy dialog if already exists + hideDownloadDialog(); - showUpdateConfirmationDialogUpdatedWithCurrentUpdateProposal(); + // Create a new window + m_download_dialog = new FvDownloadDialog(); + m_download_dialog->beginDownload(); + + // Hide update information dialog + hideUpdaterWindow(); } void FvUpdater::SkipUpdate() { - qDebug() << "Skip update"; + qDebug() << "Skip update"; - FvAvailableUpdate* proposedUpdate = GetProposedUpdate(); - if (! proposedUpdate) { - qWarning() << "Proposed update is NULL (shouldn't be at this point)"; - return; - } + FvAvailableUpdate* proposedUpdate = GetProposedUpdate(); + if (! proposedUpdate) { + qWarning() << "Proposed update is NULL (shouldn't be at this point)"; + return; + } - // Start ignoring this particular version - FVIgnoredVersions::IgnoreVersion(proposedUpdate->GetEnclosureVersion()); + // Start ignoring this particular version + FVIgnoredVersions::IgnoreVersion(proposedUpdate->GetEnclosureVersion()); - hideUpdaterWindow(); - hideUpdateConfirmationDialog(); // if any; shouldn't be shown at this point, but who knows + hideUpdaterWindow(); + hideDownloadDialog(); // if any; shouldn't be shown at this point, but who knows } void FvUpdater::RemindMeLater() { - qDebug() << "Remind me later"; + qDebug() << "Remind me later"; - hideUpdaterWindow(); - hideUpdateConfirmationDialog(); // if any; shouldn't be shown at this point, but who knows + hideUpdaterWindow(); + hideDownloadDialog(); // if any; shouldn't be shown at this point, but who knows } void FvUpdater::UpdateInstallationConfirmed() { - qDebug() << "Confirm update installation"; - - FvAvailableUpdate* proposedUpdate = GetProposedUpdate(); - if (! proposedUpdate) { - qWarning() << "Proposed update is NULL (shouldn't be at this point)"; - return; - } - - // Open a link - if (! QDesktopServices::openUrl(proposedUpdate->GetEnclosureUrl())) { - showErrorDialog(tr("Unable to open this link in a browser. Please do it manually."), true); - return; - } - - hideUpdaterWindow(); - hideUpdateConfirmationDialog(); + qDebug() << "Confirm update installation"; + + FvAvailableUpdate* proposedUpdate = GetProposedUpdate(); + if (! proposedUpdate) { + qWarning() << "Proposed update is NULL (shouldn't be at this point)"; + return; + } + + // Open a link + if (! QDesktopServices::openUrl(proposedUpdate->GetEnclosureUrl())) { + showErrorDialog(tr("Unable to open this link in a browser. Please do it manually."), true); + return; + } + + hideUpdaterWindow(); + hideDownloadDialog(); } void FvUpdater::UpdateInstallationNotConfirmed() { - qDebug() << "Do not confirm update installation"; + qDebug() << "Do not confirm update installation"; - hideUpdateConfirmationDialog(); // if any; shouldn't be shown at this point, but who knows - // leave the "update proposal window" inact + hideDownloadDialog(); // if any; shouldn't be shown at this point, but who knows + // leave the "update proposal window" inact } bool FvUpdater::CheckForUpdates(bool silentAsMuchAsItCouldGet) { - if (m_feedURL.isEmpty()) { - qCritical() << "Please set feed URL via setFeedURL() before calling CheckForUpdates()."; - return false; - } - - m_silentAsMuchAsItCouldGet = silentAsMuchAsItCouldGet; - - // Check if application's organization name and domain are set, fail otherwise - // (nowhere to store QSettings to) - if (QApplication::organizationName().isEmpty()) { - qCritical() << "QApplication::organizationName is not set. Please do that."; - return false; - } - if (QApplication::organizationDomain().isEmpty()) { - qCritical() << "QApplication::organizationDomain is not set. Please do that."; - return false; - } - - // Set application name / version is not set yet - if (QApplication::applicationName().isEmpty()) { - QString appName = QString::fromUtf8(FV_APP_NAME); - qWarning() << "QApplication::applicationName is not set, setting it to '" << appName << "'"; - QApplication::setApplicationName(appName); - } - if (QApplication::applicationVersion().isEmpty()) { - QString appVersion = QString::fromUtf8(FV_APP_VERSION); - qWarning() << "QApplication::applicationVersion is not set, setting it to '" << appVersion << "'"; - QApplication::setApplicationVersion(appVersion); - } - - cancelDownloadFeed(); - m_httpRequestAborted = false; - startDownloadFeed(m_feedURL); - - return true; + if (m_feedURL.isEmpty()) { + qCritical() << "Please set feed URL via setFeedURL() before calling CheckForUpdates()."; + return false; + } + + m_silentAsMuchAsItCouldGet = silentAsMuchAsItCouldGet; + + // Check if application's organization name and domain are set, fail otherwise + // (nowhere to store QSettings to) + if (QApplication::organizationName().isEmpty()) { + qCritical() << "QApplication::organizationName is not set. Please do that."; + return false; + } + if (QApplication::organizationDomain().isEmpty()) { + qCritical() << "QApplication::organizationDomain is not set. Please do that."; + return false; + } + + // Set application name / version is not set yet + if (QApplication::applicationName().isEmpty()) { + QString appName = QString::fromUtf8(FV_APP_NAME); + qWarning() << "QApplication::applicationName is not set, setting it to '" << appName << "'"; + QApplication::setApplicationName(appName); + } + if (QApplication::applicationVersion().isEmpty()) { + QString appVersion = QString::fromUtf8(FV_APP_VERSION); + qWarning() << "QApplication::applicationVersion is not set, setting it to '" << appVersion << "'"; + QApplication::setApplicationVersion(appVersion); + } + + cancelDownloadFeed(); + m_httpRequestAborted = false; + startDownloadFeed(m_feedURL); + + return true; } bool FvUpdater::CheckForUpdatesSilent() { - return CheckForUpdates(true); + return CheckForUpdates(true); } bool FvUpdater::CheckForUpdatesNotSilent() { - return CheckForUpdates(false); + return CheckForUpdates(false); } void FvUpdater::startDownloadFeed(QUrl url) { - m_xml.clear(); + m_xml.clear(); + + QNetworkRequest request; + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/xml"); + + // The QNetworkRequest::UserAgentHeader seems to work only in Qt5... + // however, creating the header "manually" allows the library to + // work also in Qt4. + // - QNetworkRequest request; - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/xml"); - request.setHeader(QNetworkRequest::UserAgentHeader, QApplication::applicationName()); - request.setUrl(url); + QString _agent = QString("%1/%2 (%3)") + .arg(QApplication::applicationName()) + .arg(QApplication::applicationVersion()) + .arg(QApplication::organizationName()); - m_reply = m_qnam.get(request); + request.setRawHeader("User-Agent", _agent.toUtf8()); + request.setUrl(url); - connect(m_reply, SIGNAL(readyRead()), this, SLOT(httpFeedReadyRead())); - connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(httpFeedUpdateDataReadProgress(qint64, qint64))); - connect(m_reply, SIGNAL(finished()), this, SLOT(httpFeedDownloadFinished())); + m_reply = m_qnam.get(request); + + connect(m_reply, SIGNAL(readyRead()), this, SLOT(httpFeedReadyRead())); + connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(httpFeedUpdateDataReadProgress(qint64, qint64))); + connect(m_reply, SIGNAL(finished()), this, SLOT(httpFeedDownloadFinished())); } void FvUpdater::cancelDownloadFeed() { - if (m_reply) { - m_httpRequestAborted = true; - m_reply->abort(); - } + if (m_reply) { + m_httpRequestAborted = true; + m_reply->abort(); + } } void FvUpdater::httpFeedReadyRead() { - // this slot gets called every time the QNetworkReply has new data. - // We read all of its new data and write it into the file. - // That way we use less RAM than when reading it at the finished() - // signal of the QNetworkReply - m_xml.addData(m_reply->readAll()); + // this slot gets called every time the QNetworkReply has new data. + // We read all of its new data and write it into the file. + // That way we use less RAM than when reading it at the finished() + // signal of the QNetworkReply + m_xml.addData(m_reply->readAll()); } void FvUpdater::httpFeedUpdateDataReadProgress(qint64 bytesRead, - qint64 totalBytes) + qint64 totalBytes) { - Q_UNUSED(bytesRead); - Q_UNUSED(totalBytes); + Q_UNUSED(bytesRead); + Q_UNUSED(totalBytes); - if (m_httpRequestAborted) { - return; - } + if (m_httpRequestAborted) { + return; + } } void FvUpdater::httpFeedDownloadFinished() { - if (m_httpRequestAborted) { - m_reply->deleteLater(); - return; - } + if (m_httpRequestAborted) { + m_reply->deleteLater(); + return; + } - QVariant redirectionTarget = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute); - if (m_reply->error()) { + QVariant redirectionTarget = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (m_reply->error()) { - // Error. - showErrorDialog(tr("Feed download failed: %1.").arg(m_reply->errorString()), false); + // Error. + showErrorDialog(tr("Feed download failed: %1.").arg(m_reply->errorString()), false); - } else if (! redirectionTarget.isNull()) { - QUrl newUrl = m_feedURL.resolved(redirectionTarget.toUrl()); + } else if (! redirectionTarget.isNull()) { + QUrl newUrl = m_feedURL.resolved(redirectionTarget.toUrl()); - m_feedURL = newUrl; - m_reply->deleteLater(); + m_feedURL = newUrl; + m_reply->deleteLater(); - startDownloadFeed(m_feedURL); - return; + startDownloadFeed(m_feedURL); + return; - } else { + } else { - // Done. - xmlParseFeed(); + // Done. + xmlParseFeed(); - } + } - m_reply->deleteLater(); - m_reply = 0; + m_reply->deleteLater(); + m_reply = 0; } bool FvUpdater::xmlParseFeed() { - QString currentTag, currentQualifiedTag; + QString currentTag, currentQualifiedTag; - QString xmlTitle, xmlLink, xmlReleaseNotesLink, xmlPubDate, xmlEnclosureUrl, - xmlEnclosureVersion, xmlEnclosurePlatform, xmlEnclosureType; - unsigned long xmlEnclosureLength = 0; + QString xmlTitle, xmlLink, xmlReleaseNotesLink, xmlPubDate, xmlEnclosureUrl, + xmlEnclosureVersion, xmlEnclosurePlatform, xmlEnclosureType; + unsigned long xmlEnclosureLength = 0; - // Parse - while (! m_xml.atEnd()) { + // Parse + while (! m_xml.atEnd()) { - m_xml.readNext(); + m_xml.readNext(); - if (m_xml.isStartElement()) { + if (m_xml.isStartElement()) { - currentTag = m_xml.name().toString(); - currentQualifiedTag = m_xml.qualifiedName().toString(); + currentTag = m_xml.name().toString(); + currentQualifiedTag = m_xml.qualifiedName().toString(); - if (m_xml.name() == "item") { + if (m_xml.name() == "item") { - xmlTitle.clear(); - xmlLink.clear(); - xmlReleaseNotesLink.clear(); - xmlPubDate.clear(); - xmlEnclosureUrl.clear(); - xmlEnclosureVersion.clear(); - xmlEnclosurePlatform.clear(); - xmlEnclosureLength = 0; - xmlEnclosureType.clear(); + xmlTitle.clear(); + xmlLink.clear(); + xmlReleaseNotesLink.clear(); + xmlPubDate.clear(); + xmlEnclosureUrl.clear(); + xmlEnclosureVersion.clear(); + xmlEnclosurePlatform.clear(); + xmlEnclosureLength = 0; + xmlEnclosureType.clear(); - } else if (m_xml.name() == "enclosure") { + } else if (m_xml.name() == "enclosure") { - QXmlStreamAttributes attribs = m_xml.attributes(); + QXmlStreamAttributes attribs = m_xml.attributes(); - if (attribs.hasAttribute("fervor:platform")) { + if (attribs.hasAttribute("fervor:platform")) { - if (FvPlatform::CurrentlyRunningOnPlatform(attribs.value("fervor:platform").toString().trimmed())) { + if (FvPlatform::CurrentlyRunningOnPlatform(attribs.value("fervor:platform").toString().trimmed())) { - xmlEnclosurePlatform = attribs.value("fervor:platform").toString().trimmed(); + xmlEnclosurePlatform = attribs.value("fervor:platform").toString().trimmed(); - if (attribs.hasAttribute("url")) { - xmlEnclosureUrl = attribs.value("url").toString().trimmed(); - } else { - xmlEnclosureUrl = ""; - } + if (attribs.hasAttribute("url")) { + xmlEnclosureUrl = attribs.value("url").toString().trimmed(); + } else { + xmlEnclosureUrl = ""; + } // First check for Sparkle's version, then overwrite with Fervor's version (if any) if (attribs.hasAttribute("sparkle:version")) { @@ -422,86 +429,86 @@ bool FvUpdater::xmlParseFeed() } } - if (attribs.hasAttribute("length")) { - xmlEnclosureLength = attribs.value("length").toString().toLong(); - } else { - xmlEnclosureLength = 0; - } - if (attribs.hasAttribute("type")) { - xmlEnclosureType = attribs.value("type").toString().trimmed(); - } else { - xmlEnclosureType = ""; - } + if (attribs.hasAttribute("length")) { + xmlEnclosureLength = attribs.value("length").toString().toLong(); + } else { + xmlEnclosureLength = 0; + } + if (attribs.hasAttribute("type")) { + xmlEnclosureType = attribs.value("type").toString().trimmed(); + } else { + xmlEnclosureType = ""; + } - } + } - } + } - } + } - } else if (m_xml.isEndElement()) { + } else if (m_xml.isEndElement()) { - if (m_xml.name() == "item") { + if (m_xml.name() == "item") { - // That's it - we have analyzed a single and we'll stop - // here (because the topmost is the most recent one, and thus - // the newest version. + // That's it - we have analyzed a single and we'll stop + // here (because the topmost is the most recent one, and thus + // the newest version. - return searchDownloadedFeedForUpdates(xmlTitle, - xmlLink, - xmlReleaseNotesLink, - xmlPubDate, - xmlEnclosureUrl, - xmlEnclosureVersion, - xmlEnclosurePlatform, - xmlEnclosureLength, - xmlEnclosureType); + return searchDownloadedFeedForUpdates(xmlTitle, + xmlLink, + xmlReleaseNotesLink, + xmlPubDate, + xmlEnclosureUrl, + xmlEnclosureVersion, + xmlEnclosurePlatform, + xmlEnclosureLength, + xmlEnclosureType); - } + } - } else if (m_xml.isCharacters() && ! m_xml.isWhitespace()) { + } else if (m_xml.isCharacters() && ! m_xml.isWhitespace()) { - if (currentTag == "title") { - xmlTitle += m_xml.text().toString().trimmed(); + if (currentTag == "title") { + xmlTitle += m_xml.text().toString().trimmed(); - } else if (currentTag == "link") { - xmlLink += m_xml.text().toString().trimmed(); + } else if (currentTag == "link") { + xmlLink += m_xml.text().toString().trimmed(); - } else if (currentQualifiedTag == "sparkle:releaseNotesLink") { - xmlReleaseNotesLink += m_xml.text().toString().trimmed(); + } else if (currentQualifiedTag == "sparkle:releaseNotesLink") { + xmlReleaseNotesLink += m_xml.text().toString().trimmed(); - } else if (currentTag == "pubDate") { - xmlPubDate += m_xml.text().toString().trimmed(); + } else if (currentTag == "pubDate") { + xmlPubDate += m_xml.text().toString().trimmed(); - } + } - } + } - if (m_xml.error() && m_xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) { + if (m_xml.error() && m_xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) { - showErrorDialog(tr("Feed parsing failed: %1 %2.").arg(QString::number(m_xml.lineNumber()), m_xml.errorString()), false); - return false; + showErrorDialog(tr("Feed parsing failed: %1 %2.").arg(QString::number(m_xml.lineNumber()), m_xml.errorString()), false); + return false; - } - } + } + } // No updates were found if we're at this point // (not a single element found) showInformationDialog(tr("No updates were found."), false); - return false; + return false; } bool FvUpdater::searchDownloadedFeedForUpdates(QString xmlTitle, - QString xmlLink, - QString xmlReleaseNotesLink, - QString xmlPubDate, - QString xmlEnclosureUrl, - QString xmlEnclosureVersion, - QString xmlEnclosurePlatform, - unsigned long xmlEnclosureLength, - QString xmlEnclosureType) + QString xmlLink, + QString xmlReleaseNotesLink, + QString xmlPubDate, + QString xmlEnclosureUrl, + QString xmlEnclosureVersion, + QString xmlEnclosurePlatform, + unsigned long xmlEnclosureLength, + QString xmlEnclosureType) { qDebug() << "Title:" << xmlTitle; qDebug() << "Link:" << xmlLink; @@ -513,89 +520,79 @@ bool FvUpdater::searchDownloadedFeedForUpdates(QString xmlTitle, qDebug() << "Enclosure length:" << xmlEnclosureLength; qDebug() << "Enclosure type:" << xmlEnclosureType; - // Validate - if (xmlReleaseNotesLink.isEmpty()) { - if (xmlLink.isEmpty()) { - showErrorDialog(tr("Feed error: \"release notes\" link is empty"), false); - return false; - } else { - xmlReleaseNotesLink = xmlLink; - } - } else { - xmlLink = xmlReleaseNotesLink; - } - if (! (xmlLink.startsWith("http://") || xmlLink.startsWith("https://"))) { - showErrorDialog(tr("Feed error: invalid \"release notes\" link"), false); - return false; - } - if (xmlEnclosureUrl.isEmpty() || xmlEnclosureVersion.isEmpty() || xmlEnclosurePlatform.isEmpty()) { + // Validate + if (xmlReleaseNotesLink.isEmpty()) { + if (xmlLink.isEmpty()) { + showErrorDialog(tr("Feed error: \"release notes\" link is empty"), false); + return false; + } else { + xmlReleaseNotesLink = xmlLink; + } + } else { + xmlLink = xmlReleaseNotesLink; + } + if (! (xmlLink.startsWith("http://") || xmlLink.startsWith("https://"))) { + showErrorDialog(tr("Feed error: invalid \"release notes\" link"), false); + return false; + } + if (xmlEnclosureUrl.isEmpty() || xmlEnclosureVersion.isEmpty() || xmlEnclosurePlatform.isEmpty()) { showErrorDialog(tr("Feed error: invalid \"enclosure\" with the download link"), false); - return false; - } + return false; + } - // Relevant version? - if (FVIgnoredVersions::VersionIsIgnored(xmlEnclosureVersion)) { - qDebug() << "Version '" << xmlEnclosureVersion << "' is ignored, too old or something like that."; + // Relevant version? + if (FVIgnoredVersions::VersionIsIgnored(xmlEnclosureVersion)) { + qDebug() << "Version '" << xmlEnclosureVersion << "' is ignored, too old or something like that."; - showInformationDialog(tr("No updates were found."), false); + showInformationDialog(tr("No updates were found."), false); - return true; // Things have succeeded when you think of it. - } + return true; // Things have succeeded when you think of it. + } - // - // Success! At this point, we have found an update that can be proposed - // to the user. - // + // + // Success! At this point, we have found an update that can be proposed + // to the user. + // - if (m_proposedUpdate) { - delete m_proposedUpdate; m_proposedUpdate = 0; - } - m_proposedUpdate = new FvAvailableUpdate(); - m_proposedUpdate->SetTitle(xmlTitle); - m_proposedUpdate->SetReleaseNotesLink(xmlReleaseNotesLink); - m_proposedUpdate->SetPubDate(xmlPubDate); - m_proposedUpdate->SetEnclosureUrl(xmlEnclosureUrl); - m_proposedUpdate->SetEnclosureVersion(xmlEnclosureVersion); - m_proposedUpdate->SetEnclosurePlatform(xmlEnclosurePlatform); - m_proposedUpdate->SetEnclosureLength(xmlEnclosureLength); - m_proposedUpdate->SetEnclosureType(xmlEnclosureType); + if (m_proposedUpdate) { + delete m_proposedUpdate; m_proposedUpdate = 0; + } + m_proposedUpdate = new FvAvailableUpdate(); + m_proposedUpdate->SetTitle(xmlTitle); + m_proposedUpdate->SetReleaseNotesLink(xmlReleaseNotesLink); + m_proposedUpdate->SetPubDate(xmlPubDate); + m_proposedUpdate->SetEnclosureUrl(xmlEnclosureUrl); + m_proposedUpdate->SetEnclosureVersion(xmlEnclosureVersion); + m_proposedUpdate->SetEnclosurePlatform(xmlEnclosurePlatform); + m_proposedUpdate->SetEnclosureLength(xmlEnclosureLength); + m_proposedUpdate->SetEnclosureType(xmlEnclosureType); - // Show "look, there's an update" window - showUpdaterWindowUpdatedWithCurrentUpdateProposal(); + // Show "look, there's an update" window + showUpdaterWindowUpdatedWithCurrentUpdateProposal(); - return true; + return true; } void FvUpdater::showErrorDialog(QString message, bool showEvenInSilentMode) { - if (m_silentAsMuchAsItCouldGet) { - if (! showEvenInSilentMode) { - // Don't show errors in the silent mode - return; - } - } - - QMessageBox dlFailedMsgBox; - dlFailedMsgBox.setIcon(QMessageBox::Critical); - dlFailedMsgBox.setText(tr("Error")); - dlFailedMsgBox.setInformativeText(message); - dlFailedMsgBox.exec(); + if (! (m_silentAsMuchAsItCouldGet && !showEvenInSilentMode)) { + QMessageBox dlFailedMsgBox; + dlFailedMsgBox.setIcon(QMessageBox::Critical); + dlFailedMsgBox.setText(tr("Error")); + dlFailedMsgBox.setInformativeText(message); + dlFailedMsgBox.exec(); + } } void FvUpdater::showInformationDialog(QString message, bool showEvenInSilentMode) { - if (m_silentAsMuchAsItCouldGet) { - if (! showEvenInSilentMode) { - // Don't show information dialogs in the silent mode - return; - } - } - - QMessageBox dlInformationMsgBox; - dlInformationMsgBox.setIcon(QMessageBox::Information); - dlInformationMsgBox.setText(tr("Information")); - dlInformationMsgBox.setInformativeText(message); - dlInformationMsgBox.exec(); + if (! (m_silentAsMuchAsItCouldGet && !showEvenInSilentMode)) { + QMessageBox dlInformationMsgBox; + dlInformationMsgBox.setIcon(QMessageBox::Information); + dlInformationMsgBox.setText(tr("Information")); + dlInformationMsgBox.setInformativeText(message); + dlInformationMsgBox.exec(); + } } diff --git a/fvupdater.h b/fvupdater.h index 04b69fa..edd85c6 100644 --- a/fvupdater.h +++ b/fvupdater.h @@ -6,10 +6,11 @@ #include #include #include + + class FvUpdateWindow; -class FvUpdateConfirmDialog; class FvAvailableUpdate; - +class FvDownloadDialog; class FvUpdater : public QObject { @@ -46,7 +47,7 @@ public slots: protected: friend class FvUpdateWindow; // Uses GetProposedUpdate() and others - friend class FvUpdateConfirmDialog; // Uses GetProposedUpdate() and others + friend class FvDownloadDialog; // Uses GetProposedUpdate() and others FvAvailableUpdate* GetProposedUpdate(); @@ -80,14 +81,12 @@ protected slots: // Windows / dialogs // FvUpdateWindow* m_updaterWindow; // Updater window (NULL if not shown) - void showUpdaterWindowUpdatedWithCurrentUpdateProposal(); // Show updater window + void showUpdaterWindowUpdatedWithCurrentUpdateProposal(); // Show updater window void hideUpdaterWindow(); // Hide + destroy m_updaterWindow void updaterWindowWasClosed(); // Sent by the updater window when it gets closed - FvUpdateConfirmDialog* m_updateConfirmationDialog; // Update confirmation dialog (NULL if not shown) - void showUpdateConfirmationDialogUpdatedWithCurrentUpdateProposal(); // Show update confirmation dialog - void hideUpdateConfirmationDialog(); // Hide + destroy m_updateConfirmationDialog - void updateConfirmationDialogWasClosed(); // Sent by the update confirmation dialog when it gets closed + void hideDownloadDialog(); // Hide + destroy m_updateConfirmationDialog + void downloadDialogWasClosed(); // Sent by the update confirmation dialog when it gets closed // Available update (NULL if not fetched) FvAvailableUpdate* m_proposedUpdate; @@ -145,6 +144,11 @@ private slots: // void installTranslator(); // Initialize translation mechanism + // + // Download dialog + // + FvDownloadDialog *m_download_dialog; + }; #endif // FVUPDATER_H diff --git a/sample/ui_fvupdateconfirmdialog.h b/sample/ui_fvupdateconfirmdialog.h new file mode 100644 index 0000000..c0799fb --- /dev/null +++ b/sample/ui_fvupdateconfirmdialog.h @@ -0,0 +1,93 @@ +/******************************************************************************** +** Form generated from reading UI file 'fvupdateconfirmdialog.ui' +** +** Created by: Qt User Interface Compiler version 4.8.6 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_FVUPDATECONFIRMDIALOG_H +#define UI_FVUPDATECONFIRMDIALOG_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_FvUpdateConfirmDialog +{ +public: + QVBoxLayout *verticalLayout; + QLabel *updateFileIsLocatedLabel; + QLabel *updateFileLinkLabel; + QLabel *downloadThisUpdateLabel; + QLabel *whenYouClickOkLabel; + QDialogButtonBox *confirmButtonBox; + + void setupUi(QDialog *FvUpdateConfirmDialog) + { + if (FvUpdateConfirmDialog->objectName().isEmpty()) + FvUpdateConfirmDialog->setObjectName(QString::fromUtf8("FvUpdateConfirmDialog")); + FvUpdateConfirmDialog->resize(480, 160); + verticalLayout = new QVBoxLayout(FvUpdateConfirmDialog); + verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); + updateFileIsLocatedLabel = new QLabel(FvUpdateConfirmDialog); + updateFileIsLocatedLabel->setObjectName(QString::fromUtf8("updateFileIsLocatedLabel")); + + verticalLayout->addWidget(updateFileIsLocatedLabel); + + updateFileLinkLabel = new QLabel(FvUpdateConfirmDialog); + updateFileLinkLabel->setObjectName(QString::fromUtf8("updateFileLinkLabel")); + updateFileLinkLabel->setOpenExternalLinks(true); + updateFileLinkLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + + verticalLayout->addWidget(updateFileLinkLabel); + + downloadThisUpdateLabel = new QLabel(FvUpdateConfirmDialog); + downloadThisUpdateLabel->setObjectName(QString::fromUtf8("downloadThisUpdateLabel")); + + verticalLayout->addWidget(downloadThisUpdateLabel); + + whenYouClickOkLabel = new QLabel(FvUpdateConfirmDialog); + whenYouClickOkLabel->setObjectName(QString::fromUtf8("whenYouClickOkLabel")); + + verticalLayout->addWidget(whenYouClickOkLabel); + + confirmButtonBox = new QDialogButtonBox(FvUpdateConfirmDialog); + confirmButtonBox->setObjectName(QString::fromUtf8("confirmButtonBox")); + confirmButtonBox->setOrientation(Qt::Horizontal); + confirmButtonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); + + verticalLayout->addWidget(confirmButtonBox); + + + retranslateUi(FvUpdateConfirmDialog); + + QMetaObject::connectSlotsByName(FvUpdateConfirmDialog); + } // setupUi + + void retranslateUi(QDialog *FvUpdateConfirmDialog) + { + FvUpdateConfirmDialog->setWindowTitle(QApplication::translate("FvUpdateConfirmDialog", "Software Update", 0, QApplication::UnicodeUTF8)); + updateFileIsLocatedLabel->setText(QApplication::translate("FvUpdateConfirmDialog", "The update file is located at:", 0, QApplication::UnicodeUTF8)); + updateFileLinkLabel->setText(QApplication::translate("FvUpdateConfirmDialog", "%1", 0, QApplication::UnicodeUTF8)); + downloadThisUpdateLabel->setText(QApplication::translate("FvUpdateConfirmDialog", "Download this update, close \"%1\", install it, and then reopen \"%1\".", 0, QApplication::UnicodeUTF8)); + whenYouClickOkLabel->setText(QApplication::translate("FvUpdateConfirmDialog", "When you click \"OK\", this link will be opened in your browser.", 0, QApplication::UnicodeUTF8)); + } // retranslateUi + +}; + +namespace Ui { + class FvUpdateConfirmDialog: public Ui_FvUpdateConfirmDialog {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_FVUPDATECONFIRMDIALOG_H diff --git a/update.png b/update.png new file mode 100755 index 0000000..a4a3ef2 Binary files /dev/null and b/update.png differ