From e221fefdb077e77c4c450d6469778a5b7bacbc99 Mon Sep 17 00:00:00 2001 From: Alex Spataru Date: Tue, 27 Jan 2015 18:51:53 -0600 Subject: [PATCH 1/6] Implemented download dialog & Qt4 support This commit implements a download dialog to be used inside the application (removing the need of opening the link in a web browser). The dialog manages the downloads, gives information about them (progress, time remaining, size, etc) and prompts the user to close the app while updating it. Finally, the commit also provides support for Qt4 by changing the way the UserAgent header is created. --- Fervor.pri | 8 +- fv_resources.qrc | 5 + fvdownloaddialog.cpp | 293 +++++++++++++ fvdownloaddialog.h | 51 +++ fvdownloaddialog.ui | 179 ++++++++ fvupdateconfirmdialog.cpp | 51 --- fvupdateconfirmdialog.h | 27 -- fvupdateconfirmdialog.ui | 65 --- fvupdater.cpp | 683 +++++++++++++++--------------- fvupdater.h | 20 +- sample/ui_fvupdateconfirmdialog.h | 93 ++++ update.png | Bin 0 -> 15645 bytes 12 files changed, 978 insertions(+), 497 deletions(-) create mode 100755 fv_resources.qrc create mode 100755 fvdownloaddialog.cpp create mode 100755 fvdownloaddialog.h create mode 100755 fvdownloaddialog.ui delete mode 100644 fvupdateconfirmdialog.cpp delete mode 100644 fvupdateconfirmdialog.h delete mode 100644 fvupdateconfirmdialog.ui create mode 100644 sample/ui_fvupdateconfirmdialog.h create mode 100755 update.png 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/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 0000000000000000000000000000000000000000..a4a3ef253221a3dc8d2b236b52857cb35ecbb7ed GIT binary patch literal 15645 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 Date: Tue, 27 Jan 2015 19:31:30 -0600 Subject: [PATCH 2/6] Travis CI config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Testing… --- .travis.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .travis.yml 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 From 7c713ec94ad794aec06336fe2b6064bf1b3fcf3c Mon Sep 17 00:00:00 2001 From: Alex Spataru Date: Tue, 27 Jan 2015 19:34:02 -0600 Subject: [PATCH 3/6] Add auto style scripts --- bin/autostyle.cmd | 21 +++++++++++++++++++++ bin/autostyle.sh | 19 +++++++++++++++++++ bin/readme.txt | 1 + 3 files changed, 41 insertions(+) create mode 100755 bin/autostyle.cmd create mode 100755 bin/autostyle.sh create mode 100755 bin/readme.txt 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 From 77947803750c9ca5a12647edbd75d78e0998d6de Mon Sep 17 00:00:00 2001 From: Alex Spataru Date: Tue, 27 Jan 2015 21:46:49 -0600 Subject: [PATCH 4/6] Updated README.md --- README.mdown | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.mdown b/README.mdown index dc33579..fdfbff1 100644 --- a/README.mdown +++ b/README.mdown @@ -1,3 +1,7 @@ +## Fervor + +![[Build status](https://travis-ci.org/alex-97/fervor.svg)] + Check out the [`autoupdate` branch](fervor/tree/autoupdate) by Torben Dannhauer too! ---- @@ -13,8 +17,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 +33,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/`.) From d8876c450a5628c8cd774f18b178159f6e4ae057 Mon Sep 17 00:00:00 2001 From: Alex Spataru Date: Tue, 27 Jan 2015 21:48:04 -0600 Subject: [PATCH 5/6] Update README.mdown --- README.mdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.mdown b/README.mdown index fdfbff1..d237b14 100644 --- a/README.mdown +++ b/README.mdown @@ -1,6 +1,6 @@ ## Fervor -![[Build status](https://travis-ci.org/alex-97/fervor.svg)] +![Build status](https://travis-ci.org/alex-97/fervor.svg) Check out the [`autoupdate` branch](fervor/tree/autoupdate) by Torben Dannhauer too! From 7d0c314f0c66444d703cdc6439b59ac137eb4dcb Mon Sep 17 00:00:00 2001 From: Alex Spataru Date: Tue, 27 Jan 2015 21:49:19 -0600 Subject: [PATCH 6/6] Update README.mdown --- README.mdown | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/README.mdown b/README.mdown index d237b14..6a4a943 100644 --- a/README.mdown +++ b/README.mdown @@ -4,12 +4,7 @@ Check out the [`autoupdate` branch](fervor/tree/autoupdate) by Torben Dannhauer too! ----- - -Fervor is a simple, multiplatform ([Qt](http://qt.nokia.com/)-based) application update tool, inspired by [Sparkle](http://sparkle.andymatuschak.org/). - - -# 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.