diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 5983ab8a6..b194a1cad 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -90,7 +90,6 @@ #include "statsdialog.h" #include "statusbar.h" #include "torrentcreatordialog.h" - #include "transferlistfilterswidget.h" #include "transferlistmodel.h" #include "transferlistwidget.h" @@ -148,9 +147,6 @@ MainWindow::MainWindow(QWidget *parent) , m_posInitialized(false) , m_forceExit(false) , m_unlockDlgShowing(false) -#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) - , m_wasUpdateCheckEnabled(false) -#endif , m_hasPython(false) { m_ui->setupUi(this); @@ -317,11 +313,11 @@ MainWindow::MainWindow(QWidget *parent) connect(m_ui->actionUseAlternativeSpeedLimits, &QAction::triggered, this, &MainWindow::toggleAlternativeSpeeds); #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) - m_programUpdateTimer = new QTimer(this); - m_programUpdateTimer->setInterval(60 * 60 * 1000); - m_programUpdateTimer->setSingleShot(true); - connect(m_programUpdateTimer, &QTimer::timeout, this, &MainWindow::checkProgramUpdate); - connect(m_ui->actionCheckForUpdates, &QAction::triggered, this, &MainWindow::checkProgramUpdate); + connect(m_ui->actionCheckForUpdates, &QAction::triggered, this, [this]() { checkProgramUpdate(true); }); + + // trigger an early check on startup + if (pref->isUpdateCheckEnabled()) + checkProgramUpdate(false); #else m_ui->actionCheckForUpdates->setVisible(false); #endif @@ -804,7 +800,8 @@ void MainWindow::cleanup() m_preventTimer->stop(); #if (defined(Q_OS_WIN) || defined(Q_OS_MACOS)) - m_programUpdateTimer->stop(); + if (m_programUpdateTimer) + m_programUpdateTimer->stop(); #endif // remove all child widgets @@ -1583,15 +1580,21 @@ void MainWindow::loadPreferences(const bool configureSession) m_propertiesWidget->reloadPreferences(); #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) - if (pref->isUpdateCheckEnabled() && !m_wasUpdateCheckEnabled) + if (pref->isUpdateCheckEnabled()) { - m_wasUpdateCheckEnabled = true; - checkProgramUpdate(); + if (!m_programUpdateTimer) + { + m_programUpdateTimer = new QTimer(this); + m_programUpdateTimer->setInterval(60 * 60 * 1000); + m_programUpdateTimer->setSingleShot(true); + connect(m_programUpdateTimer, &QTimer::timeout, this, [this]() { checkProgramUpdate(false); }); + m_programUpdateTimer->start(); + } } - else if (!pref->isUpdateCheckEnabled() && m_wasUpdateCheckEnabled) + else { - m_wasUpdateCheckEnabled = false; - m_programUpdateTimer->stop(); + delete m_programUpdateTimer; + m_programUpdateTimer = nullptr; } #endif @@ -1897,15 +1900,21 @@ void MainWindow::on_actionDownloadFromURL_triggered() } #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) -void MainWindow::handleUpdateCheckFinished(const bool updateAvailable, const QString &newVersion, const bool invokedByUser) +void MainWindow::handleUpdateCheckFinished(ProgramUpdater *updater, const bool invokedByUser) { m_ui->actionCheckForUpdates->setEnabled(true); m_ui->actionCheckForUpdates->setText(tr("&Check for Updates")); m_ui->actionCheckForUpdates->setToolTip(tr("Check for program updates")); - QObject *signalSender = sender(); + const auto cleanup = [this, updater]() + { + if (m_programUpdateTimer) + m_programUpdateTimer->start(); + updater->deleteLater(); + }; - if (updateAvailable) + const QString newVersion = updater->getNewVersion(); + if (!newVersion.isEmpty()) { const QString msg {tr("A new version is available.") + "
" + tr("Do you want to download %1?").arg(newVersion) + "

" @@ -1915,38 +1924,31 @@ void MainWindow::handleUpdateCheckFinished(const bool updateAvailable, const QSt msgBox->setAttribute(Qt::WA_DeleteOnClose); msgBox->setAttribute(Qt::WA_ShowWithoutActivating); msgBox->setDefaultButton(QMessageBox::Yes); - connect(msgBox, &QMessageBox::buttonClicked, this, [this, msgBox, signalSender](QAbstractButton *button) + connect(msgBox, &QMessageBox::buttonClicked, this, [this, msgBox, updater](QAbstractButton *button) { if (msgBox->buttonRole(button) == QMessageBox::YesRole) { - // The user want to update, let's download the update - auto *updater = dynamic_cast(signalSender); updater->updateProgram(); } - else - { - if (Preferences::instance()->isUpdateCheckEnabled()) - m_programUpdateTimer->start(); - } - - signalSender->deleteLater(); }); + connect(msgBox, &QDialog::finished, this, cleanup); msgBox->open(); } - else if (invokedByUser) + else { - auto *msgBox = new QMessageBox {QMessageBox::Information, QLatin1String("qBittorrent") - , tr("No updates available.\nYou are already using the latest version.") - , QMessageBox::Ok, this}; - msgBox->setAttribute(Qt::WA_DeleteOnClose); - connect(msgBox, &QDialog::finished, this, [this, signalSender](const int) + if (invokedByUser) { - if (Preferences::instance()->isUpdateCheckEnabled()) - m_programUpdateTimer->start(); - - signalSender->deleteLater(); - }); - msgBox->open(); + auto *msgBox = new QMessageBox {QMessageBox::Information, QLatin1String("qBittorrent") + , tr("No updates available.\nYou are already using the latest version.") + , QMessageBox::Ok, this}; + msgBox->setAttribute(Qt::WA_DeleteOnClose); + connect(msgBox, &QDialog::finished, this, cleanup); + msgBox->open(); + } + else + { + cleanup(); + } } } #endif @@ -2106,18 +2108,23 @@ QIcon MainWindow::getSystrayIcon() const #endif // Q_OS_MACOS #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) -void MainWindow::checkProgramUpdate() +void MainWindow::checkProgramUpdate(const bool invokedByUser) { - m_programUpdateTimer->stop(); // If the user had clicked the menu item + if (m_programUpdateTimer) + m_programUpdateTimer->stop(); + m_ui->actionCheckForUpdates->setEnabled(false); m_ui->actionCheckForUpdates->setText(tr("Checking for Updates...")); m_ui->actionCheckForUpdates->setToolTip(tr("Already checking for program updates in the background")); - bool invokedByUser = m_ui->actionCheckForUpdates == qobject_cast(sender()); - ProgramUpdater *updater = new ProgramUpdater(this, invokedByUser); - connect(updater, &ProgramUpdater::updateCheckFinished, this, &MainWindow::handleUpdateCheckFinished); + + auto *updater = new ProgramUpdater(this); + connect(updater, &ProgramUpdater::updateCheckFinished + , this, [this, invokedByUser, updater]() + { + handleUpdateCheckFinished(updater, invokedByUser); + }); updater->checkForUpdates(); } - #endif #ifdef Q_OS_WIN diff --git a/src/gui/mainwindow.h b/src/gui/mainwindow.h index 6f0ee5998..63a8096ba 100644 --- a/src/gui/mainwindow.h +++ b/src/gui/mainwindow.h @@ -47,6 +47,7 @@ class ExecutionLogWidget; class LineEdit; class OptionsDialog; class PowerManagement; +class ProgramUpdater; class PropertiesWidget; class RSSWidget; class SearchWidget; @@ -134,9 +135,6 @@ private slots: void finishedTorrent(BitTorrent::Torrent *const torrent) const; void askRecursiveTorrentDownloadConfirmation(BitTorrent::Torrent *const torrent); void optionsSaved(); -#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) - void handleUpdateCheckFinished(bool updateAvailable, const QString &newVersion, bool invokedByUser); -#endif void toggleAlternativeSpeeds(); #ifdef Q_OS_WIN @@ -177,9 +175,7 @@ private slots: void on_actionLock_triggered(); // Check for unpaused downloading or seeding torrents and prevent system suspend/sleep according to preferences void updatePowerManagementState(); -#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) - void checkProgramUpdate(); -#endif + void toolbarMenuRequested(const QPoint &point); void toolbarIconsOnly(); void toolbarTextOnly(); @@ -252,10 +248,13 @@ private: // Power Management PowerManagement *m_pwr; QTimer *m_preventTimer; -#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) - QTimer *m_programUpdateTimer; - bool m_wasUpdateCheckEnabled; -#endif bool m_hasPython; QMenu *m_toolbarMenu; + +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) + void checkProgramUpdate(bool invokedByUser); + void handleUpdateCheckFinished(ProgramUpdater *updater, bool invokedByUser); + + QTimer *m_programUpdateTimer = nullptr; +#endif }; diff --git a/src/gui/programupdater.cpp b/src/gui/programupdater.cpp index 5d813434b..7301b83ea 100644 --- a/src/gui/programupdater.cpp +++ b/src/gui/programupdater.cpp @@ -1,5 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2021 Mike Tzou (Chocobo1) * Copyright (C) 2010 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -72,12 +73,6 @@ namespace } } -ProgramUpdater::ProgramUpdater(QObject *parent, const bool invokedByUser) - : QObject(parent) - , m_invokedByUser(invokedByUser) -{ -} - void ProgramUpdater::checkForUpdates() const { const auto RSS_URL = QString::fromLatin1("https://www.fosshub.com/feed/5b8793a7f9ee5a5c3e97a3b2.xml"); @@ -88,12 +83,17 @@ void ProgramUpdater::checkForUpdates() const , this, &ProgramUpdater::rssDownloadFinished); } +QString ProgramUpdater::getNewVersion() const +{ + return m_newVersion; +} + void ProgramUpdater::rssDownloadFinished(const Net::DownloadResult &result) { if (result.status != Net::DownloadStatus::Success) { qDebug() << "Downloading the new qBittorrent updates RSS failed:" << result.errorString; - emit updateCheckFinished(false, QString(), m_invokedByUser); + emit updateCheckFinished(); return; } @@ -110,17 +110,16 @@ void ProgramUpdater::rssDownloadFinished(const Net::DownloadResult &result) #ifdef Q_OS_MACOS const QString OS_TYPE {"Mac OS X"}; #elif defined(Q_OS_WIN) - const QString OS_TYPE - {(::IsWindows7OrGreater() - && QSysInfo::currentCpuArchitecture().endsWith("64")) + const QString OS_TYPE {(::IsWindows7OrGreater() + && QSysInfo::currentCpuArchitecture().endsWith("64")) ? "Windows x64" : "Windows"}; #endif - QString version; - QXmlStreamReader xml(result.data); bool inItem = false; + QString version; QString updateLink; QString type; + QXmlStreamReader xml(result.data); while (!xml.atEnd()) { @@ -148,7 +147,10 @@ void ProgramUpdater::rssDownloadFinished(const Net::DownloadResult &result) { qDebug("Detected version is %s", qUtf8Printable(version)); if (isVersionMoreRecent(version)) - m_updateUrl = updateLink; + { + m_newVersion = version; + m_updateURL = updateLink; + } } break; } @@ -161,11 +163,10 @@ void ProgramUpdater::rssDownloadFinished(const Net::DownloadResult &result) } } - emit updateCheckFinished(!m_updateUrl.isEmpty(), version, m_invokedByUser); + emit updateCheckFinished(); } -void ProgramUpdater::updateProgram() const +bool ProgramUpdater::updateProgram() const { - Q_ASSERT(!m_updateUrl.isEmpty()); - QDesktopServices::openUrl(m_updateUrl); + return QDesktopServices::openUrl(m_updateURL); } diff --git a/src/gui/programupdater.h b/src/gui/programupdater.h index 723281d91..1a22886a4 100644 --- a/src/gui/programupdater.h +++ b/src/gui/programupdater.h @@ -1,5 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2021 Mike Tzou (Chocobo1) * Copyright (C) 2010 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -29,6 +30,8 @@ #pragma once #include +#include +#include namespace Net { @@ -41,18 +44,19 @@ class ProgramUpdater final : public QObject Q_DISABLE_COPY(ProgramUpdater) public: - explicit ProgramUpdater(QObject *parent = nullptr, bool invokedByUser = false); + using QObject::QObject; void checkForUpdates() const; - void updateProgram() const; + QString getNewVersion() const; + bool updateProgram() const; signals: - void updateCheckFinished(bool updateAvailable, const QString &version, bool invokedByUser); + void updateCheckFinished(); private slots: void rssDownloadFinished(const Net::DownloadResult &result); private: - QString m_updateUrl; - const bool m_invokedByUser; + QString m_newVersion; + QUrl m_updateURL; };