Revert "transmission: update from 2.13 to 2.22"
[tomato.git] / release / src / router / transmission / qt / torrent.cc
blob4f74cc2ae529a4336e7679c4f242d50a92614cb6
1 /*
2 * This file Copyright (C) Mnemosyne LLC
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.
8 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10 * $Id: torrent.cc 11491 2010-12-08 15:45:43Z charles $
13 #include <cassert>
14 #include <iostream>
16 #include <QApplication>
17 #include <QFileIconProvider>
18 #include <QFileInfo>
19 #include <QSet>
20 #include <QString>
21 #include <QStyle>
22 #include <QUrl>
23 #include <QVariant>
25 #include <libtransmission/transmission.h>
26 #include <libtransmission/bencode.h>
27 #include <libtransmission/utils.h> /* tr_new0, tr_strdup */
29 #include "app.h"
30 #include "prefs.h"
31 #include "torrent.h"
32 #include "utils.h"
35 Torrent :: Torrent( Prefs& prefs, int id ):
36 magnetTorrent( false ),
37 myPrefs( prefs )
39 for( int i=0; i<PROPERTY_COUNT; ++i )
40 assert( myProperties[i].id == i );
42 setInt( ID, id );
43 setIcon( MIME_ICON, QApplication::style()->standardIcon( QStyle::SP_FileIcon ) );
46 Torrent :: ~Torrent( )
50 /***
51 ****
52 ***/
54 Torrent :: Property
55 Torrent :: myProperties[] =
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 }
113 Torrent :: KeyList
114 Torrent :: buildKeyList( Group group )
116 KeyList keys;
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;
123 return keys;
126 const Torrent :: KeyList&
127 Torrent :: getInfoKeys( )
129 static KeyList keys;
130 if( keys.isEmpty( ) )
131 keys << buildKeyList( INFO ) << "files";
132 return keys;
135 const Torrent :: KeyList&
136 Torrent :: getStatKeys( )
138 static KeyList keys( buildKeyList( STAT ) );
139 return keys;
142 const Torrent :: KeyList&
143 Torrent :: getExtraStatKeys( )
145 static KeyList keys;
146 if( keys.isEmpty( ) )
147 keys << buildKeyList( STAT_EXTRA ) << "fileStats";
148 return keys;
152 bool
153 Torrent :: setInt( int i, int value )
155 bool changed = false;
157 assert( 0<=i && i<PROPERTY_COUNT );
158 assert( myProperties[i].type == QVariant::Int );
160 if( myValues[i].isNull() || myValues[i].toInt()!=value )
162 myValues[i].setValue( value );
163 changed = true;
166 return changed;
169 bool
170 Torrent :: setBool( int i, bool value )
172 bool changed = false;
174 assert( 0<=i && i<PROPERTY_COUNT );
175 assert( myProperties[i].type == QVariant::Bool );
177 if( myValues[i].isNull() || myValues[i].toBool()!=value )
179 myValues[i].setValue( value );
180 changed = true;
183 return changed;
186 bool
187 Torrent :: setDouble( int i, double value )
189 bool changed = false;
191 assert( 0<=i && i<PROPERTY_COUNT );
192 assert( myProperties[i].type == QVariant::Double );
194 if( myValues[i].isNull() || myValues[i].toDouble()!=value )
196 myValues[i].setValue( value );
197 changed = true;
200 return changed;
203 bool
204 Torrent :: setDateTime( int i, const QDateTime& value )
206 bool changed = false;
208 assert( 0<=i && i<PROPERTY_COUNT );
209 assert( myProperties[i].type == QVariant::DateTime );
211 if( myValues[i].isNull() || myValues[i].toDateTime()!=value )
213 myValues[i].setValue( value );
214 changed = true;
217 return changed;
220 bool
221 Torrent :: setSize( int i, qulonglong value )
223 bool changed = false;
225 assert( 0<=i && i<PROPERTY_COUNT );
226 assert( myProperties[i].type == QVariant::ULongLong );
228 if( myValues[i].isNull() || myValues[i].toULongLong()!=value )
230 myValues[i].setValue( value );
231 changed = true;
234 return changed;
237 bool
238 Torrent :: setString( int i, const char * value )
240 bool changed = false;
242 assert( 0<=i && i<PROPERTY_COUNT );
243 assert( myProperties[i].type == QVariant::String );
245 if( myValues[i].isNull() || myValues[i].toString()!=value )
247 myValues[i].setValue( QString::fromUtf8( value ) );
248 changed = true;
251 return changed;
254 bool
255 Torrent :: setIcon( int i, const QIcon& value )
257 assert( 0<=i && i<PROPERTY_COUNT );
258 assert( myProperties[i].type == QVariant::Icon );
260 myValues[i].setValue( value );
261 return true;
265 Torrent :: getInt( int i ) const
267 assert( 0<=i && i<PROPERTY_COUNT );
268 assert( myProperties[i].type == QVariant::Int );
270 return myValues[i].toInt( );
273 QDateTime
274 Torrent :: getDateTime( int i ) const
276 assert( 0<=i && i<PROPERTY_COUNT );
277 assert( myProperties[i].type == QVariant::DateTime );
279 return myValues[i].toDateTime( );
282 bool
283 Torrent :: getBool( int i ) const
285 assert( 0<=i && i<PROPERTY_COUNT );
286 assert( myProperties[i].type == QVariant::Bool );
288 return myValues[i].toBool( );
291 qulonglong
292 Torrent :: getSize( int i ) const
294 assert( 0<=i && i<PROPERTY_COUNT );
295 assert( myProperties[i].type == QVariant::ULongLong );
297 return myValues[i].toULongLong( );
299 double
300 Torrent :: getDouble( int i ) const
302 assert( 0<=i && i<PROPERTY_COUNT );
303 assert( myProperties[i].type == QVariant::Double );
305 return myValues[i].toDouble( );
307 QString
308 Torrent :: getString( int i ) const
310 assert( 0<=i && i<PROPERTY_COUNT );
311 assert( myProperties[i].type == QVariant::String );
313 return myValues[i].toString( );
315 QIcon
316 Torrent :: getIcon( int i ) const
318 assert( 0<=i && i<PROPERTY_COUNT );
319 assert( myProperties[i].type == QVariant::Icon );
321 return myValues[i].value<QIcon>();
324 /***
325 ****
326 ***/
328 bool
329 Torrent :: getSeedRatio( double& ratio ) const
331 bool isLimited;
333 switch( seedRatioMode( ) )
335 case TR_RATIOLIMIT_SINGLE:
336 isLimited = true;
337 ratio = seedRatioLimit( );
338 break;
340 case TR_RATIOLIMIT_GLOBAL:
341 if(( isLimited = myPrefs.getBool( Prefs :: RATIO_ENABLED )))
342 ratio = myPrefs.getDouble( Prefs :: RATIO );
343 break;
345 default: // TR_RATIOLIMIT_UNLIMITED:
346 isLimited = false;
347 break;
350 return isLimited;
353 bool
354 Torrent :: hasFileSubstring( const QString& substr ) const
356 foreach( const TrFile file, myFiles )
357 if( file.filename.contains( substr, Qt::CaseInsensitive ) )
358 return true;
359 return false;
362 bool
363 Torrent :: hasTrackerSubstring( const QString& substr ) const
365 foreach( QString s, myValues[TRACKERS].toStringList() )
366 if( s.contains( substr, Qt::CaseInsensitive ) )
367 return true;
368 return false;
372 Torrent :: compareSeedRatio( const Torrent& that ) const
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;
386 Torrent :: compareRatio( const Torrent& that ) const
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;
399 Torrent :: compareETA( const Torrent& that ) const
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;
410 Torrent :: compareTracker( const Torrent& that ) const
412 Q_UNUSED( that );
414 // FIXME
415 return 0;
418 /***
419 ****
420 ***/
422 void
423 Torrent :: updateMimeIcon( )
425 const FileList& files( myFiles );
427 QIcon icon;
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( );
436 setIcon( MIME_ICON, icon );
439 /***
440 ****
441 ***/
443 void
444 Torrent :: notifyComplete( ) const
446 // if someone wants to implement notification, here's the hook.
449 /***
450 ****
451 ***/
453 void
454 Torrent :: update( tr_benc * d )
456 bool changed = false;
458 for( int i=0; i<PROPERTY_COUNT; ++i )
460 tr_benc * child = tr_bencDictFind( d, myProperties[i].key );
461 if( !child )
462 continue;
464 switch( myProperties[i].type )
466 case QVariant :: Int: {
467 int64_t val;
468 if( tr_bencGetInt( child, &val ) )
469 changed |= setInt( i, val );
470 break;
473 case QVariant :: Bool: {
474 tr_bool val;
475 if( tr_bencGetBool( child, &val ) )
476 changed |= setBool( i, val );
477 break;
480 case QVariant :: String: {
481 const char * val;
482 if( tr_bencGetStr( child, &val ) )
483 changed |= setString( i, val );
484 break;
487 case QVariant :: ULongLong: {
488 int64_t val;
489 if( tr_bencGetInt( child, &val ) )
490 changed |= setSize( i, val );
491 break;
494 case QVariant :: Double: {
495 double val;
496 if( tr_bencGetReal( child, &val ) )
497 changed |= setDouble( i, val );
498 break;
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;
508 case QVariant :: StringList:
509 case TrTypes :: PeerList:
510 break;
512 default:
513 assert( 0 && "unhandled type" );
517 tr_benc * files;
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 );
534 updateMimeIcon( );
535 changed = true;
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;
552 changed = true;
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 ) );
567 if( myValues[TRACKERS] != list ) {
568 myValues[TRACKERS].setValue( list );
569 changed = true;
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 ) );
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;
637 myValues[TRACKERSTATS].setValue( trackerStatsList );
638 changed = true;
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;
684 myValues[PEERS].setValue( peerList );
685 changed = true;
688 if( changed )
689 emit torrentChanged( id( ) );
692 QString
693 Torrent :: activityString( ) const
695 QString str;
697 switch( getActivity( ) )
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;
706 return str;
709 QString
710 Torrent :: getError( ) const
712 QString s = getString( ERROR_STRING );
714 switch( getInt( ERROR ) )
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;
722 return s;
725 QPixmap
726 TrackerStat :: getFavicon( ) const
728 MyApp * myApp = dynamic_cast<MyApp*>(QApplication::instance());
729 return myApp->favicons.find( QUrl( announce ) );