mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2026-01-01 21:28:07 -06:00
Add a Tags (multi-label) feature to the GUI. Closes #13.
See https://github.com/qbittorrent/qBittorrent/issues/13 for details.
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
@@ -39,6 +40,7 @@ namespace BitTorrent
|
||||
{
|
||||
QString name;
|
||||
QString category;
|
||||
QSet<QString> tags;
|
||||
QString savePath;
|
||||
bool disableTempPath = false; // e.g. for imported torrents
|
||||
bool sequential = false;
|
||||
|
||||
@@ -127,6 +127,43 @@ namespace
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Entry>
|
||||
QSet<QString> entryListToSetImpl(const Entry &entry)
|
||||
{
|
||||
Q_ASSERT(entry.type() == Entry::list_t);
|
||||
QSet<QString> output;
|
||||
for (int i = 0; i < entry.list_size(); ++i) {
|
||||
const QString tag = QString::fromStdString(entry.list_string_value_at(i));
|
||||
if (Session::isValidTag(tag))
|
||||
output.insert(tag);
|
||||
else
|
||||
qWarning() << QString("Dropping invalid stored tag: %1").arg(tag);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM < 10100
|
||||
bool isList(const libt::lazy_entry *entry)
|
||||
{
|
||||
return entry && (entry->type() == libt::lazy_entry::list_t);
|
||||
}
|
||||
|
||||
QSet<QString> entryListToSet(const libt::lazy_entry *entry)
|
||||
{
|
||||
return entry ? entryListToSetImpl(*entry) : QSet<QString>();
|
||||
}
|
||||
#else
|
||||
bool isList(const libt::bdecode_node &entry)
|
||||
{
|
||||
return entry.type() == libt::bdecode_node::list_t;
|
||||
}
|
||||
|
||||
QSet<QString> entryListToSet(const libt::bdecode_node &entry)
|
||||
{
|
||||
return entryListToSetImpl(entry);
|
||||
}
|
||||
#endif
|
||||
|
||||
QString normalizePath(const QString &path)
|
||||
{
|
||||
QString tmp = Utils::Fs::fromNativePath(path.trimmed());
|
||||
@@ -260,6 +297,7 @@ Session::Session(QObject *parent)
|
||||
, m_isForceProxyEnabled(BITTORRENT_SESSION_KEY("ForceProxy"), true)
|
||||
, m_isProxyPeerConnectionsEnabled(BITTORRENT_SESSION_KEY("ProxyPeerConnections"), false)
|
||||
, m_storedCategories(BITTORRENT_SESSION_KEY("Categories"))
|
||||
, m_storedTags(BITTORRENT_SESSION_KEY("Tags"))
|
||||
, m_maxRatioAction(BITTORRENT_SESSION_KEY("MaxRatioAction"), Pause)
|
||||
, m_defaultSavePath(BITTORRENT_SESSION_KEY("DefaultSavePath"), specialFolderLocation(SpecialFolder::Downloads), normalizePath)
|
||||
, m_tempPath(BITTORRENT_SESSION_KEY("TempPath"), defaultSavePath() + "temp/", normalizePath)
|
||||
@@ -400,6 +438,8 @@ Session::Session(QObject *parent)
|
||||
m_storedCategories = map_cast(m_categories);
|
||||
}
|
||||
|
||||
m_tags = QSet<QString>::fromList(m_storedTags.value());
|
||||
|
||||
m_refreshTimer = new QTimer(this);
|
||||
m_refreshTimer->setInterval(refreshInterval());
|
||||
connect(m_refreshTimer, SIGNAL(timeout()), SLOT(refresh()));
|
||||
@@ -724,6 +764,47 @@ void Session::setSubcategoriesEnabled(bool value)
|
||||
emit subcategoriesSupportChanged();
|
||||
}
|
||||
|
||||
QSet<QString> Session::tags() const
|
||||
{
|
||||
return m_tags;
|
||||
}
|
||||
|
||||
bool Session::isValidTag(const QString &tag)
|
||||
{
|
||||
return (!tag.trimmed().isEmpty() && !tag.contains(','));
|
||||
}
|
||||
|
||||
bool Session::hasTag(const QString &tag) const
|
||||
{
|
||||
return m_tags.contains(tag);
|
||||
}
|
||||
|
||||
bool Session::addTag(const QString &tag)
|
||||
{
|
||||
if (!isValidTag(tag))
|
||||
return false;
|
||||
|
||||
if (!hasTag(tag)) {
|
||||
m_tags.insert(tag);
|
||||
m_storedTags = m_tags.toList();
|
||||
emit tagAdded(tag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Session::removeTag(const QString &tag)
|
||||
{
|
||||
if (m_tags.remove(tag)) {
|
||||
foreach (TorrentHandle *const torrent, torrents())
|
||||
torrent->removeTag(tag);
|
||||
m_storedTags = m_tags.toList();
|
||||
emit tagRemoved(tag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Session::isAutoTMMDisabledByDefault() const
|
||||
{
|
||||
return m_isAutoTMMDisabledByDefault;
|
||||
@@ -2997,6 +3078,16 @@ void Session::handleTorrentCategoryChanged(TorrentHandle *const torrent, const Q
|
||||
emit torrentCategoryChanged(torrent, oldCategory);
|
||||
}
|
||||
|
||||
void Session::handleTorrentTagAdded(TorrentHandle *const torrent, const QString &tag)
|
||||
{
|
||||
emit torrentTagAdded(torrent, tag);
|
||||
}
|
||||
|
||||
void Session::handleTorrentTagRemoved(TorrentHandle *const torrent, const QString &tag)
|
||||
{
|
||||
emit torrentTagRemoved(torrent, tag);
|
||||
}
|
||||
|
||||
void Session::handleTorrentSavingModeChanged(TorrentHandle * const torrent)
|
||||
{
|
||||
emit torrentSavingModeChanged(torrent);
|
||||
@@ -3930,6 +4021,10 @@ namespace
|
||||
if (torrentData.category.isEmpty())
|
||||
// **************************************************************************************
|
||||
torrentData.category = QString::fromStdString(fast.dict_find_string_value("qBt-category"));
|
||||
// auto because the return type depends on the #if above.
|
||||
const auto tagsEntry = fast.dict_find_list("qBt-tags");
|
||||
if (isList(tagsEntry))
|
||||
torrentData.tags = entryListToSet(tagsEntry);
|
||||
torrentData.name = QString::fromStdString(fast.dict_find_string_value("qBt-name"));
|
||||
torrentData.hasSeedStatus = fast.dict_find_int_value("qBt-seedStatus");
|
||||
torrentData.disableTempPath = fast.dict_find_int_value("qBt-tempPathDisabled");
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#endif
|
||||
#include <QNetworkConfigurationManager>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include <QStringList>
|
||||
#include <QVector>
|
||||
#include <QWaitCondition>
|
||||
@@ -223,6 +224,12 @@ namespace BitTorrent
|
||||
bool isSubcategoriesEnabled() const;
|
||||
void setSubcategoriesEnabled(bool value);
|
||||
|
||||
static bool isValidTag(const QString &tag);
|
||||
QSet<QString> tags() const;
|
||||
bool hasTag(const QString &tag) const;
|
||||
bool addTag(const QString &tag);
|
||||
bool removeTag(const QString &tag);
|
||||
|
||||
// Torrent Management Mode subsystem (TMM)
|
||||
//
|
||||
// Each torrent can be either in Manual mode or in Automatic mode
|
||||
@@ -400,6 +407,8 @@ namespace BitTorrent
|
||||
void handleTorrentShareLimitChanged(TorrentHandle *const torrent);
|
||||
void handleTorrentSavePathChanged(TorrentHandle *const torrent);
|
||||
void handleTorrentCategoryChanged(TorrentHandle *const torrent, const QString &oldCategory);
|
||||
void handleTorrentTagAdded(TorrentHandle *const torrent, const QString &tag);
|
||||
void handleTorrentTagRemoved(TorrentHandle *const torrent, const QString &tag);
|
||||
void handleTorrentSavingModeChanged(TorrentHandle *const torrent);
|
||||
void handleTorrentMetadataReceived(TorrentHandle *const torrent);
|
||||
void handleTorrentPaused(TorrentHandle *const torrent);
|
||||
@@ -431,6 +440,8 @@ namespace BitTorrent
|
||||
void torrentFinishedChecking(BitTorrent::TorrentHandle *const torrent);
|
||||
void torrentSavePathChanged(BitTorrent::TorrentHandle *const torrent);
|
||||
void torrentCategoryChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldCategory);
|
||||
void torrentTagAdded(TorrentHandle *const torrent, const QString &tag);
|
||||
void torrentTagRemoved(TorrentHandle *const torrent, const QString &tag);
|
||||
void torrentSavingModeChanged(BitTorrent::TorrentHandle *const torrent);
|
||||
void allTorrentsFinished();
|
||||
void metadataLoaded(const BitTorrent::TorrentInfo &info);
|
||||
@@ -452,6 +463,8 @@ namespace BitTorrent
|
||||
void categoryAdded(const QString &categoryName);
|
||||
void categoryRemoved(const QString &categoryName);
|
||||
void subcategoriesSupportChanged();
|
||||
void tagAdded(const QString &tag);
|
||||
void tagRemoved(const QString &tag);
|
||||
|
||||
private slots:
|
||||
void configureDeferred();
|
||||
@@ -606,6 +619,7 @@ namespace BitTorrent
|
||||
CachedSettingValue<bool> m_isForceProxyEnabled;
|
||||
CachedSettingValue<bool> m_isProxyPeerConnectionsEnabled;
|
||||
CachedSettingValue<QVariantMap> m_storedCategories;
|
||||
CachedSettingValue<QStringList> m_storedTags;
|
||||
CachedSettingValue<int> m_maxRatioAction;
|
||||
CachedSettingValue<QString> m_defaultSavePath;
|
||||
CachedSettingValue<QString> m_tempPath;
|
||||
@@ -650,6 +664,7 @@ namespace BitTorrent
|
||||
QHash<QString, AddTorrentParams> m_downloadedTorrents;
|
||||
TorrentStatusReport m_torrentStatusReport;
|
||||
QStringMap m_categories;
|
||||
QSet<QString> m_tags;
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM < 10100
|
||||
QMutex m_alertsMutex;
|
||||
|
||||
@@ -68,6 +68,19 @@ const QString QB_EXT {".!qB"};
|
||||
namespace libt = libtorrent;
|
||||
using namespace BitTorrent;
|
||||
|
||||
namespace
|
||||
{
|
||||
using ListType = libt::entry::list_type;
|
||||
|
||||
ListType setToEntryList(const QSet<QString> &input)
|
||||
{
|
||||
ListType entryList;
|
||||
foreach (const QString &setValue, input)
|
||||
entryList.emplace_back(setValue.toStdString());
|
||||
return entryList;
|
||||
}
|
||||
}
|
||||
|
||||
// AddTorrentData
|
||||
|
||||
AddTorrentData::AddTorrentData()
|
||||
@@ -89,6 +102,7 @@ AddTorrentData::AddTorrentData(const AddTorrentParams ¶ms)
|
||||
: resumed(false)
|
||||
, name(params.name)
|
||||
, category(params.category)
|
||||
, tags(params.tags)
|
||||
, savePath(params.savePath)
|
||||
, disableTempPath(params.disableTempPath)
|
||||
, sequential(params.sequential)
|
||||
@@ -213,6 +227,7 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle
|
||||
, m_name(data.name)
|
||||
, m_savePath(Utils::Fs::toNativePath(data.savePath))
|
||||
, m_category(data.category)
|
||||
, m_tags(data.tags)
|
||||
, m_hasSeedStatus(data.hasSeedStatus)
|
||||
, m_ratioLimit(data.ratioLimit)
|
||||
, m_seedingTimeLimit(data.seedingTimeLimit)
|
||||
@@ -578,6 +593,50 @@ bool TorrentHandle::belongsToCategory(const QString &category) const
|
||||
return false;
|
||||
}
|
||||
|
||||
QSet<QString> TorrentHandle::tags() const
|
||||
{
|
||||
return m_tags;
|
||||
}
|
||||
|
||||
bool TorrentHandle::hasTag(const QString &tag) const
|
||||
{
|
||||
return m_tags.contains(tag);
|
||||
}
|
||||
|
||||
bool TorrentHandle::addTag(const QString &tag)
|
||||
{
|
||||
if (!Session::isValidTag(tag))
|
||||
return false;
|
||||
|
||||
if (!hasTag(tag)) {
|
||||
if (!m_session->hasTag(tag))
|
||||
if (!m_session->addTag(tag))
|
||||
return false;
|
||||
m_tags.insert(tag);
|
||||
m_session->handleTorrentTagAdded(this, tag);
|
||||
m_needSaveResumeData = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TorrentHandle::removeTag(const QString &tag)
|
||||
{
|
||||
if (m_tags.remove(tag)) {
|
||||
m_session->handleTorrentTagRemoved(this, tag);
|
||||
m_needSaveResumeData = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TorrentHandle::removeAllTags()
|
||||
{
|
||||
// QT automatically copies the container in foreach, so it's safe to mutate it.
|
||||
foreach (const QString &tag, m_tags)
|
||||
removeTag(tag);
|
||||
}
|
||||
|
||||
QDateTime TorrentHandle::addedTime() const
|
||||
{
|
||||
return QDateTime::fromTime_t(m_nativeStatus.added_time);
|
||||
@@ -1617,6 +1676,7 @@ void TorrentHandle::handleSaveResumeDataAlert(libtorrent::save_resume_data_alert
|
||||
resumeData["qBt-ratioLimit"] = QString::number(m_ratioLimit).toStdString();
|
||||
resumeData["qBt-seedingTimeLimit"] = QString::number(m_seedingTimeLimit).toStdString();
|
||||
resumeData["qBt-category"] = m_category.toStdString();
|
||||
resumeData["qBt-tags"] = setToEntryList(m_tags);
|
||||
resumeData["qBt-name"] = m_name.toStdString();
|
||||
resumeData["qBt-seedStatus"] = m_hasSeedStatus;
|
||||
resumeData["qBt-tempPathDisabled"] = m_tempPathDisabled;
|
||||
|
||||
@@ -30,12 +30,13 @@
|
||||
#ifndef BITTORRENT_TORRENTHANDLE_H
|
||||
#define BITTORRENT_TORRENTHANDLE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
#include <QQueue>
|
||||
#include <QVector>
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
#include <libtorrent/torrent_handle.hpp>
|
||||
#include <libtorrent/version.hpp>
|
||||
@@ -93,6 +94,7 @@ namespace BitTorrent
|
||||
// for both new and resumed torrents
|
||||
QString name;
|
||||
QString category;
|
||||
QSet<QString> tags;
|
||||
QString savePath;
|
||||
bool disableTempPath;
|
||||
bool sequential;
|
||||
@@ -248,6 +250,12 @@ namespace BitTorrent
|
||||
bool belongsToCategory(const QString &category) const;
|
||||
bool setCategory(const QString &category);
|
||||
|
||||
QSet<QString> tags() const;
|
||||
bool hasTag(const QString &tag) const;
|
||||
bool addTag(const QString &tag);
|
||||
bool removeTag(const QString &tag);
|
||||
void removeAllTags();
|
||||
|
||||
bool hasRootFolder() const;
|
||||
|
||||
int filesCount() const;
|
||||
@@ -445,6 +453,7 @@ namespace BitTorrent
|
||||
QString m_name;
|
||||
QString m_savePath;
|
||||
QString m_category;
|
||||
QSet<QString> m_tags;
|
||||
bool m_hasSeedStatus;
|
||||
qreal m_ratioLimit;
|
||||
int m_seedingTimeLimit;
|
||||
|
||||
@@ -1064,6 +1064,16 @@ void Preferences::setConfirmTorrentRecheck(bool enabled)
|
||||
setValue("Preferences/Advanced/confirmTorrentRecheck", enabled);
|
||||
}
|
||||
|
||||
bool Preferences::confirmRemoveAllTags() const
|
||||
{
|
||||
return value("Preferences/Advanced/confirmRemoveAllTags", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setConfirmRemoveAllTags(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Advanced/confirmRemoveAllTags", enabled);
|
||||
}
|
||||
|
||||
TrayIcon::Style Preferences::trayIconStyle() const
|
||||
{
|
||||
return TrayIcon::Style(value("Preferences/Advanced/TrayIconStyle", TrayIcon::NORMAL).toInt());
|
||||
@@ -1327,6 +1337,16 @@ void Preferences::setCategoryFilterState(const bool checked)
|
||||
setValue("TransferListFilters/CategoryFilterState", checked);
|
||||
}
|
||||
|
||||
bool Preferences::getTagFilterState() const
|
||||
{
|
||||
return value("TransferListFilters/TagFilterState", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setTagFilterState(const bool checked)
|
||||
{
|
||||
setValue("TransferListFilters/TagFilterState", checked);
|
||||
}
|
||||
|
||||
bool Preferences::getTrackerFilterState() const
|
||||
{
|
||||
return value("TransferListFilters/trackerFilterState", true).toBool();
|
||||
|
||||
@@ -260,6 +260,8 @@ public:
|
||||
void setConfirmTorrentDeletion(bool enabled);
|
||||
bool confirmTorrentRecheck() const;
|
||||
void setConfirmTorrentRecheck(bool enabled);
|
||||
bool confirmRemoveAllTags() const;
|
||||
void setConfirmRemoveAllTags(bool enabled);
|
||||
TrayIcon::Style trayIconStyle() const;
|
||||
void setTrayIconStyle(TrayIcon::Style style);
|
||||
|
||||
@@ -313,6 +315,7 @@ public:
|
||||
void setTorImportGeometry(const QByteArray &geometry);
|
||||
bool getStatusFilterState() const;
|
||||
bool getCategoryFilterState() const;
|
||||
bool getTagFilterState() const;
|
||||
bool getTrackerFilterState() const;
|
||||
int getTransSelFilter() const;
|
||||
void setTransSelFilter(const int &index);
|
||||
@@ -340,6 +343,7 @@ public:
|
||||
public slots:
|
||||
void setStatusFilterState(bool checked);
|
||||
void setCategoryFilterState(bool checked);
|
||||
void setTagFilterState(bool checked);
|
||||
void setTrackerFilterState(bool checked);
|
||||
|
||||
void apply();
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
const QString TorrentFilter::AnyCategory;
|
||||
const QStringSet TorrentFilter::AnyHash = (QStringSet() << QString());
|
||||
const QString TorrentFilter::AnyTag;
|
||||
|
||||
const TorrentFilter TorrentFilter::DownloadingTorrent(TorrentFilter::Downloading);
|
||||
const TorrentFilter TorrentFilter::SeedingTorrent(TorrentFilter::Seeding);
|
||||
@@ -49,16 +50,18 @@ TorrentFilter::TorrentFilter()
|
||||
{
|
||||
}
|
||||
|
||||
TorrentFilter::TorrentFilter(const Type type, const QStringSet &hashSet, const QString &category)
|
||||
TorrentFilter::TorrentFilter(const Type type, const QStringSet &hashSet, const QString &category, const QString &tag)
|
||||
: m_type(type)
|
||||
, m_category(category)
|
||||
, m_tag(tag)
|
||||
, m_hashSet(hashSet)
|
||||
{
|
||||
}
|
||||
|
||||
TorrentFilter::TorrentFilter(const QString &filter, const QStringSet &hashSet, const QString &category)
|
||||
TorrentFilter::TorrentFilter(const QString &filter, const QStringSet &hashSet, const QString &category, const QString &tag)
|
||||
: m_type(All)
|
||||
, m_category(category)
|
||||
, m_tag(tag)
|
||||
, m_hashSet(hashSet)
|
||||
{
|
||||
setTypeByName(filter);
|
||||
@@ -121,11 +124,24 @@ bool TorrentFilter::setCategory(const QString &category)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TorrentFilter::setTag(const QString &tag)
|
||||
{
|
||||
// QString::operator==() doesn't distinguish between empty and null strings.
|
||||
if ((m_tag != tag)
|
||||
|| (m_tag.isNull() && !tag.isNull())
|
||||
|| (!m_tag.isNull() && tag.isNull())) {
|
||||
m_tag = tag;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TorrentFilter::match(TorrentHandle *const torrent) const
|
||||
{
|
||||
if (!torrent) return false;
|
||||
|
||||
return (matchState(torrent) && matchHash(torrent) && matchCategory(torrent));
|
||||
return (matchState(torrent) && matchHash(torrent) && matchCategory(torrent) && matchTag(torrent));
|
||||
}
|
||||
|
||||
bool TorrentFilter::matchState(BitTorrent::TorrentHandle *const torrent) const
|
||||
@@ -165,3 +181,11 @@ bool TorrentFilter::matchCategory(BitTorrent::TorrentHandle *const torrent) cons
|
||||
if (m_category.isNull()) return true;
|
||||
else return (torrent->belongsToCategory(m_category));
|
||||
}
|
||||
|
||||
bool TorrentFilter::matchTag(BitTorrent::TorrentHandle *const torrent) const
|
||||
{
|
||||
// Empty tag is a special value to indicate we're filtering for untagged torrents.
|
||||
if (m_tag.isNull()) return true;
|
||||
else if (m_tag.isEmpty()) return torrent->tags().isEmpty();
|
||||
else return (torrent->hasTag(m_tag));
|
||||
}
|
||||
|
||||
@@ -58,8 +58,10 @@ public:
|
||||
Errored
|
||||
};
|
||||
|
||||
// These mean any permutation, including no category / tag.
|
||||
static const QString AnyCategory;
|
||||
static const QStringSet AnyHash;
|
||||
static const QString AnyTag;
|
||||
|
||||
static const TorrentFilter DownloadingTorrent;
|
||||
static const TorrentFilter SeedingTorrent;
|
||||
@@ -71,14 +73,16 @@ public:
|
||||
static const TorrentFilter ErroredTorrent;
|
||||
|
||||
TorrentFilter();
|
||||
// category: pass empty string for "no category" or null string (QString()) for "any category"
|
||||
TorrentFilter(const Type type, const QStringSet &hashSet = AnyHash, const QString &category = AnyCategory);
|
||||
TorrentFilter(const QString &filter, const QStringSet &hashSet = AnyHash, const QString &category = AnyCategory);
|
||||
// category & tags: pass empty string for uncategorized / untagged torrents.
|
||||
// Pass null string (QString()) to disable filtering (i.e. all torrents).
|
||||
TorrentFilter(const Type type, const QStringSet &hashSet = AnyHash, const QString &category = AnyCategory, const QString &tag = AnyTag);
|
||||
TorrentFilter(const QString &filter, const QStringSet &hashSet = AnyHash, const QString &category = AnyCategory, const QString &tags = AnyTag);
|
||||
|
||||
bool setType(Type type);
|
||||
bool setTypeByName(const QString &filter);
|
||||
bool setHashSet(const QStringSet &hashSet);
|
||||
bool setCategory(const QString &category);
|
||||
bool setTag(const QString &tag);
|
||||
|
||||
bool match(BitTorrent::TorrentHandle *const torrent) const;
|
||||
|
||||
@@ -86,9 +90,11 @@ private:
|
||||
bool matchState(BitTorrent::TorrentHandle *const torrent) const;
|
||||
bool matchHash(BitTorrent::TorrentHandle *const torrent) const;
|
||||
bool matchCategory(BitTorrent::TorrentHandle *const torrent) const;
|
||||
bool matchTag(BitTorrent::TorrentHandle *const torrent) const;
|
||||
|
||||
Type m_type;
|
||||
QString m_category;
|
||||
QString m_tag;
|
||||
QStringSet m_hashSet;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user