diff --git a/src/gui/transferlistfilters/categoryfiltermodel.cpp b/src/gui/transferlistfilters/categoryfiltermodel.cpp index 294966c318..f9bf6ad118 100644 --- a/src/gui/transferlistfilters/categoryfiltermodel.cpp +++ b/src/gui/transferlistfilters/categoryfiltermodel.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2016 Vladimir Golovnev + * Copyright (C) 2016-2023 Vladimir Golovnev * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -38,6 +38,9 @@ class CategoryModelItem { public: + inline static const QString UID_ALL {QChar(1)}; + inline static const QString UID_UNCATEGORIZED; + CategoryModelItem() = default; CategoryModelItem(CategoryModelItem *parent, const QString &categoryName, const int torrentsCount = 0) @@ -99,9 +102,21 @@ class CategoryModelItem int pos() const { - if (!m_parent) return -1; + if (!m_parent) + return -1; + + if (const int posByName = m_parent->m_childUids.indexOf(m_name); posByName >= 0) + return posByName; + + // special cases + if (this == m_parent->m_children[UID_ALL]) + return 0; + + if (this == m_parent->m_children[UID_UNCATEGORIZED]) + return 1; - return m_parent->m_childUids.indexOf(m_name); + Q_ASSERT(false); + return -1; } bool hasChild(const QString &name) const @@ -202,7 +217,8 @@ int CategoryFilterModel::columnCount(const QModelIndex &) const QVariant CategoryFilterModel::data(const QModelIndex &index, int role) const { - if (!index.isValid()) return {}; + if (!index.isValid()) + return {}; const auto *item = static_cast(index.internalPointer()); @@ -248,8 +264,8 @@ QModelIndex CategoryFilterModel::index(int row, int column, const QModelIndex &p if (parent.isValid() && (parent.column() != 0)) return {}; - auto *parentItem = parent.isValid() ? static_cast(parent.internalPointer()) - : m_rootItem; + auto *parentItem = parent.isValid() + ? static_cast(parent.internalPointer()) : m_rootItem; if (row < parentItem->childCount()) return createIndex(row, column, parentItem->childAt(row)); @@ -262,7 +278,8 @@ QModelIndex CategoryFilterModel::parent(const QModelIndex &index) const return {}; auto *item = static_cast(index.internalPointer()); - if (!item) return {}; + if (!item) + return {}; return this->index(item->parent()); } @@ -276,7 +293,8 @@ int CategoryFilterModel::rowCount(const QModelIndex &parent) const return m_rootItem->childCount(); auto *item = static_cast(parent.internalPointer()); - if (!item) return 0; + if (!item) + return 0; return item->childCount(); } @@ -288,13 +306,16 @@ QModelIndex CategoryFilterModel::index(const QString &categoryName) const QString CategoryFilterModel::categoryName(const QModelIndex &index) const { - if (!index.isValid()) return {}; + if (!index.isValid()) + return {}; + return static_cast(index.internalPointer())->fullName(); } QModelIndex CategoryFilterModel::index(CategoryModelItem *item) const { - if (!item || !item->parent()) return {}; + if (!item || !item->parent()) + return {}; return index(item->pos(), 0, index(item->parent())); } @@ -337,8 +358,17 @@ void CategoryFilterModel::torrentsLoaded(const QVector &t Q_ASSERT(item); item->increaseTorrentsCount(); + QModelIndex i = index(item); + while (i.isValid()) + { + emit dataChanged(i, i); + i = parent(i); + } + m_rootItem->childAt(0)->increaseTorrentsCount(); } + + emit dataChanged(index(0, 0), index(0, 0)); } void CategoryFilterModel::torrentAboutToBeRemoved(BitTorrent::Torrent *const torrent) @@ -347,18 +377,24 @@ void CategoryFilterModel::torrentAboutToBeRemoved(BitTorrent::Torrent *const tor Q_ASSERT(item); item->decreaseTorrentsCount(); + QModelIndex i = index(item); + while (i.isValid()) + { + emit dataChanged(i, i); + i = parent(i); + } + m_rootItem->childAt(0)->decreaseTorrentsCount(); + emit dataChanged(index(0, 0), index(0, 0)); } void CategoryFilterModel::torrentCategoryChanged(BitTorrent::Torrent *const torrent, const QString &oldCategory) { - QModelIndex i; - auto *item = findItem(oldCategory); Q_ASSERT(item); item->decreaseTorrentsCount(); - i = index(item); + QModelIndex i = index(item); while (i.isValid()) { emit dataChanged(i, i); @@ -392,17 +428,16 @@ void CategoryFilterModel::populate() const auto torrents = session->torrents(); m_isSubcategoriesEnabled = session->isSubcategoriesEnabled(); - const QString UID_ALL; - const QString UID_UNCATEGORIZED(QChar(1)); - // All torrents - m_rootItem->addChild(UID_ALL, new CategoryModelItem(nullptr, tr("All"), torrents.count())); + m_rootItem->addChild(CategoryModelItem::UID_ALL + , new CategoryModelItem(nullptr, tr("All"), torrents.count())); // Uncategorized torrents using Torrent = BitTorrent::Torrent; const int torrentsCount = std::count_if(torrents.begin(), torrents.end() - , [](Torrent *torrent) { return torrent->category().isEmpty(); }); - m_rootItem->addChild(UID_UNCATEGORIZED, new CategoryModelItem(nullptr, tr("Uncategorized"), torrentsCount)); + , [](Torrent *torrent) { return torrent->category().isEmpty(); }); + m_rootItem->addChild(CategoryModelItem::UID_UNCATEGORIZED + , new CategoryModelItem(nullptr, tr("Uncategorized"), torrentsCount)); using BitTorrent::Torrent; if (m_isSubcategoriesEnabled) @@ -446,7 +481,9 @@ CategoryModelItem *CategoryFilterModel::findItem(const QString &fullName) const for (const QString &subcat : asConst(BitTorrent::Session::expandCategory(fullName))) { const QString subcatName = shortName(subcat); - if (!item->hasChild(subcatName)) return nullptr; + if (!item->hasChild(subcatName)) + return nullptr; + item = item->child(subcatName); } diff --git a/src/gui/transferlistfilters/categoryfiltermodel.h b/src/gui/transferlistfilters/categoryfiltermodel.h index 9576f094a7..8aa3425cf2 100644 --- a/src/gui/transferlistfilters/categoryfiltermodel.h +++ b/src/gui/transferlistfilters/categoryfiltermodel.h @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2016 Vladimir Golovnev + * Copyright (C) 2016-2023 Vladimir Golovnev * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/src/gui/transferlistfilters/tagfiltermodel.cpp b/src/gui/transferlistfilters/tagfiltermodel.cpp index 35c74a42cc..91fdaf37b0 100644 --- a/src/gui/transferlistfilters/tagfiltermodel.cpp +++ b/src/gui/transferlistfilters/tagfiltermodel.cpp @@ -1,5 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2023 Vladimir Golovnev * Copyright (C) 2017 Tony Gregerson * * This program is free software; you can redistribute it and/or @@ -36,6 +37,9 @@ #include "base/global.h" #include "gui/uithememanager.h" +const int ROW_ALL = 0; +const int ROW_UNTAGGED = 1; + namespace { QString getSpecialAllTag() @@ -203,21 +207,29 @@ void TagFilterModel::tagRemoved(const QString &tag) void TagFilterModel::torrentTagAdded(BitTorrent::Torrent *const torrent, const QString &tag) { if (torrent->tags().count() == 1) + { untaggedItem()->decreaseTorrentsCount(); + const QModelIndex i = index(ROW_UNTAGGED, 0); + emit dataChanged(i, i); + } const int row = findRow(tag); Q_ASSERT(isValidRow(row)); TagModelItem &item = m_tagItems[row]; item.increaseTorrentsCount(); - const QModelIndex i = index(row, 0, QModelIndex()); + const QModelIndex i = index(row, 0); emit dataChanged(i, i); } void TagFilterModel::torrentTagRemoved(BitTorrent::Torrent *const torrent, const QString &tag) { if (torrent->tags().empty()) + { untaggedItem()->increaseTorrentsCount(); + const QModelIndex i = index(ROW_UNTAGGED, 0); + emit dataChanged(i, i); + } const int row = findRow(tag); if (row < 0) @@ -225,7 +237,7 @@ void TagFilterModel::torrentTagRemoved(BitTorrent::Torrent *const torrent, const m_tagItems[row].decreaseTorrentsCount(); - const QModelIndex i = index(row, 0, QModelIndex()); + const QModelIndex i = index(row, 0); emit dataChanged(i, i); } @@ -242,17 +254,39 @@ void TagFilterModel::torrentsLoaded(const QVector &torren for (TagModelItem *item : items) item->increaseTorrentsCount(); } + + emit dataChanged(index(0, 0), index((rowCount() - 1), 0)); } void TagFilterModel::torrentAboutToBeRemoved(BitTorrent::Torrent *const torrent) { allTagsItem()->decreaseTorrentsCount(); + { + const QModelIndex i = index(ROW_ALL, 0); + emit dataChanged(i, i); + } + if (torrent->tags().isEmpty()) + { untaggedItem()->decreaseTorrentsCount(); - - for (TagModelItem *item : asConst(findItems(torrent->tags()))) - item->decreaseTorrentsCount(); + const QModelIndex i = index(ROW_UNTAGGED, 0); + emit dataChanged(i, i); + } + else + { + for (const QString &tag : asConst(torrent->tags())) + { + const int row = findRow(tag); + Q_ASSERT(isValidRow(row)); + if (!isValidRow(row)) [[unlikely]] + continue; + + m_tagItems[row].decreaseTorrentsCount(); + const QModelIndex i = index(row, 0); + emit dataChanged(i, i); + } + } } QString TagFilterModel::tagDisplayName(const QString &tag) @@ -299,11 +333,15 @@ void TagFilterModel::removeFromModel(int row) int TagFilterModel::findRow(const QString &tag) const { + if (!BitTorrent::Session::isValidTag(tag)) + return -1; + for (int i = 0; i < m_tagItems.size(); ++i) { if (m_tagItems[i].tag() == tag) return i; } + return -1; } @@ -333,11 +371,11 @@ QVector TagFilterModel::findItems(const TagSet &tags) TagModelItem *TagFilterModel::allTagsItem() { Q_ASSERT(!m_tagItems.isEmpty()); - return &m_tagItems[0]; + return &m_tagItems[ROW_ALL]; } TagModelItem *TagFilterModel::untaggedItem() { - Q_ASSERT(m_tagItems.size() > 1); - return &m_tagItems[1]; + Q_ASSERT(m_tagItems.size() > ROW_UNTAGGED); + return &m_tagItems[ROW_UNTAGGED]; } diff --git a/src/gui/transferlistfilters/tagfiltermodel.h b/src/gui/transferlistfilters/tagfiltermodel.h index 577530ac86..d7033941d3 100644 --- a/src/gui/transferlistfilters/tagfiltermodel.h +++ b/src/gui/transferlistfilters/tagfiltermodel.h @@ -1,5 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2023 Vladimir Golovnev * Copyright (C) 2017 Tony Gregerson * * This program is free software; you can redistribute it and/or