@ -51,447 +51,458 @@
@@ -51,447 +51,458 @@
# include "peerlistsortmodel.h"
# include "peerlistwidget.h"
PeerListWidget : : PeerListWidget ( PropertiesWidget * parent ) :
QTreeView ( parent ) , m_properties ( parent ) , m_displayFlags ( false )
PeerListWidget : : PeerListWidget ( PropertiesWidget * parent )
: QTreeView ( parent )
, m_properties ( parent )
, m_displayFlags ( false )
{
// Load settings
loadSettings ( ) ;
// Visual settings
setUniformRowHeights ( true ) ;
setRootIsDecorated ( false ) ;
setItemsExpandable ( false ) ;
setAllColumnsShowFocus ( true ) ;
setSelectionMode ( QAbstractItemView : : ExtendedSelection ) ;
// List Model
m_listModel = new QStandardItemModel ( 0 , PeerListDelegate : : COL_COUNT ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : COUNTRY , Qt : : Horizontal , QVariant ( ) ) ; // Country flag column
m_listModel - > setHeaderData ( PeerListDelegate : : IP , Qt : : Horizontal , tr ( " IP " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : PORT , Qt : : Horizontal , tr ( " Port " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : FLAGS , Qt : : Horizontal , tr ( " Flags " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : CONNECTION , Qt : : Horizontal , tr ( " Connection " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : CLIENT , Qt : : Horizontal , tr ( " Client " , " i.e.: Client application " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : PROGRESS , Qt : : Horizontal , tr ( " Progress " , " i.e: % downloaded " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : DOWN_SPEED , Qt : : Horizontal , tr ( " Down Speed " , " i.e: Download speed " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : UP_SPEED , Qt : : Horizontal , tr ( " Up Speed " , " i.e: Upload speed " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : TOT_DOWN , Qt : : Horizontal , tr ( " Downloaded " , " i.e: total data downloaded " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : TOT_UP , Qt : : Horizontal , tr ( " Uploaded " , " i.e: total data uploaded " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : RELEVANCE , Qt : : Horizontal , tr ( " Relevance " , " i.e: How relevant this peer is to us. How many pieces it has that we don't. " ) ) ;
// Proxy model to support sorting without actually altering the underlying model
m_proxyModel = new PeerListSortModel ( ) ;
m_proxyModel - > setDynamicSortFilter ( true ) ;
m_proxyModel - > setSourceModel ( m_listModel ) ;
m_proxyModel - > setSortCaseSensitivity ( Qt : : CaseInsensitive ) ;
setModel ( m_proxyModel ) ;
//Explicitly set the column visibility. When columns are added/removed
//between versions this prevents some of them being hidden due to
//incorrect restoreState() being used.
for ( unsigned int i = 0 ; i < PeerListDelegate : : IP_HIDDEN ; i + + )
showColumn ( i ) ;
hideColumn ( PeerListDelegate : : IP_HIDDEN ) ;
hideColumn ( PeerListDelegate : : COL_COUNT ) ;
if ( ! Preferences : : instance ( ) - > resolvePeerCountries ( ) )
hideColumn ( PeerListDelegate : : COUNTRY ) ;
//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
//in the above scenario.
for ( unsigned int i = 0 ; i < PeerListDelegate : : IP_HIDDEN ; i + + )
if ( ! columnWidth ( i ) )
resizeColumnToContents ( i ) ;
// Context menu
setContextMenuPolicy ( Qt : : CustomContextMenu ) ;
connect ( this , SIGNAL ( customContextMenuRequested ( QPoint ) ) , this , SLOT ( showPeerListMenu ( QPoint ) ) ) ;
// List delegate
m_listDelegate = new PeerListDelegate ( this ) ;
setItemDelegate ( m_listDelegate ) ;
// Enable sorting
setSortingEnabled ( true ) ;
// IP to Hostname resolver
updatePeerHostNameResolutionState ( ) ;
// SIGNAL/SLOT
connect ( header ( ) , SIGNAL ( sectionClicked ( int ) ) , SLOT ( handleSortColumnChanged ( int ) ) ) ;
handleSortColumnChanged ( header ( ) - > sortIndicatorSection ( ) ) ;
copyHotkey = new QShortcut ( QKeySequence ( Qt : : ControlModifier + Qt : : Key_C ) , this , SLOT ( copySelectedPeers ( ) ) , 0 , Qt : : WidgetShortcut ) ;
// Load settings
loadSettings ( ) ;
// Visual settings
setUniformRowHeights ( true ) ;
setRootIsDecorated ( false ) ;
setItemsExpandable ( false ) ;
setAllColumnsShowFocus ( true ) ;
setSelectionMode ( QAbstractItemView : : ExtendedSelection ) ;
// List Model
m_listModel = new QStandardItemModel ( 0 , PeerListDelegate : : COL_COUNT ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : COUNTRY , Qt : : Horizontal , QVariant ( ) ) ; // Country flag column
m_listModel - > setHeaderData ( PeerListDelegate : : IP , Qt : : Horizontal , tr ( " IP " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : PORT , Qt : : Horizontal , tr ( " Port " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : FLAGS , Qt : : Horizontal , tr ( " Flags " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : CONNECTION , Qt : : Horizontal , tr ( " Connection " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : CLIENT , Qt : : Horizontal , tr ( " Client " , " i.e.: Client application " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : PROGRESS , Qt : : Horizontal , tr ( " Progress " , " i.e: % downloaded " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : DOWN_SPEED , Qt : : Horizontal , tr ( " Down Speed " , " i.e: Download speed " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : UP_SPEED , Qt : : Horizontal , tr ( " Up Speed " , " i.e: Upload speed " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : TOT_DOWN , Qt : : Horizontal , tr ( " Downloaded " , " i.e: total data downloaded " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : TOT_UP , Qt : : Horizontal , tr ( " Uploaded " , " i.e: total data uploaded " ) ) ;
m_listModel - > setHeaderData ( PeerListDelegate : : RELEVANCE , Qt : : Horizontal , tr ( " Relevance " , " i.e: How relevant this peer is to us. How many pieces it has that we don't. " ) ) ;
// Proxy model to support sorting without actually altering the underlying model
m_proxyModel = new PeerListSortModel ( ) ;
m_proxyModel - > setDynamicSortFilter ( true ) ;
m_proxyModel - > setSourceModel ( m_listModel ) ;
m_proxyModel - > setSortCaseSensitivity ( Qt : : CaseInsensitive ) ;
setModel ( m_proxyModel ) ;
//Explicitly set the column visibility. When columns are added/removed
//between versions this prevents some of them being hidden due to
//incorrect restoreState() being used.
for ( unsigned int i = 0 ; i < PeerListDelegate : : IP_HIDDEN ; i + + )
showColumn ( i ) ;
hideColumn ( PeerListDelegate : : IP_HIDDEN ) ;
hideColumn ( PeerListDelegate : : COL_COUNT ) ;
if ( ! Preferences : : instance ( ) - > resolvePeerCountries ( ) )
hideColumn ( PeerListDelegate : : COUNTRY ) ;
//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
//in the above scenario.
for ( unsigned int i = 0 ; i < PeerListDelegate : : IP_HIDDEN ; i + + )
if ( ! columnWidth ( i ) )
resizeColumnToContents ( i ) ;
// Context menu
setContextMenuPolicy ( Qt : : CustomContextMenu ) ;
connect ( this , SIGNAL ( customContextMenuRequested ( QPoint ) ) , this , SLOT ( showPeerListMenu ( QPoint ) ) ) ;
// List delegate
m_listDelegate = new PeerListDelegate ( this ) ;
setItemDelegate ( m_listDelegate ) ;
// Enable sorting
setSortingEnabled ( true ) ;
// IP to Hostname resolver
updatePeerHostNameResolutionState ( ) ;
// SIGNAL/SLOT
connect ( header ( ) , SIGNAL ( sectionClicked ( int ) ) , SLOT ( handleSortColumnChanged ( int ) ) ) ;
handleSortColumnChanged ( header ( ) - > sortIndicatorSection ( ) ) ;
m_ copyHotkey = new QShortcut ( QKeySequence ( Qt : : ControlModifier + Qt : : Key_C ) , this , SLOT ( copySelectedPeers ( ) ) , 0 , Qt : : WidgetShortcut ) ;
}
PeerListWidget : : ~ PeerListWidget ( )
{
saveSettings ( ) ;
delete m_proxyModel ;
delete m_listModel ;
delete m_listDelegate ;
if ( m_resolver )
delete m_resolver ;
delete copyHotkey ;
saveSettings ( ) ;
delete m_proxyModel ;
delete m_listModel ;
delete m_listDelegate ;
if ( m_resolver )
delete m_resolver ;
delete m_ copyHotkey;
}
void PeerListWidget : : updatePeerHostNameResolutionState ( )
{
if ( Preferences : : instance ( ) - > resolvePeerHostNames ( ) ) {
if ( ! m_resolver ) {
m_resolver = new Net : : ReverseResolution ( this ) ;
connect ( m_resolver , SIGNAL ( ipResolved ( QString , QString ) ) , SLOT ( handleResolved ( QString , QString ) ) ) ;
loadPeers ( m_properties - > getCurrentTorrent ( ) , true ) ;
if ( Preferences : : instance ( ) - > resolvePeerHostNames ( ) ) {
if ( ! m_resolver ) {
m_resolver = new Net : : ReverseResolution ( this ) ;
connect ( m_resolver , SIGNAL ( ipResolved ( QString , QString ) ) , SLOT ( handleResolved ( QString , QString ) ) ) ;
loadPeers ( m_properties - > getCurrentTorrent ( ) , true ) ;
}
}
else if ( m_resolver ) {
delete m_resolver ;
}
} else {
if ( m_resolver )
delete m_resolver ;
}
}
void PeerListWidget : : updatePeerCountryResolutionState ( )
{
if ( Preferences : : instance ( ) - > resolvePeerCountries ( ) ! = m_displayFlags ) {
m_displayFlags = ! m_displayFlags ;
if ( m_displayFlags ) {
loadPeers ( m_properties - > getCurrentTorrent ( ) ) ;
showColumn ( PeerListDelegate : : COUNTRY ) ;
resizeColumnToContents ( PeerListDelegate : : COUNTRY ) ;
}
else {
hideColumn ( PeerListDelegate : : COUNTRY ) ;
if ( Preferences : : instance ( ) - > resolvePeerCountries ( ) ! = m_displayFlags ) {
m_displayFlags = ! m_displayFlags ;
if ( m_displayFlags ) {
loadPeers ( m_properties - > getCurrentTorrent ( ) ) ;
showColumn ( PeerListDelegate : : COUNTRY ) ;
resizeColumnToContents ( PeerListDelegate : : COUNTRY ) ;
}
else {
hideColumn ( PeerListDelegate : : COUNTRY ) ;
}
}
}
}
void PeerListWidget : : showPeerListMenu ( const QPoint & )
{
QMenu menu ;
bool empty_menu = true ;
BitTorrent : : TorrentHandle * const torrent = m_properties - > getCurrentTorrent ( ) ;
if ( ! torrent ) return ;
// Add Peer Action
QAction * addPeerAct = 0 ;
if ( ! torrent - > isQueued ( ) & & ! torrent - > isChecking ( ) ) {
addPeerAct = menu . addAction ( GuiIconProvider : : instance ( ) - > getIcon ( " user-group-new " ) , tr ( " Add a new peer... " ) ) ;
empty_menu = false ;
}
QAction * banAct = 0 ;
QAction * copyPeerAct = 0 ;
if ( ! selectionModel ( ) - > selectedRows ( ) . isEmpty ( ) ) {
copyPeerAct = menu . addAction ( GuiIconProvider : : instance ( ) - > getIcon ( " edit-copy " ) , tr ( " Copy selected " ) ) ;
menu . addSeparator ( ) ;
banAct = menu . addAction ( GuiIconProvider : : instance ( ) - > getIcon ( " user-group-delete " ) , tr ( " Ban peer permanently " ) ) ;
empty_menu = false ;
}
if ( empty_menu ) return ;
QAction * act = menu . exec ( QCursor : : pos ( ) ) ;
if ( act = = 0 ) return ;
if ( act = = addPeerAct ) {
QList < BitTorrent : : PeerAddress > peersList = PeersAdditionDlg : : askForPeers ( ) ;
int peerCount = 0 ;
foreach ( const BitTorrent : : PeerAddress & addr , peersList ) {
if ( torrent - > connectPeer ( addr ) ) {
qDebug ( " Adding peer %s... " , qPrintable ( addr . ip . toString ( ) ) ) ;
Logger : : instance ( ) - > addMessage ( tr ( " Manually adding peer '%1'... " ) . arg ( addr . ip . toString ( ) ) ) ;
peerCount + + ;
}
else {
Logger : : instance ( ) - > addMessage ( tr ( " The peer '%1' could not be added to this torrent. " ) . arg ( addr . ip . toString ( ) ) , Log : : WARNING ) ;
QMenu menu ;
bool emptyMenu = true ;
BitTorrent : : TorrentHandle * const torrent = m_properties - > getCurrentTorrent ( ) ;
if ( ! torrent ) return ;
// Add Peer Action
QAction * addPeerAct = 0 ;
if ( ! torrent - > isQueued ( ) & & ! torrent - > isChecking ( ) ) {
addPeerAct = menu . addAction ( GuiIconProvider : : instance ( ) - > getIcon ( " user-group-new " ) , tr ( " Add a new peer... " ) ) ;
emptyMenu = false ;
}
QAction * banAct = 0 ;
QAction * copyPeerAct = 0 ;
if ( ! selectionModel ( ) - > selectedRows ( ) . isEmpty ( ) ) {
copyPeerAct = menu . addAction ( GuiIconProvider : : instance ( ) - > getIcon ( " edit-copy " ) , tr ( " Copy selected " ) ) ;
menu . addSeparator ( ) ;
banAct = menu . addAction ( GuiIconProvider : : instance ( ) - > getIcon ( " user-group-delete " ) , tr ( " Ban peer permanently " ) ) ;
emptyMenu = false ;
}
if ( emptyMenu ) return ;
QAction * act = menu . exec ( QCursor : : pos ( ) ) ;
if ( act = = 0 ) return ;
if ( act = = addPeerAct ) {
QList < BitTorrent : : PeerAddress > peersList = PeersAdditionDlg : : askForPeers ( ) ;
int peerCount = 0 ;
foreach ( const BitTorrent : : PeerAddress & addr , peersList ) {
if ( torrent - > connectPeer ( addr ) ) {
qDebug ( " Adding peer %s... " , qPrintable ( addr . ip . toString ( ) ) ) ;
Logger : : instance ( ) - > addMessage ( tr ( " Manually adding peer '%1'... " ) . arg ( addr . ip . toString ( ) ) ) ;
peerCount + + ;
}
else {
Logger : : instance ( ) - > addMessage ( tr ( " The peer '%1' could not be added to this torrent. " ) . arg ( addr . ip . toString ( ) ) , Log : : WARNING ) ;
}
}
if ( peerCount < peersList . length ( ) )
QMessageBox : : information ( 0 , tr ( " Peer addition " ) , tr ( " Some peers could not be added. Check the Log for details. " ) ) ;
else if ( peerCount > 0 )
QMessageBox : : information ( 0 , tr ( " Peer addition " ) , tr ( " The peers were added to this torrent. " ) ) ;
return ;
}
if ( act = = banAct ) {
banSelectedPeers ( ) ;
return ;
}
if ( act = = copyPeerAct ) {
copySelectedPeers ( ) ;
return ;
}
if ( peerCount < peersList . length ( ) )
QMessageBox : : information ( 0 , tr ( " Peer addition " ) , tr ( " Some peers could not be added. Check the Log for details. " ) ) ;
else if ( peerCount > 0 )
QMessageBox : : information ( 0 , tr ( " Peer addition " ) , tr ( " The peers were added to this torrent. " ) ) ;
return ;
}
if ( act = = banAct ) {
banSelectedPeers ( ) ;
return ;
}
if ( act = = copyPeerAct ) {
copySelectedPeers ( ) ;
return ;
}
}
void PeerListWidget : : banSelectedPeers ( )
{
// Confirm first
int ret = QMessageBox : : question ( this , tr ( " Ban peer permanently " ) , tr ( " Are you sure you want to ban permanently the selected peers? " ) ,
tr ( " &Yes " ) , tr ( " &No " ) ,
QString ( ) , 0 , 1 ) ;
if ( ret )
return ;
QModelIndexList selectedIndexes = selectionModel ( ) - > selectedRows ( ) ;
foreach ( const QModelIndex & index , selectedIndexes ) {
int row = m_proxyModel - > mapToSource ( index ) . row ( ) ;
QString ip = m_listModel - > data ( m_listModel - > index ( row , PeerListDelegate : : IP_HIDDEN ) ) . toString ( ) ;
qDebug ( " Banning peer %s... " , ip . toLocal8Bit ( ) . data ( ) ) ;
Logger : : instance ( ) - > addMessage ( tr ( " Manually banning peer '%1'... " ) . arg ( ip ) ) ;
BitTorrent : : Session : : instance ( ) - > banIP ( ip ) ;
}
// Refresh list
loadPeers ( m_properties - > getCurrentTorrent ( ) ) ;
// Confirm first
int ret = QMessageBox : : question ( this , tr ( " Ban peer permanently " ) , tr ( " Are you sure you want to ban permanently the selected peers? " ) ,
tr ( " &Yes " ) , tr ( " &No " ) ,
QString ( ) , 0 , 1 ) ;
if ( ret )
return ;
QModelIndexList selectedIndexes = selectionModel ( ) - > selectedRows ( ) ;
foreach ( const QModelIndex & index , selectedIndexes ) {
int row = m_proxyModel - > mapToSource ( index ) . row ( ) ;
QString ip = m_listModel - > data ( m_listModel - > index ( row , PeerListDelegate : : IP_HIDDEN ) ) . toString ( ) ;
qDebug ( " Banning peer %s... " , ip . toLocal8Bit ( ) . data ( ) ) ;
Logger : : instance ( ) - > addMessage ( tr ( " Manually banning peer '%1'... " ) . arg ( ip ) ) ;
BitTorrent : : Session : : instance ( ) - > banIP ( ip ) ;
}
// Refresh list
loadPeers ( m_properties - > getCurrentTorrent ( ) ) ;
}
void PeerListWidget : : copySelectedPeers ( )
{
QModelIndexList selectedIndexes = selectionModel ( ) - > selectedRows ( ) ;
QStringList selectedPeers ;
foreach ( const QModelIndex & index , selectedIndexes ) {
int row = m_proxyModel - > mapToSource ( index ) . row ( ) ;
QString ip = m_listModel - > data ( m_listModel - > index ( row , PeerListDelegate : : IP_HIDDEN ) ) . toString ( ) ;
QString myport = m_listModel - > data ( m_listModel - > index ( row , PeerListDelegate : : PORT ) ) . toString ( ) ;
if ( ip . indexOf ( " . " ) = = - 1 ) // IPv6
selectedPeers < < " [ " + ip + " ]: " + myport ;
else // IPv4
selectedPeers < < ip + " : " + myport ;
}
QApplication : : clipboard ( ) - > setText ( selectedPeers . join ( " \n " ) ) ;
QModelIndexList selectedIndexes = selectionModel ( ) - > selectedRows ( ) ;
QStringList selectedPeers ;
foreach ( const QModelIndex & index , selectedIndexes ) {
int row = m_proxyModel - > mapToSource ( index ) . row ( ) ;
QString ip = m_listModel - > data ( m_listModel - > index ( row , PeerListDelegate : : IP_HIDDEN ) ) . toString ( ) ;
QString myport = m_listModel - > data ( m_listModel - > index ( row , PeerListDelegate : : PORT ) ) . toString ( ) ;
if ( ip . indexOf ( " . " ) = = - 1 ) // IPv6
selectedPeers < < " [ " + ip + " ]: " + myport ;
else // IPv4
selectedPeers < < ip + " : " + myport ;
}
QApplication : : clipboard ( ) - > setText ( selectedPeers . join ( " \n " ) ) ;
}
void PeerListWidget : : clear ( ) {
qDebug ( " clearing peer list " ) ;
m_peerItems . clear ( ) ;
m_peerAddresses . clear ( ) ;
m_missingFlags . clear ( ) ;
int nbrows = m_listModel - > rowCount ( ) ;
if ( nbrows > 0 ) {
qDebug ( " Cleared %d peers " , nbrows ) ;
m_listModel - > removeRows ( 0 , nbrows ) ;
}
void PeerListWidget : : clear ( )
{
qDebug ( " clearing peer list " ) ;
m_peerItems . clear ( ) ;
m_peerAddresses . clear ( ) ;
m_missingFlags . clear ( ) ;
int nbrows = m_listModel - > rowCount ( ) ;
if ( nbrows > 0 ) {
qDebug ( " Cleared %d peers " , nbrows ) ;
m_listModel - > removeRows ( 0 , nbrows ) ;
}
}
void PeerListWidget : : loadSettings ( ) {
header ( ) - > restoreState ( Preferences : : instance ( ) - > getPeerListState ( ) ) ;
void PeerListWidget : : loadSettings ( )
{
header ( ) - > restoreState ( Preferences : : instance ( ) - > getPeerListState ( ) ) ;
}
void PeerListWidget : : saveSettings ( ) const {
Preferences : : instance ( ) - > setPeerListState ( header ( ) - > saveState ( ) ) ;
void PeerListWidget : : saveSettings ( ) const
{
Preferences : : instance ( ) - > setPeerListState ( header ( ) - > saveState ( ) ) ;
}
void PeerListWidget : : loadPeers ( BitTorrent : : TorrentHandle * const torrent , bool force_hostname_resolution ) {
if ( ! torrent ) return ;
QList < BitTorrent : : PeerInfo > peers = torrent - > peers ( ) ;
QSet < QString > old_peers_set = m_peerItems . keys ( ) . toSet ( ) ;
foreach ( const BitTorrent : : PeerInfo & peer , peers ) {
BitTorrent : : PeerAddress addr = peer . address ( ) ;
if ( addr . ip . isNull ( ) ) continue ;
QString peer_ip = addr . ip . toString ( ) ;
if ( m_peerItems . contains ( peer_ip ) ) {
// Update existing peer
updatePeer ( peer_ip , torrent , peer ) ;
old_peers_set . remove ( peer_ip ) ;
if ( force_hostname_resolution & & m_resolver ) {
m_resolver - > resolve ( peer_ip ) ;
}
} else {
// Add new peer
m_peerItems [ peer_ip ] = addPeer ( peer_ip , torrent , peer ) ;
m_peerAddresses [ peer_ip ] = addr ;
// Resolve peer host name is asked
if ( m_resolver )
m_resolver - > resolve ( peer_ip ) ;
}
}
// Delete peers that are gone
QSetIterator < QString > it ( old_peers_set ) ;
while ( it . hasNext ( ) ) {
const QString & ip = it . next ( ) ;
m_missingFlags . remove ( ip ) ;
m_peerAddresses . remove ( ip ) ;
QStandardItem * item = m_peerItems . take ( ip ) ;
m_listModel - > removeRow ( item - > row ( ) ) ;
}
void PeerListWidget : : loadPeers ( BitTorrent : : TorrentHandle * const torrent , bool forceHostnameResolution )
{
if ( ! torrent ) return ;
QList < BitTorrent : : PeerInfo > peers = torrent - > peers ( ) ;
QSet < QString > oldeersSet = m_peerItems . keys ( ) . toSet ( ) ;
foreach ( const BitTorrent : : PeerInfo & peer , peers ) {
BitTorrent : : PeerAddress addr = peer . address ( ) ;
if ( addr . ip . isNull ( ) ) continue ;
QString peerIp = addr . ip . toString ( ) ;
if ( m_peerItems . contains ( peerIp ) ) {
// Update existing peer
updatePeer ( peerIp , torrent , peer ) ;
oldeersSet . 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
QSetIterator < QString > it ( oldeersSet ) ;
while ( it . hasNext ( ) ) {
const QString & ip = it . next ( ) ;
m_missingFlags . remove ( ip ) ;
m_peerAddresses . remove ( ip ) ;
QStandardItem * item = m_peerItems . take ( ip ) ;
m_listModel - > removeRow ( item - > row ( ) ) ;
}
}
QStandardItem * PeerListWidget : : addPeer ( const QString & ip , BitTorrent : : TorrentHandle * const torrent , const BitTorrent : : PeerInfo & peer ) {
int row = m_listModel - > rowCount ( ) ;
// Adding Peer to peer list
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 : : PORT ) , peer . address ( ) . port ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : IP_HIDDEN ) , ip ) ;
if ( m_displayFlags ) {
const QIcon ico = GuiIconProvider : : instance ( ) - > getFlagIcon ( peer . country ( ) ) ;
if ( ! ico . isNull ( ) ) {
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : COUNTRY ) , ico , Qt : : DecorationRole ) ;
const QString country_name = Net : : GeoIPManager : : CountryName ( peer . country ( ) ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : COUNTRY ) , country_name , Qt : : ToolTipRole ) ;
} else {
m_missingFlags . insert ( ip ) ;
}
}
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : CONNECTION ) , peer . connectionType ( ) ) ;
QString flags , tooltip ;
getFlags ( peer , flags , tooltip ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : FLAGS ) , flags ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : FLAGS ) , tooltip , Qt : : ToolTipRole ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : CLIENT ) , peer . client ( ) ) ;
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 ) , getPeerRelevance ( torrent - > pieces ( ) , peer . pieces ( ) ) ) ;
return m_listModel - > item ( row , PeerListDelegate : : IP ) ;
QStandardItem * PeerListWidget : : addPeer ( const QString & ip , BitTorrent : : TorrentHandle * const torrent , const BitTorrent : : PeerInfo & peer )
{
int row = m_listModel - > rowCount ( ) ;
// Adding Peer to peer list
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 : : PORT ) , peer . address ( ) . port ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : IP_HIDDEN ) , ip ) ;
if ( m_displayFlags ) {
const QIcon ico = GuiIconProvider : : instance ( ) - > getFlagIcon ( peer . country ( ) ) ;
if ( ! ico . isNull ( ) ) {
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : COUNTRY ) , ico , Qt : : DecorationRole ) ;
const QString countryName = Net : : GeoIPManager : : CountryName ( peer . country ( ) ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : COUNTRY ) , countryName , Qt : : ToolTipRole ) ;
}
else {
m_missingFlags . insert ( ip ) ;
}
}
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : CONNECTION ) , peer . connectionType ( ) ) ;
QString flags , tooltip ;
getFlags ( peer , flags , tooltip ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : FLAGS ) , flags ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : FLAGS ) , tooltip , Qt : : ToolTipRole ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : CLIENT ) , peer . client ( ) ) ;
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 ) , getPeerRelevance ( torrent - > pieces ( ) , peer . pieces ( ) ) ) ;
return m_listModel - > item ( row , PeerListDelegate : : 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_displayFlags ) {
const QIcon ico = GuiIconProvider : : instance ( ) - > getFlagIcon ( peer . country ( ) ) ;
if ( ! ico . isNull ( ) ) {
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : COUNTRY ) , ico , Qt : : DecorationRole ) ;
const QString country_name = Net : : GeoIPManager : : CountryName ( peer . country ( ) ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : COUNTRY ) , country_name , Qt : : ToolTipRole ) ;
m_missingFlags . remove ( ip ) ;
}
}
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : CONNECTION ) , peer . connectionType ( ) ) ;
QString flags , tooltip ;
getFlags ( peer , flags , tooltip ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : PORT ) , peer . address ( ) . port ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : FLAGS ) , flags ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : FLAGS ) , tooltip , Qt : : ToolTipRole ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : CLIENT ) , peer . client ( ) ) ;
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 ) , getPeerRelevance ( torrent - > pieces ( ) , peer . pieces ( ) ) ) ;
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_displayFlags ) {
const QIcon ico = GuiIconProvider : : instance ( ) - > getFlagIcon ( peer . country ( ) ) ;
if ( ! ico . isNull ( ) ) {
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : COUNTRY ) , ico , Qt : : DecorationRole ) ;
const QString countryName = Net : : GeoIPManager : : CountryName ( peer . country ( ) ) ;
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 ( ) ) ;
QString flags , tooltip ;
getFlags ( peer , flags , tooltip ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : PORT ) , peer . address ( ) . port ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : FLAGS ) , flags ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : FLAGS ) , tooltip , Qt : : ToolTipRole ) ;
m_listModel - > setData ( m_listModel - > index ( row , PeerListDelegate : : CLIENT ) , peer . client ( ) ) ;
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 ) , getPeerRelevance ( torrent - > pieces ( ) , peer . pieces ( ) ) ) ;
}
void PeerListWidget : : handleResolved ( const QString & ip , const QString & hostname ) {
QStandardItem * item = m_peerItems . value ( ip , 0 ) ;
if ( item ) {
qDebug ( " Resolved %s -> %s " , qPrintable ( ip ) , qPrintable ( hostname ) ) ;
item - > setData ( hostname , Qt : : DisplayRole ) ;
}
void PeerListWidget : : handleResolved ( const QString & ip , const QString & hostname )
{
QStandardItem * item = m_peerItems . value ( ip , 0 ) ;
if ( item ) {
qDebug ( " Resolved %s -> %s " , qPrintable ( ip ) , qPrintable ( hostname ) ) ;
item - > setData ( hostname , Qt : : DisplayRole ) ;
}
}
void PeerListWidget : : handleSortColumnChanged ( int col )
{
if ( col = = PeerListDelegate : : COUNTRY ) {
qDebug ( " Sorting by decoration " ) ;
m_proxyModel - > setSortRole ( Qt : : ToolTipRole ) ;
} else {
m_proxyModel - > setSortRole ( Qt : : DisplayRole ) ;
}
if ( col = = PeerListDelegate : : COUNTRY ) {
qDebug ( " Sorting by decoration " ) ;
m_proxyModel - > setSortRole ( Qt : : ToolTipRole ) ;
}
else {
m_proxyModel - > setSortRole ( Qt : : DisplayRole ) ;
}
}
void PeerListWidget : : getFlags ( const BitTorrent : : PeerInfo & peer , QString & flags , QString & tooltip )
{
if ( peer . isInteresting ( ) ) {
//d = Your client wants to download, but peer doesn't want to send (interested and choked)
if ( peer . isRemoteChocked ( ) ) {
flags + = " d " ;
tooltip + = tr ( " interested(local) and choked(peer) " ) ;
tooltip + = " , " ;
{
if ( peer . isInteresting ( ) ) {
//d = Your client wants to download, but peer doesn't want to send (interested and choked)
if ( peer . isRemoteChocked ( ) ) {
flags + = " d " ;
tooltip + = tr ( " interested(local) and choked(peer) " ) ;
tooltip + = " , " ;
}
else {
//D = Currently downloading (interested and not choked)
flags + = " D " ;
tooltip + = tr ( " interested(local) and unchoked(peer) " ) ;
tooltip + = " , " ;
}
}
else {
//D = Currently downloading (interested and not choked)
flags + = " D " ;
tooltip + = tr ( " interested(local) and unchoked(peer) " ) ;
tooltip + = " , " ;
if ( peer . isRemoteInterested ( ) ) {
//u = Peer wants your client to upload, but your client doesn't want to (interested and choked)
if ( peer . isChocked ( ) ) {
flags + = " u " ;
tooltip + = tr ( " interested(peer) and choked(local) " ) ;
tooltip + = " , " ;
}
else {
//U = Currently uploading (interested and not choked)
flags + = " U " ;
tooltip + = tr ( " interested(peer) and unchoked(local) " ) ;
tooltip + = " , " ;
}
}
}
if ( peer . isRemoteInterested ( ) ) {
//u = Peer wants your client to upload, but your client doesn't want to (interested and choked)
if ( peer . isChocked ( ) ) {
flags + = " u " ;
tooltip + = tr ( " interested(peer) and choked(local) " ) ;
tooltip + = " , " ;
//O = Optimistic unchoke
if ( peer . optimisticUnchoke ( ) ) {
flags + = " O " ;
tooltip + = tr ( " optimistic unchoke " ) ;
tooltip + = " , " ;
}
else {
//U = Currently uploading (interested and not choked)
flags + = " U " ;
tooltip + = tr ( " interested(peer) and unchoked(local) " ) ;
tooltip + = " , " ;
}
}
//O = Optimistic unchoke
if ( peer . optimisticUnchoke ( ) ) {
flags + = " O " ;
tooltip + = tr ( " optimistic unchoke " ) ;
tooltip + = " , " ;
}
//S = Peer is snubbed
if ( peer . isSnubbed ( ) ) {
flags + = " S " ;
tooltip + = tr ( " peer snubbed " ) ;
tooltip + = " , " ;
}
//I = Peer is an incoming connection
if ( ! peer . isLocalConnection ( ) ) {
flags + = " I " ;
tooltip + = tr ( " incoming connection " ) ;
tooltip + = " , " ;
}
//K = Peer is unchoking your client, but your client is not interested
if ( ! peer . isRemoteChocked ( ) & & ! peer . isInteresting ( ) ) {
flags + = " K " ;
tooltip + = tr ( " not interested(local) and unchoked(peer) " ) ;
tooltip + = " , " ;
}
//? = Your client unchoked the peer but the peer is not interested
if ( ! peer . isChocked ( ) & & ! peer . isRemoteInterested ( ) ) {
flags + = " ? " ;
tooltip + = tr ( " not interested(peer) and unchoked(local) " ) ;
tooltip + = " , " ;
}
//X = Peer was included in peerlists obtained through Peer Exchange (PEX)
if ( peer . fromPeX ( ) ) {
flags + = " X " ;
tooltip + = tr ( " peer from PEX " ) ;
tooltip + = " , " ;
}
//H = Peer was obtained through DHT
if ( peer . fromDHT ( ) ) {
flags + = " H " ;
tooltip + = tr ( " peer from DHT " ) ;
tooltip + = " , " ;
}
//E = Peer is using Protocol Encryption (all traffic)
if ( peer . isRC4Encrypted ( ) ) {
flags + = " E " ;
tooltip + = tr ( " encrypted traffic " ) ;
tooltip + = " , " ;
}
//e = Peer is using Protocol Encryption (handshake)
if ( peer . isPlaintextEncrypted ( ) ) {
flags + = " e " ;
tooltip + = tr ( " encrypted handshake " ) ;
tooltip + = " , " ;
}
//P = Peer is using uTorrent uTP
if ( peer . useUTPSocket ( ) ) {
flags + = " P " ;
tooltip + = QString : : fromUtf8 ( C_UTP ) ;
tooltip + = " , " ;
}
//L = Peer is local
if ( peer . fromLSD ( ) ) {
flags + = " L " ;
tooltip + = tr ( " peer from LSD " ) ;
}
flags = flags . trimmed ( ) ;
tooltip = tooltip . trimmed ( ) ;
if ( tooltip . endsWith ( ' , ' , Qt : : CaseInsensitive ) )
tooltip . chop ( 1 ) ;
//S = Peer is snubbed
if ( peer . isSnubbed ( ) ) {
flags + = " S " ;
tooltip + = tr ( " peer snubbed " ) ;
tooltip + = " , " ;
}
//I = Peer is an incoming connection
if ( ! peer . isLocalConnection ( ) ) {
flags + = " I " ;
tooltip + = tr ( " incoming connection " ) ;
tooltip + = " , " ;
}
//K = Peer is unchoking your client, but your client is not interested
if ( ! peer . isRemoteChocked ( ) & & ! peer . isInteresting ( ) ) {
flags + = " K " ;
tooltip + = tr ( " not interested(local) and unchoked(peer) " ) ;
tooltip + = " , " ;
}
//? = Your client unchoked the peer but the peer is not interested
if ( ! peer . isChocked ( ) & & ! peer . isRemoteInterested ( ) ) {
flags + = " ? " ;
tooltip + = tr ( " not interested(peer) and unchoked(local) " ) ;
tooltip + = " , " ;
}
//X = Peer was included in peerlists obtained through Peer Exchange (PEX)
if ( peer . fromPeX ( ) ) {
flags + = " X " ;
tooltip + = tr ( " peer from PEX " ) ;
tooltip + = " , " ;
}
//H = Peer was obtained through DHT
if ( peer . fromDHT ( ) ) {
flags + = " H " ;
tooltip + = tr ( " peer from DHT " ) ;
tooltip + = " , " ;
}
//E = Peer is using Protocol Encryption (all traffic)
if ( peer . isRC4Encrypted ( ) ) {
flags + = " E " ;
tooltip + = tr ( " encrypted traffic " ) ;
tooltip + = " , " ;
}
//e = Peer is using Protocol Encryption (handshake)
if ( peer . isPlaintextEncrypted ( ) ) {
flags + = " e " ;
tooltip + = tr ( " encrypted handshake " ) ;
tooltip + = " , " ;
}
//P = Peer is using uTorrent uTP
if ( peer . useUTPSocket ( ) ) {
flags + = " P " ;
tooltip + = QString : : fromUtf8 ( C_UTP ) ;
tooltip + = " , " ;
}
//L = Peer is local
if ( peer . fromLSD ( ) ) {
flags + = " L " ;
tooltip + = tr ( " peer from LSD " ) ;
}
flags = flags . trimmed ( ) ;
tooltip = tooltip . trimmed ( ) ;
if ( tooltip . endsWith ( ' , ' , Qt : : CaseInsensitive ) )
tooltip . chop ( 1 ) ;
}
qreal PeerListWidget : : getPeerRelevance ( const QBitArray & allPieces , const QBitArray & peerPieces )