(qt) #3362:Edit trackers in transmission-qt
This commit is contained in:
parent
235dbf607b
commit
c8408b755f
263
qt/details.cc
263
qt/details.cc
|
@ -25,7 +25,9 @@
|
|||
#include <QHBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QInputDialog>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QRadioButton>
|
||||
#include <QResizeEvent>
|
||||
|
@ -39,11 +41,13 @@
|
|||
#include <QVBoxLayout>
|
||||
|
||||
#include <libtransmission/transmission.h>
|
||||
#include <libtransmission/bencode.h>
|
||||
|
||||
#include "details.h"
|
||||
#include "file-tree.h"
|
||||
#include "hig.h"
|
||||
#include "prefs.h"
|
||||
#include "qticonloader.h"
|
||||
#include "session.h"
|
||||
#include "squeezelabel.h"
|
||||
#include "torrent.h"
|
||||
|
@ -117,6 +121,17 @@ class PeerItem: public QTreeWidgetItem
|
|||
****
|
||||
***/
|
||||
|
||||
QIcon
|
||||
Details :: getStockIcon( const QString& freedesktop_name, int fallback )
|
||||
{
|
||||
QIcon fallbackIcon;
|
||||
|
||||
if( fallback > 0 )
|
||||
fallbackIcon = style()->standardIcon( QStyle::StandardPixmap( fallback ), 0, this );
|
||||
|
||||
return QtIconLoader::icon( freedesktop_name, fallbackIcon );
|
||||
}
|
||||
|
||||
Details :: Details( Session& session, Prefs& prefs, TorrentModel& model, QWidget * parent ):
|
||||
QDialog( parent, Qt::Dialog ),
|
||||
mySession( session ),
|
||||
|
@ -657,30 +672,57 @@ Details :: refresh( )
|
|||
|
||||
// tracker tab
|
||||
//
|
||||
QMap<QString,QTreeWidgetItem*> trackers2;
|
||||
QList<QTreeWidgetItem*> newItems2;
|
||||
QMap<QString,QTreeWidgetItem*> trackerTiers;
|
||||
QMap<QString,QTreeWidgetItem*> trackerItems;
|
||||
const time_t now( time( 0 ) );
|
||||
const bool showBackup = myPrefs.getBool( Prefs::SHOW_BACKUP_TRACKERS );
|
||||
const bool showScrape = myPrefs.getBool( Prefs::SHOW_TRACKER_SCRAPES );
|
||||
foreach( const Torrent * t, torrents )
|
||||
{
|
||||
const QString idStr( QString::number( t->id( ) ) );
|
||||
TrackerStatsList trackerStats = t->trackerStats( );
|
||||
const TrackerStatsList trackerStats = t->trackerStats( );
|
||||
|
||||
foreach( const TrackerStat& trackerStat, trackerStats )
|
||||
{
|
||||
const QString key( idStr + ":" + QString::number(trackerStat.id) );
|
||||
QTreeWidgetItem * item = (QTreeWidgetItem*) myTrackerStats.value( key, 0 );
|
||||
QFont font;
|
||||
QString str;
|
||||
const QString tierKey( QString::number(trackerStat.tier) );
|
||||
QTreeWidgetItem * tier = (QTreeWidgetItem*) myTrackerTiers.value( tierKey, 0 );
|
||||
|
||||
if( tier == 0 ) // new tier
|
||||
{
|
||||
QFont tierFont;
|
||||
tier = new QTreeWidgetItem( myTrackerTree );
|
||||
myTrackerTree->addTopLevelItem( tier );
|
||||
str = "Tier: " + QString::number( trackerStat.tier + 1 );
|
||||
tier->setText( 0, str );
|
||||
tierFont.setBold( true );
|
||||
tier->setFont( 0, tierFont );
|
||||
}
|
||||
|
||||
const QString key( idStr + tierKey + ":" + QString::number( trackerStat.id ) );
|
||||
QTreeWidgetItem * item = (QTreeWidgetItem*) myTrackerItems.value( key, 0 );
|
||||
|
||||
if( item == 0 ) // new tracker
|
||||
{
|
||||
item = new QTreeWidgetItem( myTrackerTree );
|
||||
newItems2 << item;
|
||||
item = new QTreeWidgetItem( tier );
|
||||
tier->addChild( item );
|
||||
if( tier->childCount() == 1 )
|
||||
tier->setExpanded( true );
|
||||
}
|
||||
str = trackerStat.host;
|
||||
if( showBackup || !trackerStat.isBackup)
|
||||
|
||||
if( trackerStat.isBackup )
|
||||
{
|
||||
font.setItalic( true );
|
||||
if( showScrape )
|
||||
{
|
||||
str += "\n";
|
||||
str += "Tracker will be used as a backup";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
font.setItalic( false );
|
||||
if( trackerStat.hasAnnounced )
|
||||
{
|
||||
const QString tstr( timeToStringRounded( now - trackerStat.lastAnnounceTime ) );
|
||||
|
@ -778,21 +820,37 @@ Details :: refresh( )
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
item->setText( 0, str );
|
||||
item->setFont( 0, font );
|
||||
item->setData( 0, TRACKERID, trackerStat.id );
|
||||
item->setData( 0, TRACKERURL, trackerStat.announce );
|
||||
item->setData( 0, TRACKERTIER, trackerStat.tier );
|
||||
item->setData( 0, TORRENTID, t->id() );
|
||||
|
||||
trackers2.insert( key, item );
|
||||
tier->setData( 0, TRACKERID, -1 );
|
||||
tier->setData( 0, TRACKERURL, QString() );
|
||||
tier->setData( 0, TRACKERTIER, trackerStat.tier );
|
||||
tier->setData( 0, TORRENTID, torrents.count() > 1 ? -1 : t->id() );
|
||||
|
||||
trackerTiers.insert( tierKey, tier );
|
||||
trackerItems.insert( key, item );
|
||||
}
|
||||
}
|
||||
myTrackerTree->addTopLevelItems( newItems2 );
|
||||
foreach( QString key, myTrackerStats.keys() ) {
|
||||
if( !trackers2.contains( key ) ) { // tracker has disappeared
|
||||
QTreeWidgetItem * item = myTrackerStats.value( key, 0 );
|
||||
myTrackerTree->takeTopLevelItem( myTrackerTree->indexOfTopLevelItem( item ) );
|
||||
delete item;
|
||||
QList<QTreeWidgetItem*> tierList = trackerTiers.values();
|
||||
QList<QTreeWidgetItem*> itemList = trackerItems.values();
|
||||
for( int i = 0; i < myTrackerTree->topLevelItemCount(); ++i )
|
||||
{
|
||||
QTreeWidgetItem * tier = myTrackerTree->topLevelItem( i );
|
||||
for( int j = 0; j < tier->childCount(); ++j )
|
||||
{
|
||||
if( !itemList.contains( tier->child( j ) ) ) // tracker has disappeared
|
||||
delete tier->takeChild( j-- );
|
||||
}
|
||||
if( !tierList.contains( tier ) ) // tier has disappeared
|
||||
delete myTrackerTree->takeTopLevelItem( i-- );
|
||||
}
|
||||
myTrackerStats = trackers2;
|
||||
myTrackerTiers = trackerTiers;
|
||||
myTrackerItems = trackerItems;
|
||||
|
||||
///
|
||||
/// Peers tab
|
||||
|
@ -933,12 +991,6 @@ Details :: createInfoTab( )
|
|||
****
|
||||
***/
|
||||
|
||||
void
|
||||
Details :: onShowBackupTrackersToggled( bool val )
|
||||
{
|
||||
myPrefs.set( Prefs::SHOW_BACKUP_TRACKERS, val );
|
||||
}
|
||||
|
||||
void
|
||||
Details :: onShowTrackerScrapesToggled( bool val )
|
||||
{
|
||||
|
@ -1011,6 +1063,115 @@ Details :: onBandwidthPriorityChanged( int index )
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Details :: onTrackerSelectionChanged( )
|
||||
{
|
||||
const QList<QTreeWidgetItem*> items = myTrackerTree->selectedItems();
|
||||
if( items.count() == 1 )
|
||||
myEditTrackerButton->setEnabled( items.first()->data( 0, TRACKERID ).toInt() >= 0 );
|
||||
else
|
||||
myEditTrackerButton->setEnabled( false );
|
||||
myRemoveTrackerButton->setEnabled( !items.isEmpty() );
|
||||
}
|
||||
|
||||
bool
|
||||
Details :: findTrackerByURL( const QString& url, int torId )
|
||||
{
|
||||
bool duplicate = false;
|
||||
foreach( QTreeWidgetItem * tracker, myTrackerItems.values() )
|
||||
{
|
||||
if( tracker->data( 0, TRACKERURL ).toString() == url &&
|
||||
( torId == -1 || tracker->data( 0, TORRENTID ).toInt() == torId ) )
|
||||
{
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return duplicate;
|
||||
}
|
||||
|
||||
void
|
||||
Details :: onAddTrackerPushed( )
|
||||
{
|
||||
const QString urlString = QInputDialog::getText( this,
|
||||
tr( "Add tracker announce URL " ),
|
||||
NULL );
|
||||
if( !urlString.isEmpty() )
|
||||
{
|
||||
if( !findTrackerByURL( urlString, -1 ) )
|
||||
{
|
||||
QByteArray url = urlString.toUtf8();
|
||||
tr_benc top;
|
||||
|
||||
tr_bencInitDict( &top, 1 );
|
||||
tr_bencDictAddStr( &top, "announce", url );
|
||||
|
||||
mySession.torrentSet( myIds, "trackerAdd", &top );
|
||||
}
|
||||
else
|
||||
QMessageBox::warning( this, "Error", "Tracker already exists." );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Details :: onEditTrackerPushed( )
|
||||
{
|
||||
const QTreeWidgetItem * item = myTrackerTree->selectedItems().first();
|
||||
const QString urlString = QInputDialog::getText( this,
|
||||
tr( "Edit tracker announce URL " ),
|
||||
NULL,
|
||||
QLineEdit::Normal,
|
||||
item->data( 0, TRACKERURL ).toString() );
|
||||
if( !urlString.isEmpty() )
|
||||
{
|
||||
const int torId = item->data( 0, TORRENTID ).toInt();
|
||||
if( !findTrackerByURL( urlString, torId ) )
|
||||
{
|
||||
QByteArray url = urlString.toUtf8();
|
||||
QSet<int> ids;
|
||||
tr_benc top;
|
||||
|
||||
ids << torId;
|
||||
tr_bencInitDict( &top, 2 );
|
||||
tr_bencDictAddStr( &top, "announce", item->data( 0, TRACKERURL ).toByteArray() );
|
||||
tr_bencDictAddStr( &top, "announce-new", url );
|
||||
|
||||
mySession.torrentSet( ids, "trackerEdit", &top );
|
||||
}
|
||||
else
|
||||
QMessageBox::warning( this, "Error", "Tracker already exists." );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Details :: removeTracker( const QTreeWidgetItem * item )
|
||||
{
|
||||
QByteArray url = item->data( 0, TRACKERURL ).toByteArray();
|
||||
const int torId = item->data( 0, TORRENTID ).toInt();
|
||||
QSet<int> ids;
|
||||
tr_benc top;
|
||||
|
||||
ids << torId;
|
||||
tr_bencInitDict( &top, 1 );
|
||||
tr_bencDictAddStr( &top, "announce", url );
|
||||
|
||||
mySession.torrentSet( ids, "trackerRemove", &top );
|
||||
}
|
||||
|
||||
void
|
||||
Details :: onRemoveTrackerPushed( )
|
||||
{
|
||||
const QTreeWidgetItem * item = myTrackerTree->selectedItems().first();
|
||||
const bool isTier = item->data( 0, TRACKERID ).toInt() == -1;
|
||||
if( isTier )
|
||||
{
|
||||
for( int i = 0; i < item->childCount(); ++i )
|
||||
removeTracker( item->child( i ) );
|
||||
}
|
||||
else
|
||||
removeTracker( item );
|
||||
}
|
||||
|
||||
QWidget *
|
||||
Details :: createOptionsTab( )
|
||||
{
|
||||
|
@ -1109,21 +1270,63 @@ QWidget *
|
|||
Details :: createTrackerTab( )
|
||||
{
|
||||
QCheckBox * c;
|
||||
QPushButton * p;
|
||||
QWidget * top = new QWidget;
|
||||
QVBoxLayout * v = new QVBoxLayout( top );
|
||||
QHBoxLayout * h = new QHBoxLayout();
|
||||
QVBoxLayout * v2 = new QVBoxLayout();
|
||||
|
||||
v->setSpacing( HIG :: PAD_BIG );
|
||||
v->setSpacing( HIG::PAD_BIG );
|
||||
v->setContentsMargins( HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG );
|
||||
|
||||
h->setSpacing( HIG::PAD );
|
||||
h->setContentsMargins( HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL );
|
||||
|
||||
v2->setSpacing( HIG::PAD );
|
||||
|
||||
QStringList headers;
|
||||
headers << tr("Trackers");
|
||||
myTrackerTree = new QTreeWidget;
|
||||
myTrackerTree->setHeaderLabels( headers );
|
||||
myTrackerTree->setSelectionMode( QTreeWidget::NoSelection );
|
||||
myTrackerTree->setSelectionMode( QTreeWidget::SingleSelection );
|
||||
myTrackerTree->setRootIsDecorated( false );
|
||||
myTrackerTree->setIndentation( 2 );
|
||||
myTrackerTree->setItemsExpandable( false );
|
||||
myTrackerTree->setTextElideMode( Qt::ElideRight );
|
||||
myTrackerTree->setAlternatingRowColors( true );
|
||||
v->addWidget( myTrackerTree, 1 );
|
||||
connect( myTrackerTree, SIGNAL(itemSelectionChanged()), this, SLOT(onTrackerSelectionChanged()));
|
||||
h->addWidget( myTrackerTree, 1 );
|
||||
|
||||
p = new QPushButton();
|
||||
p->setIcon( getStockIcon( "list-add", QStyle::SP_DialogOpenButton ) );
|
||||
p->setToolTip( "Add Tracker" );
|
||||
myAddTrackerButton = p;
|
||||
v2->addWidget( p, 1 );
|
||||
connect( p, SIGNAL(clicked(bool)), this, SLOT(onAddTrackerPushed()));
|
||||
|
||||
p = new QPushButton();
|
||||
p->setIcon( getStockIcon( "document-properties", QStyle::SP_DesktopIcon ) );
|
||||
p->setToolTip( "Edit Tracker" );
|
||||
myAddTrackerButton = p;
|
||||
p->setEnabled( false );
|
||||
myEditTrackerButton = p;
|
||||
v2->addWidget( p, 1 );
|
||||
connect( p, SIGNAL(clicked(bool)), this, SLOT(onEditTrackerPushed()));
|
||||
|
||||
p = new QPushButton();
|
||||
p->setIcon( getStockIcon( "list-remove", QStyle::SP_TrashIcon ) );
|
||||
p->setToolTip( "Remove Trackers" );
|
||||
p->setEnabled( false );
|
||||
myRemoveTrackerButton = p;
|
||||
v2->addWidget( p, 1 );
|
||||
connect( p, SIGNAL(clicked(bool)), this, SLOT(onRemoveTrackerPushed()));
|
||||
|
||||
v2->addStretch( 1 );
|
||||
|
||||
h->addLayout( v2, 1 );
|
||||
h->setStretch( 1, 0 );
|
||||
|
||||
v->addLayout( h, 1 );
|
||||
|
||||
c = new QCheckBox( tr( "Show &more details" ) );
|
||||
c->setChecked( myPrefs.getBool( Prefs::SHOW_TRACKER_SCRAPES ) );
|
||||
|
@ -1131,12 +1334,6 @@ Details :: createTrackerTab( )
|
|||
v->addWidget( c, 1 );
|
||||
connect( c, SIGNAL(clicked(bool)), this, SLOT(onShowTrackerScrapesToggled(bool)) );
|
||||
|
||||
c = new QCheckBox( tr( "Show &backup trackers" ) );
|
||||
c->setChecked( myPrefs.getBool( Prefs::SHOW_BACKUP_TRACKERS ) );
|
||||
myShowBackupTrackersCheck = c;
|
||||
v->addWidget( c, 1 );
|
||||
connect( c, SIGNAL(clicked(bool)), this, SLOT(onShowBackupTrackersToggled(bool)) );
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
|
|
25
qt/details.h
25
qt/details.h
|
@ -41,6 +41,15 @@ class Details: public QDialog
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
TRACKERID = Qt::UserRole,
|
||||
TRACKERURL,
|
||||
TRACKERTIER,
|
||||
TORRENTID
|
||||
};
|
||||
|
||||
private slots:
|
||||
void onTorrentChanged( );
|
||||
void onTimer( );
|
||||
|
@ -58,12 +67,14 @@ class Details: public QDialog
|
|||
QWidget * createOptionsTab( );
|
||||
|
||||
private:
|
||||
QIcon getStockIcon( const QString& freedesktop_name, int fallback );
|
||||
QString timeToStringRounded( int seconds );
|
||||
QString trimToDesiredWidth( const QString& str );
|
||||
void enableWhenChecked( QCheckBox *, QWidget * );
|
||||
bool findTrackerByURL( const QString& url, int torId );
|
||||
void removeTracker( const QTreeWidgetItem * item );
|
||||
|
||||
private:
|
||||
|
||||
Session& mySession;
|
||||
Prefs& myPrefs;
|
||||
TorrentModel& myModel;
|
||||
|
@ -87,7 +98,9 @@ class Details: public QDialog
|
|||
QCheckBox * mySingleDownCheck;
|
||||
QCheckBox * mySingleUpCheck;
|
||||
QCheckBox * myShowTrackerScrapesCheck;
|
||||
QCheckBox * myShowBackupTrackersCheck;
|
||||
QPushButton * myAddTrackerButton;
|
||||
QPushButton * myEditTrackerButton;
|
||||
QPushButton * myRemoveTrackerButton;
|
||||
QSpinBox * mySingleDownSpin;
|
||||
QSpinBox * mySingleUpSpin;
|
||||
QRadioButton * mySeedGlobalRadio;
|
||||
|
@ -115,7 +128,8 @@ class Details: public QDialog
|
|||
|
||||
QTreeWidget * myTrackerTree;
|
||||
QTreeWidget * myPeerTree;
|
||||
QMap<QString,QTreeWidgetItem*> myTrackerStats;
|
||||
QMap<QString,QTreeWidgetItem*> myTrackerTiers;
|
||||
QMap<QString,QTreeWidgetItem*> myTrackerItems;
|
||||
QMap<QString,QTreeWidgetItem*> myPeers;
|
||||
QWidgetList myWidgets;
|
||||
|
||||
|
@ -132,8 +146,11 @@ class Details: public QDialog
|
|||
void onUploadLimitChanged( int );
|
||||
void onSeedUntilChanged( bool );
|
||||
void onSeedRatioLimitChanged( double );
|
||||
void onShowBackupTrackersToggled( bool );
|
||||
void onShowTrackerScrapesToggled( bool );
|
||||
void onTrackerSelectionChanged( );
|
||||
void onAddTrackerPushed( );
|
||||
void onEditTrackerPushed( );
|
||||
void onRemoveTrackerPushed( );
|
||||
void onMaxPeersChanged( int );
|
||||
void refresh( );
|
||||
};
|
||||
|
|
|
@ -42,7 +42,6 @@ Prefs::PrefItem Prefs::myItems[] =
|
|||
{ SORT_MODE, "sort-mode", TrTypes::SortModeType },
|
||||
{ SORT_REVERSED, "sort-reversed", QVariant::Bool },
|
||||
{ COMPACT_VIEW, "compact-view", QVariant::Bool },
|
||||
{ SHOW_BACKUP_TRACKERS, "show-backup-trackers", QVariant::Bool },
|
||||
{ FILTERBAR, "show-filterbar", QVariant::Bool },
|
||||
{ STATUSBAR, "show-statusbar", QVariant::Bool },
|
||||
{ STATUSBAR_STATS, "statusbar-stats", QVariant::String },
|
||||
|
@ -244,7 +243,6 @@ Prefs :: initDefaults( tr_benc * d )
|
|||
tr_bencDictAddInt( d, keyStr(BLOCKLIST_DATE), 0 );
|
||||
tr_bencDictAddInt( d, keyStr(BLOCKLIST_UPDATES_ENABLED), true );
|
||||
tr_bencDictAddStr( d, keyStr(OPEN_DIALOG_FOLDER), QDir::home().absolutePath().toLatin1() );
|
||||
tr_bencDictAddInt( d, keyStr(SHOW_BACKUP_TRACKERS), false );
|
||||
tr_bencDictAddInt( d, keyStr(SHOW_TRACKER_SCRAPES), false );
|
||||
tr_bencDictAddInt( d, keyStr(TOOLBAR), true );
|
||||
tr_bencDictAddInt( d, keyStr(FILTERBAR), true );
|
||||
|
|
|
@ -45,7 +45,6 @@ class Prefs: public QObject
|
|||
SORT_MODE,
|
||||
SORT_REVERSED,
|
||||
COMPACT_VIEW,
|
||||
SHOW_BACKUP_TRACKERS,
|
||||
FILTERBAR,
|
||||
STATUSBAR,
|
||||
STATUSBAR_STATS,
|
||||
|
|
|
@ -418,6 +418,20 @@ Session :: torrentSet( const QSet<int>& ids, const QString& key, const QList<int
|
|||
tr_bencFree( &top );
|
||||
}
|
||||
|
||||
void
|
||||
Session :: torrentSet( const QSet<int>& ids, const QString& key, const tr_benc * value )
|
||||
{
|
||||
tr_benc top;
|
||||
tr_bencInitDict( &top, 2 );
|
||||
tr_bencDictAddStr( &top, "method", "torrent-set" );
|
||||
tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) );
|
||||
addOptionalIds( args, ids );
|
||||
tr_benc * child( tr_bencDictAdd( args, key.toUtf8().constData() ) );
|
||||
memcpy( child, value, sizeof(tr_benc) );
|
||||
exec( &top );
|
||||
tr_bencFree( &top );
|
||||
}
|
||||
|
||||
void
|
||||
Session :: torrentSetLocation( const QSet<int>& ids, const QString& location, bool doMove )
|
||||
{
|
||||
|
|
|
@ -100,6 +100,7 @@ class Session: public QObject
|
|||
void torrentSet( const QSet<int>& ids, const QString& key, int val );
|
||||
void torrentSet( const QSet<int>& ids, const QString& key, double val );
|
||||
void torrentSet( const QSet<int>& ids, const QString& key, const QList<int>& val );
|
||||
void torrentSet( const QSet<int>& ids, const QString& key, const tr_benc * value );
|
||||
void torrentSetLocation( const QSet<int>& ids, const QString& path, bool doMove );
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue