272 lines
8.1 KiB
C++
272 lines
8.1 KiB
C++
/*
|
|
* This file Copyright (C) 2009-2014 Mnemosyne LLC
|
|
*
|
|
* It may be used under the GNU Public License v2 or v3 licenses,
|
|
* or any future license endorsed by Mnemosyne LLC.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#include <iostream>
|
|
|
|
#include <QPainter>
|
|
#include <QPixmap>
|
|
#include <QTextDocument>
|
|
|
|
#include <libtransmission/transmission.h>
|
|
#include <libtransmission/utils.h>
|
|
|
|
#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<int> (favicon.height(), textSize.height()) + myMargin.height());
|
|
}
|
|
|
|
QSize
|
|
TrackerDelegate :: sizeHint (const QStyleOptionViewItem & option,
|
|
const QModelIndex & index) const
|
|
{
|
|
const TrackerInfo trackerInfo = index.data (TrackerModel::TrackerRole).value<TrackerInfo>();
|
|
return sizeHint (option, trackerInfo);
|
|
}
|
|
|
|
void
|
|
TrackerDelegate :: paint (QPainter * painter,
|
|
const QStyleOptionViewItem & option,
|
|
const QModelIndex & index) const
|
|
{
|
|
const TrackerInfo trackerInfo = index.data (TrackerModel::TrackerRole).value<TrackerInfo>();
|
|
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 = "<span style=\"color:red\">";
|
|
const QString err_markup_end = "</span>";
|
|
const QString timeout_markup_begin = "<span style=\"color:#224466\">";
|
|
const QString timeout_markup_end = "</span>";
|
|
const QString success_markup_begin = "<span style=\"color:#008B00\">";
|
|
const QString success_markup_end = "</span>";
|
|
|
|
// hostname
|
|
str += inf.st.isBackup ? "<i>" : "<b>";
|
|
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 ? "</i>" : "</b>";
|
|
|
|
// 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 += "<br/>\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 += "<br/>\n";
|
|
str += tr ("No updates scheduled");
|
|
break;
|
|
|
|
case TR_TRACKER_WAITING:
|
|
{
|
|
const QString tstr (timeToStringRounded (inf.st.nextAnnounceTime - now));
|
|
str += "<br/>\n";
|
|
str += tr ("Asking for more peers in %1").arg (tstr);
|
|
break;
|
|
}
|
|
|
|
case TR_TRACKER_QUEUED:
|
|
str += "<br/>\n";
|
|
str += tr ("Queued to ask for more peers");
|
|
break;
|
|
|
|
case TR_TRACKER_ACTIVE: {
|
|
const QString tstr (timeToStringRounded (now - inf.st.lastAnnounceStartTime));
|
|
str += "<br/>\n";
|
|
str += tr ("Asking for more peers now... <small>%1</small>").arg (tstr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (myShowMore)
|
|
{
|
|
if (inf.st.hasScraped)
|
|
{
|
|
str += "<br/>\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 += "<br/>\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 += "<br/>\n";
|
|
str += tr ("Queued to ask for peer counts");
|
|
break;
|
|
}
|
|
|
|
case TR_TRACKER_ACTIVE:
|
|
{
|
|
str += "<br/>\n";
|
|
const QString tstr (timeToStringRounded (now - inf.st.lastScrapeStartTime));
|
|
str += tr ("Asking for peer counts now... <small>%1</small>").arg (tstr);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return str;
|
|
}
|