Changeset 8255


Ignore:
Timestamp:
Apr 18, 2009, 11:18:28 PM (13 years ago)
Author:
charles
Message:

(trunk qt) handle multiple torrent selection in the properties dialog

Location:
trunk/qt
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/qt/details.cc

    r8245 r8255  
    1616
    1717#include <QCheckBox>
     18#include <QComboBox>
    1819#include <QEvent>
    1920#include <QHeaderView>
     
    4849#include "squeezelabel.h"
    4950#include "torrent.h"
     51#include "torrent-model.h"
    5052#include "utils.h"
    5153
     
    120122***/
    121123
    122 Details :: Details( Session& session, Torrent& torrent, QWidget * parent ):
     124Details :: Details( Session& session, TorrentModel& model, QWidget * parent ):
    123125    QDialog( parent, Qt::Dialog ),
    124126    mySession( session ),
    125     myTorrent( torrent )
     127    myModel( model ),
     128    myHavePendingRefresh( false )
    126129{
    127130    QVBoxLayout * layout = new QVBoxLayout( this );
    128131
    129     setWindowTitle( tr( "%1 Properties" ).arg( torrent.name( ) ) );
     132    setWindowTitle( tr( "Torrent Properties" ) );
    130133
    131134    QTabWidget * t = new QTabWidget( this );
    132     t->addTab( createActivityTab( ),  tr( "Activity" ) );
    133     t->addTab( createPeersTab( ),     tr( "Peers" ) );
    134     t->addTab( createTrackerTab( ),   tr( "Tracker" ) );
    135     t->addTab( createInfoTab( ),      tr( "Information" ) );
    136     t->addTab( createFilesTab( ),     tr( "Files" ) );
    137     t->addTab( createOptionsTab( ),   tr( "Options" ) );
     135    QWidget * w;
     136    t->addTab( w = createActivityTab( ),  tr( "Activity" ) );
     137    myWidgets << w;
     138    t->addTab( w = createPeersTab( ),     tr( "Peers" ) );
     139    myWidgets << w;
     140    t->addTab( w = createTrackerTab( ),   tr( "Tracker" ) );
     141    myWidgets << w;
     142    t->addTab( w = createInfoTab( ),      tr( "Information" ) );
     143    myWidgets << w;
     144    t->addTab( w = createFilesTab( ),     tr( "Files" ) );
     145    myWidgets << w;
     146    t->addTab( w = createOptionsTab( ),   tr( "Options" ) );
     147    myWidgets << w;
    138148    layout->addWidget( t );
    139149
     
    142152    layout->addWidget( buttons );
    143153
    144     connect( &myTorrent, SIGNAL(torrentChanged(int)), this, SLOT(onTorrentChanged()) );
    145     connect( &myTorrent, SIGNAL(destroyed(QObject*)), this, SLOT(deleteLater()) );
    146154    connect( &myTimer, SIGNAL(timeout()), this, SLOT(onTimer()) );
    147155
     
    155163}
    156164
     165void
     166Details :: setIds( const QSet<int>& ids )
     167{
     168    if( ids == myIds )
     169        return;
     170
     171    // stop listening to the old torrents
     172    foreach( int id, myIds ) {
     173        const Torrent * tor = myModel.getTorrentFromId( id );
     174        if( tor )
     175            disconnect( tor, SIGNAL(torrentChanged(int)), this, SLOT(onTorrentChanged()) );
     176    }
     177
     178    myIds = ids;
     179
     180    // listen to the new torrents
     181    foreach( int id, myIds ) {
     182        const Torrent * tor = myModel.getTorrentFromId( id );
     183        if( tor )
     184            connect( tor, SIGNAL(torrentChanged(int)), this, SLOT(onTorrentChanged()) );
     185    }
     186
     187    foreach( QWidget * w, myWidgets )
     188        w->setEnabled( false );
     189   
     190    onTimer( );
     191}
     192
    157193/***
    158194****
     
    162198Details :: onTimer( )
    163199{
    164     mySession.refreshExtraStats( myTorrent.id( ) );
     200    if( !myIds.empty( ) )
     201        mySession.refreshExtraStats( myIds );
    165202}
    166203
     
    168205Details :: onTorrentChanged( )
    169206{
     207    if( !myHavePendingRefresh ) {
     208        myHavePendingRefresh = true;
     209        QTimer::singleShot( 100, this, SLOT(refresh()));
     210    }
     211}
     212
     213
     214void
     215Details :: refresh( )
     216{
     217    int i;
    170218    QLocale locale;
     219    const int n = myIds.size( );
     220    const bool single = n == 1;
     221    const QString blank;
    171222    const QFontMetrics fm( fontMetrics( ) );
    172 
    173     // activity tab
    174     myStateLabel->setText( myTorrent.activityString( ) );
    175     myProgressLabel->setText( locale.toString( myTorrent.percentDone( )*100.0, 'f', 2 ) );
     223    QSet<const Torrent*> torrents;
     224    const Torrent * tor;
     225    QSet<QString> strings;
     226    QString string;
     227
     228    // build a list of torrents
     229    foreach( int id, myIds ) {
     230        const Torrent * tor = myModel.getTorrentFromId( id );
     231        if( tor )
     232            torrents << tor;
     233    }
     234
     235    ///
     236    ///  activity tab
     237    ///
     238
     239    // myStateLabel
     240    if( torrents.empty( ) )
     241        string = tr( "None" );
     242    else {
     243        strings.clear( );
     244        foreach( tor, torrents ) strings.insert( tor->activityString( ) );
     245        string = strings.size()==1 ? *strings.begin() : blank;
     246    }
     247    myStateLabel->setText( string );
     248
     249    // myProgressLabel
     250    if( torrents.empty( ) )
     251        string = tr( "None" );
     252    else {
     253        double sizeWhenDone = 0;
     254        double leftUntilDone = 0;
     255        foreach( tor, torrents ) {
     256            sizeWhenDone += tor->sizeWhenDone( );
     257            leftUntilDone += tor->leftUntilDone( );
     258        }
     259        string = locale.toString( 100.0*((sizeWhenDone-leftUntilDone)/sizeWhenDone), 'f', 2 );
     260    }
     261    myProgressLabel->setText( string );
     262
     263    // myHaveLabel
     264    int64_t haveTotal = 0;
     265    int64_t haveVerified = 0;
     266    int64_t verifiedPieces = 0;
     267    foreach( tor, torrents ) {
     268        haveTotal += tor->haveTotal( );
     269        haveVerified += tor->haveVerified( );
     270        verifiedPieces += tor->haveVerified( ) / tor->pieceSize( );
     271    }
    176272    myHaveLabel->setText( tr( "%1 (%2 verified in %L3 pieces)" )
    177                             .arg( Utils::sizeToString( myTorrent.haveTotal( ) ) )
    178                             .arg( Utils::sizeToString( myTorrent.haveVerified( ) ) )
    179                             .arg( myTorrent.haveVerified()/myTorrent.pieceSize() ) );
    180     myDownloadedLabel->setText( Utils::sizeToString( myTorrent.downloadedEver( ) ) );
    181     myUploadedLabel->setText( Utils::sizeToString( myTorrent.uploadedEver( ) ) );
    182     myFailedLabel->setText( Utils::sizeToString( myTorrent.failedEver( ) ) );
    183     myRatioLabel->setText( Utils :: ratioToString( myTorrent.ratio( ) ) );
    184     mySwarmSpeedLabel->setText( Utils::speedToString( myTorrent.swarmSpeed( ) ) );
    185     myAddedDateLabel->setText( myTorrent.dateAdded().toString() );
    186 
    187     QDateTime dt = myTorrent.lastActivity( );
    188     myActivityLabel->setText( dt.isNull() ? tr("Never") : dt.toString() );
    189     QString s = myTorrent.getError( );
    190     myErrorLabel->setText( s.isEmpty() ? tr("None") : s );
    191 
    192     // information tab
    193     myPiecesLabel->setText( tr( "%L1 Pieces @ %2" ).arg( myTorrent.pieceCount() )
    194                                                    .arg( Utils::sizeToString(myTorrent.pieceSize()) ) );
    195     myHashLabel->setText( myTorrent.hashString( ) );
    196 
    197     myPrivacyLabel->setText( myTorrent.isPrivate( ) ? tr( "Private to this tracker -- PEX disabled" )
    198                                                     : tr( "Public torrent" ) );
    199     myCommentBrowser->setText( myTorrent.comment( ) );
    200     QString str = myTorrent.creator( );
    201     if( str.isEmpty( ) )
    202         str = tr( "Unknown" );
    203     myCreatorLabel->setText( str );
    204     myDateCreatedLabel->setText( myTorrent.dateCreated( ).toString( ) );
    205     myDestinationLabel->setText( myTorrent.getPath( ) );
    206     myTorrentFileLabel->setText( myTorrent.torrentFile( ) );
    207 
    208     // options tab
    209     mySessionLimitCheck->setChecked( myTorrent.honorsSessionLimits( ) );
    210     mySingleDownCheck->setChecked( myTorrent.downloadIsLimited( ) );
    211     mySingleUpCheck->setChecked( myTorrent.uploadIsLimited( ) );
    212     mySingleDownSpin->setValue( (int)myTorrent.downloadLimit().kbps() );
    213     mySingleUpSpin->setValue( (int)myTorrent.uploadLimit().kbps() );
    214     myPeerLimitSpin->setValue( myTorrent.peerLimit( ) );
    215 
    216     QRadioButton * rb;
    217     switch( myTorrent.seedRatioMode( ) ) {
    218         case TR_RATIOLIMIT_GLOBAL:    rb = mySeedGlobalRadio; break;
    219         case TR_RATIOLIMIT_SINGLE:    rb = mySeedCustomRadio; break;
    220         case TR_RATIOLIMIT_UNLIMITED: rb = mySeedForeverRadio; break;
    221     }
    222     rb->setChecked( true );
    223     mySeedCustomSpin->setValue( myTorrent.seedRatioLimit( ) );
    224 
     273                            .arg( Utils::sizeToString( haveTotal ) )
     274                            .arg( Utils::sizeToString( haveVerified ) )
     275                            .arg( verifiedPieces ) );
     276
     277    int64_t num = 0;
     278    foreach( tor, torrents ) num += tor->downloadedEver( );
     279    myDownloadedLabel->setText( Utils::sizeToString( num ) );
     280
     281    num = 0;
     282    foreach( tor, torrents ) num += tor->uploadedEver( );
     283    myUploadedLabel->setText( Utils::sizeToString( num ) );
     284
     285    num = 0;
     286    foreach( tor, torrents ) num += tor->failedEver( );
     287    myFailedLabel->setText( Utils::sizeToString( num ) );
     288
     289    double d = 0;
     290    foreach( tor, torrents ) d += tor->ratio( );
     291    myRatioLabel->setText( Utils :: ratioToString( d / n ) );
     292
     293    Speed speed;
     294    foreach( tor, torrents ) speed += tor->swarmSpeed( );
     295    mySwarmSpeedLabel->setText( Utils::speedToString( speed ) );
     296
     297    strings.clear( );
     298    foreach( tor, torrents ) strings.insert( tor->dateAdded().toString() );
     299    string = strings.size()==1 ? *strings.begin() : blank;
     300    myAddedDateLabel->setText( string );
     301
     302    strings.clear( );
     303    foreach( tor, torrents ) {
     304        QDateTime dt = tor->lastActivity( );
     305        strings.insert( dt.isNull() ? tr("Never") : dt.toString() );
     306    }
     307    string = strings.size()==1 ? *strings.begin() : blank;
     308    myActivityLabel->setText( string );
     309
     310    if( torrents.empty( ) )
     311        string = tr( "None" );
     312    else {
     313        strings.clear( );
     314        foreach( tor, torrents ) strings.insert( tor->getError( ) );
     315        string = strings.size()==1 ? *strings.begin() : blank;
     316    }
     317    myErrorLabel->setText( string );
     318
     319    ///
     320    /// information tab
     321    ///
     322
     323    // myPiecesLabel
     324    int64_t pieceCount = 0;
     325    int64_t pieceSize = 0;
     326    foreach( tor, torrents ) {
     327        pieceCount += tor->pieceCount( );
     328        pieceSize += tor->pieceSize( );
     329    }
     330    myPiecesLabel->setText( tr( "%L1 Pieces @ %2" ).arg( pieceCount )
     331                                                   .arg( Utils::sizeToString( pieceSize ) ) );
     332
     333    // myHashLabel
     334    strings.clear( );
     335    foreach( tor, torrents ) strings.insert( tor->hashString( ) );
     336    string = strings.size()==1 ? *strings.begin() : blank;
     337    myHashLabel->setText( string );
     338
     339    // myPrivacyLabel
     340    strings.clear( );
     341    foreach( tor, torrents )
     342        strings.insert( tor->isPrivate( ) ? tr( "Private to this tracker -- PEX disabled" )
     343                                          : tr( "Public torrent" ) );
     344    string = strings.size()==1 ? *strings.begin() : blank;
     345    myPrivacyLabel->setText( string );
     346
     347    // myCommentBrowser
     348    strings.clear( );
     349    foreach( tor, torrents ) strings.insert( tor->comment( ) );
     350    string = strings.size()==1 ? *strings.begin() : blank;
     351    myCommentBrowser->setText( string );
     352
     353    // myCreatorLabel
     354    strings.clear( );
     355    foreach( tor, torrents ) strings.insert( tor->creator().isEmpty() ? tr( "Unknown" ) : tor->creator() );
     356    string = strings.size()==1 ? *strings.begin() : blank;
     357    myCreatorLabel->setText( string );
     358
     359    // myDateCreatedLabel
     360    strings.clear( );
     361    foreach( tor, torrents ) strings.insert( tor->dateCreated().toString() );
     362    string = strings.size()==1 ? *strings.begin() : blank;
     363    myDateCreatedLabel->setText( string );
     364
     365    // myDestinationLabel
     366    strings.clear( );
     367    foreach( tor, torrents ) strings.insert( tor->getPath( ) );
     368    string = strings.size()==1 ? *strings.begin() : blank;
     369    myDestinationLabel->setText( string );
     370
     371    // myTorrentFileLabel
     372    strings.clear( );
     373    foreach( tor, torrents ) strings.insert( tor->torrentFile( ) );
     374    string = strings.size()==1 ? *strings.begin() : blank;
     375    myTorrentFileLabel->setText( string );
     376
     377    ///
     378    ///  Options Tab
     379    ///
     380
     381    if( !torrents.empty( ) )
     382    {
     383        int i;
     384        const Torrent * baseline = *torrents.begin();
     385        bool uniform;
     386        bool baselineFlag;
     387        int baselineInt;
     388
     389        // mySessionLimitCheck
     390        uniform = true;
     391        baselineFlag = baseline->honorsSessionLimits( );
     392        foreach( tor, torrents ) if( baselineFlag != tor->honorsSessionLimits( ) ) { uniform = false; break; }
     393        mySessionLimitCheck->setChecked( uniform && baselineFlag );
     394
     395        // mySingleDownCheck
     396        uniform = true;
     397        baselineFlag = baseline->downloadIsLimited( );
     398        foreach( tor, torrents ) if( baselineFlag != tor->downloadIsLimited( ) ) { uniform = false; break; }
     399        mySingleDownCheck->setChecked( uniform && baselineFlag );
     400
     401        // mySingleUpCheck
     402        uniform = true;
     403        baselineFlag = baseline->uploadIsLimited( );
     404        foreach( tor, torrents ) if( baselineFlag != tor->uploadIsLimited( ) ) { uniform = false; break; }
     405        mySingleUpCheck->setChecked( uniform && baselineFlag );
     406
     407        // myBandwidthPriorityCombo
     408        uniform = true;
     409        baselineInt = baseline->getBandwidthPriority( );
     410        foreach( tor, torrents ) if ( baselineInt != tor->getBandwidthPriority( ) ) { uniform = false; break; }
     411        if( uniform )
     412            i = myBandwidthPriorityCombo->findData( baselineInt );
     413        else
     414            i = -1;
     415        myBandwidthPriorityCombo->blockSignals( true );
     416        myBandwidthPriorityCombo->setCurrentIndex( i );
     417        myBandwidthPriorityCombo->blockSignals( false );
     418
     419        mySingleDownSpin->blockSignals( true );
     420        mySingleDownSpin->setValue( tor->downloadLimit().kbps() );
     421        mySingleDownSpin->blockSignals( false );
     422
     423        mySingleUpSpin->blockSignals( true );
     424        mySingleUpSpin->setValue( tor->uploadLimit().kbps() );
     425        mySingleUpSpin->blockSignals( false );
     426
     427        myPeerLimitSpin->blockSignals( true );
     428        myPeerLimitSpin->setValue( tor->peerLimit() );
     429        myPeerLimitSpin->blockSignals( false );
     430
     431        // ratio radios
     432        uniform = true;
     433        baselineInt = tor->seedRatioMode( );
     434        foreach( tor, torrents ) if( baselineInt != tor->seedRatioMode( ) ) { uniform = false; break; }
     435        if( !uniform ) {
     436            mySeedGlobalRadio->setChecked( false );
     437            mySeedCustomRadio->setChecked( false );
     438            mySeedForeverRadio->setChecked( false );
     439        } else {
     440            QRadioButton * rb;
     441            switch( baselineInt ) {
     442                case TR_RATIOLIMIT_GLOBAL:    rb = mySeedGlobalRadio; break;
     443                case TR_RATIOLIMIT_SINGLE:    rb = mySeedCustomRadio; break;
     444                case TR_RATIOLIMIT_UNLIMITED: rb = mySeedForeverRadio; break;
     445            }
     446            rb->setChecked( true );
     447        }
     448
     449        mySeedCustomSpin->setValue( tor->seedRatioLimit( ) );
     450    }
    225451
    226452    // tracker tab
    227453    const time_t now( time( 0 ) );
    228     myScrapeTimePrevLabel->setText( myTorrent.lastScrapeTime().toString() );
    229     myScrapeResponseLabel->setText( myTorrent.scrapeResponse() );
    230     myScrapeTimeNextLabel->setText( Utils :: timeToString( myTorrent.nextScrapeTime().toTime_t() - now ) );
    231     myAnnounceTimePrevLabel->setText( myTorrent.lastScrapeTime().toString() );
    232     myAnnounceTimeNextLabel->setText( Utils :: timeToString( myTorrent.nextAnnounceTime().toTime_t() - now ) );
    233     myAnnounceManualLabel->setText( Utils :: timeToString( myTorrent.manualAnnounceTime().toTime_t() - now ) );
    234     myAnnounceResponseLabel->setText( myTorrent.announceResponse( ) );
    235     const QUrl url( myTorrent.announceUrl( ) );
    236     myTrackerLabel->setText( url.host( ) );
    237 
    238     // peers tab
    239     mySeedersLabel->setText( locale.toString( myTorrent.seeders( ) ) );
    240     myLeechersLabel->setText( locale.toString( myTorrent.leechers( ) ) );
    241     myTimesCompletedLabel->setText( locale.toString( myTorrent.timesCompleted( ) ) );
    242     const PeerList peers( myTorrent.peers( ) );
     454    myScrapeTimePrevLabel->setText( tor ? tor->lastScrapeTime().toString() : blank );
     455    myScrapeResponseLabel->setText( tor ? tor->scrapeResponse() : blank );
     456    myScrapeTimeNextLabel->setText( Utils :: timeToString( tor ? tor->nextScrapeTime().toTime_t() - now : 0 ) );
     457    myAnnounceTimePrevLabel->setText( tor ? tor->lastScrapeTime().toString() : blank );
     458    myAnnounceTimeNextLabel->setText( Utils :: timeToString( tor ? tor->nextAnnounceTime().toTime_t() - now : 0  ) );
     459    myAnnounceManualLabel->setText( Utils :: timeToString( tor ? tor->manualAnnounceTime().toTime_t() - now : 0 ) );
     460    myAnnounceResponseLabel->setText( tor ? tor->announceResponse( ) : blank );
     461
     462    // myTrackerLabel
     463    strings.clear( );
     464    foreach( tor, torrents ) strings.insert( QUrl(tor->announceUrl()).host() );
     465    string = strings.size()==1 ? *strings.begin() : blank;
     466    myTrackerLabel->setText( string );
     467
     468    ///
     469    ///  Peers tab
     470    ///
     471
     472    i = 0;
     473    foreach( tor, torrents ) i += tor->seeders( );
     474    mySeedersLabel->setText( locale.toString( i ) );
     475
     476    i = 0;
     477    foreach( tor, torrents ) i += tor->leechers( );
     478    myLeechersLabel->setText( locale.toString( i ) );
     479
     480    i = 0;
     481    foreach( tor, torrents ) i += tor->timesCompleted( );
     482    myTimesCompletedLabel->setText( locale.toString( i ) );
     483
     484    PeerList peers;
     485    foreach( tor, torrents ) peers << tor->peers( );
    243486    QMap<QString,QTreeWidgetItem*> peers2;
    244487    QList<QTreeWidgetItem*> newItems;
     
    311554    myPeers = peers2;
    312555
    313     myFileTreeView->update( myTorrent.files( ) );
     556    if( single ) {
     557        tor = *torrents.begin();
     558        myFileTreeView->update( tor->files( ) );
     559    } else {
     560        myFileTreeView->clear( );
     561    }
     562
     563    myHavePendingRefresh = false;
     564    foreach( QWidget * w, myWidgets )
     565        w->setEnabled( true );
    314566}
    315567
     
    358610Details :: onHonorsSessionLimitsToggled( bool val )
    359611{
    360     mySession.torrentSet( myTorrent.id(), "honorsSessionLimits", val );
     612std::cerr << " honorsSessionLimits clicked to " << val << std::endl;
     613    mySession.torrentSet( myIds, "honorsSessionLimits", val );
    361614}
    362615void
    363616Details :: onDownloadLimitedToggled( bool val )
    364617{
    365     mySession.torrentSet( myTorrent.id(), "downloadLimited", val );
     618    mySession.torrentSet( myIds, "downloadLimited", val );
    366619}
    367620void
    368621Details :: onDownloadLimitChanged( int val )
    369622{
    370     mySession.torrentSet( myTorrent.id(), "downloadLimit", val );
     623    mySession.torrentSet( myIds, "downloadLimit", val );
    371624}
    372625void
    373626Details :: onUploadLimitedToggled( bool val )
    374627{
    375     mySession.torrentSet( myTorrent.id(), "uploadLimited", val );
     628    mySession.torrentSet( myIds, "uploadLimited", val );
    376629}
    377630void
    378631Details :: onUploadLimitChanged( int val )
    379632{
    380     mySession.torrentSet( myTorrent.id(), "uploadLimit", val );
     633    mySession.torrentSet( myIds, "uploadLimit", val );
    381634}
    382635
     
    387640{
    388641    if( b )
    389         mySession.torrentSet( myTorrent.id(), RATIO_KEY, sender()->property(RATIO_KEY).toInt() );
     642        mySession.torrentSet( myIds, RATIO_KEY, sender()->property(RATIO_KEY).toInt() );
    390643}
    391644
     
    393646Details :: onSeedRatioLimitChanged( double val )
    394647{
    395     mySession.torrentSet( myTorrent.id(), "seedRatioLimit", val );
     648    mySession.torrentSet( myIds, "seedRatioLimit", val );
    396649}
    397650
     
    399652Details :: onMaxPeersChanged( int val )
    400653{
    401     mySession.torrentSet( myTorrent.id(), "peer-limit", val );
     654    mySession.torrentSet( myIds, "peer-limit", val );
     655}
     656
     657void
     658Details :: onBandwidthPriorityChanged( int index )
     659{
     660    if( index != -1 )
     661    {
     662        const int priority = myBandwidthPriorityCombo->itemData(index).toInt( );
     663        mySession.torrentSet( myIds, "bandwidthPriority", priority );
     664    }
    402665}
    403666
     
    408671    QSpinBox * s;
    409672    QCheckBox * c;
     673    QComboBox * m;
    410674    QHBoxLayout * h;
    411675    QRadioButton * r;
     
    413677
    414678    HIG * hig = new HIG( this );
    415     hig->addSectionTitle( tr( "Speed Limits" ) );
     679    hig->addSectionTitle( tr( "Speed" ) );
    416680
    417681    c = new QCheckBox( tr( "Honor global &limits" ) );
    418682    mySessionLimitCheck = c;
    419683    hig->addWideControl( c );
    420     connect( c, SIGNAL(toggled(bool)), this, SLOT(onHonorsSessionLimitsToggled(bool)) );
     684    connect( c, SIGNAL(clicked(bool)), this, SLOT(onHonorsSessionLimitsToggled(bool)) );
    421685
    422686    c = new QCheckBox( tr( "Limit &download speed (KB/s)" ) );
     
    427691    hig->addRow( c, s );
    428692    enableWhenChecked( c, s );
    429     connect( c, SIGNAL(toggled(bool)), this, SLOT(onDownloadLimitedToggled(bool)) );
     693    connect( c, SIGNAL(clicked(bool)), this, SLOT(onDownloadLimitedToggled(bool)) );
    430694    connect( s, SIGNAL(valueChanged(int)), this, SLOT(onDownloadLimitChanged(int)));
    431695
     
    437701    hig->addRow( c, s );
    438702    enableWhenChecked( c, s );
    439     connect( c, SIGNAL(toggled(bool)), this, SLOT(onUploadLimitedToggled(bool)) );
     703    connect( c, SIGNAL(clicked(bool)), this, SLOT(onUploadLimitedToggled(bool)) );
    440704    connect( s, SIGNAL(valueChanged(int)), this, SLOT(onUploadLimitChanged(int)));
     705
     706    m = new QComboBox;
     707    m->addItem( tr( "Low" ),    TR_PRI_LOW );
     708    m->addItem( tr( "Normal" ), TR_PRI_NORMAL );
     709    m->addItem( tr( "High" ),   TR_PRI_HIGH );
     710    connect( m, SIGNAL(currentIndexChanged(int)), this, SLOT(onBandwidthPriorityChanged(int)));
     711    hig->addRow( tr( "Bandwidth priority:" ), m );
     712    myBandwidthPriorityCombo = m;
     713   
    441714
    442715    hig->addSectionDivider( );
     
    445718    r = new QRadioButton( tr( "Use &global setting" ) );
    446719    r->setProperty( RATIO_KEY, TR_RATIOLIMIT_GLOBAL );
    447     connect( r, SIGNAL(toggled(bool)), this, SLOT(onSeedUntilChanged(bool)));
     720    connect( r, SIGNAL(clicked(bool)), this, SLOT(onSeedUntilChanged(bool)));
    448721    mySeedGlobalRadio = r;
    449722    hig->addWideControl( r );
     
    451724    r = new QRadioButton( tr( "Seed &regardless of ratio" ) );
    452725    r->setProperty( RATIO_KEY, TR_RATIOLIMIT_UNLIMITED );
    453     connect( r, SIGNAL(toggled(bool)), this, SLOT(onSeedUntilChanged(bool)));
     726    connect( r, SIGNAL(clicked(bool)), this, SLOT(onSeedUntilChanged(bool)));
    454727    mySeedForeverRadio = r;
    455728    hig->addWideControl( r );
     
    459732    r = new QRadioButton( tr( "&Stop seeding when a torrent's ratio reaches" ) );
    460733    r->setProperty( RATIO_KEY, TR_RATIOLIMIT_SINGLE );
    461     connect( r, SIGNAL(toggled(bool)), this, SLOT(onSeedUntilChanged(bool)));
     734    connect( r, SIGNAL(clicked(bool)), this, SLOT(onSeedUntilChanged(bool)));
    462735    mySeedCustomRadio = r;
    463736    h->addWidget( r );
     
    634907        default:           key = "priority-normal"; break;
    635908    }
    636     mySession.torrentSet( myTorrent.id( ), key, indices.toList( ) );
     909    mySession.torrentSet( myIds, key, indices.toList( ) );
    637910}
    638911
     
    641914{
    642915    QString key( wanted ? "files-wanted" : "files-unwanted" );
    643     mySession.torrentSet( myTorrent.id( ), key, indices.toList( ) );
    644 }
     916    mySession.torrentSet( myIds, key, indices.toList( ) );
     917}
  • trunk/qt/details.h

    r8221 r8255  
    1919#include <QSet>
    2020#include <QTimer>
     21#include <QWidgetList>
    2122
    2223#include "prefs.h"
     
    2425class FileTreeView;
    2526class QTreeView;
     27class QComboBox;
    2628class QCheckBox;
    2729class QDoubleSpinBox;
     
    3436class Session;
    3537class Torrent;
     38class TorrentModel;
    3639
    3740class Details: public QDialog
     
    4447
    4548    public:
    46         Details( Session&, Torrent&, QWidget * parent = 0 );
     49        Details( Session&, TorrentModel&, QWidget * parent = 0 );
    4750        ~Details( );
     51        void setIds( const QSet<int>& ids );
    4852
    4953    private:
     
    6266
    6367        Session& mySession;
    64         Torrent& myTorrent;
     68        TorrentModel& myModel;
     69        QSet<int> myIds;
    6570        QTimer myTimer;
     71        bool myHavePendingRefresh;
    6672
    6773        QLabel * myStateLabel;
     
    8793        QDoubleSpinBox * mySeedCustomSpin;
    8894        QSpinBox * myPeerLimitSpin;
     95        QComboBox * myBandwidthPriorityCombo;
    8996
    9097        QLabel * myPiecesLabel;
     
    111118        QTreeWidget * myPeerTree;
    112119        QMap<QString,QTreeWidgetItem*> myPeers;
     120        QWidgetList myWidgets;
    113121
    114122        FileTreeView * myFileTreeView;
    115123
    116124    private slots:
     125        void onBandwidthPriorityChanged( int );
    117126        void onFilePriorityChanged( const QSet<int>& fileIndices, int );
    118127        void onFileWantedChanged( const QSet<int>& fileIndices, bool );
     
    125134        void onSeedRatioLimitChanged( double );
    126135        void onMaxPeersChanged( int );
     136        void refresh( );
    127137};
    128138
  • trunk/qt/mainwin.cc

    r8237 r8255  
    8181    myAboutDialog( new AboutDialog( this ) ),
    8282    myStatsDialog( new StatsDialog( session, this ) ),
     83    myDetailsDialog( 0 ),
    8384    myFileDialog( 0 ),
    8485    myFilterModel( prefs ),
     
    551552
    552553void
     554TrMainWindow :: onDetailsDestroyed( )
     555{
     556    myDetailsDialog = 0;
     557}
     558
     559void
    553560TrMainWindow :: openProperties( )
    554561{
    555     const int id( *getSelectedTorrents().begin() );
    556     Torrent * torrent( myModel.getTorrentFromId( id ) );
    557     assert( torrent != 0 );
    558     QDialog * d( new Details( mySession, *torrent, this ) );
    559     d->show( );
     562    if( myDetailsDialog == 0 ) {
     563        myDetailsDialog = new Details( mySession, myModel, this );
     564        connect( myDetailsDialog, SIGNAL(destroyed(QObject*)), this, SLOT(onDetailsDestroyed()));
     565    }
     566
     567    myDetailsDialog->setIds( getSelectedTorrents( ) );
     568    myDetailsDialog->show( );
    560569}
    561570
     
    659668    ui.action_Remove->setEnabled( haveSelection );
    660669    ui.action_Delete->setEnabled( haveSelection );
     670    ui.action_Properties->setEnabled( haveSelection );
    661671    ui.action_DeselectAll->setEnabled( haveSelection );
    662672
    663673    const bool oneSelection( selected == 1 );
    664     ui.action_Properties->setEnabled( oneSelection );
    665674    ui.action_OpenFolder->setEnabled( oneSelection );
    666675
     
    671680    ui.action_Pause->setEnabled( selectedAndPaused < selected );
    672681    ui.action_Announce->setEnabled( selected > 0 && ( canAnnounce == selected ) );
     682
     683    if( myDetailsDialog )
     684        myDetailsDialog->setIds( getSelectedTorrents( ) );
    673685}
    674686
  • trunk/qt/mainwin.h

    r8237 r8255  
    3636class ActionDelegator;
    3737class Prefs;
     38class Details;
    3839class Session;
    3940class TorrentDelegate;
     
    5556        QDialog * myAboutDialog;
    5657        QDialog * myStatsDialog;
     58        Details * myDetailsDialog;
    5759        QFileDialog * myFileDialog;
    5860        QCheckBox * myFileDialogOptionsCheck;
     
    8789
    8890    private slots:
     91        void onDetailsDestroyed( );
    8992        void onShowModeClicked( );
    9093        void showAll( );
  • trunk/qt/prefs-dialog.cc

    r8231 r8255  
    298298        hig->addRow( s, r );
    299299
     300        s = tr( "<small>When enabled, Speed Limit Mode overrides the Global Bandwidth Limits</small>" );
     301        hig->addWideControl( new QLabel( s ) );
     302
    300303        QCheckBox * c = checkBoxNew( tr( "Use Speed Limit Mode &between" ), Prefs::ALT_SPEED_LIMIT_TIME_ENABLED );
    301304        h = new QHBoxLayout( );
  • trunk/qt/session.cc

    r8236 r8255  
    281281
    282282void
    283 Session :: torrentSet( int id, const QString& key, double value )
    284 {
    285     QString s;
    286     QTextStream( &s ) << "{ \"method\": \"torrent-set\", \"arguments\": { \"ids\": "<<id<<", \""<<key<<"\": "<<value<<" } }";
    287 std::cerr << qPrintable(s) << std::endl;
    288     exec( s.toUtf8().constData() );
    289     refreshExtraStats( id );
    290 }
    291 
    292 void
    293 Session :: torrentSet( int id, const QString& key, int value )
    294 {
    295     QString s;
    296     QTextStream( &s ) << "{ \"method\": \"torrent-set\", \"arguments\": { \"ids\": "<<id<<", \""<<key<<"\": "<<value<<" } }";
    297 std::cerr << qPrintable(s) << std::endl;
    298     exec( s.toUtf8().constData() );
    299     refreshExtraStats( id );
    300 }
    301 
    302 void
    303 Session :: torrentSet( int id, const QString& key, bool value )
    304 {
    305     QString s;
    306     QTextStream( &s ) << "{ \"method\": \"torrent-set\", \"arguments\": { \"ids\": "<<id<<", \""<<key<<"\": "<<(value?"true":"false")<<" } }";
    307 std::cerr << qPrintable(s) << std::endl;
    308     exec( s.toUtf8().constData() );
    309     refreshExtraStats( id );
    310 }
    311 
    312 void
    313 Session :: torrentSet( int id, const QString& key, const QList<int>& value )
     283Session :: torrentSet( const QSet<int>& ids, const QString& key, double value )
     284{
     285    tr_benc top;
     286    tr_bencInitDict( &top, 2 );
     287    tr_bencDictAddStr( &top, "method", "torrent-set" );
     288    tr_benc * args = tr_bencDictAddDict( &top, "arguments", 2 );
     289    tr_bencDictAddReal( args, key.toUtf8().constData(), value );
     290    addOptionalIds( args, ids );
     291    std::cerr << tr_bencToJSON(&top) << std::endl;
     292    exec( &top );
     293    tr_bencFree( &top );
     294}
     295
     296void
     297Session :: torrentSet( const QSet<int>& ids, const QString& key, int value )
     298{
     299    tr_benc top;
     300    tr_bencInitDict( &top, 2 );
     301    tr_bencDictAddStr( &top, "method", "torrent-set" );
     302    tr_benc * args = tr_bencDictAddDict( &top, "arguments", 2 );
     303    tr_bencDictAddInt( args, key.toUtf8().constData(), value );
     304    addOptionalIds( args, ids );
     305    std::cerr << tr_bencToJSON(&top) << std::endl;
     306    exec( &top );
     307    tr_bencFree( &top );
     308}
     309
     310void
     311Session :: torrentSet( const QSet<int>& ids, const QString& key, bool value )
     312{
     313    tr_benc top;
     314    tr_bencInitDict( &top, 2 );
     315    tr_bencDictAddStr( &top, "method", "torrent-set" );
     316    tr_benc * args = tr_bencDictAddDict( &top, "arguments", 2 );
     317    tr_bencDictAddBool( args, key.toUtf8().constData(), value );
     318    addOptionalIds( args, ids );
     319    std::cerr << tr_bencToJSON(&top) << std::endl;
     320    exec( &top );
     321    tr_bencFree( &top );
     322}
     323
     324void
     325Session :: torrentSet( const QSet<int>& ids, const QString& key, const QList<int>& value )
    314326{
    315327    tr_benc top;
     
    317329    tr_bencDictAddStr( &top, "method", "torrent-set" );
    318330    tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) );
    319     tr_bencListAddInt( tr_bencDictAddList( args, "ids", 1 ), id );
     331    addOptionalIds( args, ids );
    320332    tr_benc * list( tr_bencDictAddList( args, key.toUtf8().constData(), value.size( ) ) );
    321333    foreach( int i, value )
    322334        tr_bencListAddInt( list, i );
    323     exec( &top );
    324     tr_bencFree( &top );
    325     refreshExtraStats( id );
     335    std::cerr << tr_bencToJSON(&top) << std::endl;
     336    exec( &top );
     337    tr_bencFree( &top );
    326338}
    327339
     
    349361
    350362void
    351 Session :: refreshExtraStats( int id )
     363Session :: refreshExtraStats( const QSet<int>& ids )
    352364{
    353365    tr_benc top;
     
    356368    tr_bencDictAddInt( &top, "tag", TAG_SOME_TORRENTS );
    357369    tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) );
    358     tr_bencListAddInt( tr_bencDictAddList( args, "ids", 1 ), id );
     370    addOptionalIds( args, ids );
    359371    addList( tr_bencDictAddList( args, "fields", 0 ), getStatKeys( ) + getExtraStatKeys( ));
    360372    exec( &top );
  • trunk/qt/session.h

    r8232 r8255  
    7878
    7979    public:
    80         void torrentSet( int id, const QString& key, bool val );
    81         void torrentSet( int id, const QString& key, int val );
    82         void torrentSet( int id, const QString& key, double val );
    83         void torrentSet( int id, const QString& key, const QList<int>& val );
     80        void torrentSet( const QSet<int>& ids, const QString& key, bool val );
     81        void torrentSet( const QSet<int>& ids, const QString& key, int val );
     82        void torrentSet( const QSet<int>& ids, const QString& key, double val );
     83        void torrentSet( const QSet<int>& ids, const QString& key, const QList<int>& val );
     84
    8485
    8586    public slots:
     
    99100
    100101        /** request a refresh for statistics, including the ones only used by the properties dialog, for a specific torrent */
    101         void refreshExtraStats( int torrent );
     102        void refreshExtraStats( const QSet<int>& ids );
    102103
    103104    private slots:
  • trunk/qt/torrent.cc

    r8188 r8255  
    109109    { TIMES_COMPLETED, "timesCompleted", QVariant::Int, STAT_EXTRA },
    110110    { PEERS, "peers", TrTypes::PeerList, STAT_EXTRA },
    111     { TORRENT_FILE, "torrentFile", QVariant::String, STAT_EXTRA }
     111    { TORRENT_FILE, "torrentFile", QVariant::String, STAT_EXTRA },
     112    { BANDWIDTH_PRIORITY, "bandwidthPriority", QVariant::Int, STAT_EXTRA }
    112113};
    113114
  • trunk/qt/torrent.h

    r8232 r8255  
    140140            PEERS,
    141141            TORRENT_FILE,
     142            BANDWIDTH_PRIORITY,
    142143
    143144            PROPERTY_COUNT
     
    201202
    202203    public:
     204        int getBandwidthPriority( ) const { return getInt( BANDWIDTH_PRIORITY ); }
    203205        int id( ) const { return getInt( ID ); }
    204206        QString name( ) const { return getString( NAME ); }
Note: See TracChangeset for help on using the changeset viewer.