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:
Charles Kerr
2019-11-11 19:37:05 -06:00
committed by GitHub
parent 49fdd0b430
commit c62cb35fd4
56 changed files with 504 additions and 531 deletions

View File

@@ -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);

View File

@@ -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();

View File

@@ -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);
} }

View File

@@ -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:

View File

@@ -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
) )

View File

@@ -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();

View File

@@ -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));
} }

View File

@@ -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;

View File

@@ -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);
} }
} }

View File

@@ -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;
}; };

View File

@@ -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;
}; };

View File

@@ -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;
} }

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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;
}; };

View File

@@ -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));

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}; };

View File

@@ -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;
} }

View File

@@ -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();
}; };

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;
} }

View File

@@ -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"

View File

@@ -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)

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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();

View File

@@ -53,5 +53,5 @@ public:
protected: protected:
// QWidget // QWidget
virtual void paintEvent(QPaintEvent* paintEvent); void paintEvent(QPaintEvent* paintEvent) override;
}; };

View File

@@ -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();

View File

@@ -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))

View File

@@ -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();

View File

@@ -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));

View File

@@ -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;
}; };

View File

@@ -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));

View File

@@ -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;
}; };

View File

@@ -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))
{ {

View File

@@ -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;

View File

@@ -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; };

View File

@@ -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;
}; };

View File

@@ -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;

View File

@@ -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;
} }

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
View File

@@ -0,0 +1,5 @@
#pragma once
#include <unordered_set>
using torrent_ids_t = std::unordered_set<int>;

View File

@@ -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())

View File

@@ -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

View File

@@ -28,10 +28,6 @@ WatchDir::WatchDir(TorrentModel const& model) :
{ {
} }
WatchDir::~WatchDir()
{
}
/*** /***
**** ****
***/ ***/

View File

@@ -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);

View File

@@ -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