From f0d5ce4b98428d160acbbda2ad4c52364242bb1a Mon Sep 17 00:00:00 2001 From: sledgehammer999 Date: Sun, 22 Mar 2015 01:18:21 +0200 Subject: [PATCH] Implement tracker list in the side panel. Closes #170. --- src/core/qtlibtorrent/qbtsession.cpp | 4 + src/core/qtlibtorrent/qbtsession.h | 1 + src/core/qtlibtorrent/torrentmodel.cpp | 5 + src/core/qtlibtorrent/torrentmodel.h | 1 + src/gui/mainwindow.cpp | 3 + src/gui/properties/propertieswidget.cpp | 2 + src/gui/properties/propertieswidget.h | 4 + src/gui/properties/trackerlist.cpp | 12 ++ src/gui/properties/trackerlist.h | 4 + src/gui/transferlistfilterswidget.cpp | 267 ++++++++++++++++++++++++ src/gui/transferlistfilterswidget.h | 38 ++++ src/gui/transferlistsortmodel.cpp | 32 ++- src/gui/transferlistsortmodel.h | 8 +- src/gui/transferlistwidget.cpp | 10 + src/gui/transferlistwidget.h | 2 + 15 files changed, 391 insertions(+), 2 deletions(-) diff --git a/src/core/qtlibtorrent/qbtsession.cpp b/src/core/qtlibtorrent/qbtsession.cpp index ed66e4ea7..61e331e53 100644 --- a/src/core/qtlibtorrent/qbtsession.cpp +++ b/src/core/qtlibtorrent/qbtsession.cpp @@ -1278,6 +1278,7 @@ void QBtSession::loadTorrentTempData(QTorrentHandle &h, QString savePath, bool m void QBtSession::mergeTorrents(QTorrentHandle& h_ex, const QString& magnet_uri) { + QString hash = h_ex.hash(); QList new_trackers = misc::magnetUriToTrackers(magnet_uri); bool trackers_added = false; foreach (const QUrl& new_tracker, new_trackers) { @@ -1293,6 +1294,7 @@ void QBtSession::mergeTorrents(QTorrentHandle& h_ex, const QString& magnet_uri) if (!found) { h_ex.add_tracker(announce_entry(new_tracker.toString().toStdString())); trackers_added = true; + emit trackerAdded(new_tracker.toString(), hash); } } if (trackers_added) @@ -1302,6 +1304,7 @@ void QBtSession::mergeTorrents(QTorrentHandle& h_ex, const QString& magnet_uri) void QBtSession::mergeTorrents(QTorrentHandle &h_ex, boost::intrusive_ptr t) { // Check if the torrent contains trackers or url seeds we don't know about // and add them + QString hash = h_ex.hash(); if (!h_ex.is_valid()) return; std::vector existing_trackers = h_ex.trackers(); std::vector new_trackers = t->trackers(); @@ -1320,6 +1323,7 @@ void QBtSession::mergeTorrents(QTorrentHandle &h_ex, boost::intrusive_ptr &statuses); void statsReceived(const libtorrent::stats_alert&); + void trackerAdded(const QString &tracker, const QString &hash); private: // Bittorrent diff --git a/src/core/qtlibtorrent/torrentmodel.cpp b/src/core/qtlibtorrent/torrentmodel.cpp index 43c9a28f9..e719a086d 100644 --- a/src/core/qtlibtorrent/torrentmodel.cpp +++ b/src/core/qtlibtorrent/torrentmodel.cpp @@ -312,6 +312,11 @@ QVariant TorrentModelItem::data(int column, int role) const } } +QTorrentHandle TorrentModelItem::torrentHandle() const +{ + return m_torrent; +} + // TORRENT MODEL TorrentModel::TorrentModel(QObject *parent) : diff --git a/src/core/qtlibtorrent/torrentmodel.h b/src/core/qtlibtorrent/torrentmodel.h index d2d5a64c4..5cee6a0f3 100644 --- a/src/core/qtlibtorrent/torrentmodel.h +++ b/src/core/qtlibtorrent/torrentmodel.h @@ -59,6 +59,7 @@ public: bool setData(int column, const QVariant &value, int role = Qt::DisplayRole); inline QString const& hash() const { return m_hash; } State state() const; + QTorrentHandle torrentHandle() const; signals: void labelChanged(QString previous, QString current); diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 7349e1b52..2e1d3a673 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -214,6 +214,9 @@ MainWindow::MainWindow(QWidget *parent) connect(search_filter, SIGNAL(textChanged(QString)), transferList, SLOT(applyNameFilter(QString))); connect(hSplitter, SIGNAL(splitterMoved(int, int)), this, SLOT(writeSettings())); connect(vSplitter, SIGNAL(splitterMoved(int, int)), this, SLOT(writeSettings())); + connect(properties, SIGNAL(trackerAdded(const QString&, const QString&)), transferListFilters, SLOT(addTracker(const QString&, const QString&))); + connect(properties, SIGNAL(trackerRemoved(const QString&, const QString&)), transferListFilters, SLOT(removeTracker(const QString&, const QString&))); + connect(QBtSession::instance(), SIGNAL(trackerAdded(const QString&, const QString&)), transferListFilters, SLOT(addTracker(const QString&, const QString&))); vboxLayout->addWidget(tabs); diff --git a/src/gui/properties/propertieswidget.cpp b/src/gui/properties/propertieswidget.cpp index 017902fc1..ef7be8798 100644 --- a/src/gui/properties/propertieswidget.cpp +++ b/src/gui/properties/propertieswidget.cpp @@ -111,6 +111,8 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow* main_window, Tra trackerList = new TrackerList(this); connect(trackerUpButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionUp())); connect(trackerDownButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionDown())); + connect(trackerList, SIGNAL(trackerAdded(const QString&, const QString&)), this, SIGNAL(trackerAdded(const QString&, const QString&))); + connect(trackerList, SIGNAL(trackerRemoved(const QString&, const QString&)), this, SIGNAL(trackerRemoved(const QString&, const QString&))); horizontalLayout_trackers->insertWidget(0, trackerList); connect(trackerList->header(), SIGNAL(sectionMoved(int, int, int)), trackerList, SLOT(saveSettings())); connect(trackerList->header(), SIGNAL(sectionResized(int, int, int)), trackerList, SLOT(saveSettings())); diff --git a/src/gui/properties/propertieswidget.h b/src/gui/properties/propertieswidget.h index 6af57a07c..5b9a194f4 100644 --- a/src/gui/properties/propertieswidget.h +++ b/src/gui/properties/propertieswidget.h @@ -69,6 +69,10 @@ public: PeerListWidget* getPeerList() const { return peersList; } QTreeView* getFilesList() const { return filesList; } +signals: + void trackerAdded(const QString &tracker, const QString &hash); + void trackerRemoved(const QString &tracker, const QString &hash); + protected: QPushButton* getButtonFromIndex(int index); bool applyPriorities(); diff --git a/src/gui/properties/trackerlist.cpp b/src/gui/properties/trackerlist.cpp index c3c04e90d..2a1ad3ecc 100644 --- a/src/gui/properties/trackerlist.cpp +++ b/src/gui/properties/trackerlist.cpp @@ -300,14 +300,19 @@ void TrackerList::loadTrackers() { void TrackerList::askForTrackers() { QTorrentHandle h = properties->getCurrentTorrent(); if (!h.is_valid()) return; + QString hash = h.hash(); QStringList trackers = TrackersAdditionDlg::askForTrackers(h); if (!trackers.empty()) { + if (h.trackers().empty()) + emit trackerRemoved("", hash); + for (int i=0; i selected_items = getSelectedTrackerItems(); if (selected_items.isEmpty()) return; QStringList urls_to_remove; @@ -344,6 +350,7 @@ void TrackerList::deleteSelectedTrackers() { urls_to_remove << tracker_url; tracker_items.remove(tracker_url); delete item; + emit trackerRemoved(tracker_url, hash); } // Iterate of trackers and remove selected ones std::vector remaining_trackers; @@ -357,6 +364,8 @@ void TrackerList::deleteSelectedTrackers() { } } h.replace_trackers(remaining_trackers); + if (remaining_trackers.empty()) + emit trackerAdded("", hash); if (!h.is_paused()) h.force_reannounce(); // Reload Trackers @@ -366,6 +375,7 @@ void TrackerList::deleteSelectedTrackers() { void TrackerList::editSelectedTracker() { try { QTorrentHandle h = properties->getCurrentTorrent(); + QString hash = h.hash(); QList selected_items = getSelectedTrackerItems(); if (selected_items.isEmpty()) @@ -402,6 +412,8 @@ void TrackerList::editSelectedTracker() { new_entry.tier = it->tier; match = true; *it = new_entry; + emit trackerRemoved(tracker_url.toString(), hash); + emit trackerAdded(new_tracker_url.toString(), hash); } } diff --git a/src/gui/properties/trackerlist.h b/src/gui/properties/trackerlist.h index dc739063e..277aaf2e8 100644 --- a/src/gui/properties/trackerlist.h +++ b/src/gui/properties/trackerlist.h @@ -60,6 +60,10 @@ public: TrackerList(PropertiesWidget *properties); ~TrackerList(); +signals: + void trackerAdded(const QString &tracker, const QString &hash); + void trackerRemoved(const QString &tracker, const QString &hash); + protected: QList getSelectedTrackerItems() const; diff --git a/src/gui/transferlistfilterswidget.cpp b/src/gui/transferlistfilterswidget.cpp index eedca9c49..7fa99ce0b 100644 --- a/src/gui/transferlistfilterswidget.cpp +++ b/src/gui/transferlistfilterswidget.cpp @@ -47,6 +47,9 @@ #include "fs_utils.h" #include "autoexpandabledialog.h" #include "torrentfilterenum.h" +#include "misc.h" +#include "downloadthread.h" +#include "logger.h" LabelFiltersList::LabelFiltersList(QWidget *parent): QListWidget(parent) { @@ -167,6 +170,215 @@ QSize StatusFiltersWidget::sizeHint() const return size; } +TrackerFiltersList::TrackerFiltersList(QWidget *parent): QListWidget(parent), m_downloader(new DownloadThread(this)) +{ + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + setStyleSheet("QListWidget { background: transparent; border: 0 }"); +#if defined(Q_OS_MAC) + setAttribute(Qt::WA_MacShowFocusRect, false); +#endif + QListWidgetItem *allTrackers = new QListWidgetItem(this); + allTrackers->setData(Qt::DisplayRole, QVariant(tr("All trackers (0)"))); + allTrackers->setData(Qt::DecorationRole, IconProvider::instance()->getIcon("network-server")); + QListWidgetItem *noTracker = new QListWidgetItem(this); + noTracker->setData(Qt::DisplayRole, QVariant(tr("Trackerless (0)"))); + noTracker->setData(Qt::DecorationRole, IconProvider::instance()->getIcon("network-server")); + m_trackers.insert("", QStringList()); + connect(m_downloader, SIGNAL(downloadFinished(QString, QString)), SLOT(handleFavicoDownload(QString, QString))); + connect(m_downloader, SIGNAL(downloadFailure(QString, QString)), SLOT(handleFavicoFailure(QString, QString))); +} + +TrackerFiltersList::~TrackerFiltersList() +{ + delete m_downloader; + foreach (const QString &iconPath, m_iconPaths) + fsutils::forceRemove(iconPath); +} + +void TrackerFiltersList::addItem(const QString &tracker, const QString &hash) +{ + QStringList tmp; + QListWidgetItem *trackerItem = 0; + QString host = getHost(tracker); + + if (m_trackers.contains(host)) { + tmp = m_trackers.value(host); + if (tmp.contains(hash)) + return; + + if (host != "") + trackerItem = item(rowFromTracker(host)); + else + trackerItem = item(1); + } + else { + trackerItem = new QListWidgetItem(); + trackerItem->setData(Qt::DecorationRole, IconProvider::instance()->getIcon("network-server")); + m_downloader->downloadUrl(QString("http://") + host + QString("/favicon.ico")); + } + + tmp.append(hash); + m_trackers.insert(host, tmp); + if (host == "") { + trackerItem->setText(tr("Trackerless (%1)").arg(tmp.size())); + if (currentRow() == 1) + emit currentRowChanged(1); + return; + } + + trackerItem->setText(tr("%1 (%2)", "openbittorrent.com (10)").arg(host).arg(tmp.size())); + + Q_ASSERT(count() >= 2); + for (int i = 2; itext(), less))) + less = (host.localeAwareCompare(item(i)->text()) < 0); + if (less) { + insertItem(i, trackerItem); + if (currentRow() == i) + emit currentRowChanged(i); + return; + } + } + QListWidget::addItem(trackerItem); +} + +void TrackerFiltersList::addItem(const QTorrentHandle& handle) +{ + QString hash = handle.hash(); + std::vector trackers = handle.trackers(); + for (std::vector::iterator i = trackers.begin(), e = trackers.end(); i != e; ++i) + addItem(misc::toQString(i->url), hash); + + //Check for trackerless torrent + if (trackers.size() == 0) + addItem("", hash); +} + +void TrackerFiltersList::removeItem(const QString &tracker, const QString &hash) +{ + QString host = getHost(tracker); + QListWidgetItem *trackerItem = 0; + QStringList tmp = m_trackers.value(host); + int row = 0; + + if (tmp.empty()) + return; + tmp.removeAll(hash); + + if (host != "") { + row = rowFromTracker(host); + trackerItem = item(row); + if (tmp.empty()) { + if (currentRow() == row) + setCurrentRow(0); + delete trackerItem; + m_trackers.remove(host); + return; + } + trackerItem->setText(tr("%1 (%2)", "openbittorrent.com (10)").arg(host).arg(tmp.size())); + } + else { + row = 1; + trackerItem = item(1); + trackerItem->setText(tr("Trackerless (%1)").arg(tmp.size())); + } + + m_trackers.insert(host, tmp); + if (currentRow() == row) + emit currentRowChanged(row); +} + +void TrackerFiltersList::removeItem(const QTorrentHandle& handle) +{ + QString hash = handle.hash(); + std::vector trackers = handle.trackers(); + for (std::vector::iterator i = trackers.begin(), e = trackers.end(); i != e; ++i) + removeItem(misc::toQString(i->url), hash); + + //Check for trackerless torrent + if (trackers.size() == 0) + removeItem("", hash); +} + +void TrackerFiltersList::setTorrentCount(int all) +{ + item(0)->setText(tr("All trackers (%1)").arg(all)); +} + +QStringList TrackerFiltersList::getHashes(int row) +{ + if (row == 1) + return m_trackers.value(""); + else + return m_trackers.value(trackerFromRow(row)); +} + +void TrackerFiltersList::handleFavicoDownload(const QString& url, const QString& filePath) +{ + QString host = getHost(url); + if (!m_trackers.contains(host)) + return; + + QListWidgetItem *trackerItem = item(rowFromTracker(host)); + QIcon icon(filePath); + //Detect a non-decodable icon + bool invalid = icon.pixmap(icon.availableSizes().first()).isNull(); + if (invalid) { + if (url.endsWith(".ico", Qt::CaseInsensitive)) { + Logger::instance()->addMessage(tr("Couldn't decode favico for url `%1`. Trying to download favico in PNG format.").arg(url), + Log::WARNING); + m_downloader->downloadUrl(url.left(url.size() - 4) + ".png"); + } + else { + Logger::instance()->addMessage(tr("Couldn't decode favico for url `%1`.").arg(url), Log::WARNING); + } + fsutils::forceRemove(filePath); + } + else { + trackerItem->setData(Qt::DecorationRole, QVariant(QIcon(filePath))); + m_iconPaths.append(filePath); + } +} + +void TrackerFiltersList::handleFavicoFailure(const QString& url, const QString& error) +{ + // Don't use getHost() on the url here. Print the full url. The error might relate to + // that. + Logger::instance()->addMessage(tr("Couldn't download favico for url `%1`. Reason: `%2`").arg(url).arg(error), + Log::WARNING); +} + +QString TrackerFiltersList::trackerFromRow(int row) const +{ + Q_ASSERT(row > 1); + const QString &tracker = item(row)->text(); + QStringList parts = tracker.split(" "); + Q_ASSERT(parts.size() >= 2); + parts.removeLast(); // Remove trailing number + return parts.join(" "); +} + +int TrackerFiltersList::rowFromTracker(const QString &tracker) const +{ + Q_ASSERT(!tracker.isEmpty()); + for (int i = 2; iaddWidget(labelsLabel); labelFilters = new LabelFiltersList(this); vLayout->addWidget(labelFilters); + QLabel *trackersLabel = new QLabel(tr("Trackers")); + trackersLabel->setIndent(2); + trackersLabel->setFont(font); + vLayout->addWidget(trackersLabel); + trackerFilters = new TrackerFiltersList(this); + vLayout->addWidget(trackerFilters); setLayout(vLayout); labelFilters->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + trackerFilters->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); statusFilters->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); statusFilters->setSpacing(0); setContentsMargins(0,0,0,0); @@ -222,6 +441,7 @@ TransferListFiltersWidget::TransferListFiltersWidget(QWidget *parent, TransferLi connect(transferList->getSourceModel(), SIGNAL(torrentAdded(TorrentModelItem*)), SLOT(handleNewTorrent(TorrentModelItem*))); connect(labelFilters, SIGNAL(currentRowChanged(int)), this, SLOT(applyLabelFilter(int))); connect(labelFilters, SIGNAL(torrentDropped(int)), this, SLOT(torrentDropped(int))); + connect(trackerFilters, SIGNAL(currentRowChanged(int)), this, SLOT(applyTrackerFilter(int))); connect(transferList->getSourceModel(), SIGNAL(torrentAboutToBeRemoved(TorrentModelItem*)), SLOT(torrentAboutToBeDeleted(TorrentModelItem*))); connect(transferList->getSourceModel(), SIGNAL(torrentChangedLabel(TorrentModelItem*,QString,QString)), SLOT(torrentChangedLabel(TorrentModelItem*, QString, QString))); @@ -237,11 +457,16 @@ TransferListFiltersWidget::TransferListFiltersWidget(QWidget *parent, TransferLi loadSettings(); labelFilters->setCurrentRow(0); + trackerFilters->setCurrentRow(0); //labelFilters->selectionModel()->select(labelFilters->model()->index(0,0), QItemSelectionModel::Select); // Label menu labelFilters->setContextMenuPolicy(Qt::CustomContextMenu); connect(labelFilters, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showLabelMenu(QPoint))); + + // Tracker menu + trackerFilters->setContextMenuPolicy(Qt::CustomContextMenu); + connect(trackerFilters, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showTrackerMenu(QPoint))); } TransferListFiltersWidget::~TransferListFiltersWidget() @@ -249,6 +474,7 @@ TransferListFiltersWidget::~TransferListFiltersWidget() saveSettings(); delete statusFilters; delete labelFilters; + delete trackerFilters; delete vLayout; } @@ -311,6 +537,16 @@ void TransferListFiltersWidget::addLabel(QString& label) Preferences::instance()->addTorrentLabel(label); } +void TransferListFiltersWidget::addTracker(const QString &tracker, const QString &hash) +{ + trackerFilters->addItem(tracker, hash); +} + +void TransferListFiltersWidget::removeTracker(const QString &tracker, const QString &hash) +{ + trackerFilters->removeItem(tracker, hash); +} + void TransferListFiltersWidget::showLabelMenu(QPoint) { QMenu labelMenu(labelFilters); @@ -370,6 +606,25 @@ void TransferListFiltersWidget::showLabelMenu(QPoint) } } +void TransferListFiltersWidget::showTrackerMenu(QPoint) +{ + QMenu trackerMenu(trackerFilters); + QAction *startAct = trackerMenu.addAction(IconProvider::instance()->getIcon("media-playback-start"), tr("Resume torrents")); + QAction *pauseAct = trackerMenu.addAction(IconProvider::instance()->getIcon("media-playback-pause"), tr("Pause torrents")); + QAction *deleteTorrentsAct = trackerMenu.addAction(IconProvider::instance()->getIcon("edit-delete"), tr("Delete torrents")); + QAction *act = 0; + act = trackerMenu.exec(QCursor::pos()); + + if (act) { + if (act == startAct) + transferList->startVisibleTorrents(); + else if (act == pauseAct) + transferList->pauseVisibleTorrents(); + else if (act == deleteTorrentsAct) + transferList->deleteVisibleTorrents(); + } +} + void TransferListFiltersWidget::removeSelectedLabel() { const int row = labelFilters->row(labelFilters->selectedItems().first()); @@ -416,6 +671,14 @@ void TransferListFiltersWidget::applyLabelFilter(int row) } } +void TransferListFiltersWidget::applyTrackerFilter(int row) +{ + if (row == 0) + transferList->applyTrackerFilterAll(); + else + transferList->applyTrackerFilter(trackerFilters->getHashes(row)); +} + void TransferListFiltersWidget::torrentChangedLabel(TorrentModelItem *torrentItem, QString old_label, QString new_label) { Q_UNUSED(torrentItem); @@ -471,6 +734,8 @@ void TransferListFiltersWidget::handleNewTorrent(TorrentModelItem* torrentItem) Q_ASSERT(nb_labeled >= 0); Q_ASSERT(nb_labeled <= nb_torrents); updateStickyLabelCounters(); + trackerFilters->addItem(torrentItem->torrentHandle()); + trackerFilters->setTorrentCount(nb_torrents); } void TransferListFiltersWidget::torrentAboutToBeDeleted(TorrentModelItem* torrentItem) @@ -492,6 +757,8 @@ void TransferListFiltersWidget::torrentAboutToBeDeleted(TorrentModelItem* torren Q_ASSERT(nb_labeled >= 0); Q_ASSERT(nb_labeled <= nb_torrents); updateStickyLabelCounters(); + trackerFilters->removeItem(torrentItem->torrentHandle()); + trackerFilters->setTorrentCount(nb_torrents); } void TransferListFiltersWidget::updateStickyLabelCounters() diff --git a/src/gui/transferlistfilterswidget.h b/src/gui/transferlistfilterswidget.h index 3e78ed9f9..829c90c7f 100644 --- a/src/gui/transferlistfilterswidget.h +++ b/src/gui/transferlistfilterswidget.h @@ -42,6 +42,8 @@ QT_END_NAMESPACE class TransferListWidget; class TorrentModelItem; +class QTorrentHandle; +class DownloadThread; class LabelFiltersList: public QListWidget { @@ -83,6 +85,35 @@ private: bool m_shown; }; +class TrackerFiltersList: public QListWidget +{ + Q_OBJECT + +public: + TrackerFiltersList(QWidget *parent); + ~TrackerFiltersList(); + + // Redefine addItem() to make sure the list stays sorted + void addItem(const QString &tracker, const QString &hash); + void addItem(const QTorrentHandle &handle); + void removeItem(const QString &tracker, const QString &hash); + void removeItem(const QTorrentHandle &handle); + void setTorrentCount(int all); + QStringList getHashes(int row); + +public slots: + void handleFavicoDownload(const QString &url, const QString &filePath); + void handleFavicoFailure(const QString &url, const QString &reason); + +private: + QHash m_trackers; + QString trackerFromRow(int row) const; + int rowFromTracker(const QString &tracker) const; + QString getHost(const QString &trakcer) const; + DownloadThread *m_downloader; + QStringList m_iconPaths; +}; + class TransferListFiltersWidget: public QFrame { Q_OBJECT @@ -91,6 +122,7 @@ private: QHash customLabels; StatusFiltersWidget* statusFilters; LabelFiltersList* labelFilters; + TrackerFiltersList* trackerFilters; QVBoxLayout* vLayout; TransferListWidget *transferList; int nb_labeled; @@ -105,14 +137,20 @@ public: void saveSettings() const; void loadSettings(); +public slots: + void addTracker(const QString &tracker, const QString &hash); + void removeTracker(const QString &tracker, const QString &hash); + protected slots: void updateTorrentNumbers(); void torrentDropped(int row); void addLabel(QString& label); void showLabelMenu(QPoint); + void showTrackerMenu(QPoint); void removeSelectedLabel(); void removeUnusedLabels(); void applyLabelFilter(int row); + void applyTrackerFilter(int row); void torrentChangedLabel(TorrentModelItem *torrentItem, QString old_label, QString new_label); void handleNewTorrent(TorrentModelItem* torrentItem); void torrentAboutToBeDeleted(TorrentModelItem* torrentItem); diff --git a/src/gui/transferlistsortmodel.cpp b/src/gui/transferlistsortmodel.cpp index fede02c73..a9fbdd84c 100644 --- a/src/gui/transferlistsortmodel.cpp +++ b/src/gui/transferlistsortmodel.cpp @@ -36,6 +36,8 @@ TransferListSortModel::TransferListSortModel(QObject *parent) : QSortFilterProxyModel(parent) , filter0(TorrentFilter::ALL) + , labelFilterEnabled(false) + , trackerFilterEnabled(false) {} void TransferListSortModel::setStatusFilter(const TorrentFilter::TorrentFilter &filter) { @@ -45,7 +47,7 @@ void TransferListSortModel::setStatusFilter(const TorrentFilter::TorrentFilter & } } -void TransferListSortModel::setLabelFilter(QString const& label) { +void TransferListSortModel::setLabelFilter(const QString &label) { if (!labelFilterEnabled || labelFilter != label) { labelFilterEnabled = true; labelFilter = label; @@ -61,6 +63,22 @@ void TransferListSortModel::disableLabelFilter() { } } +void TransferListSortModel::setTrackerFilter(const QStringList &hashes) { + if (!trackerFilterEnabled || trackerFilter != hashes) { + trackerFilterEnabled = true; + trackerFilter = hashes; + invalidateFilter(); + } +} + +void TransferListSortModel::disableTrackerFilter() { + if (trackerFilterEnabled) { + trackerFilterEnabled = false; + trackerFilter = QStringList(); + invalidateFilter(); + } +} + bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { const int column = sortColumn(); @@ -197,6 +215,7 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex bool TransferListSortModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { return matchStatusFilter(sourceRow, sourceParent) && matchLabelFilter(sourceRow, sourceParent) + && matchTrackerFilter(sourceRow, sourceParent) && QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); } @@ -258,3 +277,14 @@ bool TransferListSortModel::matchLabelFilter(int sourceRow, const QModelIndex &s return model->index(sourceRow, TorrentModelItem::TR_LABEL, sourceParent).data().toString() == labelFilter; } + +bool TransferListSortModel::matchTrackerFilter(int sourceRow, const QModelIndex &sourceParent) const { + if (!trackerFilterEnabled) + return true; + + TorrentModel *model = qobject_cast(sourceModel()); + if (!model) + return false; + + return trackerFilter.contains(model->torrentHash(sourceRow)); +} diff --git a/src/gui/transferlistsortmodel.h b/src/gui/transferlistsortmodel.h index e8d35d6f9..4580bbbce 100644 --- a/src/gui/transferlistsortmodel.h +++ b/src/gui/transferlistsortmodel.h @@ -32,6 +32,7 @@ #define TRANSFERLISTSORTMODEL_H #include +#include #include "torrentfilterenum.h" class TransferListSortModel : public QSortFilterProxyModel { @@ -41,8 +42,10 @@ public: TransferListSortModel(QObject *parent = 0); void setStatusFilter(const TorrentFilter::TorrentFilter &filter); - void setLabelFilter(QString const& label); + void setLabelFilter(const QString &label); void disableLabelFilter(); + void setTrackerFilter(const QStringList &hashes); + void disableTrackerFilter(); private: bool lessThan(const QModelIndex &left, const QModelIndex &right) const; @@ -50,12 +53,15 @@ private: bool matchStatusFilter(int sourceRow, const QModelIndex &sourceParent) const; bool matchLabelFilter(int sourceRow, const QModelIndex &sourceParent) const; + bool matchTrackerFilter(int sourceRow, const QModelIndex &sourceParent) const; private: TorrentFilter::TorrentFilter filter0; bool labelFilterEnabled; QString labelFilter; + bool trackerFilterEnabled; + QStringList trackerFilter; }; #endif // TRANSFERLISTSORTMODEL_H diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index 807fee7d3..1e0aede6c 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -938,6 +938,16 @@ void TransferListWidget::applyLabelFilter(QString label) nameFilterModel->setLabelFilter(label); } +void TransferListWidget::applyTrackerFilterAll() +{ + nameFilterModel->disableTrackerFilter(); +} + +void TransferListWidget::applyTrackerFilter(const QStringList &hashes) +{ + nameFilterModel->setTrackerFilter(hashes); +} + void TransferListWidget::applyNameFilter(const QString& name) { nameFilterModel->setFilterRegExp(QRegExp(QRegExp::escape(name), Qt::CaseInsensitive)); diff --git a/src/gui/transferlistwidget.h b/src/gui/transferlistwidget.h index 06c3fba8a..d8459a07b 100644 --- a/src/gui/transferlistwidget.h +++ b/src/gui/transferlistwidget.h @@ -84,6 +84,8 @@ public slots: void applyStatusFilter(int f); void applyLabelFilterAll(); void applyLabelFilter(QString label); + void applyTrackerFilterAll(); + void applyTrackerFilter(const QStringList &hashes); void previewFile(QString filePath); void removeLabelFromRows(QString label); void renameSelectedTorrent();