diff --git a/cmake/Modules/CheckPackages.cmake b/cmake/Modules/CheckPackages.cmake index 6c85b8d11..6b082ea11 100644 --- a/cmake/Modules/CheckPackages.cmake +++ b/cmake/Modules/CheckPackages.cmake @@ -47,6 +47,9 @@ find_package(Boost ${minBoostVersion} REQUIRED) find_package(OpenSSL ${minOpenSSLVersion} REQUIRED) find_package(ZLIB ${minZlibVersion} REQUIRED) find_package(Qt6 ${minQt6Version} REQUIRED COMPONENTS Core Network Sql Xml LinguistTools) +if (Qt6_FOUND AND (Qt6_VERSION VERSION_GREATER_EQUAL 6.10)) + find_package(Qt6 ${minQt6Version} REQUIRED COMPONENTS CorePrivate) +endif() if (DBUS) find_package(Qt6 ${minQt6Version} REQUIRED COMPONENTS DBus) set_package_properties(Qt6DBus PROPERTIES diff --git a/src/base/search/searchpluginmanager.cpp b/src/base/search/searchpluginmanager.cpp index 09b7a67cc..ab53c5d5e 100644 --- a/src/base/search/searchpluginmanager.cpp +++ b/src/base/search/searchpluginmanager.cpp @@ -487,14 +487,14 @@ void SearchPluginManager::updateNova() const Path enginePath = engineLocation(); QFile packageFile {(enginePath / Path(u"__init__.py"_s)).data()}; - packageFile.open(QIODevice::WriteOnly); - packageFile.close(); + if (packageFile.open(QIODevice::WriteOnly)) + packageFile.close(); Utils::Fs::mkdir(enginePath / Path(u"engines"_s)); QFile packageFile2 {(enginePath / Path(u"engines/__init__.py"_s)).data()}; - packageFile2.open(QIODevice::WriteOnly); - packageFile2.close(); + if (packageFile2.open(QIODevice::WriteOnly)) + packageFile2.close(); // Copy search plugin files (if necessary) const auto updateFile = [&enginePath](const Path &filename, const bool compareVersion) diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 1dc459fdb..dd07ea2ef 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -1161,7 +1161,7 @@ void MainWindow::closeEvent(QCloseEvent *e) if (!m_forceExit) { hide(); - e->accept(); + e->ignore(); return; } #else @@ -1660,11 +1660,11 @@ void MainWindow::handleUpdateCheckFinished(ProgramUpdater *updater, const bool i updater->deleteLater(); }; - const QString newVersion = updater->getNewVersion(); - if (!newVersion.isEmpty()) + const auto newVersion = updater->getNewVersion(); + if (newVersion.isValid()) { const QString msg {tr("A new version is available.") + u"
" - + tr("Do you want to download %1?").arg(newVersion) + u"

" + + tr("Do you want to download %1?").arg(newVersion.toString()) + u"

" + u"%1"_s.arg(tr("Open changelog..."))}; auto *msgBox = new QMessageBox {QMessageBox::Question, tr("qBittorrent Update Available"), msg , (QMessageBox::Yes | QMessageBox::No), this}; diff --git a/src/gui/programupdater.cpp b/src/gui/programupdater.cpp index 063bc5473..dc6965f29 100644 --- a/src/gui/programupdater.cpp +++ b/src/gui/programupdater.cpp @@ -35,10 +35,13 @@ #include #include #include +#include +#include #include #include #include "base/global.h" +#include "base/logger.h" #include "base/net/downloadmanager.h" #include "base/preferences.h" #include "base/utils/version.h" @@ -46,23 +49,20 @@ namespace { - bool isVersionMoreRecent(const QString &remoteVersion) + bool isVersionMoreRecent(const ProgramUpdater::Version &remoteVersion) { - using Version = Utils::Version<4, 3>; - - const auto newVersion = Version::fromString(remoteVersion); - if (!newVersion.isValid()) + if (!remoteVersion.isValid()) return false; - const Version currentVersion {QBT_VERSION_MAJOR, QBT_VERSION_MINOR, QBT_VERSION_BUGFIX, QBT_VERSION_BUILD}; - if (newVersion == currentVersion) + const ProgramUpdater::Version currentVersion {QBT_VERSION_MAJOR, QBT_VERSION_MINOR, QBT_VERSION_BUGFIX, QBT_VERSION_BUILD}; + if (remoteVersion == currentVersion) { const bool isDevVersion = QStringLiteral(QBT_VERSION_STATUS).contains( QRegularExpression(u"(alpha|beta|rc)"_s)); if (isDevVersion) return true; } - return (newVersion > currentVersion); + return (remoteVersion > currentVersion); } QString buildVariant() @@ -82,30 +82,34 @@ namespace void ProgramUpdater::checkForUpdates() const { + const auto USER_AGENT = QStringLiteral("qBittorrent/" QBT_VERSION_2 " ProgramUpdater (www.qbittorrent.org)"); const auto RSS_URL = u"https://www.fosshub.com/feed/5b8793a7f9ee5a5c3e97a3b2.xml"_s; + const auto FALLBACK_URL = u"https://www.qbittorrent.org/versions.json"_s; + // Don't change this User-Agent. In case our updater goes haywire, // the filehost can identify it and contact us. - Net::DownloadManager::instance()->download( - Net::DownloadRequest(RSS_URL).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2 " ProgramUpdater (www.qbittorrent.org)")) + Net::DownloadManager::instance()->download(Net::DownloadRequest(RSS_URL).userAgent(USER_AGENT) , Preferences::instance()->useProxyForGeneralPurposes(), this, &ProgramUpdater::rssDownloadFinished); + Net::DownloadManager::instance()->download(Net::DownloadRequest(FALLBACK_URL).userAgent(USER_AGENT) + , Preferences::instance()->useProxyForGeneralPurposes(), this, &ProgramUpdater::fallbackDownloadFinished); + + m_hasCompletedOneReq = false; } -QString ProgramUpdater::getNewVersion() const +ProgramUpdater::Version ProgramUpdater::getNewVersion() const { - return m_newVersion; + return shouldUseFallback() ? m_fallbackRemoteVersion : m_remoteVersion; } 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(); + LogMsg(tr("Failed to download the update info. URL: %1. Error: %2").arg(result.url, result.errorString) , Log::WARNING); + handleFinishedRequest(); return; } - qDebug("Finished downloading the new qBittorrent updates RSS"); - const auto getStringValue = [](QXmlStreamReader &xml) -> QString { xml.readNext(); @@ -146,9 +150,10 @@ void ProgramUpdater::rssDownloadFinished(const Net::DownloadResult &result) if (!version.isEmpty()) { qDebug("Detected version is %s", qUtf8Printable(version)); - if (isVersionMoreRecent(version)) + const ProgramUpdater::Version tmpVer {version}; + if (isVersionMoreRecent(tmpVer)) { - m_newVersion = version; + m_remoteVersion = tmpVer; m_updateURL = updateLink; } } @@ -163,10 +168,50 @@ void ProgramUpdater::rssDownloadFinished(const Net::DownloadResult &result) } } - emit updateCheckFinished(); + handleFinishedRequest(); +} + +void ProgramUpdater::fallbackDownloadFinished(const Net::DownloadResult &result) +{ + if (result.status != Net::DownloadStatus::Success) + { + LogMsg(tr("Failed to download the update info. URL: %1. Error: %2").arg(result.url, result.errorString) , Log::WARNING); + handleFinishedRequest(); + return; + } + + const auto json = QJsonDocument::fromJson(result.data); + +#if defined(Q_OS_MACOS) + const QString platformKey = u"macos"_s; +#elif defined(Q_OS_WIN) + const QString platformKey = u"win"_s; +#endif + + if (const QJsonValue verJSON = json[platformKey][u"version"_s]; verJSON.isString()) + { + const ProgramUpdater::Version tmpVer {verJSON.toString()}; + if (isVersionMoreRecent(tmpVer)) + m_fallbackRemoteVersion = tmpVer; + } + + handleFinishedRequest(); } bool ProgramUpdater::updateProgram() const { - return QDesktopServices::openUrl(m_updateURL); + return QDesktopServices::openUrl(shouldUseFallback() ? u"https://www.qbittorrent.org/download"_s : m_updateURL); +} + +void ProgramUpdater::handleFinishedRequest() +{ + if (m_hasCompletedOneReq) + emit updateCheckFinished(); + else + m_hasCompletedOneReq = true; +} + +bool ProgramUpdater::shouldUseFallback() const +{ + return m_fallbackRemoteVersion > m_remoteVersion; } diff --git a/src/gui/programupdater.h b/src/gui/programupdater.h index 88d41985f..531d12118 100644 --- a/src/gui/programupdater.h +++ b/src/gui/programupdater.h @@ -30,9 +30,10 @@ #pragma once #include -#include #include +#include "base/utils/version.h" + namespace Net { struct DownloadResult; @@ -45,9 +46,10 @@ class ProgramUpdater final : public QObject public: using QObject::QObject; + using Version = Utils::Version<4, 3>; void checkForUpdates() const; - QString getNewVersion() const; + Version getNewVersion() const; bool updateProgram() const; signals: @@ -55,8 +57,14 @@ signals: private slots: void rssDownloadFinished(const Net::DownloadResult &result); + void fallbackDownloadFinished(const Net::DownloadResult &result); private: - QString m_newVersion; + void handleFinishedRequest(); + bool shouldUseFallback() const; + + mutable bool m_hasCompletedOneReq = false; + Version m_remoteVersion; + Version m_fallbackRemoteVersion; QUrl m_updateURL; }; diff --git a/src/gui/uithemecommon.h b/src/gui/uithemecommon.h index 9f1545fe6..ba7a5c2c5 100644 --- a/src/gui/uithemecommon.h +++ b/src/gui/uithemecommon.h @@ -80,8 +80,14 @@ inline QHash defaultUIThemeColors() {u"TransferList.StoppedUploading"_s, {Color::Primer::Light::doneFg, Color::Primer::Dark::doneFg}}, {u"TransferList.Moving"_s, {Color::Primer::Light::successFg, Color::Primer::Dark::successFg}}, {u"TransferList.MissingFiles"_s, {Color::Primer::Light::dangerFg, Color::Primer::Dark::dangerFg}}, - {u"TransferList.Error"_s, {Color::Primer::Light::dangerFg, Color::Primer::Dark::dangerFg}}, + {u"TransferList.Error"_s, {Color::Primer::Light::dangerFg, Color::Primer::Dark::dangerFg}} + }; +} +// Palette isn't customizable in default theme +inline QHash defaultPaletteColors() +{ + return { {u"Palette.Window"_s, {{}, {}}}, {u"Palette.WindowText"_s, {{}, {}}}, {u"Palette.Base"_s, {{}, {}}}, diff --git a/src/gui/uithemedialog.cpp b/src/gui/uithemedialog.cpp index 24ee381da..2d06ceeba 100644 --- a/src/gui/uithemedialog.cpp +++ b/src/gui/uithemedialog.cpp @@ -273,8 +273,6 @@ void UIThemeDialog::loadColors() int row = 2; for (const QString &id : colorIDs) { - if (id == u"Log.Normal") - qDebug() << "!!!!!!!"; m_ui->colorsLayout->addWidget(new QLabel(id), row, 0); const UIThemeColor &defaultColor = defaultColors.value(id); diff --git a/src/gui/uithemesource.cpp b/src/gui/uithemesource.cpp index be0138ee0..b854986ea 100644 --- a/src/gui/uithemesource.cpp +++ b/src/gui/uithemesource.cpp @@ -105,6 +105,8 @@ DefaultThemeSource::DefaultThemeSource() , m_colors {defaultUIThemeColors()} { loadColors(); + // Palette isn't customizable in default theme + m_colors.insert(defaultPaletteColors()); } QByteArray DefaultThemeSource::readStyleSheet() diff --git a/src/webui/api/appcontroller.cpp b/src/webui/api/appcontroller.cpp index 95bb6e0d0..a1fc0e1da 100644 --- a/src/webui/api/appcontroller.cpp +++ b/src/webui/api/appcontroller.cpp @@ -673,12 +673,12 @@ void AppController::setPreferencesAction() if (hasKey(u"autorun_on_torrent_added_enabled"_s)) pref->setAutoRunOnTorrentAddedEnabled(it.value().toBool()); if (hasKey(u"autorun_on_torrent_added_program"_s)) - pref->setAutoRunOnTorrentAddedProgram(it.value().toString()); + pref->setAutoRunOnTorrentAddedProgram(it.value().toString().trimmed()); // Run an external program on torrent finished if (hasKey(u"autorun_enabled"_s)) pref->setAutoRunOnTorrentFinishedEnabled(it.value().toBool()); if (hasKey(u"autorun_program"_s)) - pref->setAutoRunOnTorrentFinishedProgram(it.value().toString()); + pref->setAutoRunOnTorrentFinishedProgram(it.value().toString().trimmed()); // Connection // Listening Port