mirror of
https://github.com/transmission/transmission.git
synced 2025-12-20 10:28:32 +00:00
qt client speedups
* faster updating of trackers combobox. * generate trackerDisplayNames just once per torrent * refactor: cache torrent delegate's warning emblem * refactor: change mainwin refresh debounce to 200ms * refactor: do not store trackers, hosts in QVariant * refactor: don't use `virtual` when it's not needed * refactor: faster counting torrents-matching-filter * refactor: faster tracker handling in filterbar * refactor: improve json parser's prealloc heuristic * refactor: make Torrent::hasError() faster * refactor: remove redundant speed stats collection * refactor: remove unnecessary tor->isQueued() calls * refactor: use unordered containers where possible * scale favicons only once, when adding to the cache
This commit is contained in:
@@ -45,6 +45,12 @@ struct json_wrapper_data
|
|||||||
struct evbuffer* strbuf;
|
struct evbuffer* strbuf;
|
||||||
char const* source;
|
char const* source;
|
||||||
tr_ptrArray stack;
|
tr_ptrArray stack;
|
||||||
|
|
||||||
|
/* A very common pattern is for a container's children to be similar,
|
||||||
|
* e.g. they may all be objects with the same set of keys. So when
|
||||||
|
* a container is popped off the stack, remember its size to use as
|
||||||
|
* a preallocation heuristic for the next container at that depth. */
|
||||||
|
size_t preallocGuess[MAX_DEPTH];
|
||||||
};
|
};
|
||||||
|
|
||||||
static tr_variant* get_node(struct jsonsl_st* jsn)
|
static tr_variant* get_node(struct jsonsl_st* jsn)
|
||||||
@@ -103,25 +109,22 @@ static void action_callback_PUSH(jsonsl_t jsn, jsonsl_action_t action UNUSED, st
|
|||||||
tr_variant* node;
|
tr_variant* node;
|
||||||
struct json_wrapper_data* data = jsn->data;
|
struct json_wrapper_data* data = jsn->data;
|
||||||
|
|
||||||
switch (state->type)
|
if ((state->type == JSONSL_T_LIST) || (state->type == JSONSL_T_OBJECT))
|
||||||
{
|
{
|
||||||
case JSONSL_T_LIST:
|
|
||||||
data->has_content = true;
|
data->has_content = true;
|
||||||
node = get_node(jsn);
|
node = get_node(jsn);
|
||||||
tr_variantInitList(node, 0);
|
|
||||||
tr_ptrArrayAppend(&data->stack, node);
|
tr_ptrArrayAppend(&data->stack, node);
|
||||||
break;
|
|
||||||
|
|
||||||
case JSONSL_T_OBJECT:
|
int const depth = tr_ptrArraySize(&data->stack);
|
||||||
data->has_content = true;
|
size_t const n = depth < MAX_DEPTH ? data->preallocGuess[depth] : 0;
|
||||||
node = get_node(jsn);
|
if (state->type == JSONSL_T_LIST)
|
||||||
tr_variantInitDict(node, 0);
|
{
|
||||||
tr_ptrArrayAppend(&data->stack, node);
|
tr_variantInitList(node, n);
|
||||||
break;
|
}
|
||||||
|
else
|
||||||
default:
|
{
|
||||||
/* nothing else interesting on push */
|
tr_variantInitDict(node, n);
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +321,12 @@ static void action_callback_POP(jsonsl_t jsn, jsonsl_action_t action UNUSED, str
|
|||||||
}
|
}
|
||||||
else if (state->type == JSONSL_T_LIST || state->type == JSONSL_T_OBJECT)
|
else if (state->type == JSONSL_T_LIST || state->type == JSONSL_T_OBJECT)
|
||||||
{
|
{
|
||||||
tr_ptrArrayPop(&data->stack);
|
int const depth = tr_ptrArraySize(&data->stack);
|
||||||
|
tr_variant const* v = tr_ptrArrayPop(&data->stack);
|
||||||
|
if (depth < MAX_DEPTH)
|
||||||
|
{
|
||||||
|
data->preallocGuess[depth] = v->val.l.count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (state->type == JSONSL_T_SPECIAL)
|
else if (state->type == JSONSL_T_SPECIAL)
|
||||||
{
|
{
|
||||||
@@ -369,6 +377,10 @@ int tr_jsonParse(char const* source, void const* vbuf, size_t len, tr_variant* s
|
|||||||
data.source = source;
|
data.source = source;
|
||||||
data.keybuf = evbuffer_new();
|
data.keybuf = evbuffer_new();
|
||||||
data.strbuf = evbuffer_new();
|
data.strbuf = evbuffer_new();
|
||||||
|
for (int i = 0; i < MAX_DEPTH; ++i)
|
||||||
|
{
|
||||||
|
data.preallocGuess[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* parse it */
|
/* parse it */
|
||||||
jsonsl_feed(jsn, vbuf, len);
|
jsonsl_feed(jsn, vbuf, len);
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ class AboutDialog : public BaseDialog
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
AboutDialog(QWidget* parent = nullptr);
|
AboutDialog(QWidget* parent = nullptr);
|
||||||
virtual ~AboutDialog() = default;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void showCredits();
|
void showCredits();
|
||||||
|
|||||||
@@ -399,7 +399,7 @@ void Application::quitLater()
|
|||||||
QTimer::singleShot(0, this, SLOT(quit()));
|
QTimer::singleShot(0, this, SLOT(quit()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList Application::getNames(QSet<int> const& ids) const
|
QStringList Application::getNames(torrent_ids_t const& ids) const
|
||||||
{
|
{
|
||||||
QStringList names;
|
QStringList names;
|
||||||
for (auto const& id : ids)
|
for (auto const& id : ids)
|
||||||
@@ -411,7 +411,7 @@ QStringList Application::getNames(QSet<int> const& ids) const
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onTorrentsAdded(QSet<int> const& ids)
|
void Application::onTorrentsAdded(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
if (myPrefs->getBool(Prefs::SHOW_NOTIFICATION_ON_ADD))
|
if (myPrefs->getBool(Prefs::SHOW_NOTIFICATION_ON_ADD))
|
||||||
{
|
{
|
||||||
@@ -421,7 +421,7 @@ void Application::onTorrentsAdded(QSet<int> const& ids)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onTorrentsCompleted(QSet<int> const& ids)
|
void Application::onTorrentsCompleted(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
if (myPrefs->getBool(Prefs::SHOW_NOTIFICATION_ON_COMPLETE))
|
if (myPrefs->getBool(Prefs::SHOW_NOTIFICATION_ON_COMPLETE))
|
||||||
{
|
{
|
||||||
@@ -440,9 +440,9 @@ void Application::onTorrentsCompleted(QSet<int> const& ids)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onTorrentsNeedInfo(QSet<int> const& ids)
|
void Application::onTorrentsNeedInfo(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
if (!ids.isEmpty())
|
if (!ids.empty())
|
||||||
{
|
{
|
||||||
mySession->initTorrents(ids);
|
mySession->initTorrents(ids);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QSet>
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
|
||||||
#include "FaviconCache.h"
|
#include "FaviconCache.h"
|
||||||
|
#include "Typedefs.h"
|
||||||
|
|
||||||
class AddData;
|
class AddData;
|
||||||
class Prefs;
|
class Prefs;
|
||||||
@@ -43,14 +43,14 @@ private slots:
|
|||||||
void onSessionSourceChanged();
|
void onSessionSourceChanged();
|
||||||
void refreshPref(int key);
|
void refreshPref(int key);
|
||||||
void refreshTorrents();
|
void refreshTorrents();
|
||||||
void onTorrentsAdded(QSet<int> const& torrents);
|
void onTorrentsAdded(torrent_ids_t const& torrents);
|
||||||
void onTorrentsCompleted(QSet<int> const& torrents);
|
void onTorrentsCompleted(torrent_ids_t const& torrents);
|
||||||
void onTorrentsNeedInfo(QSet<int> const& torrents);
|
void onTorrentsNeedInfo(torrent_ids_t const& torrents);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void maybeUpdateBlocklist();
|
void maybeUpdateBlocklist();
|
||||||
void loadTranslations();
|
void loadTranslations();
|
||||||
QStringList getNames(QSet<int> const& ids) const;
|
QStringList getNames(torrent_ids_t const& ids) const;
|
||||||
void quitLater();
|
void quitLater();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ set(${PROJECT_NAME}_HEADERS
|
|||||||
TrackerDelegate.h
|
TrackerDelegate.h
|
||||||
TrackerModel.h
|
TrackerModel.h
|
||||||
TrackerModelFilter.h
|
TrackerModelFilter.h
|
||||||
|
Typedefs.h
|
||||||
Utils.h
|
Utils.h
|
||||||
WatchDir.h
|
WatchDir.h
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public:
|
|||||||
void addLayout(QGridLayout* layout);
|
void addLayout(QGridLayout* layout);
|
||||||
|
|
||||||
// QObject
|
// QObject
|
||||||
virtual bool eventFilter(QObject* object, QEvent* event);
|
bool eventFilter(QObject* object, QEvent* event) override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void update();
|
void update();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <algorithm> // std::any_of
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <climits> /* INT_MAX */
|
#include <climits> /* INT_MAX */
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
@@ -249,7 +250,7 @@ DetailsDialog::~DetailsDialog()
|
|||||||
myTrackerModel->deleteLater();
|
myTrackerModel->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetailsDialog::setIds(QSet<int> const& ids)
|
void DetailsDialog::setIds(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
if (ids != myIds)
|
if (ids != myIds)
|
||||||
{
|
{
|
||||||
@@ -309,15 +310,20 @@ void DetailsDialog::getNewData()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetailsDialog::onTorrentsChanged(QSet<int> const& ids)
|
void DetailsDialog::onTorrentsChanged(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
auto const interesting = ids & myIds;
|
if (myHavePendingRefresh)
|
||||||
|
|
||||||
if (!interesting.isEmpty() && !myHavePendingRefresh)
|
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!std::any_of(ids.begin(), ids.end(), [this](auto const& id) { return myIds.count(id) != 0; }))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
myHavePendingRefresh = true;
|
myHavePendingRefresh = true;
|
||||||
QTimer::singleShot(100, this, SLOT(refresh()));
|
QTimer::singleShot(100, this, SLOT(refresh()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@@ -1290,7 +1296,7 @@ void DetailsDialog::onAddTrackerClicked()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QSet<int> ids;
|
torrent_ids_t ids;
|
||||||
|
|
||||||
for (int const id : myIds)
|
for (int const id : myIds)
|
||||||
{
|
{
|
||||||
@@ -1336,8 +1342,7 @@ void DetailsDialog::onEditTrackerClicked()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QSet<int> ids;
|
torrent_ids_t ids{ trackerInfo.torrentId };
|
||||||
ids << trackerInfo.torrentId;
|
|
||||||
|
|
||||||
QPair<int, QString> const idUrl = qMakePair(trackerInfo.st.id, newval);
|
QPair<int, QString> const idUrl = qMakePair(trackerInfo.st.id, newval);
|
||||||
|
|
||||||
@@ -1362,8 +1367,7 @@ void DetailsDialog::onRemoveTrackerClicked()
|
|||||||
// batch all of a tracker's torrents into one command
|
// batch all of a tracker's torrents into one command
|
||||||
for (int const id : torrentId_to_trackerIds.uniqueKeys())
|
for (int const id : torrentId_to_trackerIds.uniqueKeys())
|
||||||
{
|
{
|
||||||
QSet<int> ids;
|
torrent_ids_t const ids{ id };
|
||||||
ids << id;
|
|
||||||
mySession.torrentSet(ids, TR_KEY_trackerRemove, torrentId_to_trackerIds.values(id));
|
mySession.torrentSet(ids, TR_KEY_trackerRemove, torrentId_to_trackerIds.values(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include "BaseDialog.h"
|
#include "BaseDialog.h"
|
||||||
|
#include "Typedefs.h"
|
||||||
|
|
||||||
#include "ui_DetailsDialog.h"
|
#include "ui_DetailsDialog.h"
|
||||||
|
|
||||||
@@ -35,10 +36,10 @@ public:
|
|||||||
DetailsDialog(Session&, Prefs&, TorrentModel const&, QWidget* parent = nullptr);
|
DetailsDialog(Session&, Prefs&, TorrentModel const&, QWidget* parent = nullptr);
|
||||||
virtual ~DetailsDialog();
|
virtual ~DetailsDialog();
|
||||||
|
|
||||||
void setIds(QSet<int> const& ids);
|
void setIds(torrent_ids_t const& ids);
|
||||||
|
|
||||||
// QWidget
|
// QWidget
|
||||||
virtual QSize sizeHint() const
|
QSize sizeHint() const override
|
||||||
{
|
{
|
||||||
return QSize(440, 460);
|
return QSize(440, 460);
|
||||||
}
|
}
|
||||||
@@ -59,7 +60,7 @@ private slots:
|
|||||||
void refresh();
|
void refresh();
|
||||||
void refreshPref(int key);
|
void refreshPref(int key);
|
||||||
|
|
||||||
void onTorrentsChanged(QSet<int> const& ids);
|
void onTorrentsChanged(torrent_ids_t const& ids);
|
||||||
void onTimer();
|
void onTimer();
|
||||||
|
|
||||||
// Tracker tab
|
// Tracker tab
|
||||||
@@ -93,7 +94,7 @@ private:
|
|||||||
|
|
||||||
Ui::DetailsDialog ui;
|
Ui::DetailsDialog ui;
|
||||||
|
|
||||||
QSet<int> myIds;
|
torrent_ids_t myIds;
|
||||||
QTimer myTimer;
|
QTimer myTimer;
|
||||||
bool myChangedTorrents;
|
bool myChangedTorrents;
|
||||||
bool myHavePendingRefresh;
|
bool myHavePendingRefresh;
|
||||||
|
|||||||
@@ -40,6 +40,15 @@ QString FaviconCache::getCacheDir()
|
|||||||
return QDir(base).absoluteFilePath(QLatin1String("favicons"));
|
return QDir(base).absoluteFilePath(QLatin1String("favicons"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
QPixmap scale(QPixmap pixmap)
|
||||||
|
{
|
||||||
|
return pixmap.scaled(FaviconCache::getIconSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
void FaviconCache::ensureCacheDirHasBeenScanned()
|
void FaviconCache::ensureCacheDirHasBeenScanned()
|
||||||
{
|
{
|
||||||
static bool hasBeenScanned = false;
|
static bool hasBeenScanned = false;
|
||||||
@@ -60,24 +69,44 @@ void FaviconCache::ensureCacheDirHasBeenScanned()
|
|||||||
|
|
||||||
if (!pixmap.isNull())
|
if (!pixmap.isNull())
|
||||||
{
|
{
|
||||||
myPixmaps.insert(file, pixmap);
|
myPixmaps[file] = scale(pixmap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FaviconCache::getHost(QUrl const& url)
|
/***
|
||||||
|
****
|
||||||
|
***/
|
||||||
|
|
||||||
|
QString FaviconCache::getDisplayName(QUrl const& url)
|
||||||
{
|
{
|
||||||
QString host = url.host();
|
return getDisplayName(getKey(url));
|
||||||
int const first_dot = host.indexOf(QLatin1Char('.'));
|
}
|
||||||
int const last_dot = host.lastIndexOf(QLatin1Char('.'));
|
|
||||||
|
|
||||||
if (first_dot != -1 && last_dot != -1 && first_dot != last_dot)
|
QString FaviconCache::getDisplayName(QString const& key)
|
||||||
{
|
{
|
||||||
host.remove(0, first_dot + 1);
|
auto name = key;
|
||||||
}
|
name[0] = name.at(0).toTitleCase();
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
return host;
|
QString FaviconCache::getKey(QUrl const& url)
|
||||||
|
{
|
||||||
|
auto host = url.host();
|
||||||
|
|
||||||
|
// remove tld
|
||||||
|
auto const suffix = url.topLevelDomain();
|
||||||
|
host.truncate(host.size() - suffix.size());
|
||||||
|
|
||||||
|
// remove subdomain
|
||||||
|
auto const pos = host.indexOf(QLatin1Char('.'));
|
||||||
|
return pos < 0 ? host : host.remove(0, pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FaviconCache::getKey(QString const& displayName)
|
||||||
|
{
|
||||||
|
return displayName.toLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize FaviconCache::getIconSize()
|
QSize FaviconCache::getIconSize()
|
||||||
@@ -85,31 +114,26 @@ QSize FaviconCache::getIconSize()
|
|||||||
return QSize(16, 16);
|
return QSize(16, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap FaviconCache::find(QUrl const& url)
|
QPixmap FaviconCache::find(QString const& key)
|
||||||
{
|
|
||||||
return findFromHost(getHost(url));
|
|
||||||
}
|
|
||||||
|
|
||||||
QPixmap FaviconCache::findFromHost(QString const& host)
|
|
||||||
{
|
{
|
||||||
ensureCacheDirHasBeenScanned();
|
ensureCacheDirHasBeenScanned();
|
||||||
|
|
||||||
return myPixmaps[host];
|
return myPixmaps[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
void FaviconCache::add(QUrl const& url)
|
QString FaviconCache::add(QUrl const& url)
|
||||||
{
|
{
|
||||||
ensureCacheDirHasBeenScanned();
|
ensureCacheDirHasBeenScanned();
|
||||||
|
|
||||||
QString const host = getHost(url);
|
QString const key = getKey(url);
|
||||||
|
|
||||||
if (!myPixmaps.contains(host))
|
if (myPixmaps.count(key) == 0)
|
||||||
{
|
{
|
||||||
// add a placholder s.t. we only ping the server once per session
|
// add a placholder s.t. we only ping the server once per session
|
||||||
myPixmaps.insert(host, QPixmap());
|
myPixmaps[key] = QPixmap();
|
||||||
|
|
||||||
// try to download the favicon
|
// try to download the favicon
|
||||||
QString const path = QLatin1String("http://") + host + QLatin1String("/favicon.");
|
QString const path = QLatin1String("http://") + url.host() + QLatin1String("/favicon.");
|
||||||
QStringList suffixes;
|
QStringList suffixes;
|
||||||
suffixes << QLatin1String("ico") << QLatin1String("png") << QLatin1String("gif") << QLatin1String("jpg");
|
suffixes << QLatin1String("ico") << QLatin1String("png") << QLatin1String("gif") << QLatin1String("jpg");
|
||||||
|
|
||||||
@@ -118,11 +142,13 @@ void FaviconCache::add(QUrl const& url)
|
|||||||
myNAM->get(QNetworkRequest(path + suffix));
|
myNAM->get(QNetworkRequest(path + suffix));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FaviconCache::onRequestFinished(QNetworkReply* reply)
|
void FaviconCache::onRequestFinished(QNetworkReply* reply)
|
||||||
{
|
{
|
||||||
QString const host = reply->url().host();
|
auto const key = getKey(reply->url());
|
||||||
|
|
||||||
QPixmap pixmap;
|
QPixmap pixmap;
|
||||||
|
|
||||||
@@ -136,17 +162,17 @@ void FaviconCache::onRequestFinished(QNetworkReply* reply)
|
|||||||
if (!pixmap.isNull())
|
if (!pixmap.isNull())
|
||||||
{
|
{
|
||||||
// save it in memory...
|
// save it in memory...
|
||||||
myPixmaps.insert(host, pixmap);
|
myPixmaps[key] = scale(pixmap);
|
||||||
|
|
||||||
// save it on disk...
|
// save it on disk...
|
||||||
QDir cacheDir(getCacheDir());
|
QDir cacheDir(getCacheDir());
|
||||||
cacheDir.mkpath(cacheDir.absolutePath());
|
cacheDir.mkpath(cacheDir.absolutePath());
|
||||||
QFile file(cacheDir.absoluteFilePath(host));
|
QFile file(cacheDir.absoluteFilePath(key));
|
||||||
file.open(QIODevice::WriteOnly);
|
file.open(QIODevice::WriteOnly);
|
||||||
file.write(content);
|
file.write(content);
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
// notify listeners
|
// notify listeners
|
||||||
emit pixmapReady(host);
|
emit pixmapReady(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QMap>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
|
|
||||||
|
#include <Utils.h> // std::hash<QString>
|
||||||
|
|
||||||
class QNetworkAccessManager;
|
class QNetworkAccessManager;
|
||||||
class QNetworkReply;
|
class QNetworkReply;
|
||||||
class QUrl;
|
class QUrl;
|
||||||
@@ -26,19 +29,21 @@ public:
|
|||||||
virtual ~FaviconCache();
|
virtual ~FaviconCache();
|
||||||
|
|
||||||
// returns a cached pixmap, or a NULL pixmap if there's no match in the cache
|
// returns a cached pixmap, or a NULL pixmap if there's no match in the cache
|
||||||
QPixmap find(QUrl const& url);
|
QPixmap find(QString const& key);
|
||||||
|
QPixmap find(QUrl const& url) { return find(getKey(url)); }
|
||||||
|
|
||||||
// returns a cached pixmap, or a NULL pixmap if there's no match in the cache
|
// This will emit a signal when (if) the icon becomes ready.
|
||||||
QPixmap findFromHost(QString const& host);
|
// Returns the key.
|
||||||
|
QString add(QUrl const& url);
|
||||||
|
|
||||||
// this will emit a signal when (if) the icon becomes ready
|
static QString getDisplayName(QUrl const& url);
|
||||||
void add(QUrl const& url);
|
static QString getDisplayName(QString const& key);
|
||||||
|
static QString getKey(QUrl const& url);
|
||||||
static QString getHost(QUrl const& url);
|
static QString getKey(QString const& displayName);
|
||||||
static QSize getIconSize();
|
static QSize getIconSize();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void pixmapReady(QString const& host);
|
void pixmapReady(QString const& key);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString getCacheDir();
|
QString getCacheDir();
|
||||||
@@ -49,5 +54,5 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QNetworkAccessManager* myNAM;
|
QNetworkAccessManager* myNAM;
|
||||||
QMap<QString, QPixmap> myPixmaps;
|
std::unordered_map<QString, QPixmap> myPixmaps;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,12 +20,8 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~FileTreeDelegate()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// QAbstractItemDelegate
|
// QAbstractItemDelegate
|
||||||
virtual QSize sizeHint(QStyleOptionViewItem const&, QModelIndex const&) const;
|
QSize sizeHint(QStyleOptionViewItem const&, QModelIndex const&) const override;
|
||||||
virtual void paint(QPainter*, QStyleOptionViewItem const&, QModelIndex const&) const;
|
void paint(QPainter*, QStyleOptionViewItem const&, QModelIndex const&) const override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -292,7 +292,7 @@ int FileTreeModel::rowCount(QModelIndex const& parent) const
|
|||||||
|
|
||||||
int FileTreeModel::columnCount(QModelIndex const& parent) const
|
int FileTreeModel::columnCount(QModelIndex const& parent) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(parent);
|
Q_UNUSED(parent)
|
||||||
|
|
||||||
return NUM_COLUMNS;
|
return NUM_COLUMNS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
FileTreeModel(QObject* parent = nullptr, bool isEditable = true);
|
FileTreeModel(QObject* parent = nullptr, bool isEditable = true);
|
||||||
virtual ~FileTreeModel();
|
~FileTreeModel();
|
||||||
|
|
||||||
void setEditable(bool editable);
|
void setEditable(bool editable);
|
||||||
|
|
||||||
@@ -62,14 +62,14 @@ public:
|
|||||||
QModelIndex parent(QModelIndex const& child, int column) const;
|
QModelIndex parent(QModelIndex const& child, int column) const;
|
||||||
|
|
||||||
// QAbstractItemModel
|
// QAbstractItemModel
|
||||||
virtual QVariant data(QModelIndex const& index, int role = Qt::DisplayRole) const;
|
QVariant data(QModelIndex const& index, int role = Qt::DisplayRole) const override;
|
||||||
virtual Qt::ItemFlags flags(QModelIndex const& index) const;
|
Qt::ItemFlags flags(QModelIndex const& index) const override;
|
||||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
virtual QModelIndex index(int row, int column, QModelIndex const& parent = QModelIndex()) const;
|
QModelIndex index(int row, int column, QModelIndex const& parent = QModelIndex()) const override;
|
||||||
virtual QModelIndex parent(QModelIndex const& child) const;
|
QModelIndex parent(QModelIndex const& child) const override;
|
||||||
virtual int rowCount(QModelIndex const& parent = QModelIndex()) const;
|
int rowCount(QModelIndex const& parent = QModelIndex()) const override;
|
||||||
virtual int columnCount(QModelIndex const& parent = QModelIndex()) const;
|
int columnCount(QModelIndex const& parent = QModelIndex()) const override;
|
||||||
virtual bool setData(QModelIndex const& index, QVariant const& value, int role = Qt::EditRole);
|
bool setData(QModelIndex const& index, QVariant const& value, int role = Qt::EditRole) override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void priorityChanged(QSet<int> const& fileIndices, int);
|
void priorityChanged(QSet<int> const& fileIndices, int);
|
||||||
|
|||||||
@@ -40,13 +40,13 @@ signals:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
// QWidget
|
// QWidget
|
||||||
virtual void resizeEvent(QResizeEvent* event);
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
virtual void keyPressEvent(QKeyEvent* event);
|
void keyPressEvent(QKeyEvent* event) override;
|
||||||
virtual void mouseDoubleClickEvent(QMouseEvent* event);
|
void mouseDoubleClickEvent(QMouseEvent* event) override;
|
||||||
virtual void contextMenuEvent(QContextMenuEvent* event);
|
void contextMenuEvent(QContextMenuEvent* event) override;
|
||||||
|
|
||||||
// QAbstractItemView
|
// QAbstractItemView
|
||||||
virtual bool edit(QModelIndex const& index, EditTrigger trigger, QEvent* event);
|
bool edit(QModelIndex const& index, EditTrigger trigger, QEvent* event) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onClicked(QModelIndex const& index);
|
void onClicked(QModelIndex const& index);
|
||||||
|
|||||||
194
qt/FilterBar.cc
194
qt/FilterBar.cc
@@ -6,6 +6,9 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
@@ -21,6 +24,7 @@
|
|||||||
#include "Torrent.h"
|
#include "Torrent.h"
|
||||||
#include "TorrentFilter.h"
|
#include "TorrentFilter.h"
|
||||||
#include "TorrentModel.h"
|
#include "TorrentModel.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@@ -28,30 +32,6 @@ enum
|
|||||||
TrackerRole
|
TrackerRole
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
QString readableHostName(QString const& host)
|
|
||||||
{
|
|
||||||
// get the readable name...
|
|
||||||
QString name = host;
|
|
||||||
int const pos = name.lastIndexOf(QLatin1Char('.'));
|
|
||||||
|
|
||||||
if (pos >= 0)
|
|
||||||
{
|
|
||||||
name.truncate(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!name.isEmpty())
|
|
||||||
{
|
|
||||||
name[0] = name[0].toUpper();
|
|
||||||
}
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
****
|
****
|
||||||
***/
|
***/
|
||||||
@@ -107,122 +87,88 @@ FilterBarComboBox* FilterBar::createActivityCombo()
|
|||||||
****
|
****
|
||||||
***/
|
***/
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
QString getCountString(int n)
|
||||||
|
{
|
||||||
|
return QString::fromLatin1("%L1").arg(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void FilterBar::refreshTrackers()
|
void FilterBar::refreshTrackers()
|
||||||
{
|
{
|
||||||
FaviconCache& favicons = qApp->faviconCache();
|
enum
|
||||||
int const firstTrackerRow = 2; // skip over the "All" and separator...
|
|
||||||
|
|
||||||
// pull info from the tracker model...
|
|
||||||
QSet<QString> oldHosts;
|
|
||||||
|
|
||||||
for (int row = firstTrackerRow;; ++row)
|
|
||||||
{
|
{
|
||||||
QModelIndex index = myTrackerModel->index(row, 0);
|
ROW_TOTALS = 0, ROW_SEPARATOR, ROW_FIRST_TRACKER
|
||||||
|
};
|
||||||
|
|
||||||
if (!index.isValid())
|
auto torrentsPerHost = std::unordered_map<QString, int>{};
|
||||||
|
for (auto const& tor : myTorrents.torrents())
|
||||||
{
|
{
|
||||||
break;
|
for (auto const& displayName : tor->trackerDisplayNames())
|
||||||
}
|
|
||||||
|
|
||||||
oldHosts << index.data(TrackerRole).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// pull the new stats from the torrent model...
|
|
||||||
QSet<QString> newHosts;
|
|
||||||
QMap<QString, int> torrentsPerHost;
|
|
||||||
|
|
||||||
for (int row = 0;; ++row)
|
|
||||||
{
|
{
|
||||||
QModelIndex index = myTorrents.index(row, 0);
|
++torrentsPerHost[displayName];
|
||||||
|
|
||||||
if (!index.isValid())
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Torrent const* tor = index.data(TorrentModel::TorrentRole).value<Torrent const*>();
|
|
||||||
QSet<QString> torrentNames;
|
|
||||||
|
|
||||||
for (QString const& host : tor->hosts())
|
|
||||||
{
|
|
||||||
newHosts.insert(host);
|
|
||||||
torrentNames.insert(readableHostName(host));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (QString const& name : torrentNames)
|
|
||||||
{
|
|
||||||
++torrentsPerHost[name];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the "All" row
|
// update the "All" row
|
||||||
myTrackerModel->setData(myTrackerModel->index(0, 0), myTorrents.rowCount(), FilterBarComboBox::CountRole);
|
auto const num_trackers = torrentsPerHost.size();
|
||||||
myTrackerModel->setData(myTrackerModel->index(0, 0), getCountString(myTorrents.rowCount()),
|
auto item = myTrackerModel->item(ROW_TOTALS);
|
||||||
FilterBarComboBox::CountStringRole);
|
item->setData(int(num_trackers), FilterBarComboBox::CountRole);
|
||||||
|
item->setData(getCountString(num_trackers), FilterBarComboBox::CountStringRole);
|
||||||
|
|
||||||
// rows to update
|
auto updateTrackerItem = [](QStandardItem* i, auto const& it)
|
||||||
for (QString const& host : oldHosts & newHosts)
|
|
||||||
{
|
{
|
||||||
QString const name = readableHostName(host);
|
auto const& displayName = it->first;
|
||||||
QStandardItem* row = myTrackerModel->findItems(name).front();
|
auto const& count = it->second;
|
||||||
int const count = torrentsPerHost[name];
|
auto const icon = qApp->faviconCache().find(FaviconCache::getKey(displayName));
|
||||||
row->setData(count, FilterBarComboBox::CountRole);
|
i->setData(displayName, Qt::DisplayRole);
|
||||||
row->setData(getCountString(count), FilterBarComboBox::CountStringRole);
|
i->setData(displayName, TrackerRole);
|
||||||
row->setData(QIcon(favicons.findFromHost(host)), Qt::DecorationRole);
|
i->setData(getCountString(count), FilterBarComboBox::CountStringRole);
|
||||||
}
|
i->setData(icon, Qt::DecorationRole);
|
||||||
|
i->setData(int(count), FilterBarComboBox::CountRole);
|
||||||
|
return i;
|
||||||
|
};
|
||||||
|
|
||||||
// rows to remove
|
auto newTrackers = std::map<QString, int>(torrentsPerHost.begin(), torrentsPerHost.end());
|
||||||
for (QString const& host : oldHosts - newHosts)
|
auto old_it = myTrackerCounts.cbegin();
|
||||||
{
|
auto new_it = newTrackers.cbegin();
|
||||||
QString const name = readableHostName(host);
|
auto const old_end = myTrackerCounts.cend();
|
||||||
QStandardItem* item = myTrackerModel->findItems(name).front();
|
auto const new_end = newTrackers.cend();
|
||||||
|
|
||||||
if (!item->data(TrackerRole).toString().isEmpty()) // don't remove "All"
|
|
||||||
{
|
|
||||||
myTrackerModel->removeRows(item->row(), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rows to add
|
|
||||||
bool anyAdded = false;
|
bool anyAdded = false;
|
||||||
|
int row = ROW_FIRST_TRACKER;
|
||||||
|
|
||||||
for (QString const& host : newHosts - oldHosts)
|
while ((old_it != old_end) || (new_it != new_end))
|
||||||
{
|
{
|
||||||
QString const name = readableHostName(host);
|
if ((old_it == old_end) || ((new_it != new_end) && (old_it->first > new_it->first)))
|
||||||
|
|
||||||
if (!myTrackerModel->findItems(name).isEmpty())
|
|
||||||
{
|
{
|
||||||
continue;
|
myTrackerModel->insertRow(row, updateTrackerItem(new QStandardItem(1), new_it));
|
||||||
}
|
|
||||||
|
|
||||||
// find the sorted position to add this row
|
|
||||||
int i = firstTrackerRow;
|
|
||||||
|
|
||||||
for (int n = myTrackerModel->rowCount(); i < n; ++i)
|
|
||||||
{
|
|
||||||
QString const rowName = myTrackerModel->index(i, 0).data(Qt::DisplayRole).toString();
|
|
||||||
|
|
||||||
if (rowName >= name)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the row
|
|
||||||
QStandardItem* row = new QStandardItem(favicons.findFromHost(host), name);
|
|
||||||
int const count = torrentsPerHost[host];
|
|
||||||
row->setData(count, FilterBarComboBox::CountRole);
|
|
||||||
row->setData(getCountString(count), FilterBarComboBox::CountStringRole);
|
|
||||||
row->setData(QIcon(favicons.findFromHost(host)), Qt::DecorationRole);
|
|
||||||
row->setData(host, TrackerRole);
|
|
||||||
myTrackerModel->insertRow(i, row);
|
|
||||||
anyAdded = true;
|
anyAdded = true;
|
||||||
|
++new_it;
|
||||||
|
++row;
|
||||||
|
}
|
||||||
|
else if ((new_it == new_end) || ((old_it != old_end) && (old_it->first < new_it->first)))
|
||||||
|
{
|
||||||
|
myTrackerModel->removeRow(row);
|
||||||
|
++old_it;
|
||||||
|
}
|
||||||
|
else // update
|
||||||
|
{
|
||||||
|
updateTrackerItem(myTrackerModel->item(row), new_it);
|
||||||
|
++old_it;
|
||||||
|
++new_it;
|
||||||
|
++row;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anyAdded) // the one added might match our filter...
|
if (anyAdded) // the one added might match our filter...
|
||||||
{
|
{
|
||||||
refreshPref(Prefs::FILTER_TRACKERS);
|
refreshPref(Prefs::FILTER_TRACKERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
myTrackerCounts.swap(newTrackers);
|
||||||
}
|
}
|
||||||
|
|
||||||
FilterBarComboBox* FilterBar::createTrackerCombo(QStandardItemModel* model)
|
FilterBarComboBox* FilterBar::createTrackerCombo(QStandardItemModel* model)
|
||||||
@@ -294,10 +240,7 @@ FilterBar::FilterBar(Prefs& prefs, TorrentModel const& torrents, TorrentFilter c
|
|||||||
myIsBootstrapping = false;
|
myIsBootstrapping = false;
|
||||||
|
|
||||||
// initialize our state
|
// initialize our state
|
||||||
QList<int> initKeys;
|
for (int const key : { Prefs::FILTER_MODE, Prefs::FILTER_TRACKERS })
|
||||||
initKeys << Prefs::FILTER_MODE << Prefs::FILTER_TRACKERS;
|
|
||||||
|
|
||||||
for (int const key : initKeys)
|
|
||||||
{
|
{
|
||||||
refreshPref(key);
|
refreshPref(key);
|
||||||
}
|
}
|
||||||
@@ -338,10 +281,8 @@ void FilterBar::refreshPref(int key)
|
|||||||
|
|
||||||
case Prefs::FILTER_TRACKERS:
|
case Prefs::FILTER_TRACKERS:
|
||||||
{
|
{
|
||||||
QString const tracker = myPrefs.getString(key);
|
auto const displayName = myPrefs.getString(key);
|
||||||
QString const name = readableHostName(tracker);
|
auto rows = myTrackerModel->findItems(displayName);
|
||||||
QList<QStandardItem*> rows = myTrackerModel->findItems(name);
|
|
||||||
|
|
||||||
if (!rows.isEmpty())
|
if (!rows.isEmpty())
|
||||||
{
|
{
|
||||||
myTrackerCombo->setCurrentIndex(rows.front()->row());
|
myTrackerCombo->setCurrentIndex(rows.front()->row());
|
||||||
@@ -435,8 +376,3 @@ void FilterBar::recount()
|
|||||||
|
|
||||||
refreshTrackers();
|
refreshTrackers();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FilterBar::getCountString(int n) const
|
|
||||||
{
|
|
||||||
return QString::fromLatin1("%L1").arg(n);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
@@ -35,7 +37,6 @@ private:
|
|||||||
FilterBarComboBox* createTrackerCombo(QStandardItemModel*);
|
FilterBarComboBox* createTrackerCombo(QStandardItemModel*);
|
||||||
FilterBarComboBox* createActivityCombo();
|
FilterBarComboBox* createActivityCombo();
|
||||||
void refreshTrackers();
|
void refreshTrackers();
|
||||||
QString getCountString(int n) const;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void recountSoon();
|
void recountSoon();
|
||||||
@@ -57,4 +58,5 @@ private:
|
|||||||
QTimer* myRecountTimer;
|
QTimer* myRecountTimer;
|
||||||
bool myIsBootstrapping;
|
bool myIsBootstrapping;
|
||||||
QLineEdit* myLineEdit;
|
QLineEdit* myLineEdit;
|
||||||
|
std::map<QString, int> myTrackerCounts;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ QSize FilterBarComboBox::calculateSize(QSize const& textSize, QSize const& count
|
|||||||
|
|
||||||
void FilterBarComboBox::paintEvent(QPaintEvent* e)
|
void FilterBarComboBox::paintEvent(QPaintEvent* e)
|
||||||
{
|
{
|
||||||
Q_UNUSED(e);
|
Q_UNUSED(e)
|
||||||
|
|
||||||
QStylePainter painter(this);
|
QStylePainter painter(this);
|
||||||
painter.setPen(palette().color(QPalette::Text));
|
painter.setPen(palette().color(QPalette::Text));
|
||||||
|
|||||||
@@ -28,12 +28,12 @@ public:
|
|||||||
int currentCount() const;
|
int currentCount() const;
|
||||||
|
|
||||||
// QWidget
|
// QWidget
|
||||||
virtual QSize minimumSizeHint() const;
|
QSize minimumSizeHint() const override;
|
||||||
virtual QSize sizeHint() const;
|
QSize sizeHint() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// QWidget
|
// QWidget
|
||||||
virtual void paintEvent(QPaintEvent* e);
|
void paintEvent(QPaintEvent* e) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSize calculateSize(QSize const& textSize, QSize const& countSize) const;
|
QSize calculateSize(QSize const& textSize, QSize const& countSize) const;
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
// QAbstractItemDelegate
|
// QAbstractItemDelegate
|
||||||
virtual void paint(QPainter*, QStyleOptionViewItem const&, QModelIndex const&) const;
|
void paint(QPainter*, QStyleOptionViewItem const&, QModelIndex const&) const override;
|
||||||
virtual QSize sizeHint(QStyleOptionViewItem const&, QModelIndex const&) const;
|
QSize sizeHint(QStyleOptionViewItem const&, QModelIndex const&) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QComboBox* const myCombo;
|
QComboBox* const myCombo;
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ public:
|
|||||||
IconToolButton(QWidget* parent = nullptr);
|
IconToolButton(QWidget* parent = nullptr);
|
||||||
|
|
||||||
// QWidget
|
// QWidget
|
||||||
virtual QSize sizeHint() const;
|
QSize sizeHint() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// QWidget
|
// QWidget
|
||||||
virtual void paintEvent(QPaintEvent* event);
|
void paintEvent(QPaintEvent* event) override;
|
||||||
};
|
};
|
||||||
|
|||||||
105
qt/MainWindow.cc
105
qt/MainWindow.cc
@@ -8,14 +8,14 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include <QtGui>
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
#include <QFileDialog>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QMessageBox>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QProxyStyle>
|
#include <QProxyStyle>
|
||||||
#include <QLabel>
|
#include <QtGui>
|
||||||
#include <QFileDialog>
|
|
||||||
#include <QMessageBox>
|
|
||||||
|
|
||||||
#include <libtransmission/transmission.h>
|
#include <libtransmission/transmission.h>
|
||||||
#include <libtransmission/version.h>
|
#include <libtransmission/version.h>
|
||||||
@@ -330,8 +330,9 @@ MainWindow::MainWindow(Session& session, Prefs& prefs, TorrentModel& model, bool
|
|||||||
refreshPref(key);
|
refreshPref(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto refreshStatusSoon = [this]() { refreshSoon(REFRESH_STATUS_BAR); };
|
||||||
connect(&mySession, SIGNAL(sourceChanged()), this, SLOT(onSessionSourceChanged()));
|
connect(&mySession, SIGNAL(sourceChanged()), this, SLOT(onSessionSourceChanged()));
|
||||||
connect(&mySession, SIGNAL(statsUpdated()), this, SLOT(refreshStatusBar()));
|
connect(&mySession, &Session::statsUpdated, refreshStatusSoon);
|
||||||
connect(&mySession, SIGNAL(dataReadProgress()), this, SLOT(dataReadProgress()));
|
connect(&mySession, SIGNAL(dataReadProgress()), this, SLOT(dataReadProgress()));
|
||||||
connect(&mySession, SIGNAL(dataSendProgress()), this, SLOT(dataSendProgress()));
|
connect(&mySession, SIGNAL(dataSendProgress()), this, SLOT(dataSendProgress()));
|
||||||
connect(&mySession, SIGNAL(httpAuthenticationRequired()), this, SLOT(wrongAuthentication()));
|
connect(&mySession, SIGNAL(httpAuthenticationRequired()), this, SLOT(wrongAuthentication()));
|
||||||
@@ -518,7 +519,7 @@ void MainWindow::setSortAscendingPref(bool b)
|
|||||||
|
|
||||||
void MainWindow::showEvent(QShowEvent* event)
|
void MainWindow::showEvent(QShowEvent* event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(event);
|
Q_UNUSED(event)
|
||||||
|
|
||||||
ui.action_ShowMainWindow->setChecked(true);
|
ui.action_ShowMainWindow->setChecked(true);
|
||||||
}
|
}
|
||||||
@@ -529,7 +530,7 @@ void MainWindow::showEvent(QShowEvent* event)
|
|||||||
|
|
||||||
void MainWindow::hideEvent(QHideEvent* event)
|
void MainWindow::hideEvent(QHideEvent* event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(event);
|
Q_UNUSED(event)
|
||||||
|
|
||||||
if (!isVisible())
|
if (!isVisible())
|
||||||
{
|
{
|
||||||
@@ -610,7 +611,7 @@ static void openSelect(QString const& path)
|
|||||||
|
|
||||||
void MainWindow::openFolder()
|
void MainWindow::openFolder()
|
||||||
{
|
{
|
||||||
QSet<int> const selectedTorrents = getSelectedTorrents();
|
auto const selectedTorrents = getSelectedTorrents();
|
||||||
|
|
||||||
if (selectedTorrents.size() != 1)
|
if (selectedTorrents.size() != 1)
|
||||||
{
|
{
|
||||||
@@ -692,10 +693,26 @@ void MainWindow::refreshSoon(int fields)
|
|||||||
if (!myRefreshTimer.isActive())
|
if (!myRefreshTimer.isActive())
|
||||||
{
|
{
|
||||||
myRefreshTimer.setSingleShot(true);
|
myRefreshTimer.setSingleShot(true);
|
||||||
myRefreshTimer.start(100);
|
myRefreshTimer.start(200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MainWindow::TransferStats MainWindow::getTransferStats() const
|
||||||
|
{
|
||||||
|
TransferStats stats;
|
||||||
|
|
||||||
|
for (auto const& tor : myModel.torrents())
|
||||||
|
{
|
||||||
|
stats.speedUp += tor->uploadSpeed();
|
||||||
|
stats.speedDown += tor->downloadSpeed();
|
||||||
|
stats.peersSending += tor->webseedsWeAreDownloadingFrom();
|
||||||
|
stats.peersSending += tor->peersWeAreDownloadingFrom();
|
||||||
|
stats.peersReceiving += tor->peersWeAreUploadingTo();
|
||||||
|
}
|
||||||
|
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::onRefreshTimer()
|
void MainWindow::onRefreshTimer()
|
||||||
{
|
{
|
||||||
int fields = 0;
|
int fields = 0;
|
||||||
@@ -706,14 +723,19 @@ void MainWindow::onRefreshTimer()
|
|||||||
refreshTitle();
|
refreshTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fields & REFRESH_STATUS_BAR)
|
if (fields & (REFRESH_TRAY_ICON | REFRESH_STATUS_BAR))
|
||||||
{
|
{
|
||||||
refreshStatusBar();
|
auto const stats = getTransferStats();
|
||||||
}
|
|
||||||
|
|
||||||
if (fields & REFRESH_TRAY_ICON)
|
if (fields & REFRESH_TRAY_ICON)
|
||||||
{
|
{
|
||||||
refreshTrayIcon();
|
refreshTrayIcon(stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fields & REFRESH_STATUS_BAR)
|
||||||
|
{
|
||||||
|
refreshStatusBar(stats);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fields & REFRESH_TORRENT_VIEW_HEADER)
|
if (fields & REFRESH_TORRENT_VIEW_HEADER)
|
||||||
@@ -742,48 +764,37 @@ void MainWindow::refreshTitle()
|
|||||||
setWindowTitle(title);
|
setWindowTitle(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::refreshTrayIcon()
|
void MainWindow::refreshTrayIcon(TransferStats const& stats)
|
||||||
{
|
{
|
||||||
Speed upSpeed;
|
|
||||||
Speed downSpeed;
|
|
||||||
size_t upCount;
|
|
||||||
size_t downCount;
|
|
||||||
QString tip;
|
QString tip;
|
||||||
|
|
||||||
myModel.getTransferSpeed(upSpeed, upCount, downSpeed, downCount);
|
|
||||||
|
|
||||||
if (myNetworkError)
|
if (myNetworkError)
|
||||||
{
|
{
|
||||||
tip = tr("Network Error");
|
tip = tr("Network Error");
|
||||||
}
|
}
|
||||||
else if (upCount == 0 && downCount == 0)
|
else if (stats.peersSending == 0 && stats.peersReceiving == 0)
|
||||||
{
|
{
|
||||||
tip = tr("Idle");
|
tip = tr("Idle");
|
||||||
}
|
}
|
||||||
else if (downCount != 0)
|
else if (stats.peersSending != 0)
|
||||||
{
|
{
|
||||||
tip = Formatter::downloadSpeedToString(downSpeed) + QLatin1String(" ") + Formatter::uploadSpeedToString(upSpeed);
|
tip = Formatter::downloadSpeedToString(stats.speedDown) + QLatin1String(" ") + Formatter::uploadSpeedToString(
|
||||||
|
stats.speedUp);
|
||||||
}
|
}
|
||||||
else if (upCount != 0)
|
else if (stats.peersReceiving != 0)
|
||||||
{
|
{
|
||||||
tip = Formatter::uploadSpeedToString(upSpeed);
|
tip = Formatter::uploadSpeedToString(stats.speedUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
myTrayIcon.setToolTip(tip);
|
myTrayIcon.setToolTip(tip);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::refreshStatusBar()
|
void MainWindow::refreshStatusBar(TransferStats const& stats)
|
||||||
{
|
{
|
||||||
Speed upSpeed;
|
ui.uploadSpeedLabel->setText(Formatter::uploadSpeedToString(stats.speedUp));
|
||||||
Speed downSpeed;
|
ui.uploadSpeedLabel->setVisible(stats.peersSending || stats.peersReceiving);
|
||||||
size_t upCount;
|
ui.downloadSpeedLabel->setText(Formatter::downloadSpeedToString(stats.speedDown));
|
||||||
size_t downCount;
|
ui.downloadSpeedLabel->setVisible(stats.peersSending);
|
||||||
myModel.getTransferSpeed(upSpeed, upCount, downSpeed, downCount);
|
|
||||||
|
|
||||||
ui.uploadSpeedLabel->setText(Formatter::uploadSpeedToString(upSpeed));
|
|
||||||
ui.uploadSpeedLabel->setVisible(downCount || upCount);
|
|
||||||
ui.downloadSpeedLabel->setText(Formatter::downloadSpeedToString(downSpeed));
|
|
||||||
ui.downloadSpeedLabel->setVisible(downCount);
|
|
||||||
|
|
||||||
ui.networkLabel->setVisible(!mySession.isServer());
|
ui.networkLabel->setVisible(!mySession.isServer());
|
||||||
|
|
||||||
@@ -833,7 +844,6 @@ void MainWindow::refreshTorrentViewHeader()
|
|||||||
void MainWindow::refreshActionSensitivity()
|
void MainWindow::refreshActionSensitivity()
|
||||||
{
|
{
|
||||||
int paused(0);
|
int paused(0);
|
||||||
int queued(0);
|
|
||||||
int selected(0);
|
int selected(0);
|
||||||
int selectedAndCanAnnounce(0);
|
int selectedAndCanAnnounce(0);
|
||||||
int selectedAndPaused(0);
|
int selectedAndPaused(0);
|
||||||
@@ -848,19 +858,12 @@ void MainWindow::refreshActionSensitivity()
|
|||||||
for (int row = 0; row < rowCount; ++row)
|
for (int row = 0; row < rowCount; ++row)
|
||||||
{
|
{
|
||||||
QModelIndex const modelIndex(model->index(row, 0));
|
QModelIndex const modelIndex(model->index(row, 0));
|
||||||
assert(model == modelIndex.model());
|
auto const& tor = model->data(modelIndex, TorrentModel::TorrentRole).value<Torrent const*>();
|
||||||
Torrent const* tor(model->data(modelIndex, TorrentModel::TorrentRole).value<Torrent const*>());
|
|
||||||
|
|
||||||
if (tor != nullptr)
|
if (tor != nullptr)
|
||||||
{
|
{
|
||||||
bool const isSelected(selectionModel->isSelected(modelIndex));
|
bool const isSelected(selectionModel->isSelected(modelIndex));
|
||||||
bool const isPaused(tor->isPaused());
|
bool const isPaused(tor->isPaused());
|
||||||
bool const isQueued(tor->isQueued());
|
|
||||||
|
|
||||||
if (isQueued)
|
|
||||||
{
|
|
||||||
++queued;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPaused)
|
if (isPaused)
|
||||||
{
|
{
|
||||||
@@ -876,7 +879,7 @@ void MainWindow::refreshActionSensitivity()
|
|||||||
++selectedAndPaused;
|
++selectedAndPaused;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isQueued)
|
if (tor->isQueued())
|
||||||
{
|
{
|
||||||
++selectedAndQueued;
|
++selectedAndQueued;
|
||||||
}
|
}
|
||||||
@@ -936,9 +939,9 @@ void MainWindow::clearSelection()
|
|||||||
ui.action_DeselectAll->trigger();
|
ui.action_DeselectAll->trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSet<int> MainWindow::getSelectedTorrents(bool withMetadataOnly) const
|
torrent_ids_t MainWindow::getSelectedTorrents(bool withMetadataOnly) const
|
||||||
{
|
{
|
||||||
QSet<int> ids;
|
torrent_ids_t ids;
|
||||||
|
|
||||||
for (QModelIndex const& index : ui.listView->selectionModel()->selectedRows())
|
for (QModelIndex const& index : ui.listView->selectionModel()->selectedRows())
|
||||||
{
|
{
|
||||||
@@ -1120,7 +1123,7 @@ void MainWindow::refreshPref(int key)
|
|||||||
action->setChecked(str == action->property(STATS_MODE_KEY).toString());
|
action->setChecked(str == action->property(STATS_MODE_KEY).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshStatusBar();
|
refreshSoon(REFRESH_STATUS_BAR);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Prefs::SORT_REVERSED:
|
case Prefs::SORT_REVERSED:
|
||||||
@@ -1340,7 +1343,7 @@ void MainWindow::addTorrent(AddData const& addMe, bool showOptions)
|
|||||||
|
|
||||||
void MainWindow::removeTorrents(bool const deleteFiles)
|
void MainWindow::removeTorrents(bool const deleteFiles)
|
||||||
{
|
{
|
||||||
QSet<int> ids;
|
torrent_ids_t ids;
|
||||||
QMessageBox msgBox(this);
|
QMessageBox msgBox(this);
|
||||||
QString primary_text;
|
QString primary_text;
|
||||||
QString secondary_text;
|
QString secondary_text;
|
||||||
@@ -1364,7 +1367,7 @@ void MainWindow::removeTorrents(bool const deleteFiles)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ids.isEmpty())
|
if (ids.empty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,13 +13,15 @@
|
|||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QSet>
|
|
||||||
#include <QSystemTrayIcon>
|
#include <QSystemTrayIcon>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QWidgetList>
|
#include <QWidgetList>
|
||||||
|
|
||||||
#include "Filters.h"
|
#include "Filters.h"
|
||||||
|
#include "Speed.h"
|
||||||
#include "TorrentFilter.h"
|
#include "TorrentFilter.h"
|
||||||
|
#include "Typedefs.h"
|
||||||
|
|
||||||
#include "ui_MainWindow.h"
|
#include "ui_MainWindow.h"
|
||||||
|
|
||||||
class QAction;
|
class QAction;
|
||||||
@@ -84,15 +86,15 @@ public slots:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
// QWidget
|
// QWidget
|
||||||
virtual void contextMenuEvent(QContextMenuEvent*);
|
void contextMenuEvent(QContextMenuEvent*) override;
|
||||||
virtual void dragEnterEvent(QDragEnterEvent*);
|
void dragEnterEvent(QDragEnterEvent*) override;
|
||||||
virtual void dropEvent(QDropEvent*);
|
void dropEvent(QDropEvent*) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QIcon getStockIcon(QString const&, int fallback = -1);
|
QIcon getStockIcon(QString const&, int fallback = -1);
|
||||||
QIcon addEmblem(QIcon icon, QStringList const& emblemNames);
|
QIcon addEmblem(QIcon icon, QStringList const& emblemNames);
|
||||||
|
|
||||||
QSet<int> getSelectedTorrents(bool withMetadataOnly = false) const;
|
torrent_ids_t getSelectedTorrents(bool withMetadataOnly = false) const;
|
||||||
void updateNetworkIcon();
|
void updateNetworkIcon();
|
||||||
|
|
||||||
QMenu* createOptionsMenu();
|
QMenu* createOptionsMenu();
|
||||||
@@ -103,8 +105,8 @@ private:
|
|||||||
void addTorrent(AddData const& addMe, bool showOptions);
|
void addTorrent(AddData const& addMe, bool showOptions);
|
||||||
|
|
||||||
// QWidget
|
// QWidget
|
||||||
virtual void hideEvent(QHideEvent* event);
|
void hideEvent(QHideEvent* event) override;
|
||||||
virtual void showEvent(QShowEvent* event);
|
void showEvent(QShowEvent* event) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void addTorrents(QStringList const& filenames);
|
void addTorrents(QStringList const& filenames);
|
||||||
@@ -130,7 +132,6 @@ private slots:
|
|||||||
void openURL();
|
void openURL();
|
||||||
void refreshPref(int key);
|
void refreshPref(int key);
|
||||||
void refreshSoon(int fields = ~0);
|
void refreshSoon(int fields = ~0);
|
||||||
void refreshStatusBar();
|
|
||||||
void removeTorrents(bool const deleteFiles);
|
void removeTorrents(bool const deleteFiles);
|
||||||
void setLocation();
|
void setLocation();
|
||||||
void setSortAscendingPref(bool);
|
void setSortAscendingPref(bool);
|
||||||
@@ -176,6 +177,15 @@ private:
|
|||||||
QAction* myAltSpeedAction;
|
QAction* myAltSpeedAction;
|
||||||
QString myErrorMessage;
|
QString myErrorMessage;
|
||||||
|
|
||||||
|
struct TransferStats
|
||||||
|
{
|
||||||
|
Speed speedUp;
|
||||||
|
Speed speedDown;
|
||||||
|
size_t peersSending = 0;
|
||||||
|
size_t peersReceiving = 0;
|
||||||
|
};
|
||||||
|
TransferStats getTransferStats() const;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
REFRESH_TITLE = (1 << 0),
|
REFRESH_TITLE = (1 << 0),
|
||||||
@@ -187,6 +197,7 @@ private:
|
|||||||
int myRefreshFields = 0;
|
int myRefreshFields = 0;
|
||||||
QTimer myRefreshTimer;
|
QTimer myRefreshTimer;
|
||||||
void refreshTitle();
|
void refreshTitle();
|
||||||
void refreshTrayIcon();
|
void refreshTrayIcon(TransferStats const&);
|
||||||
|
void refreshStatusBar(TransferStats const&);
|
||||||
void refreshTorrentViewHeader();
|
void refreshTorrentViewHeader();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
// QWidget
|
// QWidget
|
||||||
virtual void dragEnterEvent(QDragEnterEvent*);
|
void dragEnterEvent(QDragEnterEvent*) override;
|
||||||
virtual void dropEvent(QDropEvent*);
|
void dropEvent(QDropEvent*) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString getSource() const;
|
QString getSource() const;
|
||||||
|
|||||||
@@ -32,14 +32,14 @@ public:
|
|||||||
QString const& path() const;
|
QString const& path() const;
|
||||||
|
|
||||||
// QWidget
|
// QWidget
|
||||||
virtual QSize sizeHint() const;
|
QSize sizeHint() const override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void pathChanged(QString const& path);
|
void pathChanged(QString const& path);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// QWidget
|
// QWidget
|
||||||
virtual void paintEvent(QPaintEvent* event);
|
void paintEvent(QPaintEvent* event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateAppearance();
|
void updateAppearance();
|
||||||
|
|||||||
@@ -433,7 +433,7 @@ void PrefsDialog::initNetworkTab()
|
|||||||
|
|
||||||
void PrefsDialog::onBlocklistDialogDestroyed(QObject* o)
|
void PrefsDialog::onBlocklistDialogDestroyed(QObject* o)
|
||||||
{
|
{
|
||||||
Q_UNUSED(o);
|
Q_UNUSED(o)
|
||||||
|
|
||||||
myBlocklistDialog = nullptr;
|
myBlocklistDialog = nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QSet>
|
|
||||||
|
|
||||||
#include "BaseDialog.h"
|
#include "BaseDialog.h"
|
||||||
#include "Prefs.h"
|
#include "Prefs.h"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ void RelocateDialog::onMoveToggled(bool b)
|
|||||||
myMoveFlag = b;
|
myMoveFlag = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
RelocateDialog::RelocateDialog(Session& session, TorrentModel const& model, QSet<int> const& ids, QWidget* parent) :
|
RelocateDialog::RelocateDialog(Session& session, TorrentModel const& model, torrent_ids_t const& ids, QWidget* parent) :
|
||||||
BaseDialog(parent),
|
BaseDialog(parent),
|
||||||
mySession(session),
|
mySession(session),
|
||||||
myIds(ids)
|
myIds(ids)
|
||||||
|
|||||||
@@ -8,9 +8,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QSet>
|
|
||||||
|
|
||||||
#include "BaseDialog.h"
|
#include "BaseDialog.h"
|
||||||
|
#include "Typedefs.h"
|
||||||
|
|
||||||
#include "ui_RelocateDialog.h"
|
#include "ui_RelocateDialog.h"
|
||||||
|
|
||||||
@@ -22,7 +21,7 @@ class RelocateDialog : public BaseDialog
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RelocateDialog(Session&, TorrentModel const&, QSet<int> const& ids, QWidget* parent = nullptr);
|
RelocateDialog(Session&, TorrentModel const&, torrent_ids_t const& ids, QWidget* parent = nullptr);
|
||||||
|
|
||||||
virtual ~RelocateDialog()
|
virtual ~RelocateDialog()
|
||||||
{
|
{
|
||||||
@@ -37,7 +36,7 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Session& mySession;
|
Session& mySession;
|
||||||
QSet<int> const myIds;
|
torrent_ids_t const myIds;
|
||||||
|
|
||||||
Ui::RelocateDialog ui;
|
Ui::RelocateDialog ui;
|
||||||
|
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ QNetworkAccessManager* RpcClient::networkAccessManager()
|
|||||||
|
|
||||||
void RpcClient::localSessionCallback(tr_session* s, tr_variant* response, void* vself)
|
void RpcClient::localSessionCallback(tr_session* s, tr_variant* response, void* vself)
|
||||||
{
|
{
|
||||||
Q_UNUSED(s);
|
Q_UNUSED(s)
|
||||||
|
|
||||||
RpcClient* self = static_cast<RpcClient*>(vself);
|
RpcClient* self = static_cast<RpcClient*>(vself);
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ struct RpcResponse
|
|||||||
QNetworkReply::NetworkError networkError = QNetworkReply::NoError;
|
QNetworkReply::NetworkError networkError = QNetworkReply::NoError;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QFutureInterface<RpcResponse>);
|
Q_DECLARE_METATYPE(QFutureInterface<RpcResponse>)
|
||||||
|
|
||||||
// The response future -- the RPC engine returns one for each request made.
|
// The response future -- the RPC engine returns one for each request made.
|
||||||
typedef QFuture<RpcResponse> RpcResponseFuture;
|
typedef QFuture<RpcResponse> RpcResponseFuture;
|
||||||
|
|||||||
@@ -54,10 +54,10 @@ void addList(tr_variant* list, KeyList const& keys)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If this object is passed as "ids" (compared by address), then recently active torrents are queried.
|
// If this object is passed as "ids" (compared by address), then recently active torrents are queried.
|
||||||
QSet<int> const recentlyActiveIds = QSet<int>() << -1;
|
auto const recentlyActiveIds = torrent_ids_t{ -1 };
|
||||||
|
|
||||||
// If this object is passed as "ids" (compared by being empty), then all torrents are queried.
|
// If this object is passed as "ids" (compared by being empty), then all torrents are queried.
|
||||||
QSet<int> const allIds;
|
auto const allIds = torrent_ids_t{};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -405,13 +405,13 @@ bool Session::isLocal() const
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
void addOptionalIds(tr_variant* args, QSet<int> const& ids)
|
void addOptionalIds(tr_variant* args, torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
if (&ids == &recentlyActiveIds)
|
if (&ids == &recentlyActiveIds)
|
||||||
{
|
{
|
||||||
tr_variantDictAddStr(args, TR_KEY_ids, "recently-active");
|
tr_variantDictAddStr(args, TR_KEY_ids, "recently-active");
|
||||||
}
|
}
|
||||||
else if (!ids.isEmpty())
|
else if (!ids.empty())
|
||||||
{
|
{
|
||||||
tr_variant* idList(tr_variantDictAddList(args, TR_KEY_ids, ids.size()));
|
tr_variant* idList(tr_variantDictAddList(args, TR_KEY_ids, ids.size()));
|
||||||
|
|
||||||
@@ -424,7 +424,7 @@ void addOptionalIds(tr_variant* args, QSet<int> const& ids)
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void Session::torrentSet(QSet<int> const& ids, tr_quark const key, double value)
|
void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, double value)
|
||||||
{
|
{
|
||||||
tr_variant args;
|
tr_variant args;
|
||||||
tr_variantInitDict(&args, 2);
|
tr_variantInitDict(&args, 2);
|
||||||
@@ -434,7 +434,7 @@ void Session::torrentSet(QSet<int> const& ids, tr_quark const key, double value)
|
|||||||
exec(TR_KEY_torrent_set, &args);
|
exec(TR_KEY_torrent_set, &args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::torrentSet(QSet<int> const& ids, tr_quark const key, int value)
|
void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, int value)
|
||||||
{
|
{
|
||||||
tr_variant args;
|
tr_variant args;
|
||||||
tr_variantInitDict(&args, 2);
|
tr_variantInitDict(&args, 2);
|
||||||
@@ -444,7 +444,7 @@ void Session::torrentSet(QSet<int> const& ids, tr_quark const key, int value)
|
|||||||
exec(TR_KEY_torrent_set, &args);
|
exec(TR_KEY_torrent_set, &args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::torrentSet(QSet<int> const& ids, tr_quark const key, bool value)
|
void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, bool value)
|
||||||
{
|
{
|
||||||
tr_variant args;
|
tr_variant args;
|
||||||
tr_variantInitDict(&args, 2);
|
tr_variantInitDict(&args, 2);
|
||||||
@@ -454,7 +454,7 @@ void Session::torrentSet(QSet<int> const& ids, tr_quark const key, bool value)
|
|||||||
exec(TR_KEY_torrent_set, &args);
|
exec(TR_KEY_torrent_set, &args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::torrentSet(QSet<int> const& ids, tr_quark const key, QStringList const& value)
|
void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, QStringList const& value)
|
||||||
{
|
{
|
||||||
tr_variant args;
|
tr_variant args;
|
||||||
tr_variantInitDict(&args, 2);
|
tr_variantInitDict(&args, 2);
|
||||||
@@ -469,7 +469,7 @@ void Session::torrentSet(QSet<int> const& ids, tr_quark const key, QStringList c
|
|||||||
exec(TR_KEY_torrent_set, &args);
|
exec(TR_KEY_torrent_set, &args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::torrentSet(QSet<int> const& ids, tr_quark const key, QList<int> const& value)
|
void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, QList<int> const& value)
|
||||||
{
|
{
|
||||||
tr_variant args;
|
tr_variant args;
|
||||||
tr_variantInitDict(&args, 2);
|
tr_variantInitDict(&args, 2);
|
||||||
@@ -484,7 +484,7 @@ void Session::torrentSet(QSet<int> const& ids, tr_quark const key, QList<int> co
|
|||||||
exec(TR_KEY_torrent_set, &args);
|
exec(TR_KEY_torrent_set, &args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::torrentSet(QSet<int> const& ids, tr_quark const key, QPair<int, QString> const& value)
|
void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, QPair<int, QString> const& value)
|
||||||
{
|
{
|
||||||
tr_variant args;
|
tr_variant args;
|
||||||
tr_variantInitDict(&args, 2);
|
tr_variantInitDict(&args, 2);
|
||||||
@@ -496,7 +496,7 @@ void Session::torrentSet(QSet<int> const& ids, tr_quark const key, QPair<int, QS
|
|||||||
exec(TR_KEY_torrent_set, &args);
|
exec(TR_KEY_torrent_set, &args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::torrentSetLocation(QSet<int> const& ids, QString const& location, bool doMove)
|
void Session::torrentSetLocation(torrent_ids_t const& ids, QString const& location, bool doMove)
|
||||||
{
|
{
|
||||||
tr_variant args;
|
tr_variant args;
|
||||||
tr_variantInitDict(&args, 3);
|
tr_variantInitDict(&args, 3);
|
||||||
@@ -507,7 +507,7 @@ void Session::torrentSetLocation(QSet<int> const& ids, QString const& location,
|
|||||||
exec(TR_KEY_torrent_set_location, &args);
|
exec(TR_KEY_torrent_set_location, &args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::torrentRenamePath(QSet<int> const& ids, QString const& oldpath, QString const& newname)
|
void Session::torrentRenamePath(torrent_ids_t const& ids, QString const& oldpath, QString const& newname)
|
||||||
{
|
{
|
||||||
tr_variant args;
|
tr_variant args;
|
||||||
tr_variantInitDict(&args, 2);
|
tr_variantInitDict(&args, 2);
|
||||||
@@ -536,20 +536,15 @@ void Session::torrentRenamePath(QSet<int> const& ids, QString const& oldpath, QS
|
|||||||
d->show();
|
d->show();
|
||||||
});
|
});
|
||||||
|
|
||||||
q->add([this](RpcResponse const& r)
|
q->add([this, ids](RpcResponse const& /*r*/)
|
||||||
{
|
{
|
||||||
int64_t id = 0;
|
refreshTorrents(ids, { TR_KEY_fileStats, TR_KEY_files, TR_KEY_id, TR_KEY_name });
|
||||||
|
|
||||||
if (tr_variantDictFindInt(r.args.get(), TR_KEY_id, &id) && id != 0)
|
|
||||||
{
|
|
||||||
refreshTorrents(QSet<int>() << id, KeyList() << TR_KEY_fileStats << TR_KEY_files << TR_KEY_id << TR_KEY_name);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
q->run();
|
q->run();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::refreshTorrents(QSet<int> const& ids, KeyList const& keys)
|
void Session::refreshTorrents(torrent_ids_t const& ids, KeyList const& keys)
|
||||||
{
|
{
|
||||||
tr_variant args;
|
tr_variant args;
|
||||||
tr_variantInitDict(&args, 3);
|
tr_variantInitDict(&args, 3);
|
||||||
@@ -584,17 +579,17 @@ void Session::refreshTorrents(QSet<int> const& ids, KeyList const& keys)
|
|||||||
q->run();
|
q->run();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::refreshDetailInfo(QSet<int> const& ids)
|
void Session::refreshDetailInfo(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
refreshTorrents(ids, Torrent::detailInfoKeys);
|
refreshTorrents(ids, Torrent::detailInfoKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::refreshExtraStats(QSet<int> const& ids)
|
void Session::refreshExtraStats(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
refreshTorrents(ids, Torrent::mainStatKeys + Torrent::detailStatKeys);
|
refreshTorrents(ids, Torrent::mainStatKeys + Torrent::detailStatKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::sendTorrentRequest(char const* request, QSet<int> const& ids)
|
void Session::sendTorrentRequest(char const* request, torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
tr_variant args;
|
tr_variant args;
|
||||||
tr_variantInitDict(&args, 1);
|
tr_variantInitDict(&args, 1);
|
||||||
@@ -615,37 +610,37 @@ void Session::sendTorrentRequest(char const* request, QSet<int> const& ids)
|
|||||||
q->run();
|
q->run();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::pauseTorrents(QSet<int> const& ids)
|
void Session::pauseTorrents(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
sendTorrentRequest("torrent-stop", ids);
|
sendTorrentRequest("torrent-stop", ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::startTorrents(QSet<int> const& ids)
|
void Session::startTorrents(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
sendTorrentRequest("torrent-start", ids);
|
sendTorrentRequest("torrent-start", ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::startTorrentsNow(QSet<int> const& ids)
|
void Session::startTorrentsNow(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
sendTorrentRequest("torrent-start-now", ids);
|
sendTorrentRequest("torrent-start-now", ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::queueMoveTop(QSet<int> const& ids)
|
void Session::queueMoveTop(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
sendTorrentRequest("queue-move-top", ids);
|
sendTorrentRequest("queue-move-top", ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::queueMoveUp(QSet<int> const& ids)
|
void Session::queueMoveUp(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
sendTorrentRequest("queue-move-up", ids);
|
sendTorrentRequest("queue-move-up", ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::queueMoveDown(QSet<int> const& ids)
|
void Session::queueMoveDown(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
sendTorrentRequest("queue-move-down", ids);
|
sendTorrentRequest("queue-move-down", ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::queueMoveBottom(QSet<int> const& ids)
|
void Session::queueMoveBottom(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
sendTorrentRequest("queue-move-bottom", ids);
|
sendTorrentRequest("queue-move-bottom", ids);
|
||||||
}
|
}
|
||||||
@@ -660,7 +655,7 @@ void Session::refreshAllTorrents()
|
|||||||
refreshTorrents(allIds, Torrent::mainStatKeys);
|
refreshTorrents(allIds, Torrent::mainStatKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::initTorrents(QSet<int> const& ids)
|
void Session::initTorrents(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
refreshTorrents(ids, Torrent::allMainKeys);
|
refreshTorrents(ids, Torrent::allMainKeys);
|
||||||
}
|
}
|
||||||
@@ -1047,9 +1042,9 @@ void Session::addNewlyCreatedTorrent(QString const& filename, QString const& loc
|
|||||||
exec("torrent-add", &args);
|
exec("torrent-add", &args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::removeTorrents(QSet<int> const& ids, bool deleteFiles)
|
void Session::removeTorrents(torrent_ids_t const& ids, bool deleteFiles)
|
||||||
{
|
{
|
||||||
if (!ids.isEmpty())
|
if (!ids.empty())
|
||||||
{
|
{
|
||||||
tr_variant args;
|
tr_variant args;
|
||||||
tr_variantInitDict(&args, 2);
|
tr_variantInitDict(&args, 2);
|
||||||
@@ -1060,9 +1055,9 @@ void Session::removeTorrents(QSet<int> const& ids, bool deleteFiles)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::verifyTorrents(QSet<int> const& ids)
|
void Session::verifyTorrents(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
if (!ids.isEmpty())
|
if (!ids.empty())
|
||||||
{
|
{
|
||||||
tr_variant args;
|
tr_variant args;
|
||||||
tr_variantInitDict(&args, 1);
|
tr_variantInitDict(&args, 1);
|
||||||
@@ -1072,9 +1067,9 @@ void Session::verifyTorrents(QSet<int> const& ids)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::reannounceTorrents(QSet<int> const& ids)
|
void Session::reannounceTorrents(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
if (!ids.isEmpty())
|
if (!ids.empty())
|
||||||
{
|
{
|
||||||
tr_variant args;
|
tr_variant args;
|
||||||
tr_variantInitDict(&args, 1);
|
tr_variantInitDict(&args, 1);
|
||||||
|
|||||||
48
qt/Session.h
48
qt/Session.h
@@ -9,7 +9,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QSet>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
@@ -18,6 +17,7 @@
|
|||||||
|
|
||||||
#include "RpcClient.h"
|
#include "RpcClient.h"
|
||||||
#include "Torrent.h"
|
#include "Torrent.h"
|
||||||
|
#include "Typedefs.h"
|
||||||
|
|
||||||
class AddData;
|
class AddData;
|
||||||
class Prefs;
|
class Prefs;
|
||||||
@@ -77,37 +77,37 @@ public:
|
|||||||
RpcResponseFuture exec(tr_quark method, tr_variant* args);
|
RpcResponseFuture exec(tr_quark method, tr_variant* args);
|
||||||
RpcResponseFuture exec(char const* method, tr_variant* args);
|
RpcResponseFuture exec(char const* method, tr_variant* args);
|
||||||
|
|
||||||
void torrentSet(QSet<int> const& ids, tr_quark const key, bool val);
|
void torrentSet(torrent_ids_t const& ids, tr_quark const key, bool val);
|
||||||
void torrentSet(QSet<int> const& ids, tr_quark const key, int val);
|
void torrentSet(torrent_ids_t const& ids, tr_quark const key, int val);
|
||||||
void torrentSet(QSet<int> const& ids, tr_quark const key, double val);
|
void torrentSet(torrent_ids_t const& ids, tr_quark const key, double val);
|
||||||
void torrentSet(QSet<int> const& ids, tr_quark const key, QList<int> const& val);
|
void torrentSet(torrent_ids_t const& ids, tr_quark const key, QList<int> const& val);
|
||||||
void torrentSet(QSet<int> const& ids, tr_quark const key, QStringList const& val);
|
void torrentSet(torrent_ids_t const& ids, tr_quark const key, QStringList const& val);
|
||||||
void torrentSet(QSet<int> const& ids, tr_quark const key, QPair<int, QString> const& val);
|
void torrentSet(torrent_ids_t const& ids, tr_quark const key, QPair<int, QString> const& val);
|
||||||
void torrentSetLocation(QSet<int> const& ids, QString const& path, bool doMove);
|
void torrentSetLocation(torrent_ids_t const& ids, QString const& path, bool doMove);
|
||||||
void torrentRenamePath(QSet<int> const& ids, QString const& oldpath, QString const& newname);
|
void torrentRenamePath(torrent_ids_t const& ids, QString const& oldpath, QString const& newname);
|
||||||
void addTorrent(AddData const& addme, tr_variant* top, bool trashOriginal);
|
void addTorrent(AddData const& addme, tr_variant* top, bool trashOriginal);
|
||||||
void initTorrents(QSet<int> const& ids = QSet<int>());
|
void initTorrents(torrent_ids_t const& ids = {});
|
||||||
void pauseTorrents(QSet<int> const& torrentIds = QSet<int>());
|
void pauseTorrents(torrent_ids_t const& torrentIds = {});
|
||||||
void startTorrents(QSet<int> const& torrentIds = QSet<int>());
|
void startTorrents(torrent_ids_t const& torrentIds = {});
|
||||||
void startTorrentsNow(QSet<int> const& torrentIds = QSet<int>());
|
void startTorrentsNow(torrent_ids_t const& torrentIds = {});
|
||||||
void refreshDetailInfo(QSet<int> const& torrentIds);
|
void refreshDetailInfo(torrent_ids_t const& torrentIds);
|
||||||
void refreshActiveTorrents();
|
void refreshActiveTorrents();
|
||||||
void refreshAllTorrents();
|
void refreshAllTorrents();
|
||||||
void addNewlyCreatedTorrent(QString const& filename, QString const& localPath);
|
void addNewlyCreatedTorrent(QString const& filename, QString const& localPath);
|
||||||
void verifyTorrents(QSet<int> const& torrentIds);
|
void verifyTorrents(torrent_ids_t const& torrentIds);
|
||||||
void reannounceTorrents(QSet<int> const& torrentIds);
|
void reannounceTorrents(torrent_ids_t const& torrentIds);
|
||||||
void refreshExtraStats(QSet<int> const& ids);
|
void refreshExtraStats(torrent_ids_t const& ids);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void addTorrent(AddData const& addme);
|
void addTorrent(AddData const& addme);
|
||||||
void launchWebInterface();
|
void launchWebInterface();
|
||||||
void queueMoveBottom(QSet<int> const& torrentIds = QSet<int>());
|
void queueMoveBottom(torrent_ids_t const& torrentIds = {});
|
||||||
void queueMoveDown(QSet<int> const& torrentIds = QSet<int>());
|
void queueMoveDown(torrent_ids_t const& torrentIds = {});
|
||||||
void queueMoveTop(QSet<int> const& torrentIds = QSet<int>());
|
void queueMoveTop(torrent_ids_t const& torrentIds = {});
|
||||||
void queueMoveUp(QSet<int> const& torrentIds = QSet<int>());
|
void queueMoveUp(torrent_ids_t const& torrentIds = {});
|
||||||
void refreshSessionInfo();
|
void refreshSessionInfo();
|
||||||
void refreshSessionStats();
|
void refreshSessionStats();
|
||||||
void removeTorrents(QSet<int> const& torrentIds, bool deleteFiles = false);
|
void removeTorrents(torrent_ids_t const& torrentIds, bool deleteFiles = false);
|
||||||
void updatePref(int key);
|
void updatePref(int key);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@@ -131,8 +131,8 @@ private:
|
|||||||
|
|
||||||
void sessionSet(tr_quark const key, QVariant const& variant);
|
void sessionSet(tr_quark const key, QVariant const& variant);
|
||||||
void pumpRequests();
|
void pumpRequests();
|
||||||
void sendTorrentRequest(char const* request, QSet<int> const& torrentIds);
|
void sendTorrentRequest(char const* request, torrent_ids_t const& torrentIds);
|
||||||
void refreshTorrents(QSet<int> const& torrentIds, Torrent::KeyList const& keys);
|
void refreshTorrents(torrent_ids_t const& torrentIds, Torrent::KeyList const& keys);
|
||||||
|
|
||||||
static void updateStats(tr_variant* d, tr_session_stats* stats);
|
static void updateStats(tr_variant* d, tr_session_stats* stats);
|
||||||
|
|
||||||
|
|||||||
@@ -24,13 +24,9 @@ class SessionDialog : public BaseDialog
|
|||||||
public:
|
public:
|
||||||
SessionDialog(Session& session, Prefs& prefs, QWidget* parent = nullptr);
|
SessionDialog(Session& session, Prefs& prefs, QWidget* parent = nullptr);
|
||||||
|
|
||||||
virtual ~SessionDialog()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
// QDialog
|
// QDialog
|
||||||
virtual void accept();
|
void accept() override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void resensitize();
|
void resensitize();
|
||||||
|
|||||||
@@ -53,5 +53,5 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
// QWidget
|
// QWidget
|
||||||
virtual void paintEvent(QPaintEvent* paintEvent);
|
void paintEvent(QPaintEvent* paintEvent) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ class StatsDialog : public BaseDialog
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
StatsDialog(Session&, QWidget* parent = nullptr);
|
StatsDialog(Session&, QWidget* parent = nullptr);
|
||||||
~StatsDialog();
|
~StatsDialog() override;
|
||||||
|
|
||||||
// QWidget
|
// QWidget
|
||||||
virtual void setVisible(bool visible);
|
void setVisible(bool visible) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updateStats();
|
void updateStats();
|
||||||
|
|||||||
@@ -75,8 +75,6 @@ Torrent::Property Torrent::myProperties[] =
|
|||||||
{ DOWNLOADED_EVER, TR_KEY_downloadedEver, QVariant::ULongLong },
|
{ DOWNLOADED_EVER, TR_KEY_downloadedEver, QVariant::ULongLong },
|
||||||
{ UPLOADED_EVER, TR_KEY_uploadedEver, QVariant::ULongLong },
|
{ UPLOADED_EVER, TR_KEY_uploadedEver, QVariant::ULongLong },
|
||||||
{ FAILED_EVER, TR_KEY_corruptEver, QVariant::ULongLong },
|
{ FAILED_EVER, TR_KEY_corruptEver, QVariant::ULongLong },
|
||||||
{ TRACKERS, TR_KEY_trackers, QVariant::StringList },
|
|
||||||
{ HOSTS, TR_KEY_NONE, QVariant::StringList },
|
|
||||||
{ TRACKERSTATS, TR_KEY_trackerStats, CustomVariantType::TrackerStatsList },
|
{ TRACKERSTATS, TR_KEY_trackerStats, CustomVariantType::TrackerStatsList },
|
||||||
{ MIME_ICON, TR_KEY_NONE, QVariant::Icon },
|
{ MIME_ICON, TR_KEY_NONE, QVariant::Icon },
|
||||||
{ SEED_RATIO_LIMIT, TR_KEY_seedRatioLimit, QVariant::Double },
|
{ SEED_RATIO_LIMIT, TR_KEY_seedRatioLimit, QVariant::Double },
|
||||||
@@ -406,7 +404,7 @@ bool Torrent::hasFileSubstring(QString const& substr) const
|
|||||||
|
|
||||||
bool Torrent::hasTrackerSubstring(QString const& substr) const
|
bool Torrent::hasTrackerSubstring(QString const& substr) const
|
||||||
{
|
{
|
||||||
for (QString const& s : myValues[TRACKERS].toStringList())
|
for (auto const& s : trackers())
|
||||||
{
|
{
|
||||||
if (s.contains(substr, Qt::CaseInsensitive))
|
if (s.contains(substr, Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
@@ -505,7 +503,7 @@ int Torrent::compareETA(Torrent const& that) const
|
|||||||
|
|
||||||
int Torrent::compareTracker(Torrent const& that) const
|
int Torrent::compareTracker(Torrent const& that) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(that);
|
Q_UNUSED(that)
|
||||||
|
|
||||||
// FIXME
|
// FIXME
|
||||||
return 0;
|
return 0;
|
||||||
@@ -657,7 +655,6 @@ bool Torrent::update(tr_quark const* keys, tr_variant** values, size_t n)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case QVariant::StringList:
|
|
||||||
case CustomVariantType::PeerList:
|
case CustomVariantType::PeerList:
|
||||||
// handled below
|
// handled below
|
||||||
break;
|
break;
|
||||||
@@ -756,21 +753,21 @@ bool Torrent::update(tr_quark const* keys, tr_variant** values, size_t n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update the trackers
|
// update the trackers
|
||||||
if (myValues[TRACKERS] != trackers)
|
if (trackers_ != trackers)
|
||||||
{
|
{
|
||||||
QStringList hosts;
|
QStringList displayNames;
|
||||||
|
displayNames.reserve(trackers.size());
|
||||||
for (auto const& tracker : trackers)
|
for (auto const& tracker : trackers)
|
||||||
{
|
{
|
||||||
auto const url = QUrl(tracker);
|
auto const url = QUrl(tracker);
|
||||||
qApp->faviconCache().add(url);
|
auto const key = qApp->faviconCache().add(url);
|
||||||
hosts.append(FaviconCache::getHost(url));
|
displayNames.append(FaviconCache::getDisplayName(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
hosts.removeDuplicates();
|
displayNames.removeDuplicates();
|
||||||
hosts.removeOne(QString());
|
|
||||||
|
|
||||||
myValues[TRACKERS].setValue(trackers);
|
trackers_.swap(trackers);
|
||||||
myValues[HOSTS].setValue(hosts);
|
trackerDisplayNames_.swap(displayNames);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -794,7 +791,6 @@ bool Torrent::update(tr_quark const* keys, tr_variant** values, size_t n)
|
|||||||
if (tr_variantDictFindStr(child, TR_KEY_announce, &str, &len))
|
if (tr_variantDictFindStr(child, TR_KEY_announce, &str, &len))
|
||||||
{
|
{
|
||||||
trackerStat.announce = QString::fromUtf8(str, len);
|
trackerStat.announce = QString::fromUtf8(str, len);
|
||||||
qApp->faviconCache().add(QUrl(trackerStat.announce));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tr_variantDictFindInt(child, TR_KEY_announceState, &i))
|
if (tr_variantDictFindInt(child, TR_KEY_announceState, &i))
|
||||||
|
|||||||
17
qt/Torrent.h
17
qt/Torrent.h
@@ -158,8 +158,6 @@ public:
|
|||||||
DOWNLOADED_EVER,
|
DOWNLOADED_EVER,
|
||||||
UPLOADED_EVER,
|
UPLOADED_EVER,
|
||||||
FAILED_EVER,
|
FAILED_EVER,
|
||||||
TRACKERS,
|
|
||||||
HOSTS,
|
|
||||||
TRACKERSTATS,
|
TRACKERSTATS,
|
||||||
MIME_ICON,
|
MIME_ICON,
|
||||||
SEED_RATIO_LIMIT,
|
SEED_RATIO_LIMIT,
|
||||||
@@ -188,8 +186,6 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Torrent(Prefs const&, int id);
|
Torrent(Prefs const&, int id);
|
||||||
virtual ~Torrent() = default;
|
|
||||||
;
|
|
||||||
|
|
||||||
int getBandwidthPriority() const
|
int getBandwidthPriority() const
|
||||||
{
|
{
|
||||||
@@ -235,7 +231,7 @@ public:
|
|||||||
|
|
||||||
bool hasError() const
|
bool hasError() const
|
||||||
{
|
{
|
||||||
return !getError().isEmpty();
|
return getInt(ERROR) != TR_STAT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isDone() const
|
bool isDone() const
|
||||||
@@ -493,14 +489,14 @@ public:
|
|||||||
return myValues[TRACKERSTATS].value<TrackerStatsList>();
|
return myValues[TRACKERSTATS].value<TrackerStatsList>();
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList trackers() const
|
QStringList const& trackers() const
|
||||||
{
|
{
|
||||||
return myValues[TRACKERS].value<QStringList>();
|
return trackers_;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList hosts() const
|
QStringList const& trackerDisplayNames() const
|
||||||
{
|
{
|
||||||
return myValues[HOSTS].value<QStringList>();
|
return trackerDisplayNames_;
|
||||||
}
|
}
|
||||||
|
|
||||||
PeerList peers() const
|
PeerList peers() const
|
||||||
@@ -619,6 +615,9 @@ private:
|
|||||||
bool setSize(int key, qulonglong);
|
bool setSize(int key, qulonglong);
|
||||||
bool setTime(int key, time_t);
|
bool setTime(int key, time_t);
|
||||||
|
|
||||||
|
QStringList trackers_;
|
||||||
|
QStringList trackerDisplayNames_;
|
||||||
|
|
||||||
char const* getMimeTypeString() const;
|
char const* getMimeTypeString() const;
|
||||||
void updateMimeIcon();
|
void updateMimeIcon();
|
||||||
|
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ TorrentDelegate::~TorrentDelegate()
|
|||||||
|
|
||||||
QSize TorrentDelegate::margin(QStyle const& style) const
|
QSize TorrentDelegate::margin(QStyle const& style) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(style);
|
Q_UNUSED(style)
|
||||||
|
|
||||||
return QSize(4, 4);
|
return QSize(4, 4);
|
||||||
}
|
}
|
||||||
@@ -420,6 +420,23 @@ QSize TorrentDelegate::sizeHint(QStyleOptionViewItem const& option, QModelIndex
|
|||||||
return QSize(option.rect.width(), *myHeightHint);
|
return QSize(option.rect.width(), *myHeightHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QIcon& TorrentDelegate::getWarningEmblem() const
|
||||||
|
{
|
||||||
|
auto& icon = myWarningEmblem;
|
||||||
|
|
||||||
|
if (icon.isNull())
|
||||||
|
{
|
||||||
|
icon = QIcon::fromTheme(QLatin1String("emblem-important"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icon.isNull())
|
||||||
|
{
|
||||||
|
icon = qApp->style()->standardIcon(QStyle::SP_MessageBoxWarning);
|
||||||
|
}
|
||||||
|
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
void TorrentDelegate::paint(QPainter* painter, QStyleOptionViewItem const& option, QModelIndex const& index) const
|
void TorrentDelegate::paint(QPainter* painter, QStyleOptionViewItem const& option, QModelIndex const& index) const
|
||||||
{
|
{
|
||||||
Torrent const* tor(index.data(TorrentModel::TorrentRole).value<Torrent const*>());
|
Torrent const* tor(index.data(TorrentModel::TorrentRole).value<Torrent const*>());
|
||||||
@@ -531,8 +548,7 @@ void TorrentDelegate::drawTorrent(QPainter* painter, QStyleOptionViewItem const&
|
|||||||
progressBarState |= QStyle::State_Small;
|
progressBarState |= QStyle::State_Small;
|
||||||
|
|
||||||
QIcon::Mode const emblemIm = isItemSelected ? QIcon::Selected : QIcon::Normal;
|
QIcon::Mode const emblemIm = isItemSelected ? QIcon::Selected : QIcon::Normal;
|
||||||
QIcon const emblemIcon = tor.hasError() ? QIcon::fromTheme(QLatin1String("emblem-important"),
|
QIcon const emblemIcon = tor.hasError() ? getWarningEmblem() : QIcon();
|
||||||
style->standardIcon(QStyle::SP_MessageBoxWarning)) : QIcon();
|
|
||||||
|
|
||||||
// layout
|
// layout
|
||||||
QSize const m(margin(*style));
|
QSize const m(margin(*style));
|
||||||
|
|||||||
@@ -26,12 +26,13 @@ public:
|
|||||||
virtual ~TorrentDelegate();
|
virtual ~TorrentDelegate();
|
||||||
|
|
||||||
// QAbstractItemDelegate
|
// QAbstractItemDelegate
|
||||||
virtual QSize sizeHint(QStyleOptionViewItem const& option, QModelIndex const& index) const;
|
QSize sizeHint(QStyleOptionViewItem const& option, QModelIndex const& index) const override;
|
||||||
virtual void paint(QPainter* painter, QStyleOptionViewItem const& option, QModelIndex const& index) const;
|
void paint(QPainter* painter, QStyleOptionViewItem const& option, QModelIndex const& index) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QSize margin(QStyle const& style) const;
|
QSize margin(QStyle const& style) const;
|
||||||
void setProgressBarPercentDone(QStyleOptionViewItem const& option, Torrent const&) const;
|
void setProgressBarPercentDone(QStyleOptionViewItem const& option, Torrent const&) const;
|
||||||
|
QIcon& getWarningEmblem() const;
|
||||||
|
|
||||||
// Our own overridables
|
// Our own overridables
|
||||||
virtual QSize sizeHint(QStyleOptionViewItem const&, Torrent const&) const;
|
virtual QSize sizeHint(QStyleOptionViewItem const&, Torrent const&) const;
|
||||||
@@ -55,4 +56,5 @@ protected:
|
|||||||
private:
|
private:
|
||||||
mutable std::optional<int> myHeightHint;
|
mutable std::optional<int> myHeightHint;
|
||||||
mutable QFont myHeightFont;
|
mutable QFont myHeightFont;
|
||||||
|
mutable QIcon myWarningEmblem;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -221,8 +221,7 @@ void TorrentDelegateMin::drawTorrent(QPainter* painter, QStyleOptionViewItem con
|
|||||||
progressBarState |= QStyle::State_Small;
|
progressBarState |= QStyle::State_Small;
|
||||||
|
|
||||||
QIcon::Mode const emblemIm = isItemSelected ? QIcon::Selected : QIcon::Normal;
|
QIcon::Mode const emblemIm = isItemSelected ? QIcon::Selected : QIcon::Normal;
|
||||||
QIcon const emblemIcon = tor.hasError() ? QIcon::fromTheme(QLatin1String("emblem-important"),
|
QIcon const emblemIcon = tor.hasError() ? getWarningEmblem() : QIcon();
|
||||||
style->standardIcon(QStyle::SP_MessageBoxWarning)) : QIcon();
|
|
||||||
|
|
||||||
// layout
|
// layout
|
||||||
QSize const m(margin(*style));
|
QSize const m(margin(*style));
|
||||||
|
|||||||
@@ -20,12 +20,8 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TorrentDelegateMin()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// TorrentDelegate
|
// TorrentDelegate
|
||||||
virtual QSize sizeHint(QStyleOptionViewItem const&, Torrent const&) const;
|
QSize sizeHint(QStyleOptionViewItem const&, Torrent const&) const override;
|
||||||
virtual void drawTorrent(QPainter* painter, QStyleOptionViewItem const& option, Torrent const&) const;
|
void drawTorrent(QPainter* painter, QStyleOptionViewItem const& option, Torrent const&) const override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -322,18 +322,9 @@ void TorrentFilter::countTorrentsPerMode(int* setmeCounts) const
|
|||||||
{
|
{
|
||||||
std::fill_n(setmeCounts, static_cast<std::size_t>(FilterMode::NUM_MODES), 0);
|
std::fill_n(setmeCounts, static_cast<std::size_t>(FilterMode::NUM_MODES), 0);
|
||||||
|
|
||||||
for (int row(0);; ++row)
|
for (auto const& tor : dynamic_cast<TorrentModel*>(sourceModel())->torrents())
|
||||||
{
|
{
|
||||||
QModelIndex index(sourceModel()->index(row, 0));
|
for (int mode = 0; mode < FilterMode::NUM_MODES; ++mode)
|
||||||
|
|
||||||
if (!index.isValid())
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Torrent const* tor(index.data(TorrentModel::TorrentRole).value<Torrent const*>());
|
|
||||||
|
|
||||||
for (int mode(0); mode < FilterMode::NUM_MODES; ++mode)
|
|
||||||
{
|
{
|
||||||
if (activityFilterAcceptsTorrent(tor, mode))
|
if (activityFilterAcceptsTorrent(tor, mode))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
// QSortFilterProxyModel
|
// QSortFilterProxyModel
|
||||||
virtual bool filterAcceptsRow(int, QModelIndex const&) const;
|
bool filterAcceptsRow(int, QModelIndex const&) const override;
|
||||||
virtual bool lessThan(QModelIndex const&, QModelIndex const&) const;
|
bool lessThan(QModelIndex const&, QModelIndex const&) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool activityFilterAcceptsTorrent(Torrent const* tor, FilterMode const& mode) const;
|
bool activityFilterAcceptsTorrent(Torrent const* tor, FilterMode const& mode) const;
|
||||||
|
|||||||
@@ -44,9 +44,9 @@ struct TorrentIdLessThan
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename Iter>
|
template<typename Iter>
|
||||||
QSet<int> getIds(Iter it, Iter end)
|
auto getIds(Iter it, Iter end)
|
||||||
{
|
{
|
||||||
QSet<int> ids;
|
torrent_ids_t ids;
|
||||||
|
|
||||||
for ( ; it != end; ++it)
|
for ( ; it != end; ++it)
|
||||||
{
|
{
|
||||||
@@ -82,7 +82,7 @@ void TorrentModel::clear()
|
|||||||
|
|
||||||
int TorrentModel::rowCount(QModelIndex const& parent) const
|
int TorrentModel::rowCount(QModelIndex const& parent) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(parent);
|
Q_UNUSED(parent)
|
||||||
|
|
||||||
return myTorrents.size();
|
return myTorrents.size();
|
||||||
}
|
}
|
||||||
@@ -124,10 +124,11 @@ QVariant TorrentModel::data(QModelIndex const& index, int role) const
|
|||||||
|
|
||||||
void TorrentModel::removeTorrents(tr_variant* list)
|
void TorrentModel::removeTorrents(tr_variant* list)
|
||||||
{
|
{
|
||||||
|
torrents_t torrents;
|
||||||
|
torrents.reserve(tr_variantListSize(list));
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
tr_variant* child;
|
tr_variant* child;
|
||||||
QSet<Torrent*> torrents;
|
|
||||||
|
|
||||||
while ((child = tr_variantListChild(list, i++)) != nullptr)
|
while ((child = tr_variantListChild(list, i++)) != nullptr)
|
||||||
{
|
{
|
||||||
int64_t id;
|
int64_t id;
|
||||||
@@ -140,11 +141,11 @@ void TorrentModel::removeTorrents(tr_variant* list)
|
|||||||
|
|
||||||
if (torrent != nullptr)
|
if (torrent != nullptr)
|
||||||
{
|
{
|
||||||
torrents.insert(torrent);
|
torrents.push_back(torrent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!torrents.isEmpty())
|
if (!torrents.empty())
|
||||||
{
|
{
|
||||||
rowsRemove(torrents);
|
rowsRemove(torrents);
|
||||||
}
|
}
|
||||||
@@ -152,13 +153,13 @@ void TorrentModel::removeTorrents(tr_variant* list)
|
|||||||
|
|
||||||
void TorrentModel::updateTorrents(tr_variant* torrents, bool isCompleteList)
|
void TorrentModel::updateTorrents(tr_variant* torrents, bool isCompleteList)
|
||||||
{
|
{
|
||||||
auto const old = QSet<Torrent*>::fromList(myTorrents.toList());
|
auto const old = isCompleteList ? myTorrents : torrents_t{};
|
||||||
auto added = QSet<int>{};
|
auto added = torrent_ids_t{};
|
||||||
auto changed = QSet<int>{};
|
auto changed = torrent_ids_t{};
|
||||||
auto completed = QSet<int>{};
|
auto completed = torrent_ids_t{};
|
||||||
auto instantiated = torrents_t{};
|
auto instantiated = torrents_t{};
|
||||||
auto needinfo = QSet<int>{};
|
auto needinfo = torrent_ids_t{};
|
||||||
auto processed = QSet<Torrent*>{};
|
auto processed = torrents_t{};
|
||||||
|
|
||||||
auto const now = time(nullptr);
|
auto const now = time(nullptr);
|
||||||
auto const recently_added = [now](auto const& tor)
|
auto const recently_added = [now](auto const& tor)
|
||||||
@@ -179,6 +180,7 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool isCompleteList)
|
|||||||
char const* str;
|
char const* str;
|
||||||
size_t len;
|
size_t len;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
keys.reserve(tr_variantListSize(firstChild));
|
||||||
while (tr_variantGetStr(tr_variantListChild(firstChild, i++), &str, &len))
|
while (tr_variantGetStr(tr_variantListChild(firstChild, i++), &str, &len))
|
||||||
{
|
{
|
||||||
keys.push_back(tr_quark_new(str, len));
|
keys.push_back(tr_quark_new(str, len));
|
||||||
@@ -210,6 +212,7 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool isCompleteList)
|
|||||||
values.reserve(keys.size());
|
values.reserve(keys.size());
|
||||||
size_t tor_index = table ? 1 : 0;
|
size_t tor_index = table ? 1 : 0;
|
||||||
tr_variant* v;
|
tr_variant* v;
|
||||||
|
processed.reserve(tr_variantListSize(torrents));
|
||||||
while ((v = tr_variantListChild(torrents, tor_index++)))
|
while ((v = tr_variantListChild(torrents, tor_index++)))
|
||||||
{
|
{
|
||||||
// Build an array of values
|
// Build an array of values
|
||||||
@@ -245,11 +248,13 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool isCompleteList)
|
|||||||
|
|
||||||
Torrent* tor = getTorrentFromId(id);
|
Torrent* tor = getTorrentFromId(id);
|
||||||
std::optional<uint64_t> leftUntilDone;
|
std::optional<uint64_t> leftUntilDone;
|
||||||
|
bool is_new = false;
|
||||||
|
|
||||||
if (tor == nullptr)
|
if (tor == nullptr)
|
||||||
{
|
{
|
||||||
tor = new Torrent(myPrefs, id);
|
tor = new Torrent(myPrefs, id);
|
||||||
instantiated.push_back(tor);
|
instantiated.push_back(tor);
|
||||||
|
is_new = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -261,12 +266,12 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool isCompleteList)
|
|||||||
changed.insert(id);
|
changed.insert(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tor->hasName() && !old.contains(tor))
|
if (is_new && !tor->hasName())
|
||||||
{
|
{
|
||||||
needinfo.insert(id);
|
needinfo.insert(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recently_added(tor) && tor->hasName() && !myAlreadyAdded.contains(id))
|
if (recently_added(tor) && tor->hasName() && !myAlreadyAdded.count(id))
|
||||||
{
|
{
|
||||||
added.insert(id);
|
added.insert(id);
|
||||||
myAlreadyAdded.insert(id);
|
myAlreadyAdded.insert(id);
|
||||||
@@ -277,39 +282,39 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool isCompleteList)
|
|||||||
completed.insert(id);
|
completed.insert(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed.insert(tor);
|
processed.push_back(tor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// model upkeep
|
// model upkeep
|
||||||
|
|
||||||
if (!instantiated.isEmpty())
|
if (!instantiated.empty())
|
||||||
{
|
{
|
||||||
rowsAdd(instantiated);
|
rowsAdd(instantiated);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!changed.isEmpty())
|
if (!changed.empty())
|
||||||
{
|
{
|
||||||
rowsEmitChanged(changed);
|
rowsEmitChanged(changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// emit signals
|
// emit signals
|
||||||
|
|
||||||
if (!added.isEmpty())
|
if (!added.empty())
|
||||||
{
|
{
|
||||||
emit torrentsAdded(added);
|
emit torrentsAdded(added);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!needinfo.isEmpty())
|
if (!needinfo.empty())
|
||||||
{
|
{
|
||||||
emit torrentsNeedInfo(needinfo);
|
emit torrentsNeedInfo(needinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!changed.isEmpty())
|
if (!changed.empty())
|
||||||
{
|
{
|
||||||
emit torrentsChanged(changed);
|
emit torrentsChanged(changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!completed.isEmpty())
|
if (!completed.empty())
|
||||||
{
|
{
|
||||||
emit torrentsCompleted(completed);
|
emit torrentsCompleted(completed);
|
||||||
}
|
}
|
||||||
@@ -318,12 +323,12 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool isCompleteList)
|
|||||||
|
|
||||||
if (isCompleteList)
|
if (isCompleteList)
|
||||||
{
|
{
|
||||||
auto const removed = old - processed;
|
std::sort(processed.begin(), processed.end(), TorrentIdLessThan());
|
||||||
if (!removed.isEmpty())
|
torrents_t removed;
|
||||||
{
|
removed.reserve(old.size());
|
||||||
|
std::set_difference(old.begin(), old.end(), processed.begin(), processed.end(), std::back_inserter(removed));
|
||||||
rowsRemove(removed);
|
rowsRemove(removed);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
@@ -365,7 +370,7 @@ Torrent const* TorrentModel::getTorrentFromId(int id) const
|
|||||||
****
|
****
|
||||||
***/
|
***/
|
||||||
|
|
||||||
std::vector<TorrentModel::span_t> TorrentModel::getSpans(QSet<int> const& ids) const
|
std::vector<TorrentModel::span_t> TorrentModel::getSpans(torrent_ids_t const& ids) const
|
||||||
{
|
{
|
||||||
// ids -> rows
|
// ids -> rows
|
||||||
std::vector<int> rows;
|
std::vector<int> rows;
|
||||||
@@ -420,7 +425,7 @@ std::vector<TorrentModel::span_t> TorrentModel::getSpans(QSet<int> const& ids) c
|
|||||||
****
|
****
|
||||||
***/
|
***/
|
||||||
|
|
||||||
void TorrentModel::rowsEmitChanged(QSet<int> const& ids)
|
void TorrentModel::rowsEmitChanged(torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
for (auto const& span : getSpans(ids))
|
for (auto const& span : getSpans(ids))
|
||||||
{
|
{
|
||||||
@@ -432,7 +437,7 @@ void TorrentModel::rowsAdd(torrents_t const& torrents)
|
|||||||
{
|
{
|
||||||
auto const compare = TorrentIdLessThan();
|
auto const compare = TorrentIdLessThan();
|
||||||
|
|
||||||
if (myTorrents.isEmpty())
|
if (myTorrents.empty())
|
||||||
{
|
{
|
||||||
beginInsertRows(QModelIndex(), 0, torrents.size() - 1);
|
beginInsertRows(QModelIndex(), 0, torrents.size() - 1);
|
||||||
myTorrents = torrents;
|
myTorrents = torrents;
|
||||||
@@ -453,7 +458,7 @@ void TorrentModel::rowsAdd(torrents_t const& torrents)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentModel::rowsRemove(QSet<Torrent*> const& torrents)
|
void TorrentModel::rowsRemove(torrents_t const& torrents)
|
||||||
{
|
{
|
||||||
// must walk in reverse to avoid invalidating row numbers
|
// must walk in reverse to avoid invalidating row numbers
|
||||||
auto const& spans = getSpans(getIds(torrents.begin(), torrents.end()));
|
auto const& spans = getSpans(getIds(torrents.begin(), torrents.end()));
|
||||||
@@ -474,29 +479,6 @@ void TorrentModel::rowsRemove(QSet<Torrent*> const& torrents)
|
|||||||
****
|
****
|
||||||
***/
|
***/
|
||||||
|
|
||||||
void TorrentModel::getTransferSpeed(Speed& uploadSpeed, size_t& uploadPeerCount, Speed& downloadSpeed,
|
|
||||||
size_t& downloadPeerCount) const
|
|
||||||
{
|
|
||||||
Speed upSpeed;
|
|
||||||
Speed downSpeed;
|
|
||||||
size_t upCount = 0;
|
|
||||||
size_t downCount = 0;
|
|
||||||
|
|
||||||
for (Torrent const* const tor : myTorrents)
|
|
||||||
{
|
|
||||||
upSpeed += tor->uploadSpeed();
|
|
||||||
upCount += tor->peersWeAreUploadingTo();
|
|
||||||
downSpeed += tor->downloadSpeed();
|
|
||||||
downCount += tor->webseedsWeAreDownloadingFrom();
|
|
||||||
downCount += tor->peersWeAreDownloadingFrom();
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadSpeed = upSpeed;
|
|
||||||
uploadPeerCount = upCount;
|
|
||||||
downloadSpeed = downSpeed;
|
|
||||||
downloadPeerCount = downCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TorrentModel::hasTorrent(QString const& hashString) const
|
bool TorrentModel::hasTorrent(QString const& hashString) const
|
||||||
{
|
{
|
||||||
auto test = [hashString](auto const& tor) { return tor->hashString() == hashString; };
|
auto test = [hashString](auto const& tor) { return tor->hashString() == hashString; };
|
||||||
|
|||||||
@@ -9,10 +9,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QSet>
|
// #include <QVector>
|
||||||
#include <QVector>
|
|
||||||
|
#include <Typedefs.h>
|
||||||
|
|
||||||
class Prefs;
|
class Prefs;
|
||||||
class Speed;
|
class Speed;
|
||||||
@@ -34,7 +36,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
explicit TorrentModel(Prefs const& prefs);
|
explicit TorrentModel(Prefs const& prefs);
|
||||||
virtual ~TorrentModel();
|
virtual ~TorrentModel() override;
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
bool hasTorrent(QString const& hashString) const;
|
bool hasTorrent(QString const& hashString) const;
|
||||||
@@ -42,7 +44,8 @@ public:
|
|||||||
Torrent* getTorrentFromId(int id);
|
Torrent* getTorrentFromId(int id);
|
||||||
Torrent const* getTorrentFromId(int id) const;
|
Torrent const* getTorrentFromId(int id) const;
|
||||||
|
|
||||||
void getTransferSpeed(Speed& uploadSpeed, size_t& uploadPeerCount, Speed& downloadSpeed, size_t& downloadPeerCount) const;
|
using torrents_t = QVector<Torrent*>;
|
||||||
|
torrents_t const& torrents() const { return myTorrents; }
|
||||||
|
|
||||||
// QAbstractItemModel
|
// QAbstractItemModel
|
||||||
int rowCount(QModelIndex const& parent = QModelIndex()) const override;
|
int rowCount(QModelIndex const& parent = QModelIndex()) const override;
|
||||||
@@ -53,23 +56,22 @@ public slots:
|
|||||||
void removeTorrents(tr_variant* torrentList);
|
void removeTorrents(tr_variant* torrentList);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void torrentsAdded(QSet<int>);
|
void torrentsAdded(torrent_ids_t const&);
|
||||||
void torrentsChanged(QSet<int>);
|
void torrentsChanged(torrent_ids_t const&);
|
||||||
void torrentsCompleted(QSet<int>);
|
void torrentsCompleted(torrent_ids_t const&);
|
||||||
void torrentsNeedInfo(QSet<int>);
|
void torrentsNeedInfo(torrent_ids_t const&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using torrents_t = QVector<Torrent*>;
|
|
||||||
void rowsAdd(torrents_t const& torrents);
|
void rowsAdd(torrents_t const& torrents);
|
||||||
void rowsRemove(QSet<Torrent*> const& torrents);
|
void rowsRemove(torrents_t const& torrents);
|
||||||
void rowsEmitChanged(QSet<int> const& ids);
|
void rowsEmitChanged(torrent_ids_t const& ids);
|
||||||
|
|
||||||
std::optional<int> getRow(int id) const;
|
std::optional<int> getRow(int id) const;
|
||||||
std::optional<int> getRow(Torrent const* tor) const;
|
std::optional<int> getRow(Torrent const* tor) const;
|
||||||
using span_t = std::pair<int, int>;
|
using span_t = std::pair<int, int>;
|
||||||
std::vector<span_t> getSpans(QSet<int> const& ids) const;
|
std::vector<span_t> getSpans(torrent_ids_t const& ids) const;
|
||||||
|
|
||||||
Prefs const& myPrefs;
|
Prefs const& myPrefs;
|
||||||
|
torrent_ids_t myAlreadyAdded;
|
||||||
torrents_t myTorrents;
|
torrents_t myTorrents;
|
||||||
QSet<int> myAlreadyAdded;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ signals:
|
|||||||
void headerDoubleClicked();
|
void headerDoubleClicked();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void resizeEvent(QResizeEvent* event);
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class HeaderWidget;
|
class HeaderWidget;
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ ItemLayout::ItemLayout(QString const& text, bool suppressColors, Qt::LayoutDirec
|
|||||||
|
|
||||||
QSize TrackerDelegate::margin(QStyle const& style) const
|
QSize TrackerDelegate::margin(QStyle const& style) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(style);
|
Q_UNUSED(style)
|
||||||
|
|
||||||
return myMargin;
|
return myMargin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,15 +26,11 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TrackerDelegate()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void setShowMore(bool b);
|
void setShowMore(bool b);
|
||||||
|
|
||||||
// QAbstractItemDelegate
|
// QAbstractItemDelegate
|
||||||
virtual QSize sizeHint(QStyleOptionViewItem const& option, QModelIndex const& index) const;
|
QSize sizeHint(QStyleOptionViewItem const& option, QModelIndex const& index) const override;
|
||||||
virtual void paint(QPainter* painter, QStyleOptionViewItem const& option, QModelIndex const& index) const;
|
void paint(QPainter* painter, QStyleOptionViewItem const& option, QModelIndex const& index) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString getText(TrackerInfo const&) const;
|
QString getText(TrackerInfo const&) const;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
int TrackerModel::rowCount(QModelIndex const& parent) const
|
int TrackerModel::rowCount(QModelIndex const& parent) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(parent);
|
Q_UNUSED(parent)
|
||||||
|
|
||||||
return parent.isValid() ? 0 : myRows.size();
|
return parent.isValid() ? 0 : myRows.size();
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ struct CompareTrackers
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void TrackerModel::refresh(TorrentModel const& torrentModel, QSet<int> const& ids)
|
void TrackerModel::refresh(TorrentModel const& torrentModel, torrent_ids_t const& ids)
|
||||||
{
|
{
|
||||||
// build a list of the TrackerInfos
|
// build a list of the TrackerInfos
|
||||||
QVector<TrackerInfo> trackers;
|
QVector<TrackerInfo> trackers;
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QSet>
|
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
#include "Torrent.h"
|
#include "Torrent.h"
|
||||||
|
#include "Typedefs.h"
|
||||||
|
|
||||||
class TorrentModel;
|
class TorrentModel;
|
||||||
|
|
||||||
@@ -35,20 +35,14 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TrackerModel()
|
TrackerModel() = default;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~TrackerModel()
|
void refresh(TorrentModel const&, torrent_ids_t const& ids);
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void refresh(TorrentModel const&, QSet<int> const& ids);
|
|
||||||
int find(int torrentId, QString const& url) const;
|
int find(int torrentId, QString const& url) const;
|
||||||
|
|
||||||
// QAbstractItemModel
|
// QAbstractItemModel
|
||||||
virtual int rowCount(QModelIndex const& parent = QModelIndex()) const;
|
int rowCount(QModelIndex const& parent = QModelIndex()) const override;
|
||||||
virtual QVariant data(QModelIndex const& index, int role = Qt::DisplayRole) const;
|
QVariant data(QModelIndex const& index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef QVector<TrackerInfo> rows_t;
|
typedef QVector<TrackerInfo> rows_t;
|
||||||
|
|||||||
5
qt/Typedefs.h
Normal file
5
qt/Typedefs.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
using torrent_ids_t = std::unordered_set<int>;
|
||||||
@@ -6,8 +6,9 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@@ -109,12 +110,13 @@ QIcon fileIcon()
|
|||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<QString, QIcon> iconCache;
|
std::unordered_map<QString, QIcon> iconCache;
|
||||||
|
|
||||||
QIcon const getMimeIcon(QString const& filename)
|
QIcon const getMimeIcon(QString const& filename)
|
||||||
{
|
{
|
||||||
// If the suffix doesn't match a mime type, treat it as a folder.
|
// If the suffix doesn't match a mime type, treat it as a folder.
|
||||||
// This heuristic is fast and yields good results for torrent names.
|
// This heuristic is fast and yields good results for torrent names.
|
||||||
static std::set<QString> suffixes;
|
static std::unordered_set<QString> suffixes;
|
||||||
if (suffixes.empty())
|
if (suffixes.empty())
|
||||||
{
|
{
|
||||||
for (auto const& type : QMimeDatabase().allMimeTypes())
|
for (auto const& type : QMimeDatabase().allMimeTypes())
|
||||||
|
|||||||
23
qt/Utils.h
23
qt/Utils.h
@@ -80,7 +80,7 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (QChar const ch : s)
|
for (auto const& ch : s)
|
||||||
{
|
{
|
||||||
if (!isxdigit(ch.unicode()))
|
if (!isxdigit(ch.unicode()))
|
||||||
{
|
{
|
||||||
@@ -93,9 +93,22 @@ public:
|
|||||||
|
|
||||||
static bool isUriWithSupportedScheme(QString const& s)
|
static bool isUriWithSupportedScheme(QString const& s)
|
||||||
{
|
{
|
||||||
static QString const ftp = QString::fromUtf8("ftp://");
|
return s.startsWith(QStringLiteral("ftp://")) ||
|
||||||
static QString const http = QString::fromUtf8("http://");
|
s.startsWith(QStringLiteral("http://")) ||
|
||||||
static QString const https = QString::fromUtf8("https://");
|
s.startsWith(QStringLiteral("https://"));
|
||||||
return s.startsWith(http) || s.startsWith(https) || s.startsWith(ftp);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<QString>
|
||||||
|
{
|
||||||
|
std::size_t operator ()(QString const& s) const
|
||||||
|
{
|
||||||
|
return qHash(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
|||||||
@@ -28,10 +28,6 @@ WatchDir::WatchDir(TorrentModel const& model) :
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
WatchDir::~WatchDir()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
****
|
****
|
||||||
***/
|
***/
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ class WatchDir : public QObject
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
WatchDir(TorrentModel const&);
|
WatchDir(TorrentModel const&);
|
||||||
virtual ~WatchDir();
|
|
||||||
|
|
||||||
void setPath(QString const& path, bool isEnabled);
|
void setPath(QString const& path, bool isEnabled);
|
||||||
|
|
||||||
|
|||||||
@@ -121,6 +121,6 @@ SOURCES += AboutDialog.cc \
|
|||||||
Utils.cc \
|
Utils.cc \
|
||||||
WatchDir.cc
|
WatchDir.cc
|
||||||
HEADERS += $$replace(SOURCES, .cc, .h)
|
HEADERS += $$replace(SOURCES, .cc, .h)
|
||||||
HEADERS += BaseDialog.h CustomVariantType.h Speed.h
|
HEADERS += BaseDialog.h CustomVariantType.h Speed.h Typedefs.h
|
||||||
|
|
||||||
win32:RC_FILE = qtr.rc
|
win32:RC_FILE = qtr.rc
|
||||||
|
|||||||
Reference in New Issue
Block a user