source: trunk/qt/torrent.cc @ 11491

Last change on this file since 11491 was 11491, checked in by charles, 11 years ago

(trunk qt) #3814 "Crash when opening properties dialog on a torrent before all its stats have been fetched" -- fixed.

  • Property svn:keywords set to Date Rev Author Id
File size: 21.6 KB
Line 
1/*
2 * This file Copyright (C) Mnemosyne LLC
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation.
7 *
8 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
9 *
10 * $Id: torrent.cc 11491 2010-12-08 15:45:43Z charles $
11 */
12
13#include <cassert>
14#include <iostream>
15
16#include <QApplication>
17#include <QFileIconProvider>
18#include <QFileInfo>
19#include <QSet>
20#include <QString>
21#include <QStyle>
22#include <QUrl>
23#include <QVariant>
24
25#include <libtransmission/transmission.h>
26#include <libtransmission/bencode.h>
27#include <libtransmission/utils.h> /* tr_new0, tr_strdup */
28
29#include "app.h"
30#include "prefs.h"
31#include "torrent.h"
32#include "utils.h"
33
34
35Torrent :: Torrent( Prefs& prefs, int id ):
36    magnetTorrent( false ),
37    myPrefs( prefs )
38{
39    for( int i=0; i<PROPERTY_COUNT; ++i )
40        assert( myProperties[i].id == i );
41
42    setInt( ID, id );
43    setIcon( MIME_ICON, QApplication::style()->standardIcon( QStyle::SP_FileIcon ) );
44}
45
46Torrent :: ~Torrent( )
47{
48}
49
50/***
51****
52***/
53
54Torrent :: Property
55Torrent :: myProperties[] =
56{
57    { ID, "id", QVariant::Int, INFO, },
58    { UPLOAD_SPEED, "rateUpload", QVariant::ULongLong, STAT } /* Bps */,
59    { DOWNLOAD_SPEED, "rateDownload", QVariant::ULongLong, STAT }, /* Bps */
60    { DOWNLOAD_DIR, "downloadDir", QVariant::String, STAT },
61    { ACTIVITY, "status", QVariant::Int, STAT },
62    { NAME, "name", QVariant::String, INFO },
63    { ERROR, "error", QVariant::Int, STAT },
64    { ERROR_STRING, "errorString", QVariant::String, STAT },
65    { SIZE_WHEN_DONE, "sizeWhenDone", QVariant::ULongLong, STAT },
66    { LEFT_UNTIL_DONE, "leftUntilDone", QVariant::ULongLong, STAT },
67    { HAVE_UNCHECKED, "haveUnchecked", QVariant::ULongLong, STAT },
68    { HAVE_VERIFIED, "haveValid", QVariant::ULongLong, STAT },
69    { DESIRED_AVAILABLE, "desiredAvailable", QVariant::ULongLong, STAT },
70    { TOTAL_SIZE, "totalSize", QVariant::ULongLong, INFO },
71    { PIECE_SIZE, "pieceSize", QVariant::ULongLong, INFO },
72    { PIECE_COUNT, "pieceCount", QVariant::Int, INFO },
73    { PEERS_GETTING_FROM_US, "peersGettingFromUs", QVariant::Int, STAT },
74    { PEERS_SENDING_TO_US, "peersSendingToUs", QVariant::Int, STAT },
75    { WEBSEEDS_SENDING_TO_US, "webseedsSendingToUs", QVariant::Int, STAT_EXTRA },
76    { PERCENT_DONE, "percentDone", QVariant::Double, STAT },
77    { METADATA_PERCENT_DONE, "metadataPercentComplete", QVariant::Double, STAT },
78    { PERCENT_VERIFIED, "recheckProgress", QVariant::Double, STAT },
79    { DATE_ACTIVITY, "activityDate", QVariant::DateTime, STAT_EXTRA },
80    { DATE_ADDED, "addedDate", QVariant::DateTime, INFO },
81    { DATE_STARTED, "startDate", QVariant::DateTime, STAT_EXTRA },
82    { DATE_CREATED, "dateCreated", QVariant::DateTime, INFO },
83    { PEERS_CONNECTED, "peersConnected", QVariant::Int, STAT },
84    { ETA, "eta", QVariant::Int, STAT },
85    { RATIO, "uploadRatio", QVariant::Double, STAT },
86    { DOWNLOADED_EVER, "downloadedEver", QVariant::ULongLong, STAT },
87    { UPLOADED_EVER, "uploadedEver", QVariant::ULongLong, STAT },
88    { FAILED_EVER, "corruptEver", QVariant::ULongLong, STAT_EXTRA },
89    { TRACKERS, "trackers", QVariant::StringList, STAT },
90    { TRACKERSTATS, "trackerStats", TrTypes::TrackerStatsList, STAT_EXTRA },
91    { MIME_ICON, "ccc", QVariant::Icon, DERIVED },
92    { SEED_RATIO_LIMIT, "seedRatioLimit", QVariant::Double, STAT },
93    { SEED_RATIO_MODE, "seedRatioMode", QVariant::Int, STAT },
94    { SEED_IDLE_LIMIT, "seedIdleLimit", QVariant::Int, STAT_EXTRA },
95    { SEED_IDLE_MODE, "seedIdleMode", QVariant::Int, STAT_EXTRA },
96    { DOWN_LIMIT, "downloadLimit", QVariant::Int, STAT_EXTRA }, /* KB/s */
97    { DOWN_LIMITED, "downloadLimited", QVariant::Bool, STAT_EXTRA },
98    { UP_LIMIT, "uploadLimit", QVariant::Int, STAT_EXTRA }, /* KB/s */
99    { UP_LIMITED, "uploadLimited", QVariant::Bool, STAT_EXTRA },
100    { HONORS_SESSION_LIMITS, "honorsSessionLimits", QVariant::Bool, STAT_EXTRA },
101    { PEER_LIMIT, "peer-limit", QVariant::Int, STAT_EXTRA },
102    { HASH_STRING, "hashString", QVariant::String, INFO },
103    { IS_FINISHED, "isFinished", QVariant::Bool, STAT },
104    { IS_PRIVATE, "isPrivate", QVariant::Bool, INFO },
105    { COMMENT, "comment", QVariant::String, INFO },
106    { CREATOR, "creator", QVariant::String, INFO },
107    { MANUAL_ANNOUNCE_TIME, "manualAnnounceTime", QVariant::DateTime, STAT_EXTRA },
108    { PEERS, "peers", TrTypes::PeerList, STAT_EXTRA },
109    { TORRENT_FILE, "torrentFile", QVariant::String, STAT_EXTRA },
110    { BANDWIDTH_PRIORITY, "bandwidthPriority", QVariant::Int, STAT_EXTRA }
111};
112
113Torrent :: KeyList
114Torrent :: buildKeyList( Group group )
115{
116    KeyList keys;
117
118    if( keys.empty( ) )
119        for( int i=0; i<PROPERTY_COUNT; ++i )
120            if( myProperties[i].id==ID || myProperties[i].group==group )
121                keys << myProperties[i].key;
122
123    return keys;
124}
125
126const Torrent :: KeyList&
127Torrent :: getInfoKeys( )
128{
129    static KeyList keys;
130    if( keys.isEmpty( ) )
131        keys << buildKeyList( INFO ) << "files";
132    return keys;
133}
134
135const Torrent :: KeyList&
136Torrent :: getStatKeys( )
137{
138    static KeyList keys( buildKeyList( STAT ) );
139    return keys;
140}
141
142const Torrent :: KeyList&
143Torrent :: getExtraStatKeys( )
144{
145    static KeyList keys;
146    if( keys.isEmpty( ) )
147        keys << buildKeyList( STAT_EXTRA ) << "fileStats";
148    return keys;
149}
150
151
152bool
153Torrent :: setInt( int i, int value )
154{
155    bool changed = false;
156
157    assert( 0<=i && i<PROPERTY_COUNT );
158    assert( myProperties[i].type == QVariant::Int );
159
160    if( myValues[i].isNull() || myValues[i].toInt()!=value )
161    {
162        myValues[i].setValue( value );
163        changed = true;
164    }
165
166    return changed;
167}
168
169bool
170Torrent :: setBool( int i, bool value )
171{
172    bool changed = false;
173
174    assert( 0<=i && i<PROPERTY_COUNT );
175    assert( myProperties[i].type == QVariant::Bool );
176
177    if( myValues[i].isNull() || myValues[i].toBool()!=value )
178    {
179        myValues[i].setValue( value );
180        changed = true;
181    }
182
183    return changed;
184}
185
186bool
187Torrent :: setDouble( int i, double value )
188{
189    bool changed = false;
190
191    assert( 0<=i && i<PROPERTY_COUNT );
192    assert( myProperties[i].type == QVariant::Double );
193
194    if( myValues[i].isNull() || myValues[i].toDouble()!=value )
195    {
196        myValues[i].setValue( value );
197        changed = true;
198    }
199
200    return changed;
201}
202
203bool
204Torrent :: setDateTime( int i, const QDateTime& value )
205{
206    bool changed = false;
207
208    assert( 0<=i && i<PROPERTY_COUNT );
209    assert( myProperties[i].type == QVariant::DateTime );
210
211    if( myValues[i].isNull() || myValues[i].toDateTime()!=value )
212    {
213        myValues[i].setValue( value );
214        changed = true;
215    }
216
217    return changed;
218}
219
220bool
221Torrent :: setSize( int i, qulonglong value )
222{
223    bool changed = false;
224
225    assert( 0<=i && i<PROPERTY_COUNT );
226    assert( myProperties[i].type == QVariant::ULongLong );
227
228    if( myValues[i].isNull() || myValues[i].toULongLong()!=value )
229    {
230        myValues[i].setValue( value );
231        changed = true;
232    }
233
234    return changed;
235}
236
237bool
238Torrent :: setString( int i, const char * value )
239{
240    bool changed = false;
241
242    assert( 0<=i && i<PROPERTY_COUNT );
243    assert( myProperties[i].type == QVariant::String );
244
245    if( myValues[i].isNull() || myValues[i].toString()!=value )
246    {
247        myValues[i].setValue( QString::fromUtf8( value ) );
248        changed = true;
249    }
250
251    return changed;
252}
253
254bool
255Torrent :: setIcon( int i, const QIcon& value )
256{
257    assert( 0<=i && i<PROPERTY_COUNT );
258    assert( myProperties[i].type == QVariant::Icon );
259
260    myValues[i].setValue( value );
261    return true;
262}
263
264int
265Torrent :: getInt( int i ) const
266{
267    assert( 0<=i && i<PROPERTY_COUNT );
268    assert( myProperties[i].type == QVariant::Int );
269
270    return myValues[i].toInt( );
271}
272
273QDateTime
274Torrent :: getDateTime( int i ) const
275{
276    assert( 0<=i && i<PROPERTY_COUNT );
277    assert( myProperties[i].type == QVariant::DateTime );
278
279    return myValues[i].toDateTime( );
280}
281
282bool
283Torrent :: getBool( int i ) const
284{
285    assert( 0<=i && i<PROPERTY_COUNT );
286    assert( myProperties[i].type == QVariant::Bool );
287
288    return myValues[i].toBool( );
289}
290
291qulonglong
292Torrent :: getSize( int i ) const
293{
294    assert( 0<=i && i<PROPERTY_COUNT );
295    assert( myProperties[i].type == QVariant::ULongLong );
296
297    return myValues[i].toULongLong( );
298}
299double
300Torrent :: getDouble( int i ) const
301{
302    assert( 0<=i && i<PROPERTY_COUNT );
303    assert( myProperties[i].type == QVariant::Double );
304
305    return myValues[i].toDouble( );
306}
307QString
308Torrent :: getString( int i ) const
309{
310    assert( 0<=i && i<PROPERTY_COUNT );
311    assert( myProperties[i].type == QVariant::String );
312
313    return myValues[i].toString( );
314}
315QIcon
316Torrent :: getIcon( int i ) const
317{
318    assert( 0<=i && i<PROPERTY_COUNT );
319    assert( myProperties[i].type == QVariant::Icon );
320
321    return myValues[i].value<QIcon>();
322}
323
324/***
325****
326***/
327
328bool
329Torrent :: getSeedRatio( double& ratio ) const
330{
331    bool isLimited;
332
333    switch( seedRatioMode( ) )
334    {
335        case TR_RATIOLIMIT_SINGLE:
336            isLimited = true;
337            ratio = seedRatioLimit( );
338            break;
339
340        case TR_RATIOLIMIT_GLOBAL:
341            if(( isLimited = myPrefs.getBool( Prefs :: RATIO_ENABLED )))
342                ratio = myPrefs.getDouble( Prefs :: RATIO );
343            break;
344
345        default: // TR_RATIOLIMIT_UNLIMITED:
346            isLimited = false;
347            break;
348    }
349
350    return isLimited;
351}
352
353bool
354Torrent :: hasFileSubstring( const QString& substr ) const
355{
356    foreach( const TrFile file, myFiles )
357        if( file.filename.contains( substr, Qt::CaseInsensitive ) )
358            return true;
359    return false;
360}
361
362bool
363Torrent :: hasTrackerSubstring( const QString& substr ) const
364{
365    foreach( QString s, myValues[TRACKERS].toStringList() )
366        if( s.contains( substr, Qt::CaseInsensitive ) )
367            return true;
368    return false;
369}
370
371int
372Torrent :: compareSeedRatio( const Torrent& that ) const
373{
374    double a;
375    double b;
376    const bool has_a = getSeedRatio( a );
377    const bool has_b = that.getSeedRatio( b );
378    if( !has_a && !has_b ) return 0;
379    if( !has_a || !has_b ) return has_a ? -1 : 1;
380    if( a < b ) return -1;
381    if( a > b ) return 1;
382    return 0;
383}
384
385int
386Torrent :: compareRatio( const Torrent& that ) const
387{
388    const double a = ratio( );
389    const double b = that.ratio( );
390    if( (int)a == TR_RATIO_INF && (int)b == TR_RATIO_INF ) return 0;
391    if( (int)a == TR_RATIO_INF ) return 1;
392    if( (int)b == TR_RATIO_INF ) return -1;
393    if( a < b ) return -1;
394    if( a > b ) return 1;
395    return 0;
396}
397
398int
399Torrent :: compareETA( const Torrent& that ) const
400{
401    const bool haveA( hasETA( ) );
402    const bool haveB( that.hasETA( ) );
403    if( haveA && haveB ) return getETA() - that.getETA();
404    if( haveA ) return 1;
405    if( haveB ) return -1;
406    return 0;
407}
408
409int
410Torrent :: compareTracker( const Torrent& that ) const
411{
412    Q_UNUSED( that );
413
414    // FIXME
415    return 0;
416}
417
418/***
419****
420***/
421
422void
423Torrent :: updateMimeIcon( )
424{
425    const FileList& files( myFiles );
426
427    QIcon icon;
428
429    if( files.size( ) > 1 )
430        icon = QFileIconProvider().icon( QFileIconProvider::Folder );
431    else if( files.size( ) == 1 )
432        icon = Utils :: guessMimeIcon( files.at(0).filename );
433    else
434        icon = QIcon( );
435
436    setIcon( MIME_ICON, icon );
437}
438
439/***
440****
441***/
442
443void
444Torrent :: notifyComplete( ) const
445{
446    // if someone wants to implement notification, here's the hook.
447}
448
449/***
450****
451***/
452
453void
454Torrent :: update( tr_benc * d )
455{
456    bool changed = false;
457
458    for( int  i=0; i<PROPERTY_COUNT; ++i )
459    {
460        tr_benc * child = tr_bencDictFind( d, myProperties[i].key );
461        if( !child )
462            continue;
463
464        switch( myProperties[i].type )
465        {
466            case QVariant :: Int: {
467                int64_t val;
468                if( tr_bencGetInt( child, &val ) )
469                    changed |= setInt( i, val );
470                break;
471            }
472
473            case QVariant :: Bool: {
474                tr_bool val;
475                if( tr_bencGetBool( child, &val ) )
476                    changed |= setBool( i, val );
477                break;
478            }
479
480            case QVariant :: String: {
481                const char * val;
482                if( tr_bencGetStr( child, &val ) )
483                    changed |= setString( i, val );
484                break;
485            }
486
487            case QVariant :: ULongLong: {
488                int64_t val;
489                if( tr_bencGetInt( child, &val ) )
490                    changed |= setSize( i, val );
491                break;
492            }
493
494            case QVariant :: Double: {
495                double val;
496                if( tr_bencGetReal( child, &val ) )
497                    changed |= setDouble( i, val );
498                break;
499            }
500
501            case QVariant :: DateTime: {
502                int64_t val;
503                if( tr_bencGetInt( child, &val ) && val )
504                    changed |= setDateTime( i, QDateTime :: fromTime_t( val ) );
505                break;
506            }
507
508            case QVariant :: StringList:
509            case TrTypes :: PeerList:
510                break;
511
512            default:
513                assert( 0 && "unhandled type" );
514        }
515    }
516
517    tr_benc * files;
518
519    if( tr_bencDictFindList( d, "files", &files ) ) {
520        const char * str;
521        int64_t intVal;
522        int i = 0;
523        myFiles.clear( );
524        tr_benc * child;
525        while(( child = tr_bencListChild( files, i ))) {
526            TrFile file;
527            file.index = i++;
528            if( tr_bencDictFindStr( child, "name", &str ) )
529                file.filename = QString::fromUtf8( str );
530            if( tr_bencDictFindInt( child, "length", &intVal ) )
531                file.size = intVal;
532            myFiles.append( file );
533        }
534        updateMimeIcon( );
535        changed = true;
536    }
537
538    if( tr_bencDictFindList( d, "fileStats", &files ) ) {
539        const int n = tr_bencListSize( files );
540        for( int i=0; i<n && i<myFiles.size(); ++i ) {
541            int64_t intVal;
542            tr_bool boolVal;
543            tr_benc * child = tr_bencListChild( files, i );
544            TrFile& file( myFiles[i] );
545            if( tr_bencDictFindInt( child, "bytesCompleted", &intVal ) )
546                file.have = intVal;
547            if( tr_bencDictFindBool( child, "wanted", &boolVal ) )
548                file.wanted = boolVal;
549            if( tr_bencDictFindInt( child, "priority", &intVal ) )
550                file.priority = intVal;
551        }
552        changed = true;
553    }
554
555    tr_benc * trackers;
556    if( tr_bencDictFindList( d, "trackers", &trackers ) ) {
557        const char * str;
558        int i = 0;
559        QStringList list;
560        tr_benc * child;
561        while(( child = tr_bencListChild( trackers, i++ ))) {
562            if( tr_bencDictFindStr( child, "announce", &str )) {
563                dynamic_cast<MyApp*>(QApplication::instance())->favicons.add( QUrl(str) );
564                list.append( QString::fromUtf8( str ) );
565            }
566        }
567        if( myValues[TRACKERS] != list ) {
568            myValues[TRACKERS].setValue( list );
569            changed = true;
570        }
571    }
572
573    tr_benc * trackerStats;
574    if( tr_bencDictFindList( d, "trackerStats", &trackerStats ) ) {
575        tr_benc * child;
576        TrackerStatsList  trackerStatsList;
577        int childNum = 0;
578        while(( child = tr_bencListChild( trackerStats, childNum++ ))) {
579            tr_bool b;
580            int64_t i;
581            const char * str;
582            TrackerStat trackerStat;
583            if( tr_bencDictFindStr( child, "announce", &str ) ) {
584                trackerStat.announce = QString::fromUtf8( str );
585                dynamic_cast<MyApp*>(QApplication::instance())->favicons.add( QUrl( trackerStat.announce ) );
586            }
587            if( tr_bencDictFindInt( child, "announceState", &i ) )
588                trackerStat.announceState = i;
589            if( tr_bencDictFindInt( child, "downloadCount", &i ) )
590                trackerStat.downloadCount = i;
591            if( tr_bencDictFindBool( child, "hasAnnounced", &b ) )
592                trackerStat.hasAnnounced = b;
593            if( tr_bencDictFindBool( child, "hasScraped", &b ) )
594                trackerStat.hasScraped = b;
595            if( tr_bencDictFindStr( child, "host", &str ) )
596                trackerStat.host = QString::fromUtf8( str );
597            if( tr_bencDictFindInt( child, "id", &i ) )
598                trackerStat.id = i;
599            if( tr_bencDictFindBool( child, "isBackup", &b ) )
600                trackerStat.isBackup = b;
601            if( tr_bencDictFindInt( child, "lastAnnouncePeerCount", &i ) )
602                trackerStat.lastAnnouncePeerCount = i;
603            if( tr_bencDictFindStr( child, "lastAnnounceResult", &str ) )
604                trackerStat.lastAnnounceResult = str;
605            if( tr_bencDictFindInt( child, "lastAnnounceStartTime", &i ) )
606                trackerStat.lastAnnounceStartTime = i;
607            if( tr_bencDictFindBool( child, "lastAnnounceSucceeded", &b ) )
608                trackerStat.lastAnnounceSucceeded = b;
609            if( tr_bencDictFindInt( child, "lastAnnounceTime", &i ) )
610                trackerStat.lastAnnounceTime = i;
611            if( tr_bencDictFindBool( child, "lastAnnounceTimedOut", &b ) )
612                trackerStat.lastAnnounceTimedOut = b;
613            if( tr_bencDictFindStr( child, "lastScrapeResult", &str ) )
614                trackerStat.lastScrapeResult = QString::fromUtf8( str );
615            if( tr_bencDictFindInt( child, "lastScrapeStartTime", &i ) )
616                trackerStat.lastScrapeStartTime = i;
617            if( tr_bencDictFindBool( child, "lastScrapeSucceeded", &b ) )
618                trackerStat.lastScrapeSucceeded = b;
619            if( tr_bencDictFindInt( child, "lastScrapeTime", &i ) )
620                trackerStat.lastScrapeTime = i;
621            if( tr_bencDictFindBool( child, "lastScrapeTimedOut", &b ) )
622                trackerStat.lastScrapeTimedOut = b;
623            if( tr_bencDictFindInt( child, "leecherCount", &i ) )
624                trackerStat.leecherCount = i;
625            if( tr_bencDictFindInt( child, "nextAnnounceTime", &i ) )
626                trackerStat.nextAnnounceTime = i;
627            if( tr_bencDictFindInt( child, "nextScrapeTime", &i ) )
628                trackerStat.nextScrapeTime = i;
629            if( tr_bencDictFindInt( child, "scrapeState", &i ) )
630                trackerStat.scrapeState = i;
631            if( tr_bencDictFindInt( child, "seederCount", &i ) )
632                trackerStat.seederCount = i;
633            if( tr_bencDictFindInt( child, "tier", &i ) )
634                trackerStat.tier = i;
635            trackerStatsList << trackerStat;
636        }
637        myValues[TRACKERSTATS].setValue( trackerStatsList );
638        changed = true;
639    }
640
641    tr_benc * peers;
642    if( tr_bencDictFindList( d, "peers", &peers ) ) {
643        tr_benc * child;
644        PeerList peerList;
645        int childNum = 0;
646        while(( child = tr_bencListChild( peers, childNum++ ))) {
647            double d;
648            tr_bool b;
649            int64_t i;
650            const char * str;
651            Peer peer;
652            if( tr_bencDictFindStr( child, "address", &str ) )
653                peer.address = QString::fromUtf8( str );
654            if( tr_bencDictFindStr( child, "clientName", &str ) )
655                peer.clientName = QString::fromUtf8( str );
656            if( tr_bencDictFindBool( child, "clientIsChoked", &b ) )
657                peer.clientIsChoked = b;
658            if( tr_bencDictFindBool( child, "clientIsInterested", &b ) )
659                peer.clientIsInterested = b;
660            if( tr_bencDictFindStr( child, "flagStr", &str ) )
661                peer.flagStr = QString::fromUtf8( str );
662            if( tr_bencDictFindBool( child, "isDownloadingFrom", &b ) )
663                peer.isDownloadingFrom = b;
664            if( tr_bencDictFindBool( child, "isEncrypted", &b ) )
665                peer.isEncrypted = b;
666            if( tr_bencDictFindBool( child, "isIncoming", &b ) )
667                peer.isIncoming = b;
668            if( tr_bencDictFindBool( child, "isUploadingTo", &b ) )
669                peer.isUploadingTo = b;
670            if( tr_bencDictFindBool( child, "peerIsChoked", &b ) )
671                peer.peerIsChoked = b;
672            if( tr_bencDictFindBool( child, "peerIsInterested", &b ) )
673                peer.peerIsInterested = b;
674            if( tr_bencDictFindInt( child, "port", &i ) )
675                peer.port = i;
676            if( tr_bencDictFindReal( child, "progress", &d ) )
677                peer.progress = d;
678            if( tr_bencDictFindInt( child, "rateToClient", &i ) )
679                peer.rateToClient = Speed::fromBps( i );
680            if( tr_bencDictFindInt( child, "rateToPeer", &i ) )
681                peer.rateToPeer = Speed::fromBps( i );
682            peerList << peer;
683        }
684        myValues[PEERS].setValue( peerList );
685        changed = true;
686    }
687
688    if( changed )
689        emit torrentChanged( id( ) );
690}
691
692QString
693Torrent :: activityString( ) const
694{
695    QString str;
696
697    switch( getActivity( ) )
698    {
699        case TR_STATUS_CHECK_WAIT: str = tr( "Waiting to verify local data" ); break;
700        case TR_STATUS_CHECK:      str = tr( "Verifying local data" ); break;
701        case TR_STATUS_DOWNLOAD:   str = tr( "Downloading" ); break;
702        case TR_STATUS_SEED:       str = tr( "Seeding" ); break;
703        case TR_STATUS_STOPPED:    str = isFinished() ? tr( "Finished" ): tr( "Paused" ); break;
704    }
705
706    return str;
707}
708
709QString
710Torrent :: getError( ) const
711{
712    QString s = getString( ERROR_STRING );
713
714    switch( getInt( ERROR ) )
715    {
716        case TR_STAT_TRACKER_WARNING: s = tr( "Tracker gave a warning: %1" ).arg( s ); break;
717        case TR_STAT_TRACKER_ERROR: s = tr( "Tracker gave an error: %1" ).arg( s ); break;
718        case TR_STAT_LOCAL_ERROR: s = tr( "Error: %1" ).arg( s ); break;
719        default: s.clear(); break;
720    }
721
722    return s;
723}
724
725QPixmap
726TrackerStat :: getFavicon( ) const
727{
728    MyApp * myApp = dynamic_cast<MyApp*>(QApplication::instance());
729    return myApp->favicons.find( QUrl( announce ) );
730}
731
Note: See TracBrowser for help on using the repository browser.