From c78a3c49900b6cccd6516c7f8bee766f2c31f56c Mon Sep 17 00:00:00 2001 From: lordmulder Date: Wed, 11 Dec 2013 15:50:26 +0100 Subject: [PATCH] Improved web-update to actually check for new versions and initiate a download. --- gui/win_updater.ui | 6 + res/buttons/shield_grey.png | Bin 0 -> 3426 bytes res/resources.qrc | 1 + src/version.h | 2 +- src/win_main.cpp | 10 +- src/win_updater.cpp | 245 ++++++++++++++++++++++++++++++------ src/win_updater.h | 13 +- 7 files changed, 237 insertions(+), 40 deletions(-) create mode 100644 res/buttons/shield_grey.png diff --git a/gui/win_updater.ui b/gui/win_updater.ui index db97974..391f33a 100644 --- a/gui/win_updater.ui +++ b/gui/win_updater.ui @@ -505,9 +505,15 @@ true + + PointingHandCursor + http://www.example.com/update_info.html + + Qt::LinksAccessibleByMouse + diff --git a/res/buttons/shield_grey.png b/res/buttons/shield_grey.png new file mode 100644 index 0000000000000000000000000000000000000000..96e4b5570ff2d70d4bc4f7c42f879d53256604ec GIT binary patch literal 3426 zcmV-o4W06dP)004&%004{+008|`004nN004b?008NW002DY000@xb3BE2000U( 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/shield_error.png buttons/shield_exclamation.png buttons/shield_green.png + buttons/shield_grey.png buttons/suspended.png buttons/transmit.png buttons/trash.png diff --git a/src/version.h b/src/version.h index c36c07c..0733844 100644 --- a/src/version.h +++ b/src/version.h @@ -26,7 +26,7 @@ #define VER_X264_MAJOR 2 #define VER_X264_MINOR 2 #define VER_X264_PATCH 7 -#define VER_X264_BUILD 686 +#define VER_X264_BUILD 691 #define VER_X264_MINIMUM_REV 2363 #define VER_X264_CURRENT_API 140 diff --git a/src/win_main.cpp b/src/win_main.cpp index 1f77a69..a03426d 100644 --- a/src/win_main.cpp +++ b/src/win_main.cpp @@ -978,7 +978,15 @@ void MainWindow::checkUpdates(void) } UpdaterDialog *updater = new UpdaterDialog(this, QString("%1/toolset").arg(m_appDir)); - updater->exec(); + const int ret = updater->exec(); + + if(ret == 42) + { + X264_DELETE(updater); + qWarning("Exitting to install update..."); + close(); + } + X264_DELETE(updater); } diff --git a/src/win_updater.cpp b/src/win_updater.cpp index f030b49..6e7d094 100644 --- a/src/win_updater.cpp +++ b/src/win_updater.cpp @@ -30,6 +30,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include /////////////////////////////////////////////////////////////////////////////// @@ -56,6 +62,7 @@ UpdaterDialog::UpdaterDialog(QWidget *parent, const QString &binDir) QDialog(parent), ui(new Ui::UpdaterDialog()), m_binDir(binDir), + m_status(UpdateCheckThread::UpdateStatus_NotStartedYet), m_thread(NULL), m_firstShow(true) { @@ -66,6 +73,14 @@ UpdaterDialog::UpdaterDialog(QWidget *parent, const QString &binDir) //Fix size setFixedSize(size()); + //Enable buttons + connect(ui->buttonCancel, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->buttonDownload, SIGNAL(clicked()), this, SLOT(installUpdate())); + connect(ui->buttonRetry, SIGNAL(clicked()), this, SLOT(checkForUpdates())); + + //Enable info label + connect(ui->labelUrl, SIGNAL(linkActivated(QString)), this, SLOT(openUrl(QString))); + //Init animation m_animator = new QMovie(":/images/loading.gif"); ui->labelLoadingCenter->setMovie(m_animator); @@ -92,6 +107,13 @@ UpdaterDialog::~UpdaterDialog(void) } } + if((!m_keysFile.isEmpty()) && QFile::exists(m_keysFile)) + { + QFile::setPermissions(m_keysFile, QFile::ReadOwner | QFile::WriteOwner); + QFile::remove(m_keysFile); + m_keysFile.clear(); + } + X264_DELETE(m_thread); X264_DELETE(m_animator); @@ -125,21 +147,34 @@ void UpdaterDialog::closeEvent(QCloseEvent *e) } } +void UpdaterDialog::keyPressEvent(QKeyEvent *event) +{ + if(event->key() == Qt::Key_F11) + { + QFile logFile(QString("%1/%2.log").arg(x264_temp_directory(), x264_rand_str())); + if(logFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + logFile.write("\xEF\xBB\xBF"); + for(QStringList::ConstIterator iter = m_logFile.constBegin(); iter != m_logFile.constEnd(); iter++) + { + logFile.write(iter->toUtf8()); + logFile.write("\r\n"); + } + logFile.close(); + QDesktopServices::openUrl(QUrl::fromLocalFile(logFile.fileName())); + } + } +} + /////////////////////////////////////////////////////////////////////////////// // Slots /////////////////////////////////////////////////////////////////////////////// void UpdaterDialog::initUpdate(void) { - - //Reset icons - - - //Show animation - //Check binary files - QStringList binaries; - if(!checkBinaries(binaries)) + QString wgetBin, gpgvBin; + if(!checkBinaries(wgetBin, gpgvBin)) { ui->buttonCancel->setEnabled(true); QMessageBox::critical(this, tr("File Error"), tr("At least one file required by web-update is missing or corrupted.
Please re-install this application and then try again!")); @@ -150,16 +185,15 @@ void UpdaterDialog::initUpdate(void) //Create and setup thread if(!m_thread) { - m_thread = new UpdateCheckThread(binaries[0], binaries[1], binaries[2], false); + m_thread = new UpdateCheckThread(wgetBin, gpgvBin, m_keysFile, false); connect(m_thread, SIGNAL(statusChanged(int)), this, SLOT(threadStatusChanged(int))); - connect(m_thread, SIGNAL(progressChanged(int)), this, SLOT(threadProgressChanged(int))); - connect(m_thread, SIGNAL(messageLogged(QString)), this, SLOT(threadMessageLogged(QString))); connect(m_thread, SIGNAL(finished()), this, SLOT(threadFinished())); connect(m_thread, SIGNAL(terminated()), this, SLOT(threadFinished())); + connect(m_thread, SIGNAL(messageLogged(QString)), this, SLOT(threadMessageLogged(QString))); } - //Begin updater test run - QTimer::singleShot(0, this, SLOT(checkForUpdates())); + //Begin updater run + QTimer::singleShot(125, this, SLOT(checkForUpdates())); } void UpdaterDialog::checkForUpdates(void) @@ -169,6 +203,9 @@ void UpdaterDialog::checkForUpdates(void) qWarning("Update in progress, cannot check for updates now!"); } + //Clear texts + ui->retranslateUi(this); + //Init buttons ui->buttonCancel->setEnabled(false); ui->buttonRetry->hide(); @@ -177,27 +214,33 @@ void UpdaterDialog::checkForUpdates(void) //Hide labels ui->labelInfo->hide(); ui->labelUrl->hide(); - + //Update status threadStatusChanged(UpdateCheckThread::UpdateStatus_NotStartedYet); + //Start animation + SHOW_ANIMATION(true); + m_animator->start(); + //Update cursor QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); QApplication::setOverrideCursor(Qt::WaitCursor); + //Clear log + m_logFile.clear(); + //Start the updater thread - m_thread->start(); + QTimer::singleShot(125, m_thread, SLOT(start())); } void UpdaterDialog::threadStatusChanged(int status) { - switch(status) + switch(m_status = status) { case UpdateCheckThread::UpdateStatus_NotStartedYet: UPDATE_ICON(1, "clock"); UPDATE_ICON(2, "clock"); UPDATE_ICON(3, "clock"); - ui->retranslateUi(this); break; case UpdateCheckThread::UpdateStatus_CheckingConnection: UPDATE_ICON(1, "play"); @@ -207,40 +250,153 @@ void UpdaterDialog::threadStatusChanged(int status) UPDATE_TEXT(1, tr("Internet connection is working.")); UPDATE_ICON(2, "play"); break; - case UpdateCheckThread::UpdateStatus_CompletedUpdateAvailable: - UPDATE_ICON(3, "shield_exclamation"); - UPDATE_TEXT(3, tr("A newer version is available!")); - break; case UpdateCheckThread::UpdateStatus_ErrorNoConnection: - case UpdateCheckThread::UpdateStatus_ErrorConnectionTestFailed: - case UpdateCheckThread::UpdateStatus_ErrorFetchUpdateInfo: + UPDATE_ICON(1, "shield_error"); + UPDATE_TEXT(1, tr("Computer is currently offline!")); + UPDATE_ICON(2, "shield_grey"); + UPDATE_ICON(3, "shield_grey"); + break; + case UpdateCheckThread::UpdateStatus_ErrorConnectionTestFailed: + UPDATE_ICON(1, "shield_error"); + UPDATE_TEXT(1, tr("Internet connectivity test failed!")); + UPDATE_ICON(2, "shield_grey"); + UPDATE_ICON(3, "shield_grey"); + break; + case UpdateCheckThread::UpdateStatus_ErrorFetchUpdateInfo: + UPDATE_ICON(2, "shield_error"); + UPDATE_TEXT(2, tr("Failed to download the update information!")); + UPDATE_ICON(3, "shield_grey"); break; - default: - throw "Unknown status code!"; - } - - switch(status) - { case UpdateCheckThread::UpdateStatus_CompletedUpdateAvailable: case UpdateCheckThread::UpdateStatus_CompletedNoUpdates: case UpdateCheckThread::UpdateStatus_CompletedNewVersionOlder: UPDATE_ICON(2, "shield_green"); - UPDATE_TEXT(2, tr("Update-information was received successfully.")); + UPDATE_TEXT(2, tr("Update information received successfully.")); + UPDATE_ICON(3, "play"); + break; + default: + throw "Unknown status code!"; + } +} + +void UpdaterDialog::threadFinished(void) +{ + //Restore cursor + QApplication::restoreOverrideCursor(); + + //Stop animation + m_animator->stop(); + + //Process final updater state + switch(m_status) + { + case UpdateCheckThread::UpdateStatus_CompletedUpdateAvailable: + UPDATE_ICON(3, "shield_exclamation"); + UPDATE_TEXT(3, tr("A newer version is available!")); ui->buttonDownload->show(); + break; + case UpdateCheckThread::UpdateStatus_CompletedNoUpdates: + UPDATE_ICON(3, "shield_green"); + UPDATE_TEXT(3, tr("Your version is up-to-date.")); + break; + case UpdateCheckThread::UpdateStatus_CompletedNewVersionOlder: + UPDATE_ICON(3, "shield_error"); + UPDATE_TEXT(3, tr("Your are using a pre-release version!")); + break; + } + + //Show update info or retry button + switch(m_status) + { + case UpdateCheckThread::UpdateStatus_CompletedUpdateAvailable: + case UpdateCheckThread::UpdateStatus_CompletedNoUpdates: + case UpdateCheckThread::UpdateStatus_CompletedNewVersionOlder: + SHOW_ANIMATION(false); + ui->labelUrl->setText(QString("%1").arg(m_thread->getUpdateInfo()->m_downloadSite)); + break; case UpdateCheckThread::UpdateStatus_ErrorNoConnection: case UpdateCheckThread::UpdateStatus_ErrorConnectionTestFailed: case UpdateCheckThread::UpdateStatus_ErrorFetchUpdateInfo: - SHOW_ANIMATION(false); - ui->buttonCancel->setEnabled(true); + ui->buttonRetry->show(); break; } + + //Re-enbale cancel button + ui->buttonCancel->setEnabled(true); + +} + +void UpdaterDialog::threadMessageLogged(const QString &message) +{ + m_logFile << message; +} + +void UpdaterDialog::openUrl(const QString &url) +{ + qDebug("Open URL: %s", url.toLatin1().constData()); + QDesktopServices::openUrl(QUrl(url)); +} + +void UpdaterDialog::installUpdate(void) +{ + if(!((m_thread) && m_thread->getSuccess())) + { + qWarning("Cannot download/install update at this point!"); + return; + } + + const UpdateInfo *updateInfo = m_thread->getUpdateInfo(); + + QProcess process; + QStringList args; + QEventLoop loop; + + x264_init_process(process, x264_temp_directory(), false); + + connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit())); + connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), &loop, SLOT(quit())); + + args << QString("/Location=%1").arg(updateInfo->m_downloadAddress); + args << QString("/Filename=%1").arg(updateInfo->m_downloadFilename); + args << QString("/TicketID=%1").arg(updateInfo->m_downloadFilecode); + args << QString("/ToFolder=%1").arg(QDir::toNativeSeparators(QDir(QApplication::applicationDirPath()).canonicalPath())); + args << QString("/ToExFile=%1.exe").arg(QFileInfo(QFileInfo(QApplication::applicationFilePath()).canonicalFilePath()).completeBaseName()); + args << QString("/AppTitle=Simple x264 Launcher (Build #%1)").arg(QString::number(updateInfo->m_buildNo)); + + process.start(m_wupdFile, args); + if(!process.waitForStarted()) + { + QMessageBox::critical(this, tr("Update Failed"), tr("Sorry, failed to launch web-update program!")); + return; + } + + QApplication::setOverrideCursor(Qt::WaitCursor); + ui->buttonDownload->hide(); + ui->buttonCancel->setEnabled(false); + + loop.exec(QEventLoop::ExcludeUserInputEvents); + + if(!process.waitForFinished()) + { + process.kill(); + process.waitForFinished(); + } + + QApplication::restoreOverrideCursor(); + ui->buttonDownload->show(); + ui->buttonCancel->setEnabled(true); + + if(process.exitCode() == 0) + { + done(42); + } } /////////////////////////////////////////////////////////////////////////////// // Private Functions /////////////////////////////////////////////////////////////////////////////// -bool UpdaterDialog::checkBinaries(QStringList &binaries) +bool UpdaterDialog::checkBinaries(QString &wgetBin, QString &gpgvBin) { qDebug("[File Verification]"); @@ -254,24 +410,41 @@ bool UpdaterDialog::checkBinaries(QStringList &binaries) { "wget.exe", "7b522345239bcb95b5b0f7f50a883ba5957894a1feb769763e38ed789a8a0f63fead0155f54b9ffd0f1cdc5dfd855d207a6e7a8e4fd192589a8838ce646c504e" }, { "gpgv.exe", "e61d28e4c47b2422ceec7b8fc08f9c70f10a3056e3779a974026eb24fe09551eedc2e7f34fbe5ef8e844fab0dbe68b85c4ca69d63bf85d445f7cae152c17f589" }, { "gpgv.gpg", "58e0f0e462bbd0b5aa4f638801c1097da7da4b3eb38c8c88ad1db23705c0f11e174b083fa55fe76bd3ba196341c967833a6f3427d6f63ad8565900745535d8fa" }, + { "wupd.exe", "9dd0ae5f386aaf5df9e261a53b81569df51bccf2f9290ed42f04a5b52b4a4e1118f2c9ce3a9b2492fd5ae597600411dfa47bd7c96e2fd7bee205d603324452a2" }, { NULL, NULL } }; + QMap binaries; + + m_keysFile.clear(); + m_wupdFile.clear(); + wgetBin.clear(); + gpgvBin.clear(); + bool okay = true; - binaries.clear(); for(size_t i = 0; FILE_INFO[i].name; i++) { const QString binPath = QString("%1/common/%2").arg(m_binDir, QString::fromLatin1(FILE_INFO[i].name)); if(okay = okay && checkFileHash(binPath, FILE_INFO[i].hash)) { - binaries << binPath; + binaries.insert(FILE_INFO[i].name, binPath); } } if(okay) { - qDebug("Completed.\n"); + wgetBin = binaries.value("wget.exe"); + gpgvBin = binaries.value("gpgv.exe"); + + m_wupdFile = binaries.value("wupd.exe"); + m_keysFile = QString("%1/%2.gpg").arg(x264_temp_directory(), x264_rand_str()); + + if(okay = QFile::copy(binaries.value("gpgv.gpg"), m_keysFile)) + { + QFile::setPermissions(m_keysFile, QFile::ReadOwner); + } + qDebug("%s\n", okay ? "Completed." : "Failed to copy GPG file!"); } return okay; diff --git a/src/win_updater.h b/src/win_updater.h index bb3f62d..3afe5e4 100644 --- a/src/win_updater.h +++ b/src/win_updater.h @@ -42,20 +42,29 @@ public: protected: virtual void showEvent(QShowEvent *event); virtual void closeEvent(QCloseEvent *e); + virtual void keyPressEvent(QKeyEvent *event); private slots: void initUpdate(void); void checkForUpdates(void); void threadStatusChanged(int status); + void threadMessageLogged(const QString &message); + void threadFinished(void); + void openUrl(const QString &url); + void installUpdate(void); private: Ui::UpdaterDialog *const ui; - bool checkBinaries(QStringList &binaries); + bool checkBinaries(QString &wgetBin, QString &gpgvBin); bool checkFileHash(const QString &filePath, const char *expectedHash); bool m_firstShow; const QString m_binDir; - UpdateCheckThread *m_thread; QMovie *m_animator; + UpdateCheckThread *m_thread; + QStringList m_logFile; + QString m_keysFile; + QString m_wupdFile; + int m_status; };