@ -1,5 +1,6 @@
/*
/*
* Bittorrent Client using Qt and libtorrent .
* Bittorrent Client using Qt and libtorrent .
* Copyright ( C ) 2023 Vladimir Golovnev < glassez @ yandex . ru >
* Copyright ( C ) 2006 Christophe Dumez < chris @ qbittorrent . org >
* Copyright ( C ) 2006 Christophe Dumez < chris @ qbittorrent . org >
*
*
* This program is free software ; you can redistribute it and / or
* This program is free software ; you can redistribute it and / or
@ -85,6 +86,21 @@ uint qHash(const PeerEndpoint &peerEndpoint, const uint seed = 0)
}
}
# endif
# endif
namespace
{
void setModelData ( QStandardItemModel * model , const int row , const int column , const QString & displayData
, const QVariant & underlyingData , const Qt : : Alignment textAlignmentData = { } , const QString & toolTip = { } )
{
const QMap < int , QVariant > data = {
{ Qt : : DisplayRole , displayData } ,
{ PeerListSortModel : : UnderlyingDataRole , underlyingData } ,
{ Qt : : TextAlignmentRole , QVariant { textAlignmentData } } ,
{ Qt : : ToolTipRole , toolTip } } ;
model - > setItemData ( model - > index ( row , column ) , data ) ;
}
}
PeerListWidget : : PeerListWidget ( PropertiesWidget * parent )
PeerListWidget : : PeerListWidget ( PropertiesWidget * parent )
: QTreeView ( parent )
: QTreeView ( parent )
, m_properties ( parent )
, m_properties ( parent )
@ -404,23 +420,58 @@ void PeerListWidget::loadPeers(const BitTorrent::Torrent *torrent)
if ( torrent ! = m_properties - > getCurrentTorrent ( ) )
if ( torrent ! = m_properties - > getCurrentTorrent ( ) )
return ;
return ;
// Remove I2P peers since they will be completely reloaded.
for ( QStandardItem * item : asConst ( m_I2PPeerItems ) )
m_listModel - > removeRow ( item - > row ( ) ) ;
m_I2PPeerItems . clear ( ) ;
QSet < PeerEndpoint > existingPeers ;
QSet < PeerEndpoint > existingPeers ;
existingPeers . reserve ( m_peerItems . size ( ) ) ;
existingPeers . reserve ( m_peerItems . size ( ) ) ;
for ( auto i = m_peerItems . cbegin ( ) ; i ! = m_peerItems . cend ( ) ; + + i )
for ( auto i = m_peerItems . cbegin ( ) ; i ! = m_peerItems . cend ( ) ; + + i )
existingPeers . insert ( i . key ( ) ) ;
existingPeers . insert ( i . key ( ) ) ;
const bool hideZeroValues = Preferences : : instance ( ) - > getHideZeroValues ( ) ;
for ( const BitTorrent : : PeerInfo & peer : peers )
for ( const BitTorrent : : PeerInfo & peer : peers )
{
{
if ( peer . address ( ) . ip . isNull ( ) )
if ( peer . address ( ) . ip . isNull ( ) )
continue ;
continue ;
bool isNewPeer = false ;
updatePeer ( torrent , peer , isNewPeer ) ;
if ( ! isNewPeer )
{
const PeerEndpoint peerEndpoint { peer . address ( ) , peer . connectionType ( ) } ;
const PeerEndpoint peerEndpoint { peer . address ( ) , peer . connectionType ( ) } ;
auto itemIter = m_peerItems . find ( peerEndpoint ) ;
const bool isNewPeer = ( itemIter = = m_peerItems . end ( ) ) ;
const int row = isNewPeer ? m_listModel - > rowCount ( ) : ( * itemIter ) - > row ( ) ;
if ( isNewPeer )
{
m_listModel - > insertRow ( row ) ;
const bool useI2PSocket = peer . useI2PSocket ( ) ;
const QString peerIPString = useI2PSocket ? tr ( " N/A " ) : peerEndpoint . address . ip . toString ( ) ;
setModelData ( m_listModel , row , PeerListColumns : : IP , peerIPString , peerIPString , { } , peerIPString ) ;
const QString peerIPHiddenString = useI2PSocket ? QString ( ) : peerEndpoint . address . ip . toString ( ) ;
setModelData ( m_listModel , row , PeerListColumns : : IP_HIDDEN , peerIPHiddenString , peerIPHiddenString ) ;
const QString peerPortString = useI2PSocket ? tr ( " N/A " ) : QString : : number ( peer . address ( ) . port ) ;
setModelData ( m_listModel , row , PeerListColumns : : PORT , peerPortString , peer . address ( ) . port , ( Qt : : AlignRight | Qt : : AlignVCenter ) ) ;
if ( useI2PSocket )
{
m_I2PPeerItems . append ( m_listModel - > item ( row , PeerListColumns : : IP ) ) ;
}
else
{
itemIter = m_peerItems . insert ( peerEndpoint , m_listModel - > item ( row , PeerListColumns : : IP ) ) ;
m_itemsByIP [ peerEndpoint . address . ip ] . insert ( itemIter . value ( ) ) ;
}
}
else
{
existingPeers . remove ( peerEndpoint ) ;
existingPeers . remove ( peerEndpoint ) ;
}
}
updatePeer ( row , torrent , peer , hideZeroValues ) ;
}
}
// Remove peers that are gone
// Remove peers that are gone
@ -438,73 +489,51 @@ void PeerListWidget::loadPeers(const BitTorrent::Torrent *torrent)
} ) ;
} ) ;
}
}
void PeerListWidget : : updatePeer ( const BitTorrent : : Torrent * torrent , const BitTorrent : : PeerInfo & peer , bool & isNewPeer )
void PeerListWidget : : updatePeer ( const int row , const BitTorrent : : Torrent * torrent , const BitTorrent : : PeerInfo & peer , const bool hideZeroValues )
{
{
const PeerEndpoint peerEndpoint { peer . address ( ) , peer . connectionType ( ) } ;
const QString peerIp = peerEndpoint . address . ip . toString ( ) ;
const Qt : : Alignment intDataTextAlignment = Qt : : AlignRight | Qt : : AlignVCenter ;
const Qt : : Alignment intDataTextAlignment = Qt : : AlignRight | Qt : : AlignVCenter ;
const auto setModelData =
const QString client = peer . client ( ) . toHtmlEscaped ( ) ;
[ this ] ( const int row , const int column , const QString & displayData
setModelData ( m_listModel , row , PeerListColumns : : CLIENT , client , client , { } , client ) ;
, const QVariant & underlyingData , const Qt : : Alignment textAlignmentData = { }
, const QString & toolTip = { } )
{
const QMap < int , QVariant > data =
{
{ Qt : : DisplayRole , displayData } ,
{ PeerListSortModel : : UnderlyingDataRole , underlyingData } ,
{ Qt : : TextAlignmentRole , QVariant { textAlignmentData } } ,
{ Qt : : ToolTipRole , toolTip }
} ;
m_listModel - > setItemData ( m_listModel - > index ( row , column ) , data ) ;
} ;
auto itemIter = m_peerItems . find ( peerEndpoint ) ;
const QString peerIdClient = peer . peerIdClient ( ) . toHtmlEscaped ( ) ;
isNewPeer = ( itemIter = = m_peerItems . end ( ) ) ;
setModelData ( m_listModel , row , PeerListColumns : : PEERID_CLIENT , peerIdClient , peerIdClient ) ;
if ( isNewPeer )
{
// new item
const int row = m_listModel - > rowCount ( ) ;
m_listModel - > insertRow ( row ) ;
setModelData ( row , PeerListColumns : : IP , peerIp , peerIp , { } , peerIp ) ;
const QString downSpeed = ( hideZeroValues & & ( peer . payloadDownSpeed ( ) < = 0 ) )
setModelData ( row , PeerListColumns : : PORT , QString : : number ( peer . address ( ) . port ) , peer . address ( ) . port , intDataTextAlignment ) ;
? QString ( ) : Utils : : Misc : : friendlyUnit ( peer . payloadDownSpeed ( ) , true ) ;
setModelData ( row , PeerListColumns : : IP_HIDDEN , peerIp , peerIp ) ;
setModelData ( m_listModel , row , PeerListColumns : : DOWN_SPEED , downSpeed , peer . payloadDownSpeed ( ) , intDataTextAlignment ) ;
itemIter = m_peerItems . insert ( peerEndpoint , m_listModel - > item ( row , PeerListColumns : : IP ) ) ;
const QString upSpeed = ( hideZeroValues & & ( peer . payloadUpSpeed ( ) < = 0 ) )
m_itemsByIP [ peerEndpoint . address . ip ] . insert ( itemIter . value ( ) ) ;
? QString ( ) : Utils : : Misc : : friendlyUnit ( peer . payloadUpSpeed ( ) , true ) ;
}
setModelData ( m_listModel , row , PeerListColumns : : UP_SPEED , upSpeed , peer . payloadUpSpeed ( ) , intDataTextAlignment ) ;
const int row = ( * itemIter ) - > row ( ) ;
const QString totalDown = ( hideZeroValues & & ( peer . totalDownload ( ) < = 0 ) )
const bool hideValues = Preferences : : instance ( ) - > getHideZeroValues ( ) ;
? QString ( ) : Utils : : Misc : : friendlyUnit ( peer . totalDownload ( ) ) ;
setModelData ( m_listModel , row , PeerListColumns : : TOT_DOWN , totalDown , peer . totalDownload ( ) , intDataTextAlignment ) ;
setModelData ( row , PeerListColumns : : CONNECTION , peer . connectionType ( ) , peer . connectionType ( ) ) ;
const QString totalUp = ( hideZeroValues & & ( peer . totalUpload ( ) < = 0 ) )
setModelData ( row , PeerListColumns : : FLAGS , peer . flags ( ) , peer . flags ( ) , { } , peer . flagsDescription ( ) ) ;
? QString ( ) : Utils : : Misc : : friendlyUnit ( peer . totalUpload ( ) ) ;
const QString client = peer . client ( ) . toHtmlEscaped ( ) ;
setModelData ( m_listModel , row , PeerListColumns : : TOT_UP , totalUp , peer . totalUpload ( ) , intDataTextAlignment ) ;
setModelData ( row , PeerListColumns : : CLIENT , client , client , { } , client ) ;
const QString peerIdClient = peer . peerIdClient ( ) . toHtmlEscaped ( ) ;
setModelData ( m_listModel , row , PeerListColumns : : CONNECTION , peer . connectionType ( ) , peer . connectionType ( ) ) ;
setModelData ( row , PeerListColumns : : PEERID_CLIENT , peerIdClient , peerIdClient ) ;
setModelData ( m_listModel , row , PeerListColumns : : FLAGS , peer . flags ( ) , peer . flags ( ) , { } , peer . flagsDescription ( ) ) ;
setModelData ( row , PeerListColumns : : PROGRESS , ( Utils : : String : : fromDouble ( peer . progress ( ) * 100 , 1 ) + u ' % ' ) , peer . progress ( ) , intDataTextAlignment ) ;
setModelData ( m_listModel , row , PeerListColumns : : PROGRESS , ( Utils : : String : : fromDouble ( peer . progress ( ) * 100 , 1 ) + u ' % ' )
const QString downSpeed = ( hideValues & & ( peer . payloadDownSpeed ( ) < = 0 ) ) ? QString { } : Utils : : Misc : : friendlyUnit ( peer . payloadDownSpeed ( ) , true ) ;
, peer . progress ( ) , intDataTextAlignment ) ;
setModelData ( row , PeerListColumns : : DOWN_SPEED , downSpeed , peer . payloadDownSpeed ( ) , intDataTextAlignment ) ;
setModelData ( m_listModel , row , PeerListColumns : : RELEVANCE , ( Utils : : String : : fromDouble ( peer . relevance ( ) * 100 , 1 ) + u ' % ' )
const QString upSpeed = ( hideValues & & ( peer . payloadUpSpeed ( ) < = 0 ) ) ? QString { } : Utils : : Misc : : friendlyUnit ( peer . payloadUpSpeed ( ) , true ) ;
, peer . relevance ( ) , intDataTextAlignment ) ;
setModelData ( row , PeerListColumns : : UP_SPEED , upSpeed , peer . payloadUpSpeed ( ) , intDataTextAlignment ) ;
const QString totalDown = ( hideValues & & ( peer . totalDownload ( ) < = 0 ) ) ? QString { } : Utils : : Misc : : friendlyUnit ( peer . totalDownload ( ) ) ;
setModelData ( row , PeerListColumns : : TOT_DOWN , totalDown , peer . totalDownload ( ) , intDataTextAlignment ) ;
const QString totalUp = ( hideValues & & ( peer . totalUpload ( ) < = 0 ) ) ? QString { } : Utils : : Misc : : friendlyUnit ( peer . totalUpload ( ) ) ;
setModelData ( row , PeerListColumns : : TOT_UP , totalUp , peer . totalUpload ( ) , intDataTextAlignment ) ;
setModelData ( row , PeerListColumns : : RELEVANCE , ( Utils : : String : : fromDouble ( peer . relevance ( ) * 100 , 1 ) + u ' % ' ) , peer . relevance ( ) , intDataTextAlignment ) ;
const PathList filePaths = torrent - > info ( ) . filesForPiece ( peer . downloadingPieceIndex ( ) ) ;
const PathList filePaths = torrent - > info ( ) . filesForPiece ( peer . downloadingPieceIndex ( ) ) ;
QStringList downloadingFiles ;
QStringList downloadingFiles ;
downloadingFiles . reserve ( filePaths . size ( ) ) ;
downloadingFiles . reserve ( filePaths . size ( ) ) ;
for ( const Path & filePath : filePaths )
for ( const Path & filePath : filePaths )
downloadingFiles . append ( filePath . toString ( ) ) ;
downloadingFiles . append ( filePath . toString ( ) ) ;
const QString downloadingFilesDisplayValue = downloadingFiles . join ( u ' ; ' ) ;
const QString downloadingFilesDisplayValue = downloadingFiles . join ( u ' ; ' ) ;
setModelData ( row , PeerListColumns : : DOWNLOADING_PIECE , downloadingFilesDisplayValue , downloadingFilesDisplayValue , { } , downloadingFiles . join ( u ' \n ' ) ) ;
setModelData ( m_listModel , row , PeerListColumns : : DOWNLOADING_PIECE , downloadingFilesDisplayValue
, downloadingFilesDisplayValue , { } , downloadingFiles . join ( u ' \n ' ) ) ;
if ( m_resolver )
if ( ! peer . useI2PSocket ( ) & & m_resolver )
m_resolver - > resolve ( peerEndpoint . address . ip ) ;
m_resolver - > resolve ( peer . address ( ) . ip ) ;
if ( m_resolveCountries )
if ( m_resolveCountries )
{
{