Browse Source

Implement tracker list in the side panel. Closes #170.

adaptive-webui-19844
sledgehammer999 10 years ago
parent
commit
f0d5ce4b98
  1. 4
      src/core/qtlibtorrent/qbtsession.cpp
  2. 1
      src/core/qtlibtorrent/qbtsession.h
  3. 5
      src/core/qtlibtorrent/torrentmodel.cpp
  4. 1
      src/core/qtlibtorrent/torrentmodel.h
  5. 3
      src/gui/mainwindow.cpp
  6. 2
      src/gui/properties/propertieswidget.cpp
  7. 4
      src/gui/properties/propertieswidget.h
  8. 12
      src/gui/properties/trackerlist.cpp
  9. 4
      src/gui/properties/trackerlist.h
  10. 267
      src/gui/transferlistfilterswidget.cpp
  11. 38
      src/gui/transferlistfilterswidget.h
  12. 32
      src/gui/transferlistsortmodel.cpp
  13. 8
      src/gui/transferlistsortmodel.h
  14. 10
      src/gui/transferlistwidget.cpp
  15. 2
      src/gui/transferlistwidget.h

4
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) void QBtSession::mergeTorrents(QTorrentHandle& h_ex, const QString& magnet_uri)
{ {
QString hash = h_ex.hash();
QList<QUrl> new_trackers = misc::magnetUriToTrackers(magnet_uri); QList<QUrl> new_trackers = misc::magnetUriToTrackers(magnet_uri);
bool trackers_added = false; bool trackers_added = false;
foreach (const QUrl& new_tracker, new_trackers) { foreach (const QUrl& new_tracker, new_trackers) {
@ -1293,6 +1294,7 @@ void QBtSession::mergeTorrents(QTorrentHandle& h_ex, const QString& magnet_uri)
if (!found) { if (!found) {
h_ex.add_tracker(announce_entry(new_tracker.toString().toStdString())); h_ex.add_tracker(announce_entry(new_tracker.toString().toStdString()));
trackers_added = true; trackers_added = true;
emit trackerAdded(new_tracker.toString(), hash);
} }
} }
if (trackers_added) 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<torrent_info> t) { void QBtSession::mergeTorrents(QTorrentHandle &h_ex, boost::intrusive_ptr<torrent_info> t) {
// Check if the torrent contains trackers or url seeds we don't know about // Check if the torrent contains trackers or url seeds we don't know about
// and add them // and add them
QString hash = h_ex.hash();
if (!h_ex.is_valid()) return; if (!h_ex.is_valid()) return;
std::vector<announce_entry> existing_trackers = h_ex.trackers(); std::vector<announce_entry> existing_trackers = h_ex.trackers();
std::vector<announce_entry> new_trackers = t->trackers(); std::vector<announce_entry> new_trackers = t->trackers();
@ -1320,6 +1323,7 @@ void QBtSession::mergeTorrents(QTorrentHandle &h_ex, boost::intrusive_ptr<torren
if (!found) { if (!found) {
h_ex.add_tracker(announce_entry(new_tracker_url)); h_ex.add_tracker(announce_entry(new_tracker_url));
trackers_added = true; trackers_added = true;
emit trackerAdded(new_tracker_url.c_str(), hash);
} }
} }

1
src/core/qtlibtorrent/qbtsession.h

@ -288,6 +288,7 @@ signals:
void metadataReceivedHidden(const QTorrentHandle &h); void metadataReceivedHidden(const QTorrentHandle &h);
void stateUpdate(const std::vector<libtorrent::torrent_status> &statuses); void stateUpdate(const std::vector<libtorrent::torrent_status> &statuses);
void statsReceived(const libtorrent::stats_alert&); void statsReceived(const libtorrent::stats_alert&);
void trackerAdded(const QString &tracker, const QString &hash);
private: private:
// Bittorrent // Bittorrent

5
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 // TORRENT MODEL
TorrentModel::TorrentModel(QObject *parent) : TorrentModel::TorrentModel(QObject *parent) :

1
src/core/qtlibtorrent/torrentmodel.h

@ -59,6 +59,7 @@ public:
bool setData(int column, const QVariant &value, int role = Qt::DisplayRole); bool setData(int column, const QVariant &value, int role = Qt::DisplayRole);
inline QString const& hash() const { return m_hash; } inline QString const& hash() const { return m_hash; }
State state() const; State state() const;
QTorrentHandle torrentHandle() const;
signals: signals:
void labelChanged(QString previous, QString current); void labelChanged(QString previous, QString current);

3
src/gui/mainwindow.cpp

@ -214,6 +214,9 @@ MainWindow::MainWindow(QWidget *parent)
connect(search_filter, SIGNAL(textChanged(QString)), transferList, SLOT(applyNameFilter(QString))); connect(search_filter, SIGNAL(textChanged(QString)), transferList, SLOT(applyNameFilter(QString)));
connect(hSplitter, SIGNAL(splitterMoved(int, int)), this, SLOT(writeSettings())); connect(hSplitter, SIGNAL(splitterMoved(int, int)), this, SLOT(writeSettings()));
connect(vSplitter, 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); vboxLayout->addWidget(tabs);

2
src/gui/properties/propertieswidget.cpp

@ -111,6 +111,8 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow* main_window, Tra
trackerList = new TrackerList(this); trackerList = new TrackerList(this);
connect(trackerUpButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionUp())); connect(trackerUpButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionUp()));
connect(trackerDownButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionDown())); 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); horizontalLayout_trackers->insertWidget(0, trackerList);
connect(trackerList->header(), SIGNAL(sectionMoved(int, int, int)), trackerList, SLOT(saveSettings())); connect(trackerList->header(), SIGNAL(sectionMoved(int, int, int)), trackerList, SLOT(saveSettings()));
connect(trackerList->header(), SIGNAL(sectionResized(int, int, int)), trackerList, SLOT(saveSettings())); connect(trackerList->header(), SIGNAL(sectionResized(int, int, int)), trackerList, SLOT(saveSettings()));

4
src/gui/properties/propertieswidget.h

@ -69,6 +69,10 @@ public:
PeerListWidget* getPeerList() const { return peersList; } PeerListWidget* getPeerList() const { return peersList; }
QTreeView* getFilesList() const { return filesList; } QTreeView* getFilesList() const { return filesList; }
signals:
void trackerAdded(const QString &tracker, const QString &hash);
void trackerRemoved(const QString &tracker, const QString &hash);
protected: protected:
QPushButton* getButtonFromIndex(int index); QPushButton* getButtonFromIndex(int index);
bool applyPriorities(); bool applyPriorities();

12
src/gui/properties/trackerlist.cpp

@ -300,14 +300,19 @@ void TrackerList::loadTrackers() {
void TrackerList::askForTrackers() { void TrackerList::askForTrackers() {
QTorrentHandle h = properties->getCurrentTorrent(); QTorrentHandle h = properties->getCurrentTorrent();
if (!h.is_valid()) return; if (!h.is_valid()) return;
QString hash = h.hash();
QStringList trackers = TrackersAdditionDlg::askForTrackers(h); QStringList trackers = TrackersAdditionDlg::askForTrackers(h);
if (!trackers.empty()) { if (!trackers.empty()) {
if (h.trackers().empty())
emit trackerRemoved("", hash);
for (int i=0; i<trackers.count(); i++) { for (int i=0; i<trackers.count(); i++) {
const QString& tracker = trackers[i]; const QString& tracker = trackers[i];
if (tracker.trimmed().isEmpty()) continue; if (tracker.trimmed().isEmpty()) continue;
announce_entry url(tracker.toStdString()); announce_entry url(tracker.toStdString());
url.tier = (topLevelItemCount() - NB_STICKY_ITEM) + i; url.tier = (topLevelItemCount() - NB_STICKY_ITEM) + i;
h.add_tracker(url); h.add_tracker(url);
emit trackerAdded(tracker, hash);
} }
// Reannounce to new trackers // Reannounce to new trackers
if (!h.is_paused()) if (!h.is_paused())
@ -336,6 +341,7 @@ void TrackerList::deleteSelectedTrackers() {
clear(); clear();
return; return;
} }
QString hash = h.hash();
QList<QTreeWidgetItem *> selected_items = getSelectedTrackerItems(); QList<QTreeWidgetItem *> selected_items = getSelectedTrackerItems();
if (selected_items.isEmpty()) return; if (selected_items.isEmpty()) return;
QStringList urls_to_remove; QStringList urls_to_remove;
@ -344,6 +350,7 @@ void TrackerList::deleteSelectedTrackers() {
urls_to_remove << tracker_url; urls_to_remove << tracker_url;
tracker_items.remove(tracker_url); tracker_items.remove(tracker_url);
delete item; delete item;
emit trackerRemoved(tracker_url, hash);
} }
// Iterate of trackers and remove selected ones // Iterate of trackers and remove selected ones
std::vector<announce_entry> remaining_trackers; std::vector<announce_entry> remaining_trackers;
@ -357,6 +364,8 @@ void TrackerList::deleteSelectedTrackers() {
} }
} }
h.replace_trackers(remaining_trackers); h.replace_trackers(remaining_trackers);
if (remaining_trackers.empty())
emit trackerAdded("", hash);
if (!h.is_paused()) if (!h.is_paused())
h.force_reannounce(); h.force_reannounce();
// Reload Trackers // Reload Trackers
@ -366,6 +375,7 @@ void TrackerList::deleteSelectedTrackers() {
void TrackerList::editSelectedTracker() { void TrackerList::editSelectedTracker() {
try { try {
QTorrentHandle h = properties->getCurrentTorrent(); QTorrentHandle h = properties->getCurrentTorrent();
QString hash = h.hash();
QList<QTreeWidgetItem *> selected_items = getSelectedTrackerItems(); QList<QTreeWidgetItem *> selected_items = getSelectedTrackerItems();
if (selected_items.isEmpty()) if (selected_items.isEmpty())
@ -402,6 +412,8 @@ void TrackerList::editSelectedTracker() {
new_entry.tier = it->tier; new_entry.tier = it->tier;
match = true; match = true;
*it = new_entry; *it = new_entry;
emit trackerRemoved(tracker_url.toString(), hash);
emit trackerAdded(new_tracker_url.toString(), hash);
} }
} }

4
src/gui/properties/trackerlist.h

@ -60,6 +60,10 @@ public:
TrackerList(PropertiesWidget *properties); TrackerList(PropertiesWidget *properties);
~TrackerList(); ~TrackerList();
signals:
void trackerAdded(const QString &tracker, const QString &hash);
void trackerRemoved(const QString &tracker, const QString &hash);
protected: protected:
QList<QTreeWidgetItem*> getSelectedTrackerItems() const; QList<QTreeWidgetItem*> getSelectedTrackerItems() const;

267
src/gui/transferlistfilterswidget.cpp

@ -47,6 +47,9 @@
#include "fs_utils.h" #include "fs_utils.h"
#include "autoexpandabledialog.h" #include "autoexpandabledialog.h"
#include "torrentfilterenum.h" #include "torrentfilterenum.h"
#include "misc.h"
#include "downloadthread.h"
#include "logger.h"
LabelFiltersList::LabelFiltersList(QWidget *parent): QListWidget(parent) LabelFiltersList::LabelFiltersList(QWidget *parent): QListWidget(parent)
{ {
@ -167,6 +170,215 @@ QSize StatusFiltersWidget::sizeHint() const
return size; 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; i<count(); ++i) {
bool less = false;
if (!(misc::naturalSort(host, item(i)->text(), 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<libtorrent::announce_entry> trackers = handle.trackers();
for (std::vector<libtorrent::announce_entry>::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<libtorrent::announce_entry> trackers = handle.trackers();
for (std::vector<libtorrent::announce_entry>::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; i<count(); ++i)
if (tracker == trackerFromRow(i)) return i;
return -1;
}
QString TrackerFiltersList::getHost(const QString &trakcer) const
{
QUrl url(trakcer);
QString longHost = url.host();
QString tld = url.topLevelDomain();
// We want the domain + tld. Subdomains should be disregarded
int index = longHost.lastIndexOf('.', -(tld.size() + 1));
if (index == -1)
return longHost;
return longHost.mid(index + 1);
}
TransferListFiltersWidget::TransferListFiltersWidget(QWidget *parent, TransferListWidget *transferList): QFrame(parent), transferList(transferList), nb_labeled(0), nb_torrents(0) TransferListFiltersWidget::TransferListFiltersWidget(QWidget *parent, TransferListWidget *transferList): QFrame(parent), transferList(transferList), nb_labeled(0), nb_torrents(0)
{ {
// Construct lists // Construct lists
@ -187,8 +399,15 @@ TransferListFiltersWidget::TransferListFiltersWidget(QWidget *parent, TransferLi
vLayout->addWidget(labelsLabel); vLayout->addWidget(labelsLabel);
labelFilters = new LabelFiltersList(this); labelFilters = new LabelFiltersList(this);
vLayout->addWidget(labelFilters); 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); setLayout(vLayout);
labelFilters->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); labelFilters->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
trackerFilters->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
statusFilters->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); statusFilters->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
statusFilters->setSpacing(0); statusFilters->setSpacing(0);
setContentsMargins(0,0,0,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(transferList->getSourceModel(), SIGNAL(torrentAdded(TorrentModelItem*)), SLOT(handleNewTorrent(TorrentModelItem*)));
connect(labelFilters, SIGNAL(currentRowChanged(int)), this, SLOT(applyLabelFilter(int))); connect(labelFilters, SIGNAL(currentRowChanged(int)), this, SLOT(applyLabelFilter(int)));
connect(labelFilters, SIGNAL(torrentDropped(int)), this, SLOT(torrentDropped(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(torrentAboutToBeRemoved(TorrentModelItem*)), SLOT(torrentAboutToBeDeleted(TorrentModelItem*)));
connect(transferList->getSourceModel(), SIGNAL(torrentChangedLabel(TorrentModelItem*,QString,QString)), SLOT(torrentChangedLabel(TorrentModelItem*, QString, QString))); connect(transferList->getSourceModel(), SIGNAL(torrentChangedLabel(TorrentModelItem*,QString,QString)), SLOT(torrentChangedLabel(TorrentModelItem*, QString, QString)));
@ -237,11 +457,16 @@ TransferListFiltersWidget::TransferListFiltersWidget(QWidget *parent, TransferLi
loadSettings(); loadSettings();
labelFilters->setCurrentRow(0); labelFilters->setCurrentRow(0);
trackerFilters->setCurrentRow(0);
//labelFilters->selectionModel()->select(labelFilters->model()->index(0,0), QItemSelectionModel::Select); //labelFilters->selectionModel()->select(labelFilters->model()->index(0,0), QItemSelectionModel::Select);
// Label menu // Label menu
labelFilters->setContextMenuPolicy(Qt::CustomContextMenu); labelFilters->setContextMenuPolicy(Qt::CustomContextMenu);
connect(labelFilters, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showLabelMenu(QPoint))); 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() TransferListFiltersWidget::~TransferListFiltersWidget()
@ -249,6 +474,7 @@ TransferListFiltersWidget::~TransferListFiltersWidget()
saveSettings(); saveSettings();
delete statusFilters; delete statusFilters;
delete labelFilters; delete labelFilters;
delete trackerFilters;
delete vLayout; delete vLayout;
} }
@ -311,6 +537,16 @@ void TransferListFiltersWidget::addLabel(QString& label)
Preferences::instance()->addTorrentLabel(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) void TransferListFiltersWidget::showLabelMenu(QPoint)
{ {
QMenu labelMenu(labelFilters); 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() void TransferListFiltersWidget::removeSelectedLabel()
{ {
const int row = labelFilters->row(labelFilters->selectedItems().first()); 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) void TransferListFiltersWidget::torrentChangedLabel(TorrentModelItem *torrentItem, QString old_label, QString new_label)
{ {
Q_UNUSED(torrentItem); Q_UNUSED(torrentItem);
@ -471,6 +734,8 @@ void TransferListFiltersWidget::handleNewTorrent(TorrentModelItem* torrentItem)
Q_ASSERT(nb_labeled >= 0); Q_ASSERT(nb_labeled >= 0);
Q_ASSERT(nb_labeled <= nb_torrents); Q_ASSERT(nb_labeled <= nb_torrents);
updateStickyLabelCounters(); updateStickyLabelCounters();
trackerFilters->addItem(torrentItem->torrentHandle());
trackerFilters->setTorrentCount(nb_torrents);
} }
void TransferListFiltersWidget::torrentAboutToBeDeleted(TorrentModelItem* torrentItem) void TransferListFiltersWidget::torrentAboutToBeDeleted(TorrentModelItem* torrentItem)
@ -492,6 +757,8 @@ void TransferListFiltersWidget::torrentAboutToBeDeleted(TorrentModelItem* torren
Q_ASSERT(nb_labeled >= 0); Q_ASSERT(nb_labeled >= 0);
Q_ASSERT(nb_labeled <= nb_torrents); Q_ASSERT(nb_labeled <= nb_torrents);
updateStickyLabelCounters(); updateStickyLabelCounters();
trackerFilters->removeItem(torrentItem->torrentHandle());
trackerFilters->setTorrentCount(nb_torrents);
} }
void TransferListFiltersWidget::updateStickyLabelCounters() void TransferListFiltersWidget::updateStickyLabelCounters()

38
src/gui/transferlistfilterswidget.h

@ -42,6 +42,8 @@ QT_END_NAMESPACE
class TransferListWidget; class TransferListWidget;
class TorrentModelItem; class TorrentModelItem;
class QTorrentHandle;
class DownloadThread;
class LabelFiltersList: public QListWidget class LabelFiltersList: public QListWidget
{ {
@ -83,6 +85,35 @@ private:
bool m_shown; 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<QString, QStringList> 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 class TransferListFiltersWidget: public QFrame
{ {
Q_OBJECT Q_OBJECT
@ -91,6 +122,7 @@ private:
QHash<QString, int> customLabels; QHash<QString, int> customLabels;
StatusFiltersWidget* statusFilters; StatusFiltersWidget* statusFilters;
LabelFiltersList* labelFilters; LabelFiltersList* labelFilters;
TrackerFiltersList* trackerFilters;
QVBoxLayout* vLayout; QVBoxLayout* vLayout;
TransferListWidget *transferList; TransferListWidget *transferList;
int nb_labeled; int nb_labeled;
@ -105,14 +137,20 @@ public:
void saveSettings() const; void saveSettings() const;
void loadSettings(); void loadSettings();
public slots:
void addTracker(const QString &tracker, const QString &hash);
void removeTracker(const QString &tracker, const QString &hash);
protected slots: protected slots:
void updateTorrentNumbers(); void updateTorrentNumbers();
void torrentDropped(int row); void torrentDropped(int row);
void addLabel(QString& label); void addLabel(QString& label);
void showLabelMenu(QPoint); void showLabelMenu(QPoint);
void showTrackerMenu(QPoint);
void removeSelectedLabel(); void removeSelectedLabel();
void removeUnusedLabels(); void removeUnusedLabels();
void applyLabelFilter(int row); void applyLabelFilter(int row);
void applyTrackerFilter(int row);
void torrentChangedLabel(TorrentModelItem *torrentItem, QString old_label, QString new_label); void torrentChangedLabel(TorrentModelItem *torrentItem, QString old_label, QString new_label);
void handleNewTorrent(TorrentModelItem* torrentItem); void handleNewTorrent(TorrentModelItem* torrentItem);
void torrentAboutToBeDeleted(TorrentModelItem* torrentItem); void torrentAboutToBeDeleted(TorrentModelItem* torrentItem);

32
src/gui/transferlistsortmodel.cpp

@ -36,6 +36,8 @@
TransferListSortModel::TransferListSortModel(QObject *parent) TransferListSortModel::TransferListSortModel(QObject *parent)
: QSortFilterProxyModel(parent) : QSortFilterProxyModel(parent)
, filter0(TorrentFilter::ALL) , filter0(TorrentFilter::ALL)
, labelFilterEnabled(false)
, trackerFilterEnabled(false)
{} {}
void TransferListSortModel::setStatusFilter(const TorrentFilter::TorrentFilter &filter) { 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) { if (!labelFilterEnabled || labelFilter != label) {
labelFilterEnabled = true; labelFilterEnabled = true;
labelFilter = label; 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 { bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const {
const int column = sortColumn(); 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 { bool TransferListSortModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
return matchStatusFilter(sourceRow, sourceParent) return matchStatusFilter(sourceRow, sourceParent)
&& matchLabelFilter(sourceRow, sourceParent) && matchLabelFilter(sourceRow, sourceParent)
&& matchTrackerFilter(sourceRow, sourceParent)
&& QSortFilterProxyModel::filterAcceptsRow(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; 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<TorrentModel *>(sourceModel());
if (!model)
return false;
return trackerFilter.contains(model->torrentHash(sourceRow));
}

8
src/gui/transferlistsortmodel.h

@ -32,6 +32,7 @@
#define TRANSFERLISTSORTMODEL_H #define TRANSFERLISTSORTMODEL_H
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QStringList>
#include "torrentfilterenum.h" #include "torrentfilterenum.h"
class TransferListSortModel : public QSortFilterProxyModel { class TransferListSortModel : public QSortFilterProxyModel {
@ -41,8 +42,10 @@ public:
TransferListSortModel(QObject *parent = 0); TransferListSortModel(QObject *parent = 0);
void setStatusFilter(const TorrentFilter::TorrentFilter &filter); void setStatusFilter(const TorrentFilter::TorrentFilter &filter);
void setLabelFilter(QString const& label); void setLabelFilter(const QString &label);
void disableLabelFilter(); void disableLabelFilter();
void setTrackerFilter(const QStringList &hashes);
void disableTrackerFilter();
private: private:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const; bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
@ -50,12 +53,15 @@ private:
bool matchStatusFilter(int sourceRow, const QModelIndex &sourceParent) const; bool matchStatusFilter(int sourceRow, const QModelIndex &sourceParent) const;
bool matchLabelFilter(int sourceRow, const QModelIndex &sourceParent) const; bool matchLabelFilter(int sourceRow, const QModelIndex &sourceParent) const;
bool matchTrackerFilter(int sourceRow, const QModelIndex &sourceParent) const;
private: private:
TorrentFilter::TorrentFilter filter0; TorrentFilter::TorrentFilter filter0;
bool labelFilterEnabled; bool labelFilterEnabled;
QString labelFilter; QString labelFilter;
bool trackerFilterEnabled;
QStringList trackerFilter;
}; };
#endif // TRANSFERLISTSORTMODEL_H #endif // TRANSFERLISTSORTMODEL_H

10
src/gui/transferlistwidget.cpp

@ -938,6 +938,16 @@ void TransferListWidget::applyLabelFilter(QString label)
nameFilterModel->setLabelFilter(label); nameFilterModel->setLabelFilter(label);
} }
void TransferListWidget::applyTrackerFilterAll()
{
nameFilterModel->disableTrackerFilter();
}
void TransferListWidget::applyTrackerFilter(const QStringList &hashes)
{
nameFilterModel->setTrackerFilter(hashes);
}
void TransferListWidget::applyNameFilter(const QString& name) void TransferListWidget::applyNameFilter(const QString& name)
{ {
nameFilterModel->setFilterRegExp(QRegExp(QRegExp::escape(name), Qt::CaseInsensitive)); nameFilterModel->setFilterRegExp(QRegExp(QRegExp::escape(name), Qt::CaseInsensitive));

2
src/gui/transferlistwidget.h

@ -84,6 +84,8 @@ public slots:
void applyStatusFilter(int f); void applyStatusFilter(int f);
void applyLabelFilterAll(); void applyLabelFilterAll();
void applyLabelFilter(QString label); void applyLabelFilter(QString label);
void applyTrackerFilterAll();
void applyTrackerFilter(const QStringList &hashes);
void previewFile(QString filePath); void previewFile(QString filePath);
void removeLabelFromRows(QString label); void removeLabelFromRows(QString label);
void renameSelectedTorrent(); void renameSelectedTorrent();

Loading…
Cancel
Save