source: trunk/qt/details.cc @ 8232

Last change on this file since 8232 was 8232, checked in by charles, 13 years ago

(trunk qt) clean up #includes

File size: 22.2 KB
Line 
1/*
2 * This file Copyright (C) 2009 Charles Kerr <charles@transmissionbt.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id:$
11 */
12
13#include <cassert>
14#include <ctime>
15#include <iostream>
16
17#include <QCheckBox>
18#include <QEvent>
19#include <QHeaderView>
20#include <QResizeEvent>
21#include <QDialogButtonBox>
22#include <QDoubleSpinBox>
23#include <QFont>
24#include <QFontMetrics>
25#include <QHBoxLayout>
26#include <QVBoxLayout>
27#include <QLabel>
28#include <QLocale>
29#include <QPushButton>
30#include <QSpinBox>
31#include <QRadioButton>
32#include <QStyle>
33#include <QTabWidget>
34#include <QTreeView>
35#include <QTextBrowser>
36#include <QDateTime>
37#include <QTreeWidget>
38#include <QTreeWidgetItem>
39#include <QVBoxLayout>
40#include <QHBoxLayout>
41
42#include <libtransmission/transmission.h>
43
44#include "details.h"
45#include "file-tree.h"
46#include "hig.h"
47#include "session.h"
48#include "squeezelabel.h"
49#include "torrent.h"
50#include "utils.h"
51
52class Prefs;
53class Session;
54
55/****
56*****
57****/
58
59namespace
60{
61    const int REFRESH_INTERVAL_MSEC = 4000;
62
63    enum // peer columns
64    {
65        COL_LOCK,
66        COL_UP,
67        COL_DOWN,
68        COL_PERCENT,
69        COL_STATUS,
70        COL_ADDRESS,
71        COL_CLIENT,
72        N_COLUMNS
73    };
74}
75
76/***
77****
78***/
79
80class PeerItem: public QTreeWidgetItem
81{
82        Peer peer;
83        int quads[4];
84        QString status;
85
86        bool quadsLessThan( const PeerItem * that ) const {
87            for( int i=0; i<4; ++i ) {
88                if( quads[i] < that->quads[i] ) return true;
89                if( quads[i] > that->quads[i] ) return false;
90            }
91            return false;
92        }
93
94    public:
95        PeerItem( ) { }
96        virtual ~PeerItem( ) { }
97
98    public:
99        void setStatus( const QString& s ) {
100            status = s;
101        }
102        void setPeer( const Peer& p ) {
103            peer = p;
104            const QStringList tokens( p.address.split(".") );
105            for( int i=0; i<4; ++i )
106                quads[i] = tokens.at(i).toInt();
107        }
108        virtual bool operator< ( const QTreeWidgetItem & other ) const {
109            const PeerItem * that = dynamic_cast<const PeerItem*>(&other);
110            QTreeWidget * tw( treeWidget( ) );
111            const int column = tw ? tw->sortColumn() : 0;
112            switch( column ) {
113                case COL_UP: return peer.rateToPeer < that->peer.rateToPeer;
114                case COL_DOWN: return peer.rateToClient < that->peer.rateToClient;
115                case COL_PERCENT: return peer.progress < that->peer.progress;
116                case COL_STATUS: return status < that->status;
117                case COL_ADDRESS: return quadsLessThan( that );
118                case COL_CLIENT: return peer.clientName < that->peer.clientName;
119                default: /*COL_LOCK*/ return peer.isEncrypted && !that->peer.isEncrypted;
120            }
121        }
122};
123
124/***
125****
126***/
127
128Details :: Details( Session& session, Torrent& torrent, QWidget * parent ):
129    QDialog( parent, Qt::Dialog ),
130    mySession( session ),
131    myTorrent( torrent )
132{
133    QVBoxLayout * layout = new QVBoxLayout( this );
134
135    setWindowTitle( tr( "%1 Properties" ).arg( torrent.name( ) ) );
136
137    QTabWidget * t = new QTabWidget( this );
138    t->addTab( createActivityTab( ),  tr( "Activity" ) );
139    t->addTab( createPeersTab( ),     tr( "Peers" ) );
140    t->addTab( createTrackerTab( ),   tr( "Tracker" ) );
141    t->addTab( createInfoTab( ),      tr( "Information" ) );
142    t->addTab( createFilesTab( ),     tr( "Files" ) );
143    t->addTab( createOptionsTab( ),   tr( "Options" ) );
144    layout->addWidget( t );
145
146    QDialogButtonBox * buttons = new QDialogButtonBox( QDialogButtonBox::Close, Qt::Horizontal, this );
147    connect( buttons, SIGNAL(rejected()), this, SLOT(deleteLater()) ); // "close" triggers rejected
148    layout->addWidget( buttons );
149
150    connect( &myTorrent, SIGNAL(torrentChanged(int)), this, SLOT(onTorrentChanged()) );
151    connect( &myTorrent, SIGNAL(destroyed(QObject*)), this, SLOT(deleteLater()) );
152    connect( &myTimer, SIGNAL(timeout()), this, SLOT(onTimer()) );
153
154    onTimer( );
155    myTimer.setSingleShot( false );
156    myTimer.start( REFRESH_INTERVAL_MSEC );
157}
158   
159Details :: ~Details( )
160{
161}
162
163/***
164****
165***/
166
167void
168Details :: onTimer( )
169{
170    mySession.refreshExtraStats( myTorrent.id( ) );
171}
172
173void
174Details :: onTorrentChanged( )
175{
176    QLocale locale;
177    const QFontMetrics fm( fontMetrics( ) );
178
179    // activity tab
180    myStateLabel->setText( myTorrent.activityString( ) );
181    myProgressLabel->setText( locale.toString( myTorrent.percentDone( )*100.0, 'f', 2 ) );
182    myHaveLabel->setText( tr( "%1 (%2 verified in %L3 pieces)" )
183                            .arg( Utils::sizeToString( myTorrent.haveTotal( ) ) )
184                            .arg( Utils::sizeToString( myTorrent.haveVerified( ) ) )
185                            .arg( myTorrent.haveVerified()/myTorrent.pieceSize() ) );
186    myDownloadedLabel->setText( Utils::sizeToString( myTorrent.downloadedEver( ) ) );
187    myUploadedLabel->setText( Utils::sizeToString( myTorrent.uploadedEver( ) ) );
188    myFailedLabel->setText( Utils::sizeToString( myTorrent.failedEver( ) ) );
189    myRatioLabel->setText( Utils :: ratioToString( myTorrent.ratio( ) ) );
190    mySwarmSpeedLabel->setText( Utils::speedToString( myTorrent.swarmSpeed( ) ) );
191    myAddedDateLabel->setText( myTorrent.dateAdded().toString() );
192
193    QDateTime dt = myTorrent.lastActivity( );
194    myActivityLabel->setText( dt.isNull() ? tr("Never") : dt.toString() );
195    QString s = myTorrent.getError( );
196    myErrorLabel->setText( s.isEmpty() ? tr("None") : s );
197
198    // information tab
199    myPiecesLabel->setText( tr( "%L1 Pieces @ %2" ).arg( myTorrent.pieceCount() )
200                                                   .arg( Utils::sizeToString(myTorrent.pieceSize()) ) );
201    myHashLabel->setText( myTorrent.hashString( ) );
202
203    myPrivacyLabel->setText( myTorrent.isPrivate( ) ? tr( "Private to this tracker -- PEX disabled" )
204                                                    : tr( "Public torrent" ) );
205    myCommentBrowser->setText( myTorrent.comment( ) );
206    QString str = myTorrent.creator( );
207    if( str.isEmpty( ) )
208        str = tr( "Unknown" );
209    myCreatorLabel->setText( str );
210    myDateCreatedLabel->setText( myTorrent.dateCreated( ).toString( ) );
211    myDestinationLabel->setText( myTorrent.getPath( ) );
212    myTorrentFileLabel->setText( myTorrent.torrentFile( ) );
213
214    // options tab
215    mySessionLimitCheck->setChecked( myTorrent.honorsSessionLimits( ) );
216    mySingleDownCheck->setChecked( myTorrent.downloadIsLimited( ) );
217    mySingleUpCheck->setChecked( myTorrent.uploadIsLimited( ) );
218    mySingleDownSpin->setValue( (int)myTorrent.downloadLimit().kbps() );
219    mySingleUpSpin->setValue( (int)myTorrent.uploadLimit().kbps() );
220    myPeerLimitSpin->setValue( myTorrent.peerLimit( ) );
221
222    QRadioButton * rb;
223    switch( myTorrent.seedRatioMode( ) ) {
224        case TR_RATIOLIMIT_GLOBAL:    rb = mySeedGlobalRadio; break;
225        case TR_RATIOLIMIT_SINGLE:    rb = mySeedCustomRadio; break;
226        case TR_RATIOLIMIT_UNLIMITED: rb = mySeedForeverRadio; break;
227    }
228    rb->setChecked( true );
229    mySeedCustomSpin->setValue( myTorrent.seedRatioLimit( ) );
230
231
232    // tracker tab
233    const time_t now( time( 0 ) );
234    myScrapeTimePrevLabel->setText( myTorrent.lastScrapeTime().toString() );
235    myScrapeResponseLabel->setText( myTorrent.scrapeResponse() );
236    myScrapeTimeNextLabel->setText( Utils :: timeToString( myTorrent.nextScrapeTime().toTime_t() - now ) );
237    myAnnounceTimePrevLabel->setText( myTorrent.lastScrapeTime().toString() );
238    myAnnounceTimeNextLabel->setText( Utils :: timeToString( myTorrent.nextAnnounceTime().toTime_t() - now ) );
239    myAnnounceManualLabel->setText( Utils :: timeToString( myTorrent.manualAnnounceTime().toTime_t() - now ) );
240    myAnnounceResponseLabel->setText( myTorrent.announceResponse( ) );
241    const QUrl url( myTorrent.announceUrl( ) );
242    myTrackerLabel->setText( url.host( ) );
243
244    // peers tab
245    mySeedersLabel->setText( locale.toString( myTorrent.seeders( ) ) );
246    myLeechersLabel->setText( locale.toString( myTorrent.leechers( ) ) );
247    myTimesCompletedLabel->setText( locale.toString( myTorrent.timesCompleted( ) ) );
248    const PeerList peers( myTorrent.peers( ) );
249    QMap<QString,QTreeWidgetItem*> peers2;
250    QList<QTreeWidgetItem*> newItems;
251    static const QIcon myEncryptionIcon( ":/icons/encrypted.png" );
252    static const QIcon myEmptyIcon;
253    foreach( const Peer& peer, peers )
254    {
255        PeerItem * item = (PeerItem*) myPeers.value( peer.address, 0 );
256        if( item == 0 ) { // new peer has connected
257            item = new PeerItem;
258            item->setTextAlignment( COL_UP, Qt::AlignRight );
259            item->setTextAlignment( COL_DOWN, Qt::AlignRight );
260            item->setTextAlignment( COL_PERCENT, Qt::AlignRight );
261            newItems << item;
262        }
263
264        QString code;
265        if( peer.isDownloadingFrom )                           { code += 'D'; }
266        else if( peer.clientIsInterested )                     { code += 'd'; }
267        if( peer.isUploadingTo )                               { code += 'U'; }
268        else if( peer.peerIsInterested )                       { code += 'u'; }
269        if( !peer.clientIsChoked && !peer.clientIsInterested ) { code += 'K'; }
270        if( !peer.peerIsChoked && !peer.peerIsInterested )     { code += '?'; }
271        if( peer.isEncrypted )                                 { code += 'E'; }
272        if( peer.isIncoming )                                  { code += 'I'; }
273
274        item->setPeer( peer );
275        item->setStatus( code );
276
277        QString codeTip;
278        foreach( QChar ch, code ) {
279            QString txt;
280            switch( ch.toAscii() ) {
281                case 'O': txt = tr( "Optimistic unchoke" ); break;
282                case 'D': txt = tr( "Downloading from this peer" ); break;
283                case 'd': txt = tr( "We would download from this peer if they would let us" ); break;
284                case 'U': txt = tr( "Uploading to peer" ); break;
285                case 'u': txt = tr( "We would upload to this peer if they asked" ); break;
286                case 'K': txt = tr( "Peer has unchoked us, but we're not interested" ); break;
287                case '?': txt = tr( "We unchoked this peer, but they're not interested" ); break;
288                case 'E': txt = tr( "Encrypted connection" ); break;
289                case 'X': txt = tr( "Peer was discovered through Peer Exchange (PEX)" ); break;
290                case 'I': txt = tr( "Peer is an incoming connection" ); break;
291            }
292            if( !txt.isEmpty( ) )
293                codeTip += QString("%1: %2\n").arg(ch).arg(txt);
294        }
295        if( !codeTip.isEmpty() )
296            codeTip.resize( codeTip.size()-1 ); // eat the trailing linefeed
297
298        item->setIcon( COL_LOCK, peer.isEncrypted ? myEncryptionIcon : myEmptyIcon );
299        item->setToolTip( COL_LOCK, peer.isEncrypted ? tr( "Encrypted connection" ) : "" );
300        item->setText( COL_UP, peer.rateToPeer.isZero() ? "" : Utils::speedToString( peer.rateToPeer ) );
301        item->setText( COL_DOWN, peer.rateToClient.isZero() ? "" : Utils::speedToString( peer.rateToClient ) );
302        item->setText( COL_PERCENT, peer.progress > 0 ? QString( "%1%" ).arg( locale.toString((int)(peer.progress*100.0))) : "" );
303        item->setText( COL_STATUS, code );
304        item->setToolTip( COL_STATUS, codeTip );
305        item->setText( COL_ADDRESS, peer.address );
306        item->setText( COL_CLIENT, peer.clientName );
307        peers2.insert( peer.address, item );
308    }
309    myPeerTree->addTopLevelItems( newItems );
310    foreach( QString key, myPeers.keys() ) {
311        if( !peers2.contains( key ) ) { // old peer has disconnected
312            QTreeWidgetItem * item = myPeers.value( key, 0 );
313            myPeerTree->takeTopLevelItem( myPeerTree->indexOfTopLevelItem( item ) );
314            delete item;
315        }
316    }
317    myPeers = peers2;
318
319    myFileTreeView->update( myTorrent.files( ) );
320}
321
322void
323Details :: enableWhenChecked( QCheckBox * box, QWidget * w )
324{
325    connect( box, SIGNAL(toggled(bool)), w, SLOT(setEnabled(bool)) );
326    w->setEnabled( box->isChecked( ) );
327}
328
329
330/***
331****
332***/
333
334QWidget *
335Details :: createActivityTab( )
336{
337    HIG * hig = new HIG( this );
338
339    hig->addSectionTitle( tr( "Transfer" ) );
340    hig->addRow( tr( "State:" ), myStateLabel = new SqueezeLabel );
341    hig->addRow( tr( "Progress:" ), myProgressLabel = new SqueezeLabel );
342    hig->addRow( tr( "Have:" ), myHaveLabel = new SqueezeLabel );
343    hig->addRow( tr( "Downloaded:" ), myDownloadedLabel = new SqueezeLabel );
344    hig->addRow( tr( "Uploaded:" ), myUploadedLabel = new SqueezeLabel );
345    hig->addRow( tr( "Failed DL:" ), myFailedLabel = new SqueezeLabel );
346    hig->addRow( tr( "Ratio:" ), myRatioLabel = new SqueezeLabel );
347    hig->addRow( tr( "Swarm Rate:" ), mySwarmSpeedLabel = new SqueezeLabel );
348    hig->addRow( tr( "Error:" ), myErrorLabel = new SqueezeLabel );
349    hig->addSectionDivider( );
350
351    hig->addSectionTitle( tr( "Dates" ) );
352    hig->addRow( tr( "Added on:" ), myAddedDateLabel = new SqueezeLabel );
353    hig->addRow( tr( "Last activity on:" ), myActivityLabel = new SqueezeLabel );
354    hig->finish( );
355
356    return hig;
357}
358
359/***
360****
361***/
362
363void
364Details :: onHonorsSessionLimitsToggled( bool val )
365{
366    mySession.torrentSet( myTorrent.id(), "honorsSessionLimits", val );
367}
368void
369Details :: onDownloadLimitedToggled( bool val )
370{
371    mySession.torrentSet( myTorrent.id(), "downloadLimited", val );
372}
373void
374Details :: onDownloadLimitChanged( int val )
375{
376    mySession.torrentSet( myTorrent.id(), "downloadLimit", val );
377}
378void
379Details :: onUploadLimitedToggled( bool val )
380{
381    mySession.torrentSet( myTorrent.id(), "uploadLimited", val );
382}
383void
384Details :: onUploadLimitChanged( int val )
385{
386    mySession.torrentSet( myTorrent.id(), "uploadLimit", val );
387}
388
389#define RATIO_KEY "seedRatioMode"
390
391void
392Details :: onSeedUntilChanged( bool b )
393{
394    if( b )
395        mySession.torrentSet( myTorrent.id(), RATIO_KEY, sender()->property(RATIO_KEY).toInt() );
396}
397
398void
399Details :: onSeedRatioLimitChanged( double val )
400{
401    mySession.torrentSet( myTorrent.id(), "seedRatioLimit", val );
402}
403
404void
405Details :: onMaxPeersChanged( int val )
406{
407    mySession.torrentSet( myTorrent.id(), "peer-limit", val );
408}
409
410QWidget *
411Details :: createOptionsTab( )
412{
413    //QWidget * l;
414    QSpinBox * s;
415    QCheckBox * c;
416    QHBoxLayout * h;
417    QRadioButton * r;
418    QDoubleSpinBox * ds;
419
420    HIG * hig = new HIG( this );
421    hig->addSectionTitle( tr( "Speed Limits" ) );
422
423    c = new QCheckBox( tr( "Honor global &limits" ) );
424    mySessionLimitCheck = c;
425    hig->addWideControl( c );
426    connect( c, SIGNAL(toggled(bool)), this, SLOT(onHonorsSessionLimitsToggled(bool)) );
427
428    c = new QCheckBox( tr( "Limit &download speed (KB/s)" ) );
429    mySingleDownCheck = c;
430    s = new QSpinBox( );
431    mySingleDownSpin = s;
432    s->setRange( 0, INT_MAX );
433    hig->addRow( c, s );
434    enableWhenChecked( c, s );
435    connect( c, SIGNAL(toggled(bool)), this, SLOT(onDownloadLimitedToggled(bool)) );
436    connect( s, SIGNAL(valueChanged(int)), this, SLOT(onDownloadLimitChanged(int)));
437
438    c = new QCheckBox( tr( "Limit &upload speed (KB/s)" ) );
439    mySingleUpCheck = c;
440    s = new QSpinBox( );
441    mySingleUpSpin = s;
442    s->setRange( 0, INT_MAX );
443    hig->addRow( c, s );
444    enableWhenChecked( c, s );
445    connect( c, SIGNAL(toggled(bool)), this, SLOT(onUploadLimitedToggled(bool)) );
446    connect( s, SIGNAL(valueChanged(int)), this, SLOT(onUploadLimitChanged(int)));
447
448    hig->addSectionDivider( );
449    hig->addSectionTitle( tr( "Seed-Until Ratio" ) );
450
451    r = new QRadioButton( tr( "Use &global setting" ) );
452    r->setProperty( RATIO_KEY, TR_RATIOLIMIT_GLOBAL );
453    connect( r, SIGNAL(toggled(bool)), this, SLOT(onSeedUntilChanged(bool)));
454    mySeedGlobalRadio = r;
455    hig->addWideControl( r );
456
457    r = new QRadioButton( tr( "Seed &regardless of ratio" ) );
458    r->setProperty( RATIO_KEY, TR_RATIOLIMIT_UNLIMITED );
459    connect( r, SIGNAL(toggled(bool)), this, SLOT(onSeedUntilChanged(bool)));
460    mySeedForeverRadio = r;
461    hig->addWideControl( r );
462
463    h = new QHBoxLayout( );
464    h->setSpacing( HIG :: PAD );
465    r = new QRadioButton( tr( "&Stop seeding when a torrent's ratio reaches" ) );
466    r->setProperty( RATIO_KEY, TR_RATIOLIMIT_SINGLE );
467    connect( r, SIGNAL(toggled(bool)), this, SLOT(onSeedUntilChanged(bool)));
468    mySeedCustomRadio = r;
469    h->addWidget( r );
470    ds = new QDoubleSpinBox( );
471    ds->setRange( 0.5, INT_MAX );
472    connect( ds, SIGNAL(valueChanged(double)), this, SLOT(onSeedRatioLimitChanged(double)));
473    mySeedCustomSpin = ds;
474    h->addWidget( ds );
475    hig->addWideControl( h );
476
477    hig->addSectionDivider( );
478    hig->addSectionTitle( tr( "Peer Connections" ) );
479
480    s = new QSpinBox( );
481    s->setRange( 1, 300 );
482    connect( s, SIGNAL(valueChanged(int)), this, SLOT(onMaxPeersChanged(int)));
483    myPeerLimitSpin = s;
484    hig->addRow( tr( "&Maximum Peers" ), s );
485
486    hig->finish( );
487
488    return hig;
489}
490
491/***
492****
493***/
494
495QWidget *
496Details :: createInfoTab( )
497{
498    HIG * hig = new HIG( );
499    hig->addSectionTitle( tr( "Details" ) );
500    hig->addRow( tr( "Pieces:" ), myPiecesLabel = new SqueezeLabel );
501    hig->addRow( tr( "Hash:" ), myHashLabel = new SqueezeLabel );
502    hig->addRow( tr( "Privacy:" ), myPrivacyLabel = new SqueezeLabel );
503    hig->addRow( tr( "Comment:" ), myCommentBrowser = new QTextBrowser );
504    hig->addSectionDivider( );
505    hig->addSectionTitle( tr( "Origins" ) );
506    hig->addRow( tr( "Creator:" ), myCreatorLabel = new SqueezeLabel );
507    hig->addRow( tr( "Date:" ), myDateCreatedLabel = new SqueezeLabel );
508    hig->addSectionDivider( );
509    hig->addSectionTitle( tr( "Origins" ) );
510    hig->addRow( tr( "Destination folder:" ), myDestinationLabel = new SqueezeLabel );
511    hig->addRow( tr( "Torrent file:" ), myTorrentFileLabel = new SqueezeLabel );
512    const int h = QFontMetrics(myCommentBrowser->font()).lineSpacing() * 4;
513    myTorrentFileLabel->setMinimumWidth( 300 );
514    myTorrentFileLabel->setSizePolicy ( QSizePolicy::Expanding, QSizePolicy::Preferred );
515
516    myCommentBrowser->setMinimumHeight( h );
517    myCommentBrowser->setMaximumHeight( h );
518
519    hig->finish( );
520    return hig;
521}
522
523/***
524****
525***/
526
527QWidget *
528Details :: createTrackerTab( )
529{
530    HIG * hig = new HIG( );
531
532    hig->addSectionTitle( tr( "Scrape" ) );
533    hig->addRow( tr( "Last scrape at:" ), myScrapeTimePrevLabel = new SqueezeLabel );
534    hig->addRow( tr( "Tracker responded:" ), myScrapeResponseLabel = new SqueezeLabel );
535    hig->addRow( tr( "Next scrape in:" ), myScrapeTimeNextLabel = new SqueezeLabel );
536    hig->addSectionDivider( );
537    hig->addSectionTitle( tr( "Announce" ) );
538    hig->addRow( tr( "Tracker:" ), myTrackerLabel = new SqueezeLabel );
539    hig->addRow( tr( "Last announce at:" ), myAnnounceTimePrevLabel = new SqueezeLabel );
540    hig->addRow( tr( "Tracker responded:" ), myAnnounceResponseLabel = new SqueezeLabel );
541    hig->addRow( tr( "Next announce in:" ), myAnnounceTimeNextLabel = new SqueezeLabel );
542    hig->addRow( tr( "Manual announce allowed in:" ), myAnnounceManualLabel = new SqueezeLabel );
543    hig->finish( );
544
545    myTrackerLabel->setScaledContents( true );
546
547    return hig;
548}
549
550/***
551****
552***/
553
554QWidget *
555Details :: createPeersTab( )
556{
557    QWidget * top = new QWidget;
558    QVBoxLayout * v = new QVBoxLayout( top );
559    v->setSpacing( HIG :: PAD_BIG );
560    v->setContentsMargins( HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG );
561
562    QStringList headers;
563    headers << QString() << tr("Up") << tr("Down") << tr("%") << tr("Status") << tr("Address") << tr("Client");
564    myPeerTree = new QTreeWidget;
565    myPeerTree->setUniformRowHeights( true );
566    myPeerTree->setHeaderLabels( headers );
567    myPeerTree->setColumnWidth( 0, 20 );
568    myPeerTree->setSortingEnabled( true );
569    myPeerTree->setRootIsDecorated( false );
570    myPeerTree->setTextElideMode( Qt::ElideRight );
571    v->addWidget( myPeerTree, 1 );
572
573    const QFontMetrics m( font( ) );
574    QSize size = m.size( 0, "1024 MB/s" );
575    myPeerTree->setColumnWidth( COL_UP, size.width( ) );
576    myPeerTree->setColumnWidth( COL_DOWN, size.width( ) );
577    size = m.size( 0, " 100% " );
578    myPeerTree->setColumnWidth( COL_PERCENT, size.width( ) );
579    size = m.size( 0, "ODUK?EXI" );
580    myPeerTree->setColumnWidth( COL_STATUS, size.width( ) );
581    size = m.size( 0, "888.888.888.888" );
582    myPeerTree->setColumnWidth( COL_ADDRESS, size.width( ) );
583    size = m.size( 0, "Some BitTorrent Client" );
584    myPeerTree->setColumnWidth( COL_CLIENT, size.width( ) );
585    //myPeerTree->sortItems( myTorrent.isDone() ? COL_UP : COL_DOWN, Qt::DescendingOrder );
586    myPeerTree->setAlternatingRowColors( true );
587
588    QHBoxLayout * h = new QHBoxLayout;
589    h->setSpacing( HIG :: PAD );
590    v->addLayout( h );
591
592    QLabel * l = new QLabel( "Seeders:" );
593    l->setStyleSheet( "font: bold" );
594    h->addWidget( l );
595    l = mySeedersLabel = new QLabel( "a" );
596    h->addWidget( l );
597    h->addStretch( 1 );
598   
599    l = new QLabel( "Leechers:" );
600    l->setStyleSheet( "font: bold" );
601    h->addWidget( l );
602    l = myLeechersLabel = new QLabel( "b" );
603    h->addWidget( l );
604    h->addStretch( 1 );
605   
606    l = new QLabel( "Times Completed:" );
607    l->setStyleSheet( "font: bold" );
608    h->addWidget( l );
609    l = myTimesCompletedLabel = new QLabel( "c" );
610    h->addWidget( l );
611
612    return top;
613}
614
615/***
616****
617***/
618
619QWidget *
620Details :: createFilesTab( )
621{
622    myFileTreeView = new FileTreeView( );
623
624    connect( myFileTreeView, SIGNAL(      priorityChanged(const QSet<int>&, int)),
625             this,           SLOT(  onFilePriorityChanged(const QSet<int>&, int)));
626
627    connect( myFileTreeView, SIGNAL(      wantedChanged(const QSet<int>&, bool)),
628             this,           SLOT(  onFileWantedChanged(const QSet<int>&, bool)));
629
630    return myFileTreeView;
631}
632
633void
634Details :: onFilePriorityChanged( const QSet<int>& indices, int priority )
635{
636    QString key;
637    switch( priority ) {
638        case TR_PRI_LOW:   key = "priority-low"; break;
639        case TR_PRI_HIGH:  key = "priority-high"; break;
640        default:           key = "priority-normal"; break;
641    }
642    mySession.torrentSet( myTorrent.id( ), key, indices.toList( ) );
643}
644
645void
646Details :: onFileWantedChanged( const QSet<int>& indices, bool wanted )
647{
648    QString key( wanted ? "files-wanted" : "files-unwanted" );
649    mySession.torrentSet( myTorrent.id( ), key, indices.toList( ) );
650}
Note: See TracBrowser for help on using the repository browser.