mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2026-01-05 15:12:32 -06:00
committed by
GitHub
parent
65771d66fc
commit
7a41192597
@@ -363,7 +363,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::TorrentDescriptor &to
|
||||
|
||||
connect(m_ui->categoryComboBox, &QComboBox::currentIndexChanged, this, &AddNewTorrentDialog::categoryChanged);
|
||||
|
||||
m_ui->tagsLineEdit->setText(m_torrentParams.tags.join(u", "_s));
|
||||
m_ui->tagsLineEdit->setText(QStringList(m_torrentParams.tags.cbegin(), m_torrentParams.tags.cend()).join(u", "_s));
|
||||
connect(m_ui->tagsEditButton, &QAbstractButton::clicked, this, [this]
|
||||
{
|
||||
auto *dlg = new TorrentTagsDialog(m_torrentParams.tags, this);
|
||||
@@ -371,7 +371,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::TorrentDescriptor &to
|
||||
connect(dlg, &TorrentTagsDialog::accepted, this, [this, dlg]
|
||||
{
|
||||
m_torrentParams.tags = dlg->tags();
|
||||
m_ui->tagsLineEdit->setText(m_torrentParams.tags.join(u", "_s));
|
||||
m_ui->tagsLineEdit->setText(QStringList(m_torrentParams.tags.cbegin(), m_torrentParams.tags.cend()).join(u", "_s));
|
||||
});
|
||||
dlg->open();
|
||||
});
|
||||
|
||||
@@ -112,7 +112,7 @@ AddTorrentParamsWidget::AddTorrentParamsWidget(BitTorrent::AddTorrentParams addT
|
||||
connect(dlg, &TorrentTagsDialog::accepted, this, [this, dlg]
|
||||
{
|
||||
m_addTorrentParams.tags = dlg->tags();
|
||||
m_ui->tagsLineEdit->setText(m_addTorrentParams.tags.join(u", "_s));
|
||||
m_ui->tagsLineEdit->setText(QStringList(m_addTorrentParams.tags.cbegin(), m_addTorrentParams.tags.cend()).join(u", "_s));
|
||||
});
|
||||
dlg->open();
|
||||
});
|
||||
@@ -230,7 +230,7 @@ void AddTorrentParamsWidget::populate()
|
||||
m_addTorrentParams.stopCondition = data.value<BitTorrent::Torrent::StopCondition>();
|
||||
});
|
||||
|
||||
m_ui->tagsLineEdit->setText(m_addTorrentParams.tags.join(u", "_s));
|
||||
m_ui->tagsLineEdit->setText(QStringList(m_addTorrentParams.tags.cbegin(), m_addTorrentParams.tags.cend()).join(u", "_s));
|
||||
|
||||
m_ui->startTorrentComboBox->disconnect(this);
|
||||
m_ui->startTorrentComboBox->setCurrentIndex(m_addTorrentParams.addPaused
|
||||
|
||||
@@ -464,7 +464,7 @@ MainWindow::MainWindow(IGUIApplication *app, WindowState initialState)
|
||||
{
|
||||
m_transferListWidget->applyStatusFilter(pref->getTransSelFilter());
|
||||
m_transferListWidget->applyCategoryFilter(QString());
|
||||
m_transferListWidget->applyTagFilter(QString());
|
||||
m_transferListWidget->applyTagFilter(std::nullopt);
|
||||
m_transferListWidget->applyTrackerFilterAll();
|
||||
}
|
||||
|
||||
|
||||
@@ -53,9 +53,9 @@ TorrentTagsDialog::TorrentTagsDialog(const TagSet &initialTags, QWidget *parent)
|
||||
connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
auto *tagsLayout = new FlowLayout(m_ui->scrollArea);
|
||||
for (const QString &tag : asConst(initialTags.united(BitTorrent::Session::instance()->tags())))
|
||||
for (const Tag &tag : asConst(initialTags.united(BitTorrent::Session::instance()->tags())))
|
||||
{
|
||||
auto *tagWidget = new QCheckBox(tag);
|
||||
auto *tagWidget = new QCheckBox(tag.toString());
|
||||
if (initialTags.contains(tag))
|
||||
tagWidget->setChecked(true);
|
||||
tagsLayout->addWidget(tagWidget);
|
||||
@@ -83,7 +83,7 @@ TagSet TorrentTagsDialog::tags() const
|
||||
{
|
||||
const auto *tagWidget = static_cast<QCheckBox *>(layout->itemAt(i)->widget());
|
||||
if (tagWidget->isChecked())
|
||||
tags.insert(tagWidget->text());
|
||||
tags.insert(Tag(tagWidget->text()));
|
||||
}
|
||||
|
||||
return tags;
|
||||
@@ -92,18 +92,18 @@ TagSet TorrentTagsDialog::tags() const
|
||||
void TorrentTagsDialog::addNewTag()
|
||||
{
|
||||
bool done = false;
|
||||
QString tag;
|
||||
Tag tag;
|
||||
while (!done)
|
||||
{
|
||||
bool ok = false;
|
||||
tag = AutoExpandableDialog::getText(this
|
||||
, tr("New Tag"), tr("Tag:"), QLineEdit::Normal, tag, &ok).trimmed();
|
||||
tag = Tag(AutoExpandableDialog::getText(this, tr("New Tag")
|
||||
, tr("Tag:"), QLineEdit::Normal, tag.toString(), &ok));
|
||||
if (!ok || tag.isEmpty())
|
||||
break;
|
||||
|
||||
if (!BitTorrent::Session::isValidTag(tag))
|
||||
if (!tag.isValid())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid tag name"), tr("Tag name '%1' is invalid.").arg(tag));
|
||||
QMessageBox::warning(this, tr("Invalid tag name"), tr("Tag name '%1' is invalid.").arg(tag.toString()));
|
||||
}
|
||||
else if (BitTorrent::Session::instance()->tags().contains(tag))
|
||||
{
|
||||
@@ -113,7 +113,7 @@ void TorrentTagsDialog::addNewTag()
|
||||
{
|
||||
auto *layout = m_ui->scrollArea->layout();
|
||||
auto *btn = layout->takeAt(layout->count() - 1);
|
||||
auto *tagWidget = new QCheckBox(tag);
|
||||
auto *tagWidget = new QCheckBox(tag.toString());
|
||||
tagWidget->setChecked(true);
|
||||
layout->addWidget(tagWidget);
|
||||
layout->addItem(btn);
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
#include "tagfiltermodel.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QIcon>
|
||||
#include <QVector>
|
||||
|
||||
@@ -40,33 +39,16 @@
|
||||
const int ROW_ALL = 0;
|
||||
const int ROW_UNTAGGED = 1;
|
||||
|
||||
namespace
|
||||
{
|
||||
QString getSpecialAllTag()
|
||||
{
|
||||
const QString ALL_TAG = u" "_s;
|
||||
Q_ASSERT(!BitTorrent::Session::isValidTag(ALL_TAG));
|
||||
return ALL_TAG;
|
||||
}
|
||||
|
||||
QString getSpecialUntaggedTag()
|
||||
{
|
||||
const QString UNTAGGED_TAG = u" "_s;
|
||||
Q_ASSERT(!BitTorrent::Session::isValidTag(UNTAGGED_TAG));
|
||||
return UNTAGGED_TAG;
|
||||
}
|
||||
}
|
||||
|
||||
class TagModelItem
|
||||
{
|
||||
public:
|
||||
TagModelItem(const QString &tag, int torrentsCount = 0)
|
||||
: m_tag(tag)
|
||||
, m_torrentsCount(torrentsCount)
|
||||
TagModelItem(const Tag &tag, int torrentsCount = 0)
|
||||
: m_tag {tag}
|
||||
, m_torrentsCount {torrentsCount}
|
||||
{
|
||||
}
|
||||
|
||||
QString tag() const
|
||||
Tag tag() const
|
||||
{
|
||||
return m_tag;
|
||||
}
|
||||
@@ -88,7 +70,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
QString m_tag;
|
||||
Tag m_tag;
|
||||
int m_torrentsCount;
|
||||
};
|
||||
|
||||
@@ -124,12 +106,25 @@ QVariant TagFilterModel::data(const QModelIndex &index, int role) const
|
||||
Q_ASSERT(isValidRow(row));
|
||||
const TagModelItem &item = m_tagItems[row];
|
||||
|
||||
const auto displayName = [&row, tag = item.tag()]
|
||||
{
|
||||
switch (row)
|
||||
{
|
||||
case 0:
|
||||
return tr("All");
|
||||
case 1:
|
||||
return tr("Untagged");
|
||||
default:
|
||||
return tag.toString();
|
||||
}
|
||||
};
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DecorationRole:
|
||||
return UIThemeManager::instance()->getIcon(u"tags"_s, u"inode-directory"_s);
|
||||
case Qt::DisplayRole:
|
||||
return u"%1 (%2)"_s.arg(tagDisplayName(item.tag())).arg(item.torrentsCount());
|
||||
return u"%1 (%2)"_s.arg(displayName(), QString::number(item.torrentsCount()));
|
||||
case Qt::UserRole:
|
||||
return item.torrentsCount();
|
||||
default:
|
||||
@@ -171,7 +166,7 @@ bool TagFilterModel::isValidRow(int row) const
|
||||
return (row >= 0) && (row < m_tagItems.size());
|
||||
}
|
||||
|
||||
QModelIndex TagFilterModel::index(const QString &tag) const
|
||||
QModelIndex TagFilterModel::index(const Tag &tag) const
|
||||
{
|
||||
const int row = findRow(tag);
|
||||
if (!isValidRow(row))
|
||||
@@ -179,7 +174,7 @@ QModelIndex TagFilterModel::index(const QString &tag) const
|
||||
return index(row, 0, QModelIndex());
|
||||
}
|
||||
|
||||
QString TagFilterModel::tag(const QModelIndex &index) const
|
||||
Tag TagFilterModel::tag(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return {};
|
||||
@@ -188,7 +183,7 @@ QString TagFilterModel::tag(const QModelIndex &index) const
|
||||
return m_tagItems[row].tag();
|
||||
}
|
||||
|
||||
void TagFilterModel::tagAdded(const QString &tag)
|
||||
void TagFilterModel::tagAdded(const Tag &tag)
|
||||
{
|
||||
const int row = m_tagItems.count();
|
||||
beginInsertRows(QModelIndex(), row, row);
|
||||
@@ -196,7 +191,7 @@ void TagFilterModel::tagAdded(const QString &tag)
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void TagFilterModel::tagRemoved(const QString &tag)
|
||||
void TagFilterModel::tagRemoved(const Tag &tag)
|
||||
{
|
||||
QModelIndex i = index(tag);
|
||||
beginRemoveRows(i.parent(), i.row(), i.row());
|
||||
@@ -204,7 +199,7 @@ void TagFilterModel::tagRemoved(const QString &tag)
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
void TagFilterModel::torrentTagAdded(BitTorrent::Torrent *const torrent, const QString &tag)
|
||||
void TagFilterModel::torrentTagAdded(BitTorrent::Torrent *const torrent, const Tag &tag)
|
||||
{
|
||||
if (torrent->tags().count() == 1)
|
||||
{
|
||||
@@ -222,7 +217,7 @@ void TagFilterModel::torrentTagAdded(BitTorrent::Torrent *const torrent, const Q
|
||||
emit dataChanged(i, i);
|
||||
}
|
||||
|
||||
void TagFilterModel::torrentTagRemoved(BitTorrent::Torrent *const torrent, const QString &tag)
|
||||
void TagFilterModel::torrentTagRemoved(BitTorrent::Torrent *const torrent, const Tag &tag)
|
||||
{
|
||||
if (torrent->tags().empty())
|
||||
{
|
||||
@@ -275,7 +270,7 @@ void TagFilterModel::torrentAboutToBeRemoved(BitTorrent::Torrent *const torrent)
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const QString &tag : asConst(torrent->tags()))
|
||||
for (const Tag &tag : asConst(torrent->tags()))
|
||||
{
|
||||
const int row = findRow(tag);
|
||||
Q_ASSERT(isValidRow(row));
|
||||
@@ -289,15 +284,6 @@ void TagFilterModel::torrentAboutToBeRemoved(BitTorrent::Torrent *const torrent)
|
||||
}
|
||||
}
|
||||
|
||||
QString TagFilterModel::tagDisplayName(const QString &tag)
|
||||
{
|
||||
if (tag == getSpecialAllTag())
|
||||
return tr("All");
|
||||
if (tag == getSpecialUntaggedTag())
|
||||
return tr("Untagged");
|
||||
return tag;
|
||||
}
|
||||
|
||||
void TagFilterModel::populate()
|
||||
{
|
||||
using Torrent = BitTorrent::Torrent;
|
||||
@@ -306,21 +292,21 @@ void TagFilterModel::populate()
|
||||
const auto torrents = session->torrents();
|
||||
|
||||
// All torrents
|
||||
addToModel(getSpecialAllTag(), torrents.count());
|
||||
addToModel(Tag(), torrents.count());
|
||||
|
||||
const int untaggedCount = std::count_if(torrents.cbegin(), torrents.cend(),
|
||||
[](Torrent *torrent) { return torrent->tags().isEmpty(); });
|
||||
addToModel(getSpecialUntaggedTag(), untaggedCount);
|
||||
const int untaggedCount = std::count_if(torrents.cbegin(), torrents.cend()
|
||||
, [](Torrent *torrent) { return torrent->tags().isEmpty(); });
|
||||
addToModel(Tag(), untaggedCount);
|
||||
|
||||
for (const QString &tag : asConst(session->tags()))
|
||||
for (const Tag &tag : asConst(session->tags()))
|
||||
{
|
||||
const int count = std::count_if(torrents.cbegin(), torrents.cend(),
|
||||
[tag](Torrent *torrent) { return torrent->hasTag(tag); });
|
||||
const int count = std::count_if(torrents.cbegin(), torrents.cend()
|
||||
, [tag](Torrent *torrent) { return torrent->hasTag(tag); });
|
||||
addToModel(tag, count);
|
||||
}
|
||||
}
|
||||
|
||||
void TagFilterModel::addToModel(const QString &tag, int count)
|
||||
void TagFilterModel::addToModel(const Tag &tag, const int count)
|
||||
{
|
||||
m_tagItems.append(TagModelItem(tag, count));
|
||||
}
|
||||
@@ -331,9 +317,9 @@ void TagFilterModel::removeFromModel(int row)
|
||||
m_tagItems.removeAt(row);
|
||||
}
|
||||
|
||||
int TagFilterModel::findRow(const QString &tag) const
|
||||
int TagFilterModel::findRow(const Tag &tag) const
|
||||
{
|
||||
if (!BitTorrent::Session::isValidTag(tag))
|
||||
if (!tag.isValid())
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i < m_tagItems.size(); ++i)
|
||||
@@ -345,7 +331,7 @@ int TagFilterModel::findRow(const QString &tag) const
|
||||
return -1;
|
||||
}
|
||||
|
||||
TagModelItem *TagFilterModel::findItem(const QString &tag)
|
||||
TagModelItem *TagFilterModel::findItem(const Tag &tag)
|
||||
{
|
||||
const int row = findRow(tag);
|
||||
if (!isValidRow(row))
|
||||
@@ -357,13 +343,13 @@ QVector<TagModelItem *> TagFilterModel::findItems(const TagSet &tags)
|
||||
{
|
||||
QVector<TagModelItem *> items;
|
||||
items.reserve(tags.count());
|
||||
for (const QString &tag : tags)
|
||||
for (const Tag &tag : tags)
|
||||
{
|
||||
TagModelItem *item = findItem(tag);
|
||||
if (item)
|
||||
items.push_back(item);
|
||||
else
|
||||
qWarning() << u"Requested tag '%1' missing from the model."_s.arg(tag);
|
||||
qWarning() << u"Requested tag '%1' missing from the model."_s.arg(tag.toString());
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -56,26 +56,24 @@ public:
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent = {}) const override;
|
||||
int rowCount(const QModelIndex &parent = {}) const override;
|
||||
|
||||
QModelIndex index(const QString &tag) const;
|
||||
QString tag(const QModelIndex &index) const;
|
||||
QModelIndex index(const Tag &tag) const;
|
||||
Tag tag(const QModelIndex &index) const;
|
||||
|
||||
private slots:
|
||||
void tagAdded(const QString &tag);
|
||||
void tagRemoved(const QString &tag);
|
||||
void torrentTagAdded(BitTorrent::Torrent *torrent, const QString &tag);
|
||||
void torrentTagRemoved(BitTorrent::Torrent *, const QString &tag);
|
||||
void tagAdded(const Tag &tag);
|
||||
void tagRemoved(const Tag &tag);
|
||||
void torrentTagAdded(BitTorrent::Torrent *torrent, const Tag &tag);
|
||||
void torrentTagRemoved(BitTorrent::Torrent *, const Tag &tag);
|
||||
void torrentsLoaded(const QVector<BitTorrent::Torrent *> &torrents);
|
||||
void torrentAboutToBeRemoved(BitTorrent::Torrent *torrent);
|
||||
|
||||
private:
|
||||
static QString tagDisplayName(const QString &tag);
|
||||
|
||||
void populate();
|
||||
void addToModel(const QString &tag, int count);
|
||||
void addToModel(const Tag &tag, int count);
|
||||
void removeFromModel(int row);
|
||||
bool isValidRow(int row) const;
|
||||
int findRow(const QString &tag) const;
|
||||
TagModelItem *findItem(const QString &tag);
|
||||
int findRow(const Tag &tag) const;
|
||||
TagModelItem *findItem(const Tag &tag);
|
||||
QVector<TagModelItem *> findItems(const TagSet &tags);
|
||||
TagModelItem *allTagsItem();
|
||||
TagModelItem *untaggedItem();
|
||||
|
||||
@@ -35,12 +35,12 @@ TagFilterProxyModel::TagFilterProxyModel(QObject *parent)
|
||||
{
|
||||
}
|
||||
|
||||
QModelIndex TagFilterProxyModel::index(const QString &tag) const
|
||||
QModelIndex TagFilterProxyModel::index(const Tag &tag) const
|
||||
{
|
||||
return mapFromSource(static_cast<TagFilterModel *>(sourceModel())->index(tag));
|
||||
}
|
||||
|
||||
QString TagFilterProxyModel::tag(const QModelIndex &index) const
|
||||
Tag TagFilterProxyModel::tag(const QModelIndex &index) const
|
||||
{
|
||||
return static_cast<TagFilterModel *>(sourceModel())->tag(mapToSource(index));
|
||||
}
|
||||
|
||||
@@ -34,14 +34,16 @@
|
||||
|
||||
class QString;
|
||||
|
||||
class Tag;
|
||||
|
||||
class TagFilterProxyModel final : public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
explicit TagFilterProxyModel(QObject *parent = nullptr);
|
||||
|
||||
// TagFilterModel methods which we need to relay
|
||||
QModelIndex index(const QString &tag) const;
|
||||
QString tag(const QModelIndex &index) const;
|
||||
QModelIndex index(const Tag &tag) const;
|
||||
Tag tag(const QModelIndex &index) const;
|
||||
|
||||
protected:
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2017 Tony Gregerson <tony.gregerson@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -41,17 +42,15 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
QString getTagFilter(const TagFilterProxyModel *const model, const QModelIndex &index)
|
||||
std::optional<Tag> getTagFilter(const TagFilterProxyModel *const model, const QModelIndex &index)
|
||||
{
|
||||
QString tagFilter; // Defaults to All
|
||||
if (index.isValid())
|
||||
{
|
||||
if (index.row() == 1)
|
||||
tagFilter = u""_s; // Untagged
|
||||
else if (index.row() > 1)
|
||||
tagFilter = model->tag(index);
|
||||
}
|
||||
return tagFilter;
|
||||
if (!index.isValid() || (index.row() == 0))
|
||||
return std::nullopt; // All tags
|
||||
|
||||
if (index.row() == 1)
|
||||
return Tag(); // Untagged
|
||||
|
||||
return model->tag(index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +84,7 @@ TagFilterWidget::TagFilterWidget(QWidget *parent)
|
||||
connect(model(), &QAbstractItemModel::modelReset, this, &TagFilterWidget::callUpdateGeometry);
|
||||
}
|
||||
|
||||
QString TagFilterWidget::currentTag() const
|
||||
std::optional<Tag> TagFilterWidget::currentTag() const
|
||||
{
|
||||
QModelIndex current;
|
||||
const auto selectedRows = selectionModel()->selectedRows();
|
||||
@@ -157,35 +156,36 @@ void TagFilterWidget::rowsInserted(const QModelIndex &parent, int start, int end
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
QString TagFilterWidget::askTagName()
|
||||
Tag TagFilterWidget::askTagName()
|
||||
{
|
||||
bool ok = false;
|
||||
QString tag = u""_s;
|
||||
Tag tag;
|
||||
bool invalid = true;
|
||||
while (invalid)
|
||||
{
|
||||
invalid = false;
|
||||
tag = AutoExpandableDialog::getText(
|
||||
this, tr("New Tag"), tr("Tag:"), QLineEdit::Normal, tag, &ok).trimmed();
|
||||
tag = Tag(AutoExpandableDialog::getText(this, tr("New Tag"), tr("Tag:")
|
||||
, QLineEdit::Normal, tag.toString(), &ok));
|
||||
if (ok && !tag.isEmpty())
|
||||
{
|
||||
if (!BitTorrent::Session::isValidTag(tag))
|
||||
if (!tag.isValid())
|
||||
{
|
||||
QMessageBox::warning(
|
||||
this, tr("Invalid tag name")
|
||||
, tr("Tag name '%1' is invalid").arg(tag));
|
||||
, tr("Tag name '%1' is invalid").arg(tag.toString()));
|
||||
invalid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ok ? tag : QString();
|
||||
return ok ? tag : Tag();
|
||||
}
|
||||
|
||||
void TagFilterWidget::addTag()
|
||||
{
|
||||
const QString tag = askTagName();
|
||||
if (tag.isEmpty()) return;
|
||||
const Tag tag = askTagName();
|
||||
if (tag.isEmpty())
|
||||
return;
|
||||
|
||||
if (BitTorrent::Session::instance()->tags().contains(tag))
|
||||
QMessageBox::warning(this, tr("Tag exists"), tr("Tag name already exists."));
|
||||
@@ -207,7 +207,7 @@ void TagFilterWidget::removeTag()
|
||||
void TagFilterWidget::removeUnusedTags()
|
||||
{
|
||||
auto *session = BitTorrent::Session::instance();
|
||||
for (const QString &tag : asConst(session->tags()))
|
||||
for (const Tag &tag : asConst(session->tags()))
|
||||
if (model()->data(static_cast<TagFilterProxyModel *>(model())->index(tag), Qt::UserRole) == 0)
|
||||
session->removeTag(tag);
|
||||
updateGeometry();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2017 Tony Gregerson <tony.gregerson@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -30,6 +31,8 @@
|
||||
|
||||
#include <QTreeView>
|
||||
|
||||
class Tag;
|
||||
|
||||
class TagFilterWidget final : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -38,10 +41,10 @@ class TagFilterWidget final : public QTreeView
|
||||
public:
|
||||
explicit TagFilterWidget(QWidget *parent = nullptr);
|
||||
|
||||
QString currentTag() const;
|
||||
std::optional<Tag> currentTag() const;
|
||||
|
||||
signals:
|
||||
void tagChanged(const QString &tag);
|
||||
void tagChanged(const std::optional<Tag> &tag);
|
||||
void actionResumeTorrentsTriggered();
|
||||
void actionPauseTorrentsTriggered();
|
||||
void actionDeleteTorrentsTriggered();
|
||||
@@ -58,5 +61,5 @@ private:
|
||||
QSize sizeHint() const override;
|
||||
QSize minimumSizeHint() const override;
|
||||
void rowsInserted(const QModelIndex &parent, int start, int end) override;
|
||||
QString askTagName();
|
||||
Tag askTagName();
|
||||
};
|
||||
|
||||
@@ -218,5 +218,5 @@ void TransferListFiltersWidget::onTagFilterStateChanged(bool enabled)
|
||||
void TransferListFiltersWidget::toggleTagFilter(bool enabled)
|
||||
{
|
||||
m_tagFilterWidget->setVisible(enabled);
|
||||
m_transferList->applyTagFilter(enabled ? m_tagFilterWidget->currentTag() : QString());
|
||||
m_transferList->applyTagFilter(enabled ? m_tagFilterWidget->currentTag() : std::nullopt);
|
||||
}
|
||||
|
||||
@@ -380,7 +380,10 @@ QString TransferListModel::displayValue(const BitTorrent::Torrent *torrent, cons
|
||||
case TR_CATEGORY:
|
||||
return torrent->category();
|
||||
case TR_TAGS:
|
||||
return torrent->tags().join(u", "_s);
|
||||
{
|
||||
const TagSet &tags = torrent->tags();
|
||||
return QStringList(tags.cbegin(), tags.cend()).join(u", "_s);
|
||||
}
|
||||
case TR_ADD_DATE:
|
||||
return QLocale().toString(torrent->addedTime().toLocalTime(), QLocale::ShortFormat);
|
||||
case TR_SEED_DATE:
|
||||
|
||||
@@ -59,10 +59,10 @@ namespace
|
||||
int customCompare(const TagSet &left, const TagSet &right, const Utils::Compare::NaturalCompare<Qt::CaseInsensitive> &compare)
|
||||
{
|
||||
for (auto leftIter = left.cbegin(), rightIter = right.cbegin();
|
||||
(leftIter != left.cend()) && (rightIter != right.cend());
|
||||
++leftIter, ++rightIter)
|
||||
(leftIter != left.cend()) && (rightIter != right.cend());
|
||||
++leftIter, ++rightIter)
|
||||
{
|
||||
const int result = compare(*leftIter, *rightIter);
|
||||
const int result = compare(leftIter->toString(), rightIter->toString());
|
||||
if (result != 0)
|
||||
return result;
|
||||
}
|
||||
@@ -130,7 +130,7 @@ void TransferListSortModel::disableCategoryFilter()
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void TransferListSortModel::setTagFilter(const QString &tag)
|
||||
void TransferListSortModel::setTagFilter(const Tag &tag)
|
||||
{
|
||||
if (m_filter.setTag(tag))
|
||||
invalidateFilter();
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
void setStatusFilter(TorrentFilter::Type filter);
|
||||
void setCategoryFilter(const QString &category);
|
||||
void disableCategoryFilter();
|
||||
void setTagFilter(const QString &tag);
|
||||
void setTagFilter(const Tag &tag);
|
||||
void disableTagFilter();
|
||||
void setTrackerFilter(const QSet<BitTorrent::TorrentID> &torrentIDs);
|
||||
void disableTrackerFilter();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -770,8 +771,8 @@ void TransferListWidget::askNewCategoryForSelection()
|
||||
|
||||
void TransferListWidget::askAddTagsForSelection()
|
||||
{
|
||||
const QStringList tags = askTagsForSelection(tr("Add Tags"));
|
||||
for (const QString &tag : tags)
|
||||
const TagSet tags = askTagsForSelection(tr("Add Tags"));
|
||||
for (const Tag &tag : tags)
|
||||
addSelectionTag(tag);
|
||||
}
|
||||
|
||||
@@ -871,9 +872,9 @@ void TransferListWidget::confirmRemoveAllTagsForSelection()
|
||||
clearSelectionTags();
|
||||
}
|
||||
|
||||
QStringList TransferListWidget::askTagsForSelection(const QString &dialogTitle)
|
||||
TagSet TransferListWidget::askTagsForSelection(const QString &dialogTitle)
|
||||
{
|
||||
QStringList tags;
|
||||
TagSet tags;
|
||||
bool invalid = true;
|
||||
while (invalid)
|
||||
{
|
||||
@@ -883,18 +884,23 @@ QStringList TransferListWidget::askTagsForSelection(const QString &dialogTitle)
|
||||
this, dialogTitle, tr("Comma-separated tags:"), QLineEdit::Normal, {}, &ok).trimmed();
|
||||
if (!ok || tagsInput.isEmpty())
|
||||
return {};
|
||||
tags = tagsInput.split(u',', Qt::SkipEmptyParts);
|
||||
for (QString &tag : tags)
|
||||
|
||||
const QStringList tagStrings = tagsInput.split(u',', Qt::SkipEmptyParts);
|
||||
tags.clear();
|
||||
for (const QString &tagStr : tagStrings)
|
||||
{
|
||||
tag = tag.trimmed();
|
||||
if (!BitTorrent::Session::isValidTag(tag))
|
||||
const Tag tag {tagStr};
|
||||
if (!tag.isValid())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid tag")
|
||||
, tr("Tag name: '%1' is invalid").arg(tag));
|
||||
QMessageBox::warning(this, tr("Invalid tag"), tr("Tag name: '%1' is invalid").arg(tag.toString()));
|
||||
invalid = true;
|
||||
}
|
||||
|
||||
if (!invalid)
|
||||
tags.insert(tag);
|
||||
}
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
@@ -939,12 +945,12 @@ void TransferListWidget::setSelectionCategory(const QString &category)
|
||||
applyToSelectedTorrents([&category](BitTorrent::Torrent *torrent) { torrent->setCategory(category); });
|
||||
}
|
||||
|
||||
void TransferListWidget::addSelectionTag(const QString &tag)
|
||||
void TransferListWidget::addSelectionTag(const Tag &tag)
|
||||
{
|
||||
applyToSelectedTorrents([&tag](BitTorrent::Torrent *const torrent) { torrent->addTag(tag); });
|
||||
}
|
||||
|
||||
void TransferListWidget::removeSelectionTag(const QString &tag)
|
||||
void TransferListWidget::removeSelectionTag(const Tag &tag)
|
||||
{
|
||||
applyToSelectedTorrents([&tag](BitTorrent::Torrent *const torrent) { torrent->removeTag(tag); });
|
||||
}
|
||||
@@ -1187,9 +1193,6 @@ void TransferListWidget::displayListMenu()
|
||||
}
|
||||
|
||||
// Tag Menu
|
||||
QStringList tags(BitTorrent::Session::instance()->tags().values());
|
||||
std::sort(tags.begin(), tags.end(), Utils::Compare::NaturalLessThan<Qt::CaseInsensitive>());
|
||||
|
||||
QMenu *tagsMenu = listMenu->addMenu(UIThemeManager::instance()->getIcon(u"tags"_s, u"view-categories"_s), tr("Ta&gs"));
|
||||
|
||||
tagsMenu->addAction(UIThemeManager::instance()->getIcon(u"list-add"_s), tr("&Add...", "Add / assign multiple tags...")
|
||||
@@ -1204,9 +1207,10 @@ void TransferListWidget::displayListMenu()
|
||||
});
|
||||
tagsMenu->addSeparator();
|
||||
|
||||
for (const QString &tag : asConst(tags))
|
||||
const TagSet tags = BitTorrent::Session::instance()->tags();
|
||||
for (const Tag &tag : asConst(tags))
|
||||
{
|
||||
auto *action = new TriStateAction(tag, tagsMenu);
|
||||
auto *action = new TriStateAction(tag.toString(), tagsMenu);
|
||||
action->setCloseOnInteraction(false);
|
||||
|
||||
const Qt::CheckState initialState = tagsInAll.contains(tag) ? Qt::Checked
|
||||
@@ -1320,12 +1324,12 @@ void TransferListWidget::applyCategoryFilter(const QString &category)
|
||||
m_sortFilterModel->setCategoryFilter(category);
|
||||
}
|
||||
|
||||
void TransferListWidget::applyTagFilter(const QString &tag)
|
||||
void TransferListWidget::applyTagFilter(const std::optional<Tag> &tag)
|
||||
{
|
||||
if (tag.isNull())
|
||||
if (!tag)
|
||||
m_sortFilterModel->disableTagFilter();
|
||||
else
|
||||
m_sortFilterModel->setTagFilter(tag);
|
||||
m_sortFilterModel->setTagFilter(*tag);
|
||||
}
|
||||
|
||||
void TransferListWidget::applyTrackerFilterAll()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -63,8 +64,8 @@ public:
|
||||
|
||||
public slots:
|
||||
void setSelectionCategory(const QString &category);
|
||||
void addSelectionTag(const QString &tag);
|
||||
void removeSelectionTag(const QString &tag);
|
||||
void addSelectionTag(const Tag &tag);
|
||||
void removeSelectionTag(const Tag &tag);
|
||||
void clearSelectionTags();
|
||||
void setSelectedTorrentsLocation();
|
||||
void pauseAllTorrents();
|
||||
@@ -96,7 +97,7 @@ public slots:
|
||||
void applyFilter(const QString &name, const TransferListModel::Column &type);
|
||||
void applyStatusFilter(int f);
|
||||
void applyCategoryFilter(const QString &category);
|
||||
void applyTagFilter(const QString &tag);
|
||||
void applyTagFilter(const std::optional<Tag> &tag);
|
||||
void applyTrackerFilterAll();
|
||||
void applyTrackerFilter(const QSet<BitTorrent::TorrentID> &torrentIDs);
|
||||
void previewFile(const Path &filePath);
|
||||
@@ -128,7 +129,7 @@ private:
|
||||
void editTorrentTrackers();
|
||||
void exportTorrent();
|
||||
void confirmRemoveAllTagsForSelection();
|
||||
QStringList askTagsForSelection(const QString &dialogTitle);
|
||||
TagSet askTagsForSelection(const QString &dialogTitle);
|
||||
void applyToSelectedTorrents(const std::function<void (BitTorrent::Torrent *const)> &fn);
|
||||
QVector<BitTorrent::Torrent *> getVisibleTorrents() const;
|
||||
int visibleColumnsCount() const;
|
||||
|
||||
Reference in New Issue
Block a user