diff --git a/src/base/bittorrent/peeraddress.cpp b/src/base/bittorrent/peeraddress.cpp index b7dd5c754..a9a70f0bf 100644 --- a/src/base/bittorrent/peeraddress.cpp +++ b/src/base/bittorrent/peeraddress.cpp @@ -68,3 +68,13 @@ QString PeerAddress::toString() const : ip.toString(); return (ipStr + ':' + QString::number(port)); } + +bool BitTorrent::operator==(const BitTorrent::PeerAddress &left, const BitTorrent::PeerAddress &right) +{ + return (left.ip == right.ip) && (left.port == right.port); +} + +uint BitTorrent::qHash(const BitTorrent::PeerAddress &addr, const uint seed) +{ + return (::qHash(addr.ip, seed) ^ ::qHash(addr.port)); +} diff --git a/src/base/bittorrent/peeraddress.h b/src/base/bittorrent/peeraddress.h index 4233a6e1f..142cf048f 100644 --- a/src/base/bittorrent/peeraddress.h +++ b/src/base/bittorrent/peeraddress.h @@ -42,4 +42,7 @@ namespace BitTorrent static PeerAddress parse(const QString &address); QString toString() const; }; + + bool operator==(const PeerAddress &left, const PeerAddress &right); + uint qHash(const PeerAddress &addr, uint seed); } diff --git a/src/gui/properties/peerlistwidget.cpp b/src/gui/properties/peerlistwidget.cpp index 960a6f656..fbb70638c 100644 --- a/src/gui/properties/peerlistwidget.cpp +++ b/src/gui/properties/peerlistwidget.cpp @@ -57,6 +57,22 @@ #include "propertieswidget.h" #include "uithememanager.h" +struct PeerEndpoint +{ + BitTorrent::PeerAddress address; + QString connectionType; // matches return type of `PeerInfo::connectionType()` +}; + +bool operator==(const PeerEndpoint &left, const PeerEndpoint &right) +{ + return (left.address == right.address) && (left.connectionType == right.connectionType); +} + +uint qHash(const PeerEndpoint &peerEndpoint, const uint seed) +{ + return (qHash(peerEndpoint.address, seed) ^ ::qHash(peerEndpoint.connectionType)); +} + PeerListWidget::PeerListWidget(PropertiesWidget *parent) : QTreeView(parent) , m_properties(parent) @@ -331,42 +347,45 @@ void PeerListWidget::loadPeers(const BitTorrent::TorrentHandle *torrent) if (!torrent) return; const QVector peers = torrent->peers(); - QSet existingPeers; + QSet existingPeers; for (auto i = m_peerItems.cbegin(); i != m_peerItems.cend(); ++i) existingPeers << i.key(); for (const BitTorrent::PeerInfo &peer : peers) { - const BitTorrent::PeerAddress addr = peer.address(); - if (addr.ip.isNull()) continue; + if (peer.address().ip.isNull()) continue; - const QString peerIp = addr.ip.toString(); bool isNewPeer = false; - updatePeer(peerIp, torrent, peer, isNewPeer); - if (!isNewPeer) - existingPeers.remove(peerIp); + updatePeer(torrent, peer, isNewPeer); + if (!isNewPeer) { + const PeerEndpoint peerEndpoint {peer.address(), peer.connectionType()}; + existingPeers.remove(peerEndpoint); + } } // Remove peers that are gone - for (const QString &ip : asConst(existingPeers)) { - const QStandardItem *item = m_peerItems.take(ip); + for (const PeerEndpoint &peerEndpoint : asConst(existingPeers)) { + const QStandardItem *item = m_peerItems.take(peerEndpoint); m_listModel->removeRow(item->row()); } } -void PeerListWidget::updatePeer(const QString &ip, const BitTorrent::TorrentHandle *torrent, const BitTorrent::PeerInfo &peer, bool &isNewPeer) +void PeerListWidget::updatePeer(const BitTorrent::TorrentHandle *torrent, const BitTorrent::PeerInfo &peer, bool &isNewPeer) { - auto itemIter = m_peerItems.find(ip); + const PeerEndpoint peerEndpoint {peer.address(), peer.connectionType()}; + const QString peerIp = peerEndpoint.address.ip.toString(); + + auto itemIter = m_peerItems.find(peerEndpoint); isNewPeer = (itemIter == m_peerItems.end()); if (isNewPeer) { // new item const int row = m_listModel->rowCount(); m_listModel->insertRow(row); - m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP), ip); - m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP), ip, Qt::ToolTipRole); + m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP), peerIp); + m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP), peerIp, Qt::ToolTipRole); m_listModel->setData(m_listModel->index(row, PeerListDelegate::PORT), peer.address().port); - m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP_HIDDEN), ip); + m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP_HIDDEN), peerIp); - itemIter = m_peerItems.insert(ip, m_listModel->item(row, PeerListDelegate::IP)); + itemIter = m_peerItems.insert(peerEndpoint, m_listModel->item(row, PeerListDelegate::IP)); } const int row = (*itemIter)->row(); @@ -386,7 +405,7 @@ void PeerListWidget::updatePeer(const QString &ip, const BitTorrent::TorrentHand m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWNLOADING_PIECE), downloadingFiles.join('\n'), Qt::ToolTipRole); if (m_resolver) - m_resolver->resolve(ip); + m_resolver->resolve(peerIp); if (m_resolveCountries) { const QIcon icon = UIThemeManager::instance()->getFlagIcon(peer.country()); @@ -400,9 +419,13 @@ void PeerListWidget::updatePeer(const QString &ip, const BitTorrent::TorrentHand void PeerListWidget::handleResolved(const QString &ip, const QString &hostname) { - QStandardItem *item = m_peerItems.value(ip, nullptr); - if (item) - item->setData(hostname, Qt::DisplayRole); + for (auto iter = m_peerItems.cbegin(); iter != m_peerItems.cend(); ++iter) { + if (iter.key().address.ip.toString() == ip) { + QStandardItem *item {iter.value()}; + item->setData(hostname, Qt::DisplayRole); + break; + } + } } void PeerListWidget::handleSortColumnChanged(const int col) diff --git a/src/gui/properties/peerlistwidget.h b/src/gui/properties/peerlistwidget.h index d8c6dbdb9..314938c75 100644 --- a/src/gui/properties/peerlistwidget.h +++ b/src/gui/properties/peerlistwidget.h @@ -38,6 +38,8 @@ class QStandardItemModel; class PeerListSortModel; class PropertiesWidget; +struct PeerEndpoint; + namespace BitTorrent { class TorrentHandle; @@ -73,7 +75,7 @@ private slots: void handleResolved(const QString &ip, const QString &hostname); private: - void updatePeer(const QString &ip, const BitTorrent::TorrentHandle *torrent, const BitTorrent::PeerInfo &peer, bool &isNewPeer); + void updatePeer(const BitTorrent::TorrentHandle *torrent, const BitTorrent::PeerInfo &peer, bool &isNewPeer); void wheelEvent(QWheelEvent *event) override; @@ -81,7 +83,7 @@ private: PeerListSortModel *m_proxyModel = nullptr; PropertiesWidget *m_properties = nullptr; Net::ReverseResolution *m_resolver = nullptr; - QHash m_peerItems; + QHash m_peerItems; bool m_resolveCountries; };