mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-11-24 02:06:07 +03:00
parent
2ef059807a
commit
890630944d
12 changed files with 541 additions and 347 deletions
|
@ -88,6 +88,7 @@
|
|||
|
||||
#ifndef DISABLE_GUI
|
||||
#include "gui/addnewtorrentdialog.h"
|
||||
#include "gui/desktopintegration.h"
|
||||
#include "gui/mainwindow.h"
|
||||
#include "gui/shutdownconfirmdialog.h"
|
||||
#include "gui/uithememanager.h"
|
||||
|
@ -102,6 +103,7 @@ namespace
|
|||
{
|
||||
#define SETTINGS_KEY(name) u"Application/" name
|
||||
#define FILELOGGER_SETTINGS_KEY(name) (SETTINGS_KEY(u"FileLogger/") name)
|
||||
#define NOTIFICATIONS_SETTINGS_KEY(name) (SETTINGS_KEY(u"GUI/Notifications/"_qs) name)
|
||||
|
||||
const QString LOG_FOLDER = u"logs"_qs;
|
||||
const QChar PARAMS_SEPARATOR = u'|';
|
||||
|
@ -112,7 +114,7 @@ namespace
|
|||
const int MAX_FILELOG_SIZE = 1000 * 1024 * 1024; // 1000MiB
|
||||
const int DEFAULT_FILELOG_SIZE = 65 * 1024; // 65KiB
|
||||
|
||||
#if !defined(DISABLE_GUI)
|
||||
#ifndef DISABLE_GUI
|
||||
const int PIXMAP_CACHE_SIZE = 64 * 1024 * 1024; // 64MiB
|
||||
#endif
|
||||
}
|
||||
|
@ -132,6 +134,9 @@ Application::Application(int &argc, char **argv)
|
|||
#ifdef Q_OS_WIN
|
||||
, m_processMemoryPriority(SETTINGS_KEY(u"ProcessMemoryPriority"_qs))
|
||||
#endif
|
||||
#ifndef DISABLE_GUI
|
||||
, m_storeNotificationTorrentAdded(NOTIFICATIONS_SETTINGS_KEY(u"TorrentAdded"_qs))
|
||||
#endif
|
||||
{
|
||||
qRegisterMetaType<Log::Msg>("Log::Msg");
|
||||
qRegisterMetaType<Log::Peer>("Log::Peer");
|
||||
|
@ -198,10 +203,25 @@ Application::~Application()
|
|||
}
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
DesktopIntegration *Application::desktopIntegration()
|
||||
{
|
||||
return m_desktopIntegration;
|
||||
}
|
||||
|
||||
MainWindow *Application::mainWindow()
|
||||
{
|
||||
return m_window;
|
||||
}
|
||||
|
||||
bool Application::isTorrentAddedNotificationsEnabled() const
|
||||
{
|
||||
return m_storeNotificationTorrentAdded;
|
||||
}
|
||||
|
||||
void Application::setTorrentAddedNotificationsEnabled(const bool value)
|
||||
{
|
||||
m_storeNotificationTorrentAdded = value;
|
||||
}
|
||||
#endif
|
||||
|
||||
const QBtCommandLineParameters &Application::commandLineArgs() const
|
||||
|
@ -683,6 +703,40 @@ int Application::exec(const QStringList ¶ms)
|
|||
#endif // DISABLE_WEBUI
|
||||
#else
|
||||
UIThemeManager::initInstance();
|
||||
|
||||
const auto *btSession = BitTorrent::Session::instance();
|
||||
|
||||
m_desktopIntegration = new DesktopIntegration(this);
|
||||
connect(btSession, &BitTorrent::Session::fullDiskError, this
|
||||
, [this](const BitTorrent::Torrent *torrent, const QString &msg)
|
||||
{
|
||||
m_desktopIntegration->showNotification(tr("I/O Error", "i.e: Input/Output Error")
|
||||
, tr("An I/O error occurred for torrent '%1'.\n Reason: %2"
|
||||
, "e.g: An error occurred for torrent 'xxx.avi'.\n Reason: disk is full.").arg(torrent->name(), msg));
|
||||
});
|
||||
connect(btSession, &BitTorrent::Session::loadTorrentFailed, this
|
||||
, [this](const QString &error)
|
||||
{
|
||||
m_desktopIntegration->showNotification(tr("Error"), tr("Failed to add torrent: %1").arg(error));
|
||||
});
|
||||
connect(btSession, &BitTorrent::Session::torrentAdded, this
|
||||
, [this](const BitTorrent::Torrent *torrent)
|
||||
{
|
||||
if (isTorrentAddedNotificationsEnabled())
|
||||
m_desktopIntegration->showNotification(tr("Torrent added"), tr("'%1' was added.", "e.g: xxx.avi was added.").arg(torrent->name()));
|
||||
});
|
||||
connect(btSession, &BitTorrent::Session::torrentFinished, this
|
||||
, [this](const BitTorrent::Torrent *torrent)
|
||||
{
|
||||
m_desktopIntegration->showNotification(tr("Download completed"), tr("'%1' has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(torrent->name()));
|
||||
});
|
||||
connect(btSession, &BitTorrent::Session::downloadFromUrlFailed, this
|
||||
, [this](const QString &url, const QString &reason)
|
||||
{
|
||||
m_desktopIntegration->showNotification(tr("URL download error")
|
||||
, tr("Couldn't download file at URL '%1', reason: %2.").arg(url, reason));
|
||||
});
|
||||
|
||||
m_window = new MainWindow(this);
|
||||
#endif // DISABLE_GUI
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ namespace RSS
|
|||
}
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
class DesktopIntegration;
|
||||
class MainWindow;
|
||||
|
||||
using BaseApplication = QApplication;
|
||||
|
@ -124,7 +125,11 @@ public:
|
|||
#endif
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
DesktopIntegration *desktopIntegration() override;
|
||||
MainWindow *mainWindow() override;
|
||||
|
||||
bool isTorrentAddedNotificationsEnabled() const override;
|
||||
void setTorrentAddedNotificationsEnabled(bool value) override;
|
||||
#endif
|
||||
|
||||
private slots:
|
||||
|
@ -194,6 +199,9 @@ private:
|
|||
#endif
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
SettingValue<bool> m_storeNotificationTorrentAdded;
|
||||
|
||||
DesktopIntegration *m_desktopIntegration = nullptr;
|
||||
MainWindow *m_window = nullptr;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ add_library(qbt_gui STATIC
|
|||
cookiesdialog.h
|
||||
cookiesmodel.h
|
||||
deletionconfirmationdialog.h
|
||||
desktopintegration.h
|
||||
downloadfromurldialog.h
|
||||
executionlogwidget.h
|
||||
fspathedit.h
|
||||
|
@ -128,6 +129,7 @@ add_library(qbt_gui STATIC
|
|||
cookiesdialog.cpp
|
||||
cookiesmodel.cpp
|
||||
deletionconfirmationdialog.cpp
|
||||
desktopintegration.cpp
|
||||
downloadfromurldialog.cpp
|
||||
executionlogwidget.cpp
|
||||
fspathedit.cpp
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "base/preferences.h"
|
||||
#include "base/unicodestrings.h"
|
||||
#include "gui/addnewtorrentdialog.h"
|
||||
#include "gui/desktopintegration.h"
|
||||
#include "gui/mainwindow.h"
|
||||
#include "interfaces/iguiapplication.h"
|
||||
|
||||
|
@ -271,16 +272,15 @@ void AdvancedSettings::saveAdvancedSettings() const
|
|||
// Stop tracker timeout
|
||||
session->setStopTrackerTimeout(m_spinBoxStopTrackerTimeout.value());
|
||||
// Program notification
|
||||
MainWindow *mainWindow = app()->mainWindow();
|
||||
mainWindow->setNotificationsEnabled(m_checkBoxProgramNotifications.isChecked());
|
||||
mainWindow->setTorrentAddedNotificationsEnabled(m_checkBoxTorrentAddedNotifications.isChecked());
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && defined(QT_DBUS_LIB)
|
||||
mainWindow->setNotificationTimeout(m_spinBoxNotificationTimeout.value());
|
||||
app()->desktopIntegration()->setNotificationsEnabled(m_checkBoxProgramNotifications.isChecked());
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
app()->desktopIntegration()->setNotificationTimeout(m_spinBoxNotificationTimeout.value());
|
||||
#endif
|
||||
app()->setTorrentAddedNotificationsEnabled(m_checkBoxTorrentAddedNotifications.isChecked());
|
||||
// Reannounce to all trackers when ip/port changed
|
||||
session->setReannounceWhenAddressChangedEnabled(m_checkBoxReannounceWhenAddressChanged.isChecked());
|
||||
// Misc GUI properties
|
||||
mainWindow->setDownloadTrackerFavicon(m_checkBoxTrackerFavicon.isChecked());
|
||||
app()->mainWindow()->setDownloadTrackerFavicon(m_checkBoxTrackerFavicon.isChecked());
|
||||
AddNewTorrentDialog::setSavePathHistoryLength(m_spinBoxSavePathHistoryLength.value());
|
||||
pref->setSpeedWidgetEnabled(m_checkBoxSpeedWidgetEnabled.isChecked());
|
||||
#ifndef Q_OS_MACOS
|
||||
|
@ -677,17 +677,16 @@ void AdvancedSettings::loadAdvancedSettings()
|
|||
, &m_spinBoxStopTrackerTimeout);
|
||||
|
||||
// Program notifications
|
||||
const MainWindow *mainWindow = app()->mainWindow();
|
||||
m_checkBoxProgramNotifications.setChecked(mainWindow->isNotificationsEnabled());
|
||||
m_checkBoxProgramNotifications.setChecked(app()->desktopIntegration()->isNotificationsEnabled());
|
||||
addRow(PROGRAM_NOTIFICATIONS, tr("Display notifications"), &m_checkBoxProgramNotifications);
|
||||
// Torrent added notifications
|
||||
m_checkBoxTorrentAddedNotifications.setChecked(mainWindow->isTorrentAddedNotificationsEnabled());
|
||||
m_checkBoxTorrentAddedNotifications.setChecked(app()->isTorrentAddedNotificationsEnabled());
|
||||
addRow(TORRENT_ADDED_NOTIFICATIONS, tr("Display notifications for added torrents"), &m_checkBoxTorrentAddedNotifications);
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && defined(QT_DBUS_LIB)
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
// Notification timeout
|
||||
m_spinBoxNotificationTimeout.setMinimum(-1);
|
||||
m_spinBoxNotificationTimeout.setMaximum(std::numeric_limits<int>::max());
|
||||
m_spinBoxNotificationTimeout.setValue(mainWindow->getNotificationTimeout());
|
||||
m_spinBoxNotificationTimeout.setValue(app()->desktopIntegration()->notificationTimeout());
|
||||
m_spinBoxNotificationTimeout.setSpecialValueText(tr("System default"));
|
||||
m_spinBoxNotificationTimeout.setSuffix(tr(" ms", " milliseconds"));
|
||||
addRow(NOTIFICATION_TIMEOUT, tr("Notification timeout [0: infinite]"), &m_spinBoxNotificationTimeout);
|
||||
|
@ -696,7 +695,7 @@ void AdvancedSettings::loadAdvancedSettings()
|
|||
m_checkBoxReannounceWhenAddressChanged.setChecked(session->isReannounceWhenAddressChangedEnabled());
|
||||
addRow(REANNOUNCE_WHEN_ADDRESS_CHANGED, tr("Reannounce to all trackers when IP or port changed"), &m_checkBoxReannounceWhenAddressChanged);
|
||||
// Download tracker's favicon
|
||||
m_checkBoxTrackerFavicon.setChecked(mainWindow->isDownloadTrackerFavicon());
|
||||
m_checkBoxTrackerFavicon.setChecked(app()->mainWindow()->isDownloadTrackerFavicon());
|
||||
addRow(DOWNLOAD_TRACKER_FAVICON, tr("Download tracker's favicon"), &m_checkBoxTrackerFavicon);
|
||||
// Save path history length
|
||||
m_spinBoxSavePathHistoryLength.setRange(AddNewTorrentDialog::minPathHistoryLength, AddNewTorrentDialog::maxPathHistoryLength);
|
||||
|
|
273
src/gui/desktopintegration.cpp
Normal file
273
src/gui/desktopintegration.cpp
Normal file
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2022 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include "desktopintegration.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <QMenu>
|
||||
#include <QTimer>
|
||||
|
||||
#ifndef Q_OS_MACOS
|
||||
#include <QSystemTrayIcon>
|
||||
#endif
|
||||
|
||||
#include "base/logger.h"
|
||||
#include "base/preferences.h"
|
||||
#include "uithememanager.h"
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
#include "macutilities.h"
|
||||
#endif
|
||||
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
#include "notifications/dbusnotifier.h"
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
#ifdef Q_OS_MACOS
|
||||
DesktopIntegration *desktopIntegrationInstance = nullptr;
|
||||
|
||||
bool handleDockClicked(id self, SEL cmd, ...)
|
||||
{
|
||||
Q_UNUSED(self);
|
||||
Q_UNUSED(cmd);
|
||||
|
||||
Q_ASSERT(desktopIntegrationInstance);
|
||||
emit desktopIntegrationInstance->activationRequested();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#define SETTINGS_KEY(name) u"GUI/" name
|
||||
#define NOTIFICATIONS_SETTINGS_KEY(name) (SETTINGS_KEY(u"Notifications/"_qs) name)
|
||||
|
||||
DesktopIntegration::DesktopIntegration(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_storeNotificationEnabled {NOTIFICATIONS_SETTINGS_KEY(u"Enabled"_qs), true}
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
, m_storeNotificationTimeOut {NOTIFICATIONS_SETTINGS_KEY(u"Timeout"_qs), -1}
|
||||
#endif
|
||||
{
|
||||
#ifdef Q_OS_MACOS
|
||||
desktopIntegrationInstance = this;
|
||||
MacUtils::overrideDockClickHandler(handleDockClicked);
|
||||
#else
|
||||
if (Preferences::instance()->systemTrayEnabled())
|
||||
createTrayIcon(20);
|
||||
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
if (isNotificationsEnabled())
|
||||
{
|
||||
m_notifier = new DBusNotifier(this);
|
||||
connect(m_notifier, &DBusNotifier::messageClicked, this, &DesktopIntegration::notificationClicked);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
connect(Preferences::instance(), &Preferences::changed, this, &DesktopIntegration::onPreferencesChanged);
|
||||
}
|
||||
|
||||
bool DesktopIntegration::isActive() const
|
||||
{
|
||||
#ifdef Q_OS_MACOS
|
||||
return true;
|
||||
#else
|
||||
return (m_systrayIcon != nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
QString DesktopIntegration::toolTip() const
|
||||
{
|
||||
return m_toolTip;
|
||||
}
|
||||
|
||||
void DesktopIntegration::setToolTip(const QString &toolTip)
|
||||
{
|
||||
if (m_toolTip == toolTip)
|
||||
return;
|
||||
|
||||
#ifndef Q_OS_MACOS
|
||||
if (m_systrayIcon)
|
||||
m_systrayIcon->setToolTip(toolTip);
|
||||
#endif
|
||||
}
|
||||
|
||||
QMenu *DesktopIntegration::menu() const
|
||||
{
|
||||
return m_menu;
|
||||
}
|
||||
|
||||
void DesktopIntegration::setMenu(QMenu *menu)
|
||||
{
|
||||
if (menu == m_menu)
|
||||
return;
|
||||
|
||||
m_menu = menu;
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
if (m_menu)
|
||||
m_menu->setAsDockMenu();
|
||||
#else
|
||||
if (m_systrayIcon)
|
||||
m_systrayIcon->setContextMenu(m_menu);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool DesktopIntegration::isNotificationsEnabled() const
|
||||
{
|
||||
return m_storeNotificationEnabled;
|
||||
}
|
||||
|
||||
void DesktopIntegration::setNotificationsEnabled(const bool value)
|
||||
{
|
||||
if (m_storeNotificationEnabled == value)
|
||||
return;
|
||||
|
||||
m_storeNotificationEnabled = value;
|
||||
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
if (value)
|
||||
{
|
||||
m_notifier = new DBusNotifier(this);
|
||||
connect(m_notifier, &DBusNotifier::messageClicked, this, &DesktopIntegration::notificationClicked);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete m_notifier;
|
||||
m_notifier = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int DesktopIntegration::notificationTimeout() const
|
||||
{
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
return m_storeNotificationTimeOut;
|
||||
#else
|
||||
return 5000;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
void DesktopIntegration::setNotificationTimeout(const int value)
|
||||
{
|
||||
m_storeNotificationTimeOut = value;
|
||||
}
|
||||
#endif
|
||||
|
||||
void DesktopIntegration::showNotification(const QString &title, const QString &msg) const
|
||||
{
|
||||
if (!isNotificationsEnabled())
|
||||
return;
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
MacUtils::displayNotification(title, msg);
|
||||
#else
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
m_notifier->showMessage(title, msg, notificationTimeout());
|
||||
#else
|
||||
if (m_systrayIcon && QSystemTrayIcon::supportsMessages())
|
||||
m_systrayIcon->showMessage(title, msg, QSystemTrayIcon::Information, notificationTimeout());
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void DesktopIntegration::onPreferencesChanged()
|
||||
{
|
||||
#ifndef Q_OS_MACOS
|
||||
if (Preferences::instance()->systemTrayEnabled())
|
||||
{
|
||||
if (m_systrayIcon)
|
||||
{
|
||||
// Reload systray icon
|
||||
m_systrayIcon->setIcon(UIThemeManager::instance()->getSystrayIcon());
|
||||
}
|
||||
else
|
||||
{
|
||||
createTrayIcon(20);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete m_systrayIcon;
|
||||
m_systrayIcon = nullptr;
|
||||
emit stateChanged();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef Q_OS_MACOS
|
||||
void DesktopIntegration::createTrayIcon(const int retries)
|
||||
{
|
||||
Q_ASSERT(!m_systrayIcon);
|
||||
|
||||
if (QSystemTrayIcon::isSystemTrayAvailable())
|
||||
{
|
||||
m_systrayIcon = new QSystemTrayIcon(UIThemeManager::instance()->getSystrayIcon(), this);
|
||||
|
||||
m_systrayIcon->setToolTip(m_toolTip);
|
||||
|
||||
if (m_menu)
|
||||
m_systrayIcon->setContextMenu(m_menu);
|
||||
|
||||
connect(m_systrayIcon, &QSystemTrayIcon::activated, this
|
||||
, [this](const QSystemTrayIcon::ActivationReason reason)
|
||||
{
|
||||
if (reason == QSystemTrayIcon::Trigger)
|
||||
emit activationRequested();
|
||||
});
|
||||
#ifndef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
connect(m_systrayIcon, &QSystemTrayIcon::messageClicked, this, &DesktopIntegration::notificationClicked);
|
||||
#endif
|
||||
|
||||
m_systrayIcon->show();
|
||||
emit stateChanged();
|
||||
}
|
||||
else if (retries > 0)
|
||||
{
|
||||
LogMsg(tr("System tray icon is not available, retrying..."), Log::WARNING);
|
||||
QTimer::singleShot(2s, this, [this, retries]()
|
||||
{
|
||||
if (Preferences::instance()->systemTrayEnabled())
|
||||
createTrayIcon(retries - 1);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
LogMsg(tr("System tray icon is still not available after retries. Disabling it."), Log::WARNING);
|
||||
Preferences::instance()->setSystemTrayEnabled(false);
|
||||
}
|
||||
}
|
||||
#endif // Q_OS_MACOS
|
93
src/gui/desktopintegration.h
Normal file
93
src/gui/desktopintegration.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2022 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "base/settingvalue.h"
|
||||
|
||||
class QMenu;
|
||||
#ifndef Q_OS_MACOS
|
||||
class QSystemTrayIcon;
|
||||
#endif
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && defined(QT_DBUS_LIB)
|
||||
#define QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
class DBusNotifier;
|
||||
#endif
|
||||
|
||||
class DesktopIntegration final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(DesktopIntegration)
|
||||
|
||||
public:
|
||||
explicit DesktopIntegration(QObject *parent = nullptr);
|
||||
|
||||
bool isActive() const;
|
||||
|
||||
QString toolTip() const;
|
||||
void setToolTip(const QString &toolTip);
|
||||
|
||||
QMenu *menu() const;
|
||||
void setMenu(QMenu *menu);
|
||||
|
||||
bool isNotificationsEnabled() const;
|
||||
void setNotificationsEnabled(bool value);
|
||||
|
||||
int notificationTimeout() const;
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
void setNotificationTimeout(const int value);
|
||||
#endif
|
||||
|
||||
void showNotification(const QString &title, const QString &msg) const;
|
||||
|
||||
signals:
|
||||
void activationRequested();
|
||||
void notificationClicked();
|
||||
void stateChanged();
|
||||
|
||||
private:
|
||||
void onPreferencesChanged();
|
||||
#ifndef Q_OS_MACOS
|
||||
void createTrayIcon(int retries);
|
||||
#endif // Q_OS_MACOS
|
||||
|
||||
CachedSettingValue<bool> m_storeNotificationEnabled;
|
||||
|
||||
QMenu *m_menu = nullptr;
|
||||
QString m_toolTip;
|
||||
#ifndef Q_OS_MACOS
|
||||
QSystemTrayIcon *m_systrayIcon = nullptr;
|
||||
#endif
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
CachedSettingValue<int> m_storeNotificationTimeOut;
|
||||
DBusNotifier *m_notifier = nullptr;
|
||||
#endif
|
||||
};
|
|
@ -12,6 +12,7 @@ HEADERS += \
|
|||
$$PWD/cookiesdialog.h \
|
||||
$$PWD/cookiesmodel.h \
|
||||
$$PWD/deletionconfirmationdialog.h \
|
||||
$$PWD/desktopintegration.h \
|
||||
$$PWD/downloadfromurldialog.h \
|
||||
$$PWD/executionlogwidget.h \
|
||||
$$PWD/fspathedit.h \
|
||||
|
@ -95,6 +96,7 @@ SOURCES += \
|
|||
$$PWD/cookiesdialog.cpp \
|
||||
$$PWD/cookiesmodel.cpp \
|
||||
$$PWD/deletionconfirmationdialog.cpp \
|
||||
$$PWD/desktopintegration.cpp \
|
||||
$$PWD/downloadfromurldialog.cpp \
|
||||
$$PWD/executionlogwidget.cpp \
|
||||
$$PWD/fspathedit.cpp \
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "base/interfaces/iapplication.h"
|
||||
|
||||
class DesktopIntegration;
|
||||
class MainWindow;
|
||||
|
||||
class IGUIApplication : public IApplication
|
||||
|
@ -39,5 +40,9 @@ class IGUIApplication : public IApplication
|
|||
public:
|
||||
virtual ~IGUIApplication() = default;
|
||||
|
||||
virtual DesktopIntegration *desktopIntegration() = 0;
|
||||
virtual MainWindow *mainWindow() = 0;
|
||||
|
||||
virtual bool isTorrentAddedNotificationsEnabled() const = 0;
|
||||
virtual void setTorrentAddedNotificationsEnabled(bool value) = 0;
|
||||
};
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
#include "addnewtorrentdialog.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "cookiesdialog.h"
|
||||
#include "desktopintegration.h"
|
||||
#include "downloadfromurldialog.h"
|
||||
#include "executionlogwidget.h"
|
||||
#include "hidabletabwidget.h"
|
||||
|
@ -106,12 +107,8 @@ namespace
|
|||
{
|
||||
#define SETTINGS_KEY(name) u"GUI/" name
|
||||
#define EXECUTIONLOG_SETTINGS_KEY(name) (SETTINGS_KEY(u"Log/"_qs) name)
|
||||
#define NOTIFICATIONS_SETTINGS_KEY(name) (SETTINGS_KEY(u"Notifications/"_qs) name)
|
||||
|
||||
const std::chrono::seconds PREVENT_SUSPEND_INTERVAL {60};
|
||||
#if !defined(Q_OS_MACOS)
|
||||
const int TIME_TRAY_BALLOON = 5000;
|
||||
#endif
|
||||
|
||||
bool isTorrentLink(const QString &str)
|
||||
{
|
||||
|
@ -120,21 +117,6 @@ namespace
|
|||
|| (!str.startsWith(u"file:", Qt::CaseInsensitive)
|
||||
&& Net::DownloadManager::hasSupportedScheme(str));
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
MainWindow *dockMainWindowHandle = nullptr;
|
||||
|
||||
bool dockClickHandler(id self, SEL cmd, ...)
|
||||
{
|
||||
Q_UNUSED(self)
|
||||
Q_UNUSED(cmd)
|
||||
|
||||
if (dockMainWindowHandle && !dockMainWindowHandle->isVisible())
|
||||
dockMainWindowHandle->activate();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(IGUIApplication *app, QWidget *parent)
|
||||
|
@ -143,12 +125,7 @@ MainWindow::MainWindow(IGUIApplication *app, QWidget *parent)
|
|||
, m_ui(new Ui::MainWindow)
|
||||
, m_storeExecutionLogEnabled(EXECUTIONLOG_SETTINGS_KEY(u"Enabled"_qs))
|
||||
, m_storeDownloadTrackerFavicon(SETTINGS_KEY(u"DownloadTrackerFavicon"_qs))
|
||||
, m_storeNotificationEnabled(NOTIFICATIONS_SETTINGS_KEY(u"Enabled"_qs))
|
||||
, m_storeNotificationTorrentAdded(NOTIFICATIONS_SETTINGS_KEY(u"TorrentAdded"_qs))
|
||||
, m_storeExecutionLogTypes(EXECUTIONLOG_SETTINGS_KEY(u"Types"_qs), Log::MsgType::ALL)
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
, m_storeNotificationTimeOut(NOTIFICATIONS_SETTINGS_KEY(u"Timeout"_qs))
|
||||
#endif
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
|
@ -197,27 +174,10 @@ MainWindow::MainWindow(IGUIApplication *app, QWidget *parent)
|
|||
lockMenu->addAction(tr("&Set Password"), this, &MainWindow::defineUILockPassword);
|
||||
lockMenu->addAction(tr("&Clear Password"), this, &MainWindow::clearUILockPassword);
|
||||
m_ui->actionLock->setMenu(lockMenu);
|
||||
connect(this, &MainWindow::systemTrayIconCreated, this, [this]()
|
||||
{
|
||||
m_ui->actionLock->setVisible(true);
|
||||
});
|
||||
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
if (isNotificationsEnabled())
|
||||
{
|
||||
m_notifier = new DBusNotifier(this);
|
||||
connect(m_notifier, &DBusNotifier::messageClicked, this, &MainWindow::balloonClicked);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Creating Bittorrent session
|
||||
updateAltSpeedsBtn(BitTorrent::Session::instance()->isAltGlobalSpeedLimitEnabled());
|
||||
|
||||
connect(BitTorrent::Session::instance(), &BitTorrent::Session::fullDiskError, this, &MainWindow::fullDiskError);
|
||||
connect(BitTorrent::Session::instance(), &BitTorrent::Session::loadTorrentFailed, this, &MainWindow::addTorrentFailed);
|
||||
connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentAdded,this, &MainWindow::torrentNew);
|
||||
connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentFinished, this, &MainWindow::finishedTorrent);
|
||||
connect(BitTorrent::Session::instance(), &BitTorrent::Session::downloadFromUrlFailed, this, &MainWindow::handleDownloadFromUrlFailure);
|
||||
connect(BitTorrent::Session::instance(), &BitTorrent::Session::speedLimitModeChanged, this, &MainWindow::updateAltSpeedsBtn);
|
||||
connect(BitTorrent::Session::instance(), &BitTorrent::Session::recursiveTorrentDownloadPossible, this, &MainWindow::askRecursiveTorrentDownloadConfirmation);
|
||||
|
||||
|
@ -311,7 +271,7 @@ MainWindow::MainWindow(IGUIApplication *app, QWidget *parent)
|
|||
connect(m_ui->actionDecreaseQueuePos, &QAction::triggered, m_transferListWidget, &TransferListWidget::decreaseQueuePosSelectedTorrents);
|
||||
connect(m_ui->actionBottomQueuePos, &QAction::triggered, m_transferListWidget, &TransferListWidget::bottomQueuePosSelectedTorrents);
|
||||
#ifndef Q_OS_MACOS
|
||||
connect(m_ui->actionToggleVisibility, &QAction::triggered, this, [this]() { toggleVisibility(); });
|
||||
connect(m_ui->actionToggleVisibility, &QAction::triggered, this, &MainWindow::toggleVisibility);
|
||||
#endif
|
||||
connect(m_ui->actionMinimize, &QAction::triggered, this, &MainWindow::minimizeWindow);
|
||||
connect(m_ui->actionUseAlternativeSpeedLimits, &QAction::triggered, this, &MainWindow::toggleAlternativeSpeeds);
|
||||
|
@ -400,6 +360,25 @@ MainWindow::MainWindow(IGUIApplication *app, QWidget *parent)
|
|||
// Load Window state and sizes
|
||||
readSettings();
|
||||
|
||||
app->desktopIntegration()->setMenu(createDesktopIntegrationMenu());
|
||||
#ifndef Q_OS_MACOS
|
||||
m_ui->actionLock->setVisible(app->desktopIntegration()->isActive());
|
||||
connect(app->desktopIntegration(), &DesktopIntegration::stateChanged, this, [this, app]()
|
||||
{
|
||||
m_ui->actionLock->setVisible(app->desktopIntegration()->isActive());
|
||||
});
|
||||
#endif
|
||||
connect(app->desktopIntegration(), &DesktopIntegration::notificationClicked, this, &MainWindow::desktopNotificationClicked);
|
||||
connect(app->desktopIntegration(), &DesktopIntegration::activationRequested, this, [this]()
|
||||
{
|
||||
#ifdef Q_OS_MACOS
|
||||
if (!isVisible())
|
||||
activate();
|
||||
#else
|
||||
toggleVisibility();
|
||||
#endif
|
||||
});
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
// Make sure the Window is visible if we don't have a tray icon
|
||||
if (pref->startMinimized())
|
||||
|
@ -413,7 +392,7 @@ MainWindow::MainWindow(IGUIApplication *app, QWidget *parent)
|
|||
raise();
|
||||
}
|
||||
#else
|
||||
if (m_systrayIcon)
|
||||
if (app->desktopIntegration()->isActive())
|
||||
{
|
||||
if (!(pref->startMinimized() || m_uiLocked))
|
||||
{
|
||||
|
@ -429,7 +408,7 @@ MainWindow::MainWindow(IGUIApplication *app, QWidget *parent)
|
|||
hide();
|
||||
if (!pref->minimizeToTrayNotified())
|
||||
{
|
||||
showNotificationBalloon(tr("qBittorrent is minimized to tray"), tr("This behavior can be changed in the settings. You won't be reminded again."));
|
||||
app->desktopIntegration()->showNotification(tr("qBittorrent is minimized to tray"), tr("This behavior can be changed in the settings. You won't be reminded again."));
|
||||
pref->setMinimizeToTrayNotified(true);
|
||||
}
|
||||
}
|
||||
|
@ -498,11 +477,6 @@ MainWindow::MainWindow(IGUIApplication *app, QWidget *parent)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef Q_OS_MACOS
|
||||
setupDockClickHandler();
|
||||
createTrayIconMenu();
|
||||
m_trayIconMenu->setAsDockMenu();
|
||||
#endif
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
|
@ -531,54 +505,6 @@ void MainWindow::setExecutionLogMsgTypes(const Log::MsgTypes value)
|
|||
m_storeExecutionLogTypes = value;
|
||||
}
|
||||
|
||||
bool MainWindow::isNotificationsEnabled() const
|
||||
{
|
||||
return m_storeNotificationEnabled.get(true);
|
||||
}
|
||||
|
||||
void MainWindow::setNotificationsEnabled(const bool value)
|
||||
{
|
||||
if (m_storeNotificationEnabled == value)
|
||||
return;
|
||||
|
||||
m_storeNotificationEnabled = value;
|
||||
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
if (value)
|
||||
{
|
||||
m_notifier = new DBusNotifier(this);
|
||||
connect(m_notifier, &DBusNotifier::messageClicked, this, &MainWindow::balloonClicked);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete m_notifier;
|
||||
m_notifier = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MainWindow::isTorrentAddedNotificationsEnabled() const
|
||||
{
|
||||
return m_storeNotificationTorrentAdded;
|
||||
}
|
||||
|
||||
void MainWindow::setTorrentAddedNotificationsEnabled(const bool value)
|
||||
{
|
||||
m_storeNotificationTorrentAdded = value;
|
||||
}
|
||||
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && defined(QT_DBUS_LIB)
|
||||
int MainWindow::getNotificationTimeout() const
|
||||
{
|
||||
return m_storeNotificationTimeOut.get(-1);
|
||||
}
|
||||
|
||||
void MainWindow::setNotificationTimeout(const int value)
|
||||
{
|
||||
m_storeNotificationTimeOut = value;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool MainWindow::isDownloadTrackerFavicon() const
|
||||
{
|
||||
return m_storeDownloadTrackerFavicon;
|
||||
|
@ -721,7 +647,7 @@ void MainWindow::on_actionLock_triggered()
|
|||
// Lock the interface
|
||||
m_uiLocked = true;
|
||||
pref->setUILocked(true);
|
||||
m_trayIconMenu->setEnabled(false);
|
||||
app()->desktopIntegration()->menu()->setEnabled(false);
|
||||
hide();
|
||||
}
|
||||
|
||||
|
@ -778,7 +704,7 @@ void MainWindow::displaySearchTab(bool enable)
|
|||
// RSS tab
|
||||
if (!m_searchWidget)
|
||||
{
|
||||
m_searchWidget = new SearchWidget(this);
|
||||
m_searchWidget = new SearchWidget(app(), this);
|
||||
m_tabs->insertTab(1, m_searchWidget,
|
||||
#ifndef Q_OS_MACOS
|
||||
UIThemeManager::instance()->getIcon(u"edit-find"_qs),
|
||||
|
@ -873,7 +799,7 @@ void MainWindow::readSettings()
|
|||
m_posInitialized = true;
|
||||
}
|
||||
|
||||
void MainWindow::balloonClicked()
|
||||
void MainWindow::desktopNotificationClicked()
|
||||
{
|
||||
if (isHidden())
|
||||
{
|
||||
|
@ -892,32 +818,6 @@ void MainWindow::balloonClicked()
|
|||
activateWindow();
|
||||
}
|
||||
|
||||
void MainWindow::addTorrentFailed(const QString &error) const
|
||||
{
|
||||
showNotificationBalloon(tr("Error"), tr("Failed to add torrent: %1").arg(error));
|
||||
}
|
||||
|
||||
// called when a torrent was added
|
||||
void MainWindow::torrentNew(BitTorrent::Torrent *const torrent) const
|
||||
{
|
||||
if (isTorrentAddedNotificationsEnabled())
|
||||
showNotificationBalloon(tr("Torrent added"), tr("'%1' was added.", "e.g: xxx.avi was added.").arg(torrent->name()));
|
||||
}
|
||||
|
||||
// called when a torrent has finished
|
||||
void MainWindow::finishedTorrent(BitTorrent::Torrent *const torrent) const
|
||||
{
|
||||
showNotificationBalloon(tr("Download completed"), tr("'%1' has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(torrent->name()));
|
||||
}
|
||||
|
||||
// Notification when disk is full
|
||||
void MainWindow::fullDiskError(BitTorrent::Torrent *const torrent, const QString &msg) const
|
||||
{
|
||||
showNotificationBalloon(tr("I/O Error", "i.e: Input/Output Error")
|
||||
, tr("An I/O error occurred for torrent '%1'.\n Reason: %2"
|
||||
, "e.g: An error occurred for torrent 'xxx.avi'.\n Reason: disk is full.").arg(torrent->name(), msg));
|
||||
}
|
||||
|
||||
void MainWindow::createKeyboardShortcuts()
|
||||
{
|
||||
m_ui->actionCreateTorrent->setShortcut(QKeySequence::New);
|
||||
|
@ -1026,13 +926,6 @@ void MainWindow::askRecursiveTorrentDownloadConfirmation(BitTorrent::Torrent *co
|
|||
confirmBox->open();
|
||||
}
|
||||
|
||||
void MainWindow::handleDownloadFromUrlFailure(const QString &url, const QString &reason) const
|
||||
{
|
||||
// Display a message box
|
||||
showNotificationBalloon(tr("URL download error")
|
||||
, tr("Couldn't download file at URL '%1', reason: %2.").arg(url, reason));
|
||||
}
|
||||
|
||||
void MainWindow::on_actionSetGlobalSpeedLimits_triggered()
|
||||
{
|
||||
auto dialog = new SpeedLimitDialog {this};
|
||||
|
@ -1098,7 +991,7 @@ bool MainWindow::unlockUI()
|
|||
|
||||
m_uiLocked = false;
|
||||
pref->setUILocked(false);
|
||||
m_trayIconMenu->setEnabled(true);
|
||||
app()->desktopIntegration()->menu()->setEnabled(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1115,32 +1008,24 @@ void MainWindow::notifyOfUpdate(const QString &)
|
|||
|
||||
#ifndef Q_OS_MACOS
|
||||
// Toggle Main window visibility
|
||||
void MainWindow::toggleVisibility(const QSystemTrayIcon::ActivationReason reason)
|
||||
void MainWindow::toggleVisibility()
|
||||
{
|
||||
switch (reason)
|
||||
if (isHidden())
|
||||
{
|
||||
case QSystemTrayIcon::Trigger:
|
||||
if (isHidden())
|
||||
{
|
||||
if (m_uiLocked && !unlockUI()) // Ask for UI lock password
|
||||
return;
|
||||
if (m_uiLocked && !unlockUI()) // Ask for UI lock password
|
||||
return;
|
||||
|
||||
// Make sure the window is not minimized
|
||||
setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
|
||||
// Make sure the window is not minimized
|
||||
setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
|
||||
|
||||
// Then show it
|
||||
show();
|
||||
raise();
|
||||
activateWindow();
|
||||
}
|
||||
else
|
||||
{
|
||||
hide();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
// Then show it
|
||||
show();
|
||||
raise();
|
||||
activateWindow();
|
||||
}
|
||||
else
|
||||
{
|
||||
hide();
|
||||
}
|
||||
}
|
||||
#endif // Q_OS_MACOS
|
||||
|
@ -1245,13 +1130,13 @@ void MainWindow::closeEvent(QCloseEvent *e)
|
|||
}
|
||||
#else
|
||||
const bool goToSystrayOnExit = pref->closeToTray();
|
||||
if (!m_forceExit && m_systrayIcon && goToSystrayOnExit && !this->isHidden())
|
||||
if (!m_forceExit && app()->desktopIntegration()->isActive() && goToSystrayOnExit && !this->isHidden())
|
||||
{
|
||||
e->ignore();
|
||||
QMetaObject::invokeMethod(this, &QWidget::hide, Qt::QueuedConnection);
|
||||
if (!pref->closeToTrayNotified())
|
||||
{
|
||||
showNotificationBalloon(tr("qBittorrent is closed to tray"), tr("This behavior can be changed in the settings. You won't be reminded again."));
|
||||
app()->desktopIntegration()->showNotification(tr("qBittorrent is closed to tray"), tr("This behavior can be changed in the settings. You won't be reminded again."));
|
||||
pref->setCloseToTrayNotified(true);
|
||||
}
|
||||
return;
|
||||
|
@ -1287,14 +1172,9 @@ void MainWindow::closeEvent(QCloseEvent *e)
|
|||
}
|
||||
|
||||
// Disable some UI to prevent user interactions
|
||||
#ifndef Q_OS_MACOS
|
||||
if (m_systrayIcon)
|
||||
{
|
||||
m_systrayIcon->disconnect();
|
||||
m_systrayIcon->setToolTip(tr("qBittorrent is shutting down..."));
|
||||
m_trayIconMenu->setEnabled(false);
|
||||
}
|
||||
#endif
|
||||
app()->desktopIntegration()->disconnect();
|
||||
app()->desktopIntegration()->setToolTip(tr("qBittorrent is shutting down..."));
|
||||
app()->desktopIntegration()->menu()->setEnabled(false);
|
||||
|
||||
// Accept exit
|
||||
e->accept();
|
||||
|
@ -1328,14 +1208,13 @@ bool MainWindow::event(QEvent *e)
|
|||
switch (e->type())
|
||||
{
|
||||
case QEvent::WindowStateChange:
|
||||
{
|
||||
qDebug("Window change event");
|
||||
// Now check to see if the window is minimised
|
||||
if (isMinimized())
|
||||
{
|
||||
qDebug("minimisation");
|
||||
Preferences *const pref = Preferences::instance();
|
||||
if (m_systrayIcon && pref->minimizeToTray())
|
||||
if (app()->desktopIntegration()->isActive() && pref->minimizeToTray())
|
||||
{
|
||||
qDebug() << "Has active window:" << (qApp->activeWindow() != nullptr);
|
||||
// Check if there is a modal window
|
||||
|
@ -1350,7 +1229,7 @@ bool MainWindow::event(QEvent *e)
|
|||
QMetaObject::invokeMethod(this, &QWidget::hide, Qt::QueuedConnection);
|
||||
if (!pref->minimizeToTrayNotified())
|
||||
{
|
||||
showNotificationBalloon(tr("qBittorrent is minimized to tray"), tr("This behavior can be changed in the settings. You won't be reminded again."));
|
||||
app()->desktopIntegration()->showNotification(tr("qBittorrent is minimized to tray"), tr("This behavior can be changed in the settings. You won't be reminded again."));
|
||||
pref->setMinimizeToTrayNotified(true);
|
||||
}
|
||||
return true;
|
||||
|
@ -1358,17 +1237,16 @@ bool MainWindow::event(QEvent *e)
|
|||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::ToolBarChange:
|
||||
{
|
||||
qDebug("MAC: Received a toolbar change event!");
|
||||
bool ret = QMainWindow::event(e);
|
||||
{
|
||||
qDebug("MAC: Received a toolbar change event!");
|
||||
const bool ret = QMainWindow::event(e);
|
||||
|
||||
qDebug("MAC: new toolbar visibility is %d", !m_ui->actionTopToolBar->isChecked());
|
||||
m_ui->actionTopToolBar->toggle();
|
||||
Preferences::instance()->setToolbarDisplayed(m_ui->actionTopToolBar->isChecked());
|
||||
return ret;
|
||||
}
|
||||
qDebug("MAC: new toolbar visibility is %d", !m_ui->actionTopToolBar->isChecked());
|
||||
m_ui->actionTopToolBar->toggle();
|
||||
Preferences::instance()->setToolbarDisplayed(m_ui->actionTopToolBar->isChecked());
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1443,14 +1321,6 @@ void MainWindow::dragEnterEvent(QDragEnterEvent *event)
|
|||
event->acceptProposedAction();
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
void MainWindow::setupDockClickHandler()
|
||||
{
|
||||
dockMainWindowHandle = this;
|
||||
MacUtils::overrideDockClickHandler(dockClickHandler);
|
||||
}
|
||||
#endif // Q_OS_MACOS
|
||||
|
||||
/*****************************************************
|
||||
* *
|
||||
* Torrent *
|
||||
|
@ -1552,28 +1422,6 @@ void MainWindow::loadPreferences()
|
|||
{
|
||||
const Preferences *pref = Preferences::instance();
|
||||
|
||||
#ifndef Q_OS_MACOS
|
||||
// system tray icon
|
||||
if (pref->systemTrayEnabled())
|
||||
{
|
||||
if (m_systrayIcon)
|
||||
{
|
||||
// Reload systray icon
|
||||
m_systrayIcon->setIcon(UIThemeManager::instance()->getSystrayIcon());
|
||||
}
|
||||
else
|
||||
{
|
||||
createTrayIcon(20);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete m_systrayIcon;
|
||||
delete m_trayIconMenu;
|
||||
m_ui->actionLock->setVisible(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
// General
|
||||
if (pref->isToolbarDisplayed())
|
||||
{
|
||||
|
@ -1680,12 +1528,12 @@ void MainWindow::reloadSessionStats()
|
|||
MacUtils::setBadgeLabelText({});
|
||||
}
|
||||
#else
|
||||
if (m_systrayIcon)
|
||||
if (app()->desktopIntegration()->isActive())
|
||||
{
|
||||
const auto toolTip = u"%1\n%2"_qs.arg(
|
||||
tr("DL speed: %1", "e.g: Download speed: 10 KiB/s").arg(Utils::Misc::friendlyUnit(status.payloadDownloadRate, true))
|
||||
, tr("UP speed: %1", "e.g: Upload speed: 10 KiB/s").arg(Utils::Misc::friendlyUnit(status.payloadUploadRate, true)));
|
||||
m_systrayIcon->setToolTip(toolTip); // tray icon
|
||||
app()->desktopIntegration()->setToolTip(toolTip); // tray icon
|
||||
}
|
||||
#endif // Q_OS_MACOS
|
||||
|
||||
|
@ -1707,21 +1555,6 @@ void MainWindow::reloadTorrentStats(const QVector<BitTorrent::Torrent *> &torren
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::showNotificationBalloon(const QString &title, const QString &msg) const
|
||||
{
|
||||
if (!isNotificationsEnabled())
|
||||
return;
|
||||
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
m_notifier->showMessage(title, msg, getNotificationTimeout());
|
||||
#elif defined(Q_OS_MACOS)
|
||||
MacUtils::displayNotification(title, msg);
|
||||
#else
|
||||
if (m_systrayIcon && QSystemTrayIcon::supportsMessages())
|
||||
m_systrayIcon->showMessage(title, msg, QSystemTrayIcon::Information, TIME_TRAY_BALLOON);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
* *
|
||||
* Utils *
|
||||
|
@ -1746,82 +1579,40 @@ void MainWindow::downloadFromURLList(const QStringList &urlList)
|
|||
* *
|
||||
*****************************************************/
|
||||
|
||||
#ifndef Q_OS_MACOS
|
||||
void MainWindow::createTrayIcon(const int retries)
|
||||
QMenu *MainWindow::createDesktopIntegrationMenu()
|
||||
{
|
||||
if (m_systrayIcon)
|
||||
return;
|
||||
|
||||
if (QSystemTrayIcon::isSystemTrayAvailable())
|
||||
{
|
||||
m_systrayIcon = new QSystemTrayIcon(UIThemeManager::instance()->getSystrayIcon(), this);
|
||||
|
||||
createTrayIconMenu();
|
||||
m_systrayIcon->setContextMenu(m_trayIconMenu);
|
||||
|
||||
connect(m_systrayIcon, &QSystemTrayIcon::activated, this, &MainWindow::toggleVisibility);
|
||||
#ifndef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
connect(m_systrayIcon, &QSystemTrayIcon::messageClicked, this, &MainWindow::balloonClicked);
|
||||
#endif
|
||||
|
||||
m_systrayIcon->show();
|
||||
emit systemTrayIconCreated();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (retries > 0)
|
||||
{
|
||||
LogMsg(tr("System tray icon is not available, retrying..."), Log::WARNING);
|
||||
QTimer::singleShot(2s, this, [this, retries]()
|
||||
{
|
||||
if (Preferences::instance()->systemTrayEnabled())
|
||||
createTrayIcon(retries - 1);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
LogMsg(tr("System tray icon is still not available after retries. Disabling it."), Log::WARNING);
|
||||
Preferences::instance()->setSystemTrayEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // Q_OS_MACOS
|
||||
|
||||
void MainWindow::createTrayIconMenu()
|
||||
{
|
||||
if (m_trayIconMenu)
|
||||
return;
|
||||
|
||||
m_trayIconMenu = new QMenu(this);
|
||||
auto *menu = new QMenu(this);
|
||||
|
||||
#ifndef Q_OS_MACOS
|
||||
connect(m_trayIconMenu, &QMenu::aboutToShow, this, [this]()
|
||||
connect(menu, &QMenu::aboutToShow, this, [this]()
|
||||
{
|
||||
m_ui->actionToggleVisibility->setText(isVisible() ? tr("Hide") : tr("Show"));
|
||||
});
|
||||
|
||||
m_trayIconMenu->addAction(m_ui->actionToggleVisibility);
|
||||
m_trayIconMenu->addSeparator();
|
||||
menu->addAction(m_ui->actionToggleVisibility);
|
||||
menu->addSeparator();
|
||||
#endif
|
||||
|
||||
m_trayIconMenu->addAction(m_ui->actionOpen);
|
||||
m_trayIconMenu->addAction(m_ui->actionDownloadFromURL);
|
||||
m_trayIconMenu->addSeparator();
|
||||
menu->addAction(m_ui->actionOpen);
|
||||
menu->addAction(m_ui->actionDownloadFromURL);
|
||||
menu->addSeparator();
|
||||
|
||||
m_trayIconMenu->addAction(m_ui->actionUseAlternativeSpeedLimits);
|
||||
m_trayIconMenu->addAction(m_ui->actionSetGlobalSpeedLimits);
|
||||
m_trayIconMenu->addSeparator();
|
||||
menu->addAction(m_ui->actionUseAlternativeSpeedLimits);
|
||||
menu->addAction(m_ui->actionSetGlobalSpeedLimits);
|
||||
menu->addSeparator();
|
||||
|
||||
m_trayIconMenu->addAction(m_ui->actionStartAll);
|
||||
m_trayIconMenu->addAction(m_ui->actionPauseAll);
|
||||
menu->addAction(m_ui->actionStartAll);
|
||||
menu->addAction(m_ui->actionPauseAll);
|
||||
|
||||
#ifndef Q_OS_MACOS
|
||||
m_trayIconMenu->addSeparator();
|
||||
m_trayIconMenu->addAction(m_ui->actionExit);
|
||||
menu->addSeparator();
|
||||
menu->addAction(m_ui->actionExit);
|
||||
#endif
|
||||
|
||||
if (m_uiLocked)
|
||||
m_trayIconMenu->setEnabled(false);
|
||||
menu->setEnabled(false);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
void MainWindow::updateAltSpeedsBtn(const bool alternative)
|
||||
|
|
|
@ -31,10 +31,6 @@
|
|||
#include <QMainWindow>
|
||||
#include <QPointer>
|
||||
|
||||
#ifndef Q_OS_MACOS
|
||||
#include <QSystemTrayIcon>
|
||||
#endif
|
||||
|
||||
#include "base/bittorrent/torrent.h"
|
||||
#include "base/logger.h"
|
||||
#include "base/settingvalue.h"
|
||||
|
@ -97,14 +93,6 @@ public:
|
|||
void setExecutionLogMsgTypes(Log::MsgTypes value);
|
||||
|
||||
// Notifications properties
|
||||
bool isNotificationsEnabled() const;
|
||||
void setNotificationsEnabled(bool value);
|
||||
bool isTorrentAddedNotificationsEnabled() const;
|
||||
void setTorrentAddedNotificationsEnabled(bool value);
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && defined(QT_DBUS_LIB)
|
||||
int getNotificationTimeout() const;
|
||||
void setNotificationTimeout(int value);
|
||||
#endif
|
||||
|
||||
// Misc properties
|
||||
bool isDownloadTrackerFavicon() const;
|
||||
|
@ -113,19 +101,12 @@ public:
|
|||
void activate();
|
||||
void cleanup();
|
||||
|
||||
void showNotificationBalloon(const QString &title, const QString &msg) const;
|
||||
|
||||
signals:
|
||||
void systemTrayIconCreated();
|
||||
|
||||
private slots:
|
||||
void showFilterContextMenu();
|
||||
void balloonClicked();
|
||||
void desktopNotificationClicked();
|
||||
void writeSettings();
|
||||
void writeSplitterSettings();
|
||||
void readSettings();
|
||||
void fullDiskError(BitTorrent::Torrent *const torrent, const QString &msg) const;
|
||||
void handleDownloadFromUrlFailure(const QString &, const QString &) const;
|
||||
void tabChanged(int newTab);
|
||||
bool defineUILockPassword();
|
||||
void clearUILockPassword();
|
||||
|
@ -143,9 +124,6 @@ private slots:
|
|||
void reloadSessionStats();
|
||||
void reloadTorrentStats(const QVector<BitTorrent::Torrent *> &torrents);
|
||||
void loadPreferences();
|
||||
void addTorrentFailed(const QString &error) const;
|
||||
void torrentNew(BitTorrent::Torrent *const torrent) const;
|
||||
void finishedTorrent(BitTorrent::Torrent *const torrent) const;
|
||||
void askRecursiveTorrentDownloadConfirmation(BitTorrent::Torrent *const torrent);
|
||||
void optionsSaved();
|
||||
void toggleAlternativeSpeeds();
|
||||
|
@ -199,16 +177,11 @@ private slots:
|
|||
#ifdef Q_OS_MACOS
|
||||
void on_actionCloseWindow_triggered();
|
||||
#else
|
||||
void toggleVisibility(const QSystemTrayIcon::ActivationReason reason = QSystemTrayIcon::Trigger);
|
||||
void toggleVisibility();
|
||||
#endif
|
||||
|
||||
private:
|
||||
void createTrayIconMenu();
|
||||
#ifdef Q_OS_MACOS
|
||||
void setupDockClickHandler();
|
||||
#else
|
||||
void createTrayIcon(int retries);
|
||||
#endif
|
||||
QMenu *createDesktopIntegrationMenu();
|
||||
#ifdef Q_OS_WIN
|
||||
void installPython();
|
||||
#endif
|
||||
|
@ -238,9 +211,6 @@ private:
|
|||
QPointer<TorrentCreatorDialog> m_createTorrentDlg;
|
||||
QPointer<DownloadFromURLDialog> m_downloadFromURLDialog;
|
||||
|
||||
#ifndef Q_OS_MACOS
|
||||
QPointer<QSystemTrayIcon> m_systrayIcon;
|
||||
#endif
|
||||
QPointer<QMenu> m_trayIconMenu;
|
||||
|
||||
TransferListWidget *m_transferListWidget = nullptr;
|
||||
|
@ -267,15 +237,8 @@ private:
|
|||
|
||||
SettingValue<bool> m_storeExecutionLogEnabled;
|
||||
SettingValue<bool> m_storeDownloadTrackerFavicon;
|
||||
SettingValue<bool> m_storeNotificationEnabled;
|
||||
SettingValue<bool> m_storeNotificationTorrentAdded;
|
||||
CachedSettingValue<Log::MsgTypes> m_storeExecutionLogTypes;
|
||||
|
||||
#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS
|
||||
SettingValue<int> m_storeNotificationTimeOut;
|
||||
DBusNotifier *m_notifier = nullptr;
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
|
||||
void checkProgramUpdate(bool invokedByUser);
|
||||
void handleUpdateCheckFinished(ProgramUpdater *updater, bool invokedByUser);
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "base/search/searchhandler.h"
|
||||
#include "base/search/searchpluginmanager.h"
|
||||
#include "base/utils/foreignapps.h"
|
||||
#include "gui/desktopintegration.h"
|
||||
#include "gui/mainwindow.h"
|
||||
#include "gui/uithememanager.h"
|
||||
#include "pluginselectdialog.h"
|
||||
|
@ -83,10 +84,11 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
SearchWidget::SearchWidget(MainWindow *mainWindow)
|
||||
SearchWidget::SearchWidget(IGUIApplication *app, MainWindow *mainWindow)
|
||||
: QWidget(mainWindow)
|
||||
, m_ui(new Ui::SearchWidget())
|
||||
, m_mainWindow(mainWindow)
|
||||
, GUIApplicationComponent(app)
|
||||
, m_ui {new Ui::SearchWidget()}
|
||||
, m_mainWindow {mainWindow}
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_ui->tabWidget->tabBar()->installEventFilter(this);
|
||||
|
@ -304,7 +306,7 @@ void SearchWidget::on_searchButton_clicked()
|
|||
{
|
||||
if (!Utils::ForeignApps::pythonInfo().isValid())
|
||||
{
|
||||
m_mainWindow->showNotificationBalloon(tr("Search Engine"), tr("Please install Python to use the Search Engine."));
|
||||
app()->desktopIntegration()->showNotification(tr("Search Engine"), tr("Please install Python to use the Search Engine."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -370,12 +372,12 @@ void SearchWidget::tabStatusChanged(QWidget *tab)
|
|||
{
|
||||
Q_ASSERT(m_activeSearchTab->status() != SearchJobWidget::Status::Ongoing);
|
||||
|
||||
if (m_mainWindow->isNotificationsEnabled() && (m_mainWindow->currentTabWidget() != this))
|
||||
if (app()->desktopIntegration()->isNotificationsEnabled() && (m_mainWindow->currentTabWidget() != this))
|
||||
{
|
||||
if (m_activeSearchTab->status() == SearchJobWidget::Status::Error)
|
||||
m_mainWindow->showNotificationBalloon(tr("Search Engine"), tr("Search has failed"));
|
||||
app()->desktopIntegration()->showNotification(tr("Search Engine"), tr("Search has failed"));
|
||||
else
|
||||
m_mainWindow->showNotificationBalloon(tr("Search Engine"), tr("Search has finished"));
|
||||
app()->desktopIntegration()->showNotification(tr("Search Engine"), tr("Search has finished"));
|
||||
}
|
||||
|
||||
m_activeSearchTab = nullptr;
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <QPointer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "gui/guiapplicationcomponent.h"
|
||||
|
||||
class QEvent;
|
||||
class QObject;
|
||||
class QTabWidget;
|
||||
|
@ -46,13 +48,13 @@ namespace Ui
|
|||
class SearchWidget;
|
||||
}
|
||||
|
||||
class SearchWidget : public QWidget
|
||||
class SearchWidget : public QWidget, public GUIApplicationComponent
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(SearchWidget)
|
||||
|
||||
public:
|
||||
explicit SearchWidget(MainWindow *mainWindow);
|
||||
explicit SearchWidget(IGUIApplication *app, MainWindow *mainWindow);
|
||||
~SearchWidget() override;
|
||||
|
||||
void giveFocusToSearchInput();
|
||||
|
|
Loading…
Reference in a new issue