Merge pull request #11120 from Chocobo1/peerwidget

Clean up PeerListWidget class
This commit is contained in:
Mike Tzou 2019-08-28 12:04:12 +08:00 committed by GitHub
commit 4a0f5a0c15
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 92 additions and 138 deletions

View file

@ -119,7 +119,7 @@ namespace Net
static DownloadManager *instance(); static DownloadManager *instance();
template <typename Context, typename Func> template <typename Context, typename Func>
void download(const DownloadRequest &downloadRequest, Context context, Func slot); void download(const DownloadRequest &downloadRequest, Context context, Func &&slot);
void registerSequentialService(const ServiceID &serviceID); void registerSequentialService(const ServiceID &serviceID);
@ -150,7 +150,7 @@ namespace Net
}; };
template <typename Context, typename Func> template <typename Context, typename Func>
void DownloadManager::download(const DownloadRequest &downloadRequest, Context context, Func slot) void DownloadManager::download(const DownloadRequest &downloadRequest, Context context, Func &&slot)
{ {
const DownloadHandler *handler = download(downloadRequest); const DownloadHandler *handler = download(downloadRequest);
connect(handler, &DownloadHandler::finished, context, slot); connect(handler, &DownloadHandler::finished, context, slot);

View file

@ -44,6 +44,7 @@
#include "base/bittorrent/peerinfo.h" #include "base/bittorrent/peerinfo.h"
#include "base/bittorrent/session.h" #include "base/bittorrent/session.h"
#include "base/bittorrent/torrenthandle.h" #include "base/bittorrent/torrenthandle.h"
#include "base/global.h"
#include "base/logger.h" #include "base/logger.h"
#include "base/net/geoipmanager.h" #include "base/net/geoipmanager.h"
#include "base/net/reverseresolution.h" #include "base/net/reverseresolution.h"
@ -114,15 +115,15 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent)
// To also mitigate the above issue, we have to resize each column when // To also mitigate the above issue, we have to resize each column when
// its size is 0, because explicitly 'showing' the column isn't enough // its size is 0, because explicitly 'showing' the column isn't enough
// in the above scenario. // in the above scenario.
for (int i = 0; i < PeerListDelegate::IP_HIDDEN; ++i) for (int i = 0; i < PeerListDelegate::IP_HIDDEN; ++i) {
if ((columnWidth(i) <= 0) && !isColumnHidden(i)) if ((columnWidth(i) <= 0) && !isColumnHidden(i))
resizeColumnToContents(i); resizeColumnToContents(i);
}
// Context menu // Context menu
setContextMenuPolicy(Qt::CustomContextMenu); setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, &QWidget::customContextMenuRequested, this, &PeerListWidget::showPeerListMenu); connect(this, &QWidget::customContextMenuRequested, this, &PeerListWidget::showPeerListMenu);
// List delegate // List delegate
m_listDelegate = new PeerListDelegate(this); setItemDelegate(new PeerListDelegate(this));
setItemDelegate(m_listDelegate);
// Enable sorting // Enable sorting
setSortingEnabled(true); setSortingEnabled(true);
// IP to Hostname resolver // IP to Hostname resolver
@ -149,8 +150,6 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent)
PeerListWidget::~PeerListWidget() PeerListWidget::~PeerListWidget()
{ {
saveSettings(); saveSettings();
if (m_resolver)
delete m_resolver;
} }
void PeerListWidget::displayToggleColumnsMenu(const QPoint &) void PeerListWidget::displayToggleColumnsMenu(const QPoint &)
@ -201,28 +200,31 @@ void PeerListWidget::updatePeerHostNameResolutionState()
if (Preferences::instance()->resolvePeerHostNames()) { if (Preferences::instance()->resolvePeerHostNames()) {
if (!m_resolver) { if (!m_resolver) {
m_resolver = new Net::ReverseResolution(this); m_resolver = new Net::ReverseResolution(this);
connect(m_resolver.data(), &Net::ReverseResolution::ipResolved, this, &PeerListWidget::handleResolved); connect(m_resolver, &Net::ReverseResolution::ipResolved, this, &PeerListWidget::handleResolved);
loadPeers(m_properties->getCurrentTorrent(), true); loadPeers(m_properties->getCurrentTorrent());
} }
} }
else if (m_resolver) { else {
delete m_resolver; delete m_resolver;
m_resolver = nullptr;
} }
} }
void PeerListWidget::updatePeerCountryResolutionState() void PeerListWidget::updatePeerCountryResolutionState()
{ {
if (Preferences::instance()->resolvePeerCountries() != m_resolveCountries) { const bool resolveCountries = Preferences::instance()->resolvePeerCountries();
m_resolveCountries = !m_resolveCountries; if (resolveCountries == m_resolveCountries)
if (m_resolveCountries) { return;
loadPeers(m_properties->getCurrentTorrent());
showColumn(PeerListDelegate::COUNTRY); m_resolveCountries = resolveCountries;
if (columnWidth(PeerListDelegate::COUNTRY) <= 0) if (m_resolveCountries) {
resizeColumnToContents(PeerListDelegate::COUNTRY); loadPeers(m_properties->getCurrentTorrent());
} showColumn(PeerListDelegate::COUNTRY);
else { if (columnWidth(PeerListDelegate::COUNTRY) <= 0)
hideColumn(PeerListDelegate::COUNTRY); resizeColumnToContents(PeerListDelegate::COUNTRY);
} }
else {
hideColumn(PeerListDelegate::COUNTRY);
} }
} }
@ -243,17 +245,17 @@ void PeerListWidget::showPeerListMenu(const QPoint &)
int peerCount = 0; int peerCount = 0;
for (const BitTorrent::PeerAddress &addr : peersList) { for (const BitTorrent::PeerAddress &addr : peersList) {
if (torrent->connectPeer(addr)) { if (torrent->connectPeer(addr)) {
Logger::instance()->addMessage(tr("Manually adding peer '%1'...").arg(addr.ip.toString()));
++peerCount; ++peerCount;
LogMsg(tr("Peer \"%1\" added to \"%2\"").arg(addr.ip.toString(), torrent->name()));
} }
else { else {
Logger::instance()->addMessage(tr("The peer '%1' could not be added to this torrent.").arg(addr.ip.toString()), Log::WARNING); LogMsg(tr("Failed to add peer \"%1\" to \"%2\".").arg(addr.ip.toString(), torrent->name()), Log::WARNING);
} }
} }
if (peerCount < peersList.length()) if (peerCount < peersList.length())
QMessageBox::information(this, tr("Peer addition"), tr("Some peers could not be added. Check the Log for details.")); QMessageBox::information(this, tr("Adding peers"), tr("Some peers cannot be added. Check the Log for details."));
else if (peerCount > 0) else if (peerCount > 0)
QMessageBox::information(this, tr("Peer addition"), tr("The peers were added to this torrent.")); QMessageBox::information(this, tr("Adding peers"), tr("Peers are added to this torrent."));
}); });
} }
@ -276,18 +278,16 @@ void PeerListWidget::showPeerListMenu(const QPoint &)
void PeerListWidget::banSelectedPeers() void PeerListWidget::banSelectedPeers()
{ {
// Confirm first // Confirm first
int ret = QMessageBox::question(this, tr("Ban peer permanently"), tr("Are you sure you want to permanently ban the selected peers?"), const QMessageBox::StandardButton btn = QMessageBox::question(this, tr("Ban peer permanently")
tr("&Yes"), tr("&No"), , tr("Are you sure you want to permanently ban the selected peers?"));
QString(), 0, 1); if (btn != QMessageBox::Yes) return;
if (ret) return;
const QModelIndexList selectedIndexes = selectionModel()->selectedRows(); const QModelIndexList selectedIndexes = selectionModel()->selectedRows();
for (const QModelIndex &index : selectedIndexes) { for (const QModelIndex &index : selectedIndexes) {
int row = m_proxyModel->mapToSource(index).row(); const int row = m_proxyModel->mapToSource(index).row();
QString ip = m_listModel->data(m_listModel->index(row, PeerListDelegate::IP_HIDDEN)).toString(); const QString ip = m_listModel->item(row, PeerListDelegate::IP_HIDDEN)->text();
qDebug("Banning peer %s...", ip.toLocal8Bit().data());
Logger::instance()->addMessage(tr("Manually banning peer '%1'...").arg(ip));
BitTorrent::Session::instance()->banIP(ip); BitTorrent::Session::instance()->banIP(ip);
LogMsg(tr("Peer \"%1\" is manually banned").arg(ip));
} }
// Refresh list // Refresh list
loadPeers(m_properties->getCurrentTorrent()); loadPeers(m_properties->getCurrentTorrent());
@ -297,29 +297,27 @@ void PeerListWidget::copySelectedPeers()
{ {
const QModelIndexList selectedIndexes = selectionModel()->selectedRows(); const QModelIndexList selectedIndexes = selectionModel()->selectedRows();
QStringList selectedPeers; QStringList selectedPeers;
for (const QModelIndex &index : selectedIndexes) { for (const QModelIndex &index : selectedIndexes) {
int row = m_proxyModel->mapToSource(index).row(); const int row = m_proxyModel->mapToSource(index).row();
QString ip = m_listModel->data(m_listModel->index(row, PeerListDelegate::IP_HIDDEN)).toString(); const QString ip = m_listModel->item(row, PeerListDelegate::IP_HIDDEN)->text();
QString myport = m_listModel->data(m_listModel->index(row, PeerListDelegate::PORT)).toString(); const QString port = m_listModel->item(row, PeerListDelegate::PORT)->text();
if (!ip.contains('.')) // IPv6
selectedPeers << '[' + ip + "]:" + myport; if (!ip.contains('.')) // IPv6
else // IPv4 selectedPeers << ('[' + ip + "]:" + port);
selectedPeers << ip + ':' + myport; else // IPv4
selectedPeers << (ip + ':' + port);
} }
QApplication::clipboard()->setText(selectedPeers.join('\n')); QApplication::clipboard()->setText(selectedPeers.join('\n'));
} }
void PeerListWidget::clear() void PeerListWidget::clear()
{ {
qDebug("clearing peer list");
m_peerItems.clear(); m_peerItems.clear();
m_peerAddresses.clear(); const int nbrows = m_listModel->rowCount();
m_missingFlags.clear(); if (nbrows > 0)
int nbrows = m_listModel->rowCount();
if (nbrows > 0) {
qDebug("Cleared %d peers", nbrows);
m_listModel->removeRows(0, nbrows); m_listModel->removeRows(0, nbrows);
}
} }
void PeerListWidget::loadSettings() void PeerListWidget::loadSettings()
@ -332,63 +330,50 @@ void PeerListWidget::saveSettings() const
Preferences::instance()->setPeerListState(header()->saveState()); Preferences::instance()->setPeerListState(header()->saveState());
} }
void PeerListWidget::loadPeers(BitTorrent::TorrentHandle *const torrent, bool forceHostnameResolution) void PeerListWidget::loadPeers(const BitTorrent::TorrentHandle *torrent)
{ {
if (!torrent) return; if (!torrent) return;
const QVector<BitTorrent::PeerInfo> peers = torrent->peers(); const QVector<BitTorrent::PeerInfo> peers = torrent->peers();
QSet<QString> oldPeersSet = m_peerItems.keys().toSet(); QSet<QString> existingPeers;
for (auto i = m_peerItems.cbegin(); i != m_peerItems.cend(); ++i)
existingPeers << i.key();
for (const BitTorrent::PeerInfo &peer : peers) { for (const BitTorrent::PeerInfo &peer : peers) {
BitTorrent::PeerAddress addr = peer.address(); const BitTorrent::PeerAddress addr = peer.address();
if (addr.ip.isNull()) continue; if (addr.ip.isNull()) continue;
QString peerIp = addr.ip.toString(); const QString peerIp = addr.ip.toString();
if (m_peerItems.contains(peerIp)) { bool isNewPeer = false;
// Update existing peer updatePeer(peerIp, torrent, peer, isNewPeer);
updatePeer(peerIp, torrent, peer); if (!isNewPeer)
oldPeersSet.remove(peerIp); existingPeers.remove(peerIp);
if (forceHostnameResolution && m_resolver)
m_resolver->resolve(peerIp);
}
else {
// Add new peer
m_peerItems[peerIp] = addPeer(peerIp, torrent, peer);
m_peerAddresses[peerIp] = addr;
// Resolve peer host name is asked
if (m_resolver)
m_resolver->resolve(peerIp);
}
} }
// Delete peers that are gone
for (const QString &ip : oldPeersSet) { // Remove peers that are gone
m_missingFlags.remove(ip); for (const QString &ip : asConst(existingPeers)) {
m_peerAddresses.remove(ip); const QStandardItem *item = m_peerItems.take(ip);
QStandardItem *item = m_peerItems.take(ip);
m_listModel->removeRow(item->row()); m_listModel->removeRow(item->row());
} }
} }
QStandardItem *PeerListWidget::addPeer(const QString &ip, BitTorrent::TorrentHandle *const torrent, const BitTorrent::PeerInfo &peer) void PeerListWidget::updatePeer(const QString &ip, const BitTorrent::TorrentHandle *torrent, const BitTorrent::PeerInfo &peer, bool &isNewPeer)
{ {
int row = m_listModel->rowCount(); auto itemIter = m_peerItems.find(ip);
// Adding Peer to peer list isNewPeer = (itemIter == m_peerItems.end());
m_listModel->insertRow(row); if (isNewPeer) {
m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP), ip); // new item
m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP), ip, Qt::ToolTipRole); const int row = m_listModel->rowCount();
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PORT), peer.address().port); m_listModel->insertRow(row);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP_HIDDEN), ip); m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP), ip);
if (m_resolveCountries) { m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP), ip, Qt::ToolTipRole);
const QIcon ico = UIThemeManager::instance()->getFlagIcon(peer.country()); m_listModel->setData(m_listModel->index(row, PeerListDelegate::PORT), peer.address().port);
if (!ico.isNull()) { m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP_HIDDEN), ip);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), ico, Qt::DecorationRole);
const QString countryName = Net::GeoIPManager::CountryName(peer.country()); itemIter = m_peerItems.insert(ip, m_listModel->item(row, PeerListDelegate::IP));
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), countryName, Qt::ToolTipRole);
}
else {
m_missingFlags.insert(ip);
}
} }
const int row = (*itemIter)->row();
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CONNECTION), peer.connectionType()); m_listModel->setData(m_listModel->index(row, PeerListDelegate::CONNECTION), peer.connectionType());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flags()); m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flags());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flagsDescription(), Qt::ToolTipRole); m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flagsDescription(), Qt::ToolTipRole);
@ -399,60 +384,37 @@ QStandardItem *PeerListWidget::addPeer(const QString &ip, BitTorrent::TorrentHan
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_DOWN), peer.totalDownload()); m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_DOWN), peer.totalDownload());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_UP), peer.totalUpload()); m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_UP), peer.totalUpload());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::RELEVANCE), peer.relevance()); m_listModel->setData(m_listModel->index(row, PeerListDelegate::RELEVANCE), peer.relevance());
QStringList downloadingFiles(torrent->info().filesForPiece(peer.downloadingPieceIndex()));
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWNLOADING_PIECE), downloadingFiles.join(QLatin1Char(';')));
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWNLOADING_PIECE), downloadingFiles.join(QLatin1Char('\n')), Qt::ToolTipRole);
return m_listModel->item(row, PeerListDelegate::IP); const QStringList downloadingFiles {torrent->info().filesForPiece(peer.downloadingPieceIndex())};
} m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWNLOADING_PIECE), downloadingFiles.join(';'));
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWNLOADING_PIECE), downloadingFiles.join('\n'), Qt::ToolTipRole);
if (m_resolver)
m_resolver->resolve(ip);
void PeerListWidget::updatePeer(const QString &ip, BitTorrent::TorrentHandle *const torrent, const BitTorrent::PeerInfo &peer)
{
QStandardItem *item = m_peerItems.value(ip);
int row = item->row();
if (m_resolveCountries) { if (m_resolveCountries) {
const QIcon ico = UIThemeManager::instance()->getFlagIcon(peer.country()); const QIcon icon = UIThemeManager::instance()->getFlagIcon(peer.country());
if (!ico.isNull()) { if (!icon.isNull()) {
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), ico, Qt::DecorationRole); m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), icon, Qt::DecorationRole);
const QString countryName = Net::GeoIPManager::CountryName(peer.country()); const QString countryName = Net::GeoIPManager::CountryName(peer.country());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), countryName, Qt::ToolTipRole); m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), countryName, Qt::ToolTipRole);
m_missingFlags.remove(ip);
} }
} }
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CONNECTION), peer.connectionType());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PORT), peer.address().port);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flags());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flagsDescription(), Qt::ToolTipRole);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), peer.client().toHtmlEscaped());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payloadDownSpeed());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payloadUpSpeed());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_DOWN), peer.totalDownload());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_UP), peer.totalUpload());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::RELEVANCE), peer.relevance());
QStringList downloadingFiles(torrent->info().filesForPiece(peer.downloadingPieceIndex()));
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWNLOADING_PIECE), downloadingFiles.join(QLatin1String(";")));
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWNLOADING_PIECE), downloadingFiles.join(QLatin1String("\n")), Qt::ToolTipRole);
} }
void PeerListWidget::handleResolved(const QString &ip, const QString &hostname) void PeerListWidget::handleResolved(const QString &ip, const QString &hostname)
{ {
QStandardItem *item = m_peerItems.value(ip, nullptr); QStandardItem *item = m_peerItems.value(ip, nullptr);
if (item) { if (item)
qDebug("Resolved %s -> %s", qUtf8Printable(ip), qUtf8Printable(hostname));
item->setData(hostname, Qt::DisplayRole); item->setData(hostname, Qt::DisplayRole);
}
} }
void PeerListWidget::handleSortColumnChanged(int col) void PeerListWidget::handleSortColumnChanged(const int col)
{ {
if (col == PeerListDelegate::COUNTRY) { if (col == PeerListDelegate::COUNTRY)
qDebug("Sorting by decoration");
m_proxyModel->setSortRole(Qt::ToolTipRole); m_proxyModel->setSortRole(Qt::ToolTipRole);
} else
else {
m_proxyModel->setSortRole(Qt::DisplayRole); m_proxyModel->setSortRole(Qt::DisplayRole);
}
} }
void PeerListWidget::wheelEvent(QWheelEvent *event) void PeerListWidget::wheelEvent(QWheelEvent *event)

View file

@ -30,15 +30,11 @@
#define PEERLISTWIDGET_H #define PEERLISTWIDGET_H
#include <QHash> #include <QHash>
#include <QPointer>
#include <QSet>
#include <QTreeView> #include <QTreeView>
class QSortFilterProxyModel;
class QStandardItem; class QStandardItem;
class QStandardItemModel; class QStandardItemModel;
class PeerListDelegate;
class PeerListSortModel; class PeerListSortModel;
class PropertiesWidget; class PropertiesWidget;
@ -46,7 +42,6 @@ namespace BitTorrent
{ {
class TorrentHandle; class TorrentHandle;
class PeerInfo; class PeerInfo;
struct PeerAddress;
} }
namespace Net namespace Net
@ -62,9 +57,7 @@ public:
explicit PeerListWidget(PropertiesWidget *parent); explicit PeerListWidget(PropertiesWidget *parent);
~PeerListWidget() override; ~PeerListWidget() override;
void loadPeers(BitTorrent::TorrentHandle *const torrent, bool forceHostnameResolution = false); void loadPeers(const BitTorrent::TorrentHandle *torrent);
QStandardItem *addPeer(const QString &ip, BitTorrent::TorrentHandle *const torrent, const BitTorrent::PeerInfo &peer);
void updatePeer(const QString &ip, BitTorrent::TorrentHandle *const torrent, const BitTorrent::PeerInfo &peer);
void updatePeerHostNameResolutionState(); void updatePeerHostNameResolutionState();
void updatePeerCountryResolutionState(); void updatePeerCountryResolutionState();
void clear(); void clear();
@ -80,16 +73,15 @@ private slots:
void handleResolved(const QString &ip, const QString &hostname); void handleResolved(const QString &ip, const QString &hostname);
private: private:
void updatePeer(const QString &ip, const BitTorrent::TorrentHandle *torrent, const BitTorrent::PeerInfo &peer, bool &isNewPeer);
void wheelEvent(QWheelEvent *event) override; void wheelEvent(QWheelEvent *event) override;
QStandardItemModel *m_listModel; QStandardItemModel *m_listModel;
PeerListDelegate *m_listDelegate;
PeerListSortModel *m_proxyModel; PeerListSortModel *m_proxyModel;
QHash<QString, QStandardItem *> m_peerItems;
QHash<QString, BitTorrent::PeerAddress> m_peerAddresses;
QSet<QString> m_missingFlags;
QPointer<Net::ReverseResolution> m_resolver;
PropertiesWidget *m_properties; PropertiesWidget *m_properties;
Net::ReverseResolution *m_resolver;
QHash<QString, QStandardItem *> m_peerItems;
bool m_resolveCountries; bool m_resolveCountries;
}; };