diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index dfcf3b6b7..ca5107d67 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -430,9 +430,15 @@ namespace BitTorrent virtual void setResumeDataStorageType(ResumeDataStorageType type) = 0; virtual bool isMergeTrackersEnabled() const = 0; virtual void setMergeTrackersEnabled(bool enabled) = 0; + virtual bool isStartPaused() const = 0; + virtual void setStartPaused(bool value) = 0; virtual bool isRestored() const = 0; + virtual bool isPaused() const = 0; + virtual void pause() = 0; + virtual void resume() = 0; + virtual Torrent *getTorrent(const TorrentID &id) const = 0; virtual Torrent *findTorrent(const InfoHash &infoHash) const = 0; virtual QVector torrents() const = 0; @@ -466,6 +472,8 @@ namespace BitTorrent void loadTorrentFailed(const QString &error); void metadataDownloaded(const TorrentInfo &info); void restored(); + void paused(); + void resumed(); void speedLimitModeChanged(bool alternative); void statsUpdated(); void subcategoriesSupportChanged(); diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index 6a6c49183..dde72af85 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -523,6 +523,7 @@ SessionImpl::SessionImpl(QObject *parent) , m_I2POutboundQuantity {BITTORRENT_SESSION_KEY(u"I2P/OutboundQuantity"_s), 3} , m_I2PInboundLength {BITTORRENT_SESSION_KEY(u"I2P/InboundLength"_s), 3} , m_I2POutboundLength {BITTORRENT_SESSION_KEY(u"I2P/OutboundLength"_s), 3} + , m_startPaused {BITTORRENT_SESSION_KEY(u"StartPaused"_s)} , m_seedingLimitTimer {new QTimer(this)} , m_resumeDataTimer {new QTimer(this)} , m_ioThread {new QThread} @@ -1541,7 +1542,9 @@ void SessionImpl::endStartup(ResumeSessionContext *context) context->deleteLater(); connect(context, &QObject::destroyed, this, [this] { - m_nativeSession->resume(); + if (!m_isPaused) + m_nativeSession->resume(); + if (m_refreshEnqueued) m_refreshEnqueued = false; else @@ -3913,6 +3916,16 @@ void SessionImpl::setMergeTrackersEnabled(const bool enabled) m_isMergeTrackersEnabled = enabled; } +bool SessionImpl::isStartPaused() const +{ + return m_startPaused.get(false); +} + +void SessionImpl::setStartPaused(const bool value) +{ + m_startPaused = value; +} + QStringList SessionImpl::bannedIPs() const { return m_bannedIPs; @@ -3923,6 +3936,35 @@ bool SessionImpl::isRestored() const return m_isRestored; } +bool SessionImpl::isPaused() const +{ + return m_isPaused; +} + +void SessionImpl::pause() +{ + if (!m_isPaused) + { + if (isRestored()) + m_nativeSession->pause(); + + m_isPaused = true; + emit paused(); + } +} + +void SessionImpl::resume() +{ + if (m_isPaused) + { + if (isRestored()) + m_nativeSession->resume(); + + m_isPaused = false; + emit resumed(); + } +} + int SessionImpl::maxConnectionsPerTorrent() const { return m_maxConnectionsPerTorrent; @@ -4370,6 +4412,9 @@ void SessionImpl::setQueueingSystemEnabled(const bool enabled) m_torrentsQueueChanged = true; else removeTorrentsQueue(); + + for (TorrentImpl *torrent : asConst(m_torrents)) + torrent->handleQueueingModeChanged(); } } diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h index 91b986aff..334c0baf9 100644 --- a/src/base/bittorrent/sessionimpl.h +++ b/src/base/bittorrent/sessionimpl.h @@ -407,9 +407,15 @@ namespace BitTorrent void setResumeDataStorageType(ResumeDataStorageType type) override; bool isMergeTrackersEnabled() const override; void setMergeTrackersEnabled(bool enabled) override; + bool isStartPaused() const override; + void setStartPaused(bool value) override; bool isRestored() const override; + bool isPaused() const override; + void pause() override; + void resume() override; + Torrent *getTorrent(const TorrentID &id) const override; Torrent *findTorrent(const InfoHash &infoHash) const override; QVector torrents() const override; @@ -722,8 +728,10 @@ namespace BitTorrent CachedSettingValue m_I2POutboundQuantity; CachedSettingValue m_I2PInboundLength; CachedSettingValue m_I2POutboundLength; + SettingValue m_startPaused; bool m_isRestored = false; + bool m_isPaused = isStartPaused(); // Order is important. This needs to be declared after its CachedSettingsValue // counterpart, because it uses it for initialization in the constructor diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index 47b40e455..4cc41c084 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -999,6 +999,9 @@ bool TorrentImpl::isStopped() const bool TorrentImpl::isQueued() const { + if (!m_session->isQueueingSystemEnabled()) + return false; + // Torrent is Queued if it isn't in Stopped state but paused internally return (!isStopped() && (m_nativeStatus.flags & lt::torrent_flags::auto_managed) @@ -1153,7 +1156,7 @@ void TorrentImpl::updateState() { if (isStopped()) m_state = TorrentState::StoppedDownloading; - else if (m_session->isQueueingSystemEnabled() && isQueued()) + else if (isQueued()) m_state = TorrentState::QueuedDownloading; else m_state = isForced() ? TorrentState::ForcedDownloadingMetadata : TorrentState::DownloadingMetadata; @@ -1167,7 +1170,7 @@ void TorrentImpl::updateState() { if (isStopped()) m_state = TorrentState::StoppedUploading; - else if (m_session->isQueueingSystemEnabled() && isQueued()) + else if (isQueued()) m_state = TorrentState::QueuedUploading; else if (isForced()) m_state = TorrentState::ForcedUploading; @@ -1180,7 +1183,7 @@ void TorrentImpl::updateState() { if (isStopped()) m_state = TorrentState::StoppedDownloading; - else if (m_session->isQueueingSystemEnabled() && isQueued()) + else if (isQueued()) m_state = TorrentState::QueuedDownloading; else if (isForced()) m_state = TorrentState::ForcedDownloading; @@ -1963,6 +1966,11 @@ void TorrentImpl::handleStateUpdate(const lt::torrent_status &nativeStatus) updateStatus(nativeStatus); } +void TorrentImpl::handleQueueingModeChanged() +{ + updateState(); +} + void TorrentImpl::handleMoveStorageJobFinished(const Path &path, const MoveStorageContext context, const bool hasOutstandingJob) { if (context == MoveStorageContext::ChangeSavePath) diff --git a/src/base/bittorrent/torrentimpl.h b/src/base/bittorrent/torrentimpl.h index 44907c164..54b84c1f4 100644 --- a/src/base/bittorrent/torrentimpl.h +++ b/src/base/bittorrent/torrentimpl.h @@ -269,6 +269,7 @@ namespace BitTorrent void handleAlert(const lt::alert *a); void handleStateUpdate(const lt::torrent_status &nativeStatus); + void handleQueueingModeChanged(); void handleCategoryOptionsChanged(); void handleAppendExtensionToggled(); void handleUnwantedFolderToggled(); diff --git a/src/base/preferences.cpp b/src/base/preferences.cpp index 32ddcc0ab..13c1c8b00 100644 --- a/src/base/preferences.cpp +++ b/src/base/preferences.cpp @@ -1397,19 +1397,6 @@ void Preferences::setConfirmRemoveAllTags(const bool enabled) setValue(u"Preferences/Advanced/confirmRemoveAllTags"_s, enabled); } -bool Preferences::confirmPauseAndResumeAll() const -{ - return value(u"GUI/ConfirmActions/PauseAndResumeAllTorrents"_s, true); -} - -void Preferences::setConfirmPauseAndResumeAll(const bool enabled) -{ - if (enabled == confirmPauseAndResumeAll()) - return; - - setValue(u"GUI/ConfirmActions/PauseAndResumeAllTorrents"_s, enabled); -} - bool Preferences::confirmMergeTrackers() const { return value(u"GUI/ConfirmActions/MergeTrackers"_s, true); diff --git a/src/base/preferences.h b/src/base/preferences.h index 8d78a6404..90f26b055 100644 --- a/src/base/preferences.h +++ b/src/base/preferences.h @@ -305,8 +305,6 @@ public: void setConfirmTorrentRecheck(bool enabled); bool confirmRemoveAllTags() const; void setConfirmRemoveAllTags(bool enabled); - bool confirmPauseAndResumeAll() const; - void setConfirmPauseAndResumeAll(bool enabled); bool confirmMergeTrackers() const; void setConfirmMergeTrackers(bool enabled); bool confirmRemoveTrackerFromAllTorrents() const; diff --git a/src/gui/advancedsettings.cpp b/src/gui/advancedsettings.cpp index dac681628..61d43000e 100644 --- a/src/gui/advancedsettings.cpp +++ b/src/gui/advancedsettings.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2016 qBittorrent project + * Copyright (C) 2016-2024 qBittorrent project * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -105,6 +105,7 @@ namespace ENABLE_MARK_OF_THE_WEB, #endif // Q_OS_MACOS || Q_OS_WIN PYTHON_EXECUTABLE_PATH, + START_SESSION_PAUSED, // libtorrent section LIBTORRENT_HEADER, @@ -331,6 +332,8 @@ void AdvancedSettings::saveAdvancedSettings() const #endif // Q_OS_MACOS || Q_OS_WIN // Python executable path pref->setPythonExecutablePath(Path(m_pythonExecutablePath.text().trimmed())); + // Start session paused + session->setStartPaused(m_checkBoxStartSessionPaused.isChecked()); // Choking algorithm session->setChokingAlgorithm(m_comboBoxChokingAlgorithm.currentData().value()); // Seed choking algorithm @@ -843,6 +846,9 @@ void AdvancedSettings::loadAdvancedSettings() m_pythonExecutablePath.setPlaceholderText(tr("(Auto detect if empty)")); m_pythonExecutablePath.setText(pref->getPythonExecutablePath().toString()); addRow(PYTHON_EXECUTABLE_PATH, tr("Python executable path (may require restart)"), &m_pythonExecutablePath); + // Start session paused + m_checkBoxStartSessionPaused.setChecked(session->isStartPaused()); + addRow(START_SESSION_PAUSED, tr("Start session in paused state"), &m_checkBoxStartSessionPaused); // Choking algorithm m_comboBoxChokingAlgorithm.addItem(tr("Fixed slots"), QVariant::fromValue(BitTorrent::ChokingAlgorithm::FixedSlots)); m_comboBoxChokingAlgorithm.addItem(tr("Upload rate based"), QVariant::fromValue(BitTorrent::ChokingAlgorithm::RateBased)); diff --git a/src/gui/advancedsettings.h b/src/gui/advancedsettings.h index 91473c8e2..1ad82da8c 100644 --- a/src/gui/advancedsettings.h +++ b/src/gui/advancedsettings.h @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2015 qBittorrent project + * Copyright (C) 2015-2024 qBittorrent project * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -79,7 +79,7 @@ private: m_checkBoxProgramNotifications, m_checkBoxTorrentAddedNotifications, m_checkBoxReannounceWhenAddressChanged, m_checkBoxTrackerFavicon, m_checkBoxTrackerStatus, m_checkBoxTrackerPortForwarding, m_checkBoxConfirmTorrentRecheck, m_checkBoxConfirmRemoveAllTags, m_checkBoxAnnounceAllTrackers, m_checkBoxAnnounceAllTiers, m_checkBoxMultiConnectionsPerIp, m_checkBoxValidateHTTPSTrackerCertificate, m_checkBoxSSRFMitigation, m_checkBoxBlockPeersOnPrivilegedPorts, m_checkBoxPieceExtentAffinity, - m_checkBoxSuggestMode, m_checkBoxSpeedWidgetEnabled, m_checkBoxIDNSupport, m_checkBoxConfirmRemoveTrackerFromAllTorrents; + m_checkBoxSuggestMode, m_checkBoxSpeedWidgetEnabled, m_checkBoxIDNSupport, m_checkBoxConfirmRemoveTrackerFromAllTorrents, m_checkBoxStartSessionPaused; QComboBox m_comboBoxInterface, m_comboBoxInterfaceAddress, m_comboBoxDiskIOReadMode, m_comboBoxDiskIOWriteMode, m_comboBoxUtpMixedMode, m_comboBoxChokingAlgorithm, m_comboBoxSeedChokingAlgorithm, m_comboBoxResumeDataStorage; QLineEdit m_lineEditAppInstanceName, m_pythonExecutablePath, m_lineEditAnnounceIP, m_lineEditDHTBootstrapNodes; diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 14a43ec99..71012ee19 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -125,18 +125,18 @@ namespace MainWindow::MainWindow(IGUIApplication *app, const WindowState initialState, const QString &titleSuffix) : GUIApplicationComponent(app) - , m_ui(new Ui::MainWindow) - , m_storeExecutionLogEnabled(EXECUTIONLOG_SETTINGS_KEY(u"Enabled"_s)) - , m_storeDownloadTrackerFavicon(SETTINGS_KEY(u"DownloadTrackerFavicon"_s)) - , m_storeExecutionLogTypes(EXECUTIONLOG_SETTINGS_KEY(u"Types"_s), Log::MsgType::ALL) + , m_ui {new Ui::MainWindow} + , m_downloadRate {Utils::Misc::friendlyUnit(0, true)} + , m_uploadRate {Utils::Misc::friendlyUnit(0, true)} + , m_storeExecutionLogEnabled {EXECUTIONLOG_SETTINGS_KEY(u"Enabled"_s)} + , m_storeDownloadTrackerFavicon {SETTINGS_KEY(u"DownloadTrackerFavicon"_s)} + , m_storeExecutionLogTypes {EXECUTIONLOG_SETTINGS_KEY(u"Types"_s), Log::MsgType::ALL} #ifdef Q_OS_MACOS - , m_badger(std::make_unique()) + , m_badger {std::make_unique()} #endif // Q_OS_MACOS { m_ui->setupUi(this); - setTitleSuffix(titleSuffix); - Preferences *const pref = Preferences::instance(); m_uiLocked = pref->isUILocked(); m_displaySpeedInTitle = pref->speedInTitleBar(); @@ -145,6 +145,8 @@ MainWindow::MainWindow(IGUIApplication *app, const WindowState initialState, con setWindowIcon(UIThemeManager::instance()->getIcon(u"qbittorrent"_s)); #endif // Q_OS_MACOS + setTitleSuffix(titleSuffix); + #if (defined(Q_OS_UNIX)) m_ui->actionOptions->setText(tr("Preferences")); #endif @@ -167,21 +169,37 @@ MainWindow::MainWindow(IGUIApplication *app, const WindowState initialState, con m_ui->actionExit->setIcon(UIThemeManager::instance()->getIcon(u"application-exit"_s)); m_ui->actionLock->setIcon(UIThemeManager::instance()->getIcon(u"object-locked"_s)); m_ui->actionOptions->setIcon(UIThemeManager::instance()->getIcon(u"configure"_s, u"preferences-system"_s)); - m_ui->actionStop->setIcon(UIThemeManager::instance()->getIcon(u"torrent-stop"_s, u"media-playback-pause"_s)); - m_ui->actionStopAll->setIcon(UIThemeManager::instance()->getIcon(u"torrent-stop"_s, u"media-playback-pause"_s)); m_ui->actionStart->setIcon(UIThemeManager::instance()->getIcon(u"torrent-start"_s, u"media-playback-start"_s)); - m_ui->actionStartAll->setIcon(UIThemeManager::instance()->getIcon(u"torrent-start"_s, u"media-playback-start"_s)); + m_ui->actionStop->setIcon(UIThemeManager::instance()->getIcon(u"torrent-stop"_s, u"media-playback-pause"_s)); + m_ui->actionPauseSession->setIcon(UIThemeManager::instance()->getIcon(u"pause-session"_s, u"media-playback-pause"_s)); + m_ui->actionResumeSession->setIcon(UIThemeManager::instance()->getIcon(u"torrent-start"_s, u"media-playback-start"_s)); m_ui->menuAutoShutdownOnDownloadsCompletion->setIcon(UIThemeManager::instance()->getIcon(u"task-complete"_s, u"application-exit"_s)); m_ui->actionManageCookies->setIcon(UIThemeManager::instance()->getIcon(u"browser-cookies"_s, u"preferences-web-browser-cookies"_s)); m_ui->menuLog->setIcon(UIThemeManager::instance()->getIcon(u"help-contents"_s)); m_ui->actionCheckForUpdates->setIcon(UIThemeManager::instance()->getIcon(u"view-refresh"_s)); + m_ui->actionPauseSession->setVisible(!BitTorrent::Session::instance()->isPaused()); + m_ui->actionResumeSession->setVisible(BitTorrent::Session::instance()->isPaused()); + connect(BitTorrent::Session::instance(), &BitTorrent::Session::paused, this, [this] + { + m_ui->actionPauseSession->setVisible(false); + m_ui->actionResumeSession->setVisible(true); + refreshWindowTitle(); + refreshTrayIconTooltip(); + }); + connect(BitTorrent::Session::instance(), &BitTorrent::Session::resumed, this, [this] + { + m_ui->actionPauseSession->setVisible(true); + m_ui->actionResumeSession->setVisible(false); + refreshWindowTitle(); + refreshTrayIconTooltip(); + }); + auto *lockMenu = new QMenu(m_ui->menuView); lockMenu->addAction(tr("&Set Password"), this, &MainWindow::defineUILockPassword); lockMenu->addAction(tr("&Clear Password"), this, &MainWindow::clearUILockPassword); m_ui->actionLock->setMenu(lockMenu); - // Creating Bittorrent session updateAltSpeedsBtn(BitTorrent::Session::instance()->isAltGlobalSpeedLimitEnabled()); connect(BitTorrent::Session::instance(), &BitTorrent::Session::speedLimitModeChanged, this, &MainWindow::updateAltSpeedsBtn); @@ -285,9 +303,9 @@ MainWindow::MainWindow(IGUIApplication *app, const WindowState initialState, con // Transfer list slots connect(m_ui->actionStart, &QAction::triggered, m_transferListWidget, &TransferListWidget::startSelectedTorrents); - connect(m_ui->actionStartAll, &QAction::triggered, m_transferListWidget, &TransferListWidget::startAllTorrents); connect(m_ui->actionStop, &QAction::triggered, m_transferListWidget, &TransferListWidget::stopSelectedTorrents); - connect(m_ui->actionStopAll, &QAction::triggered, m_transferListWidget, &TransferListWidget::stopAllTorrents); + connect(m_ui->actionPauseSession, &QAction::triggered, m_transferListWidget, &TransferListWidget::pauseSession); + connect(m_ui->actionResumeSession, &QAction::triggered, m_transferListWidget, &TransferListWidget::resumeSession); connect(m_ui->actionDelete, &QAction::triggered, m_transferListWidget, &TransferListWidget::softDeleteSelectedTorrents); connect(m_ui->actionTopQueuePos, &QAction::triggered, m_transferListWidget, &TransferListWidget::topQueuePosSelectedTorrents); connect(m_ui->actionIncreaseQueuePos, &QAction::triggered, m_transferListWidget, &TransferListWidget::increaseQueuePosSelectedTorrents); @@ -326,7 +344,7 @@ MainWindow::MainWindow(IGUIApplication *app, const WindowState initialState, con // Configure BT session according to options loadPreferences(); - connect(BitTorrent::Session::instance(), &BitTorrent::Session::statsUpdated, this, &MainWindow::reloadSessionStats); + connect(BitTorrent::Session::instance(), &BitTorrent::Session::statsUpdated, this, &MainWindow::loadSessionStats); connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentsUpdated, this, &MainWindow::reloadTorrentStats); // Accept drag 'n drops @@ -530,7 +548,7 @@ void MainWindow::setTitleSuffix(const QString &suffix) m_windowTitle = QStringLiteral("qBittorrent " QBT_VERSION) + (!suffix.isEmpty() ? (separator + suffix) : QString()); - setWindowTitle(m_windowTitle); + refreshWindowTitle(); } void MainWindow::addToolbarContextMenu() @@ -881,9 +899,9 @@ void MainWindow::createKeyboardShortcuts() m_ui->actionOptions->setShortcut(Qt::ALT | Qt::Key_O); m_ui->actionStatistics->setShortcut(Qt::CTRL | Qt::Key_I); m_ui->actionStart->setShortcut(Qt::CTRL | Qt::Key_S); - m_ui->actionStartAll->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_S); m_ui->actionStop->setShortcut(Qt::CTRL | Qt::Key_P); - m_ui->actionStopAll->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_P); + m_ui->actionPauseSession->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_P); + m_ui->actionResumeSession->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_S); m_ui->actionBottomQueuePos->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Minus); m_ui->actionDecreaseQueuePos->setShortcut(Qt::CTRL | Qt::Key_Minus); m_ui->actionIncreaseQueuePos->setShortcut(Qt::CTRL | Qt::Key_Plus); @@ -1488,28 +1506,21 @@ void MainWindow::loadPreferences() qDebug("GUI settings loaded"); } -void MainWindow::reloadSessionStats() +void MainWindow::loadSessionStats() { - const BitTorrent::SessionStatus &status = BitTorrent::Session::instance()->status(); - const QString downloadRate = Utils::Misc::friendlyUnit(status.payloadDownloadRate, true); - const QString uploadRate = Utils::Misc::friendlyUnit(status.payloadUploadRate, true); + const auto *btSession = BitTorrent::Session::instance(); + const BitTorrent::SessionStatus &status = btSession->status(); + const QString m_downloadRate = Utils::Misc::friendlyUnit(status.payloadDownloadRate, true); + const QString m_uploadRate = Utils::Misc::friendlyUnit(status.payloadUploadRate, true); // update global information #ifdef Q_OS_MACOS m_badger->updateSpeed(status.payloadDownloadRate, status.payloadUploadRate); #else - const auto toolTip = u"%1\n%2"_s.arg( - tr("DL speed: %1", "e.g: Download speed: 10 KiB/s").arg(downloadRate) - , tr("UP speed: %1", "e.g: Upload speed: 10 KiB/s").arg(uploadRate)); - app()->desktopIntegration()->setToolTip(toolTip); // tray icon + refreshTrayIconTooltip(); #endif // Q_OS_MACOS - if (m_displaySpeedInTitle) - { - const QString title = tr("[D: %1, U: %2] %3", "D = Download; U = Upload; %3 is the rest of the window title") - .arg(downloadRate, uploadRate, m_windowTitle); - setWindowTitle(title); - } + refreshWindowTitle(); } void MainWindow::reloadTorrentStats(const QVector &torrents) @@ -1551,8 +1562,8 @@ void MainWindow::populateDesktopIntegrationMenu() menu->addAction(m_ui->actionSetGlobalSpeedLimits); menu->addSeparator(); - menu->addAction(m_ui->actionStartAll); - menu->addAction(m_ui->actionStopAll); + menu->addAction(m_ui->actionResumeSession); + menu->addAction(m_ui->actionPauseSession); #ifndef Q_OS_MACOS menu->addSeparator(); @@ -1613,10 +1624,7 @@ void MainWindow::on_actionSpeedInTitleBar_triggered() { m_displaySpeedInTitle = static_cast(sender())->isChecked(); Preferences::instance()->showSpeedInTitleBar(m_displaySpeedInTitle); - if (m_displaySpeedInTitle) - reloadSessionStats(); - else - setWindowTitle(m_windowTitle); + refreshWindowTitle(); } void MainWindow::on_actionRSSReader_triggered() @@ -1881,6 +1889,45 @@ void MainWindow::applyTransferListFilter() m_transferListWidget->applyFilter(m_columnFilterEdit->text(), m_columnFilterComboBox->currentData().value()); } +void MainWindow::refreshWindowTitle() +{ + const auto *btSession = BitTorrent::Session::instance(); + if (btSession->isPaused()) + { + const QString title = tr("[PAUSED] %1", "%1 is the rest of the window title").arg(m_windowTitle); + setWindowTitle(title); + } + else + { + if (m_displaySpeedInTitle) + { + const QString title = tr("[D: %1, U: %2] %3", "D = Download; U = Upload; %3 is the rest of the window title") + .arg(m_downloadRate, m_uploadRate, m_windowTitle); + setWindowTitle(title); + } + else + { + setWindowTitle(m_windowTitle); + } + } +} + +void MainWindow::refreshTrayIconTooltip() +{ + const auto *btSession = BitTorrent::Session::instance(); + if (!btSession->isPaused()) + { + const auto toolTip = u"%1\n%2"_s.arg( + tr("DL speed: %1", "e.g: Download speed: 10 KiB/s").arg(m_downloadRate) + , tr("UP speed: %1", "e.g: Upload speed: 10 KiB/s").arg(m_uploadRate)); + app()->desktopIntegration()->setToolTip(toolTip); + } + else + { + app()->desktopIntegration()->setToolTip(tr("Paused")); + } +} + #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) void MainWindow::checkProgramUpdate(const bool invokedByUser) { diff --git a/src/gui/mainwindow.h b/src/gui/mainwindow.h index 1f03f3225..f749db1ed 100644 --- a/src/gui/mainwindow.h +++ b/src/gui/mainwindow.h @@ -127,7 +127,7 @@ private slots: void displayRSSTab(); void displayExecutionLogTab(); void toggleFocusBetweenLineEdits(); - void reloadSessionStats(); + void loadSessionStats(); void reloadTorrentStats(const QVector &torrents); void loadPreferences(); void optionsSaved(); @@ -203,14 +203,19 @@ private: void showStatusBar(bool show); void showFiltersSidebar(bool show); void applyTransferListFilter(); + void refreshWindowTitle(); + void refreshTrayIconTooltip(); Ui::MainWindow *m_ui = nullptr; - QFileSystemWatcher *m_executableWatcher = nullptr; - // GUI related QString m_windowTitle; + QString m_downloadRate; + QString m_uploadRate; bool m_posInitialized = false; bool m_neverShown = true; + + QFileSystemWatcher *m_executableWatcher = nullptr; + // GUI related QPointer m_tabs; QPointer m_statusBar; QPointer m_options; diff --git a/src/gui/mainwindow.ui b/src/gui/mainwindow.ui index 61d456159..f2f7167d7 100644 --- a/src/gui/mainwindow.ui +++ b/src/gui/mainwindow.ui @@ -44,14 +44,15 @@ - - + + + @@ -196,14 +197,14 @@ Sto&p - + - Star&t All + &Resume Session - + - &Stop All + Pau&se Session diff --git a/src/gui/optionsdialog.cpp b/src/gui/optionsdialog.cpp index dd3520a56..dd76877b3 100644 --- a/src/gui/optionsdialog.cpp +++ b/src/gui/optionsdialog.cpp @@ -281,7 +281,6 @@ void OptionsDialog::loadBehaviorTabOptions() m_ui->checkShowSplash->setChecked(!pref->isSplashScreenDisabled()); m_ui->checkProgramExitConfirm->setChecked(pref->confirmOnExit()); m_ui->checkProgramAutoExitConfirm->setChecked(!pref->dontConfirmAutoExit()); - m_ui->checkConfirmStopAndStartAll->setChecked(pref->confirmPauseAndResumeAll()); m_ui->windowStateComboBox->addItem(tr("Normal"), QVariant::fromValue(WindowState::Normal)); m_ui->windowStateComboBox->addItem(tr("Minimized"), QVariant::fromValue(WindowState::Minimized)); @@ -381,7 +380,6 @@ void OptionsDialog::loadBehaviorTabOptions() connect(m_ui->checkShowSplash, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkProgramExitConfirm, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkProgramAutoExitConfirm, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkConfirmStopAndStartAll, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkShowSystray, &QGroupBox::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkMinimizeToSysTray, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkCloseToSystray, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); @@ -464,7 +462,6 @@ void OptionsDialog::saveBehaviorTabOptions() const pref->setSplashScreenDisabled(isSplashScreenDisabled()); pref->setConfirmOnExit(m_ui->checkProgramExitConfirm->isChecked()); pref->setDontConfirmAutoExit(!m_ui->checkProgramAutoExitConfirm->isChecked()); - pref->setConfirmPauseAndResumeAll(m_ui->checkConfirmStopAndStartAll->isChecked()); #ifdef Q_OS_WIN pref->setWinStartup(WinStartup()); diff --git a/src/gui/optionsdialog.ui b/src/gui/optionsdialog.ui index 7035c5f63..fcfba3f3b 100644 --- a/src/gui/optionsdialog.ui +++ b/src/gui/optionsdialog.ui @@ -226,19 +226,6 @@ - - - - Shows a confirmation dialog upon pausing/starting all the torrents - - - Confirm "Stop/Start all" actions - - - true - - - diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index 334854c95..a1b79b29e 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -377,36 +377,14 @@ void TransferListWidget::setSelectedTorrentsLocation() fileDialog->open(); } -void TransferListWidget::stopAllTorrents() +void TransferListWidget::pauseSession() { - if (Preferences::instance()->confirmPauseAndResumeAll()) - { - // Show confirmation if user would really like to Stop All - const QMessageBox::StandardButton ret = QMessageBox::question(this, tr("Confirm stop all torrents") - , tr("Would you like to stop all torrents?"), (QMessageBox::Yes | QMessageBox::No)); - - if (ret != QMessageBox::Yes) - return; - } - - for (BitTorrent::Torrent *const torrent : asConst(BitTorrent::Session::instance()->torrents())) - torrent->stop(); + BitTorrent::Session::instance()->pause(); } -void TransferListWidget::startAllTorrents() +void TransferListWidget::resumeSession() { - if (Preferences::instance()->confirmPauseAndResumeAll()) - { - // Show confirmation if user would really like to Start All - const QMessageBox::StandardButton ret = QMessageBox::question(this, tr("Confirm start all torrents") - , tr("Would you like to start all torrents?"), (QMessageBox::Yes | QMessageBox::No)); - - if (ret != QMessageBox::Yes) - return; - } - - for (BitTorrent::Torrent *const torrent : asConst(BitTorrent::Session::instance()->torrents())) - torrent->start(); + BitTorrent::Session::instance()->resume(); } void TransferListWidget::startSelectedTorrents() @@ -1142,8 +1120,7 @@ void TransferListWidget::displayListMenu() needsStop = true; } - const bool queued = (BitTorrent::Session::instance()->isQueueingSystemEnabled() && torrent->isQueued()); - + const bool queued = torrent->isQueued(); if (!isStopped && !rechecking && !queued) oneCanForceReannounce = true; diff --git a/src/gui/transferlistwidget.h b/src/gui/transferlistwidget.h index 5cc794e82..257ffd7ab 100644 --- a/src/gui/transferlistwidget.h +++ b/src/gui/transferlistwidget.h @@ -68,8 +68,8 @@ public slots: void removeSelectionTag(const Tag &tag); void clearSelectionTags(); void setSelectedTorrentsLocation(); - void stopAllTorrents(); - void startAllTorrents(); + void pauseSession(); + void resumeSession(); void startSelectedTorrents(); void forceStartSelectedTorrents(); void startVisibleTorrents();