source: trunk/qt/details.cc @ 8221

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

(trunk qt) first stab at getting the properties dialog's "options" controls operational.

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