diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index 2ec5dbf4c..28be659de 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -2085,6 +2085,11 @@ QVector Session::torrents() const return result; } +qsizetype Session::torrentsCount() const +{ + return m_torrents.size(); +} + bool Session::addTorrent(const QString &source, const AddTorrentParams ¶ms) { // `source`: .torrent file path/url or magnet uri diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index b478f1a31..376868a86 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -459,6 +459,7 @@ namespace BitTorrent void startUpTorrents(); Torrent *findTorrent(const TorrentID &id) const; QVector torrents() const; + qsizetype torrentsCount() const; bool hasActiveTorrents() const; bool hasUnfinishedTorrents() const; bool hasRunningSeed() const; diff --git a/src/gui/transferlistfilterswidget.cpp b/src/gui/transferlistfilterswidget.cpp index 8d313a39d..86bc01a38 100644 --- a/src/gui/transferlistfilterswidget.cpp +++ b/src/gui/transferlistfilterswidget.cpp @@ -169,13 +169,6 @@ void BaseFilterWidget::toggleFilter(bool checked) StatusFilterWidget::StatusFilterWidget(QWidget *parent, TransferListWidget *transferList) : BaseFilterWidget(parent, transferList) { - connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentLoaded - , this, &StatusFilterWidget::updateTorrentNumbers); - connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentsUpdated - , this, &StatusFilterWidget::updateTorrentNumbers); - connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentAboutToBeRemoved - , this, &StatusFilterWidget::updateTorrentNumbers); - // Add status filters auto *all = new QListWidgetItem(this); all->setData(Qt::DisplayRole, tr("All (0)", "this is for the status filter")); @@ -220,6 +213,11 @@ StatusFilterWidget::StatusFilterWidget(QWidget *parent, TransferListWidget *tran const Preferences *const pref = Preferences::instance(); setCurrentRow(pref->getTransSelFilter(), QItemSelectionModel::SelectCurrent); toggleFilter(pref->getStatusFilterState()); + + populate(); + + connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentsUpdated + , this, &StatusFilterWidget::handleTorrentsUpdated); } StatusFilterWidget::~StatusFilterWidget() @@ -227,63 +225,87 @@ StatusFilterWidget::~StatusFilterWidget() Preferences::instance()->setTransSelFilter(currentRow()); } -void StatusFilterWidget::updateTorrentNumbers() +void StatusFilterWidget::populate() { - int nbDownloading = 0; - int nbSeeding = 0; - int nbCompleted = 0; - int nbResumed = 0; - int nbPaused = 0; - int nbActive = 0; - int nbInactive = 0; - int nbStalled = 0; - int nbStalledUploading = 0; - int nbStalledDownloading = 0; - int nbChecking = 0; - int nbErrored = 0; + m_torrentsStatus.clear(); const QVector torrents = BitTorrent::Session::instance()->torrents(); for (const BitTorrent::Torrent *torrent : torrents) { - if (torrent->isDownloading()) - ++nbDownloading; - if (torrent->isUploading()) - ++nbSeeding; - if (torrent->isCompleted()) - ++nbCompleted; - if (torrent->isResumed()) - ++nbResumed; - if (torrent->isPaused()) - ++nbPaused; - if (torrent->isActive()) - ++nbActive; - if (torrent->isInactive()) - ++nbInactive; - if (torrent->state() == BitTorrent::TorrentState::StalledUploading) - ++nbStalledUploading; - if (torrent->state() == BitTorrent::TorrentState::StalledDownloading) - ++nbStalledDownloading; - if (torrent->isChecking()) - ++nbChecking; - if (torrent->isErrored()) - ++nbErrored; + updateTorrentStatus(torrent); } - nbStalled = nbStalledUploading + nbStalledDownloading; + updateTexts(); +} + +void StatusFilterWidget::updateTorrentStatus(const BitTorrent::Torrent *torrent) +{ + const auto update = [this, torrent](const TorrentFilter::Type status, const bool insert, int &count) + { + const bool contains = m_torrentsStatus.contains(torrent, status); + if (insert && !contains) + { + ++count; + m_torrentsStatus.insert(torrent, status); + } + else if (!insert && contains) + { + --count; + m_torrentsStatus.remove(torrent, status); + } + }; + + update(TorrentFilter::Downloading, torrent->isDownloading(), m_nbDownloading); + + update(TorrentFilter::Seeding, torrent->isUploading(), m_nbSeeding); + + update(TorrentFilter::Completed, torrent->isCompleted(), m_nbCompleted); + + update(TorrentFilter::Resumed, torrent->isResumed(), m_nbResumed); + + update(TorrentFilter::Paused, torrent->isPaused(), m_nbPaused); + + update(TorrentFilter::Active, torrent->isActive(), m_nbActive); + + update(TorrentFilter::Inactive, torrent->isInactive(), m_nbInactive); - item(TorrentFilter::All)->setData(Qt::DisplayRole, tr("All (%1)").arg(torrents.count())); - item(TorrentFilter::Downloading)->setData(Qt::DisplayRole, tr("Downloading (%1)").arg(nbDownloading)); - item(TorrentFilter::Seeding)->setData(Qt::DisplayRole, tr("Seeding (%1)").arg(nbSeeding)); - item(TorrentFilter::Completed)->setData(Qt::DisplayRole, tr("Completed (%1)").arg(nbCompleted)); - item(TorrentFilter::Resumed)->setData(Qt::DisplayRole, tr("Resumed (%1)").arg(nbResumed)); - item(TorrentFilter::Paused)->setData(Qt::DisplayRole, tr("Paused (%1)").arg(nbPaused)); - item(TorrentFilter::Active)->setData(Qt::DisplayRole, tr("Active (%1)").arg(nbActive)); - item(TorrentFilter::Inactive)->setData(Qt::DisplayRole, tr("Inactive (%1)").arg(nbInactive)); - item(TorrentFilter::Stalled)->setData(Qt::DisplayRole, tr("Stalled (%1)").arg(nbStalled)); - item(TorrentFilter::StalledUploading)->setData(Qt::DisplayRole, tr("Stalled Uploading (%1)").arg(nbStalledUploading)); - item(TorrentFilter::StalledDownloading)->setData(Qt::DisplayRole, tr("Stalled Downloading (%1)").arg(nbStalledDownloading)); - item(TorrentFilter::Checking)->setData(Qt::DisplayRole, tr("Checking (%1)").arg(nbChecking)); - item(TorrentFilter::Errored)->setData(Qt::DisplayRole, tr("Errored (%1)").arg(nbErrored)); + const bool isStalledUploading = (torrent->state() == BitTorrent::TorrentState::StalledUploading); + update(TorrentFilter::StalledUploading, isStalledUploading, m_nbStalledUploading); + + const bool isStalledDownloading = (torrent->state() == BitTorrent::TorrentState::StalledDownloading); + update(TorrentFilter::StalledDownloading, isStalledDownloading, m_nbStalledDownloading); + + update(TorrentFilter::Checking, torrent->isChecking(), m_nbChecking); + + update(TorrentFilter::Errored, torrent->isErrored(), m_nbErrored); + + m_nbStalled = m_nbStalledUploading + m_nbStalledDownloading; +} + +void StatusFilterWidget::updateTexts() +{ + const qsizetype torrentsCount = BitTorrent::Session::instance()->torrentsCount(); + item(TorrentFilter::All)->setData(Qt::DisplayRole, tr("All (%1)").arg(torrentsCount)); + item(TorrentFilter::Downloading)->setData(Qt::DisplayRole, tr("Downloading (%1)").arg(m_nbDownloading)); + item(TorrentFilter::Seeding)->setData(Qt::DisplayRole, tr("Seeding (%1)").arg(m_nbSeeding)); + item(TorrentFilter::Completed)->setData(Qt::DisplayRole, tr("Completed (%1)").arg(m_nbCompleted)); + item(TorrentFilter::Resumed)->setData(Qt::DisplayRole, tr("Resumed (%1)").arg(m_nbResumed)); + item(TorrentFilter::Paused)->setData(Qt::DisplayRole, tr("Paused (%1)").arg(m_nbPaused)); + item(TorrentFilter::Active)->setData(Qt::DisplayRole, tr("Active (%1)").arg(m_nbActive)); + item(TorrentFilter::Inactive)->setData(Qt::DisplayRole, tr("Inactive (%1)").arg(m_nbInactive)); + item(TorrentFilter::Stalled)->setData(Qt::DisplayRole, tr("Stalled (%1)").arg(m_nbStalled)); + item(TorrentFilter::StalledUploading)->setData(Qt::DisplayRole, tr("Stalled Uploading (%1)").arg(m_nbStalledUploading)); + item(TorrentFilter::StalledDownloading)->setData(Qt::DisplayRole, tr("Stalled Downloading (%1)").arg(m_nbStalledDownloading)); + item(TorrentFilter::Checking)->setData(Qt::DisplayRole, tr("Checking (%1)").arg(m_nbChecking)); + item(TorrentFilter::Errored)->setData(Qt::DisplayRole, tr("Errored (%1)").arg(m_nbErrored)); +} + +void StatusFilterWidget::handleTorrentsUpdated(const QVector torrents) +{ + for (const BitTorrent::Torrent *torrent : torrents) + updateTorrentStatus(torrent); + + updateTexts(); } void StatusFilterWidget::showMenu() @@ -306,9 +328,64 @@ void StatusFilterWidget::applyFilter(int row) transferList->applyStatusFilter(row); } -void StatusFilterWidget::handleNewTorrent(BitTorrent::Torrent *const) {} +void StatusFilterWidget::handleNewTorrent(BitTorrent::Torrent *const torrent) +{ + updateTorrentStatus(torrent); + updateTexts(); +} -void StatusFilterWidget::torrentAboutToBeDeleted(BitTorrent::Torrent *const) {} +void StatusFilterWidget::torrentAboutToBeDeleted(BitTorrent::Torrent *const torrent) +{ + for (const TorrentFilter::Type status : m_torrentsStatus.values(torrent)) + { + switch (status) + { + case TorrentFilter::Downloading: + --m_nbDownloading; + break; + case TorrentFilter::Seeding: + --m_nbSeeding; + break; + case TorrentFilter::Completed: + --m_nbCompleted; + break; + case TorrentFilter::Resumed: + --m_nbResumed; + break; + case TorrentFilter::Paused: + --m_nbPaused; + break; + case TorrentFilter::Active: + --m_nbActive; + break; + case TorrentFilter::Inactive: + --m_nbInactive; + break; + case TorrentFilter::StalledUploading: + --m_nbStalledUploading; + break; + case TorrentFilter::StalledDownloading: + --m_nbStalledDownloading; + break; + case TorrentFilter::Checking: + --m_nbChecking; + break; + case TorrentFilter::Errored: + --m_nbErrored; + break; + + default: + Q_ASSERT(false); + break; + } + } + + m_nbStalled = m_nbStalledUploading + m_nbStalledDownloading; + + m_torrentsStatus.remove(torrent); + + updateTexts(); +} TrackerFiltersList::TrackerFiltersList(QWidget *parent, TransferListWidget *transferList, const bool downloadFavicon) : BaseFilterWidget(parent, transferList) diff --git a/src/gui/transferlistfilterswidget.h b/src/gui/transferlistfilterswidget.h index c60f6a4ef..68c55422d 100644 --- a/src/gui/transferlistfilterswidget.h +++ b/src/gui/transferlistfilterswidget.h @@ -35,6 +35,7 @@ #include "base/bittorrent/infohash.h" #include "base/bittorrent/session.h" #include "base/bittorrent/trackerentry.h" +#include "base/torrentfilter.h" #include "base/path.h" class QCheckBox; @@ -81,7 +82,7 @@ public: ~StatusFilterWidget() override; private slots: - void updateTorrentNumbers(); + void handleTorrentsUpdated(const QVector torrents); private: // These 4 methods are virtual slots in the base class. @@ -90,6 +91,24 @@ private: void applyFilter(int row) override; void handleNewTorrent(BitTorrent::Torrent *const) override; void torrentAboutToBeDeleted(BitTorrent::Torrent *const) override; + + void populate(); + void updateTorrentStatus(const BitTorrent::Torrent *torrent); + void updateTexts(); + + QMultiHash m_torrentsStatus; + int m_nbDownloading = 0; + int m_nbSeeding = 0; + int m_nbCompleted = 0; + int m_nbResumed = 0; + int m_nbPaused = 0; + int m_nbActive = 0; + int m_nbInactive = 0; + int m_nbStalled = 0; + int m_nbStalledUploading = 0; + int m_nbStalledDownloading = 0; + int m_nbChecking = 0; + int m_nbErrored = 0; }; class TrackerFiltersList final : public BaseFilterWidget