/* * This file Copyright (C) Mnemosyne LLC * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * $Id$ */ #include #include #include #include #include #include #include "favicon.h" #include "formatter.h" #include "torrent.h" #include "tracker-delegate.h" #include "tracker-model.h" /*** **** ***/ namespace { const int mySpacing = 6; const QSize myMargin( 10, 6 ); } QSize TrackerDelegate :: margin( const QStyle& style ) const { Q_UNUSED( style ); return myMargin; } /*** **** ***/ QSize TrackerDelegate :: sizeHint( const QStyleOptionViewItem& option, const TrackerInfo& info ) const { Q_UNUSED( option ); QPixmap favicon = info.st.getFavicon( ); const QString text = TrackerDelegate :: getText( info ); QTextDocument textDoc; textDoc.setHtml( text ); const QSize textSize = textDoc.size().toSize(); return QSize( myMargin.width() + favicon.width() + mySpacing + textSize.width() + myMargin.width(), myMargin.height() + qMax( favicon.height(), textSize.height() ) + myMargin.height() ); } QSize TrackerDelegate :: sizeHint( const QStyleOptionViewItem & option, const QModelIndex & index ) const { const TrackerInfo trackerInfo = index.data( TrackerModel::TrackerRole ).value(); return sizeHint( option, trackerInfo ); } void TrackerDelegate :: paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { const TrackerInfo trackerInfo = index.data( TrackerModel::TrackerRole ).value(); painter->save( ); painter->setClipRect( option.rect ); drawBackground( painter, option, index ); drawTracker( painter, option, trackerInfo ); drawFocus(painter, option, option.rect ); painter->restore( ); } void TrackerDelegate :: drawTracker( QPainter * painter, const QStyleOptionViewItem & option, const TrackerInfo & inf ) const { painter->save( ); QPixmap icon = inf.st.getFavicon( ); QRect iconArea( option.rect.x() + myMargin.width(), option.rect.y() + myMargin.height(), icon.width(), icon.height() ); painter->drawPixmap( iconArea.x(), iconArea.y()+4, icon ); const int textWidth = option.rect.width() - myMargin.width()*2 - mySpacing - icon.width(); const int textX = myMargin.width() + icon.width() + mySpacing; const QString text = getText( inf ); QTextDocument textDoc; textDoc.setHtml( text ); const QRect textRect( textX, iconArea.y(), textWidth, option.rect.height() - myMargin.height()*2 ); painter->translate( textRect.topLeft( ) ); textDoc.drawContents( painter, textRect.translated( -textRect.topLeft( ) ) ); painter->restore( ); } void TrackerDelegate :: setShowMore( bool b ) { myShowMore = b; } namespace { QString timeToStringRounded( int seconds ) { if( seconds > 60 ) seconds -= ( seconds % 60 ); return Formatter::timeToString ( seconds ); } } QString TrackerDelegate :: getText( const TrackerInfo& inf ) const { QString key; QString str; const time_t now( time( 0 ) ); const QString err_markup_begin = ""; const QString err_markup_end = ""; const QString timeout_markup_begin = ""; const QString timeout_markup_end = ""; const QString success_markup_begin = ""; const QString success_markup_end = ""; // hostname str += inf.st.isBackup ? "" : ""; char * host = NULL; int port = 0; tr_urlParse( inf.st.announce.toUtf8().constData(), -1, NULL, &host, &port, NULL ); str += QString( "%1:%2" ).arg( host ).arg( port ); tr_free( host ); if( !key.isEmpty( ) ) str += " - " + key; str += inf.st.isBackup ? "" : ""; // announce & scrape info if( !inf.st.isBackup ) { if( inf.st.hasAnnounced && inf.st.announceState != TR_TRACKER_INACTIVE ) { const QString tstr( timeToStringRounded( now - inf.st.lastAnnounceTime ) ); str += "
\n"; if( inf.st.lastAnnounceSucceeded ) { str += tr( "Got a list of %1%2 peers%3 %4 ago" ) .arg( success_markup_begin ) .arg( inf.st.lastAnnouncePeerCount ) .arg( success_markup_end ) .arg( tstr ); } else if( inf.st.lastAnnounceTimedOut ) { str += tr( "Peer list request %1timed out%2 %3 ago; will retry" ) .arg( timeout_markup_begin ) .arg( timeout_markup_end ) .arg( tstr ); } else { str += tr( "Got an error %1\"%2\"%3 %4 ago" ) .arg( err_markup_begin ) .arg( inf.st.lastAnnounceResult ) .arg( err_markup_end ) .arg( tstr ); } } switch( inf.st.announceState ) { case TR_TRACKER_INACTIVE: str += "
\n"; str += tr( "No updates scheduled" ); break; case TR_TRACKER_WAITING: { const QString tstr( timeToStringRounded( inf.st.nextAnnounceTime - now ) ); str += "
\n"; str += tr( "Asking for more peers in %1" ).arg( tstr ); break; } case TR_TRACKER_QUEUED: str += "
\n"; str += tr( "Queued to ask for more peers" ); break; case TR_TRACKER_ACTIVE: { const QString tstr( timeToStringRounded( now - inf.st.lastAnnounceStartTime ) ); str += "
\n"; str += tr( "Asking for more peers now... %1" ).arg( tstr ); break; } } if( myShowMore ) { if( inf.st.hasScraped ) { str += "
\n"; const QString tstr( timeToStringRounded( now - inf.st.lastScrapeTime ) ); if( inf.st.lastScrapeSucceeded ) { str += tr( "Tracker had %1%2 seeders%3 and %4%5 leechers%6 %7 ago" ) .arg( success_markup_begin ) .arg( inf.st.seederCount ) .arg( success_markup_end ) .arg( success_markup_begin ) .arg( inf.st.leecherCount ) .arg( success_markup_end ) .arg( tstr ); } else { str += tr( "Got a scrape error %1\"%2\"%3 %4 ago" ) .arg( err_markup_begin ) .arg( inf.st.lastScrapeResult ) .arg( err_markup_end ) .arg( tstr ); } } switch( inf.st.scrapeState ) { case TR_TRACKER_INACTIVE: break; case TR_TRACKER_WAITING: { str += "
\n"; const QString tstr( timeToStringRounded( inf.st.nextScrapeTime - now ) ); str += tr( "Asking for peer counts in %1" ).arg( tstr ); break; } case TR_TRACKER_QUEUED: { str += "
\n"; str += tr( "Queued to ask for peer counts" ); break; } case TR_TRACKER_ACTIVE: { str += "
\n"; const QString tstr( timeToStringRounded( now - inf.st.lastScrapeStartTime ) ); str += tr( "Asking for peer counts now... %1" ).arg( tstr ); break; } } } } return str; }