From e2198faedcc00eb3b592d3163d6714b1c28a1392 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 25 Sep 2020 09:29:50 +0200 Subject: [PATCH] Sort cats/feeds in export/import model and in msg filter dialog. --- .../gui/dialogs/formmessagefiltersmanager.cpp | 12 ++-- .../gui/dialogs/formmessagefiltersmanager.h | 4 +- src/librssguard/miscellaneous/application.cpp | 11 --- src/librssguard/miscellaneous/application.h | 2 - .../services/abstract/accountcheckmodel.cpp | 68 +++++++++++++++++++ .../services/abstract/accountcheckmodel.h | 23 +++++++ .../standardfeedsimportexportmodel.cpp | 13 ++-- .../standard/standardfeedsimportexportmodel.h | 2 +- .../services/standard/standardserviceroot.cpp | 4 +- 9 files changed, 109 insertions(+), 30 deletions(-) diff --git a/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp b/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp index e38f63fb5..71fac2231 100644 --- a/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp +++ b/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp @@ -18,7 +18,7 @@ #include "services/abstract/feed.h" FormMessageFiltersManager::FormMessageFiltersManager(FeedReader* reader, const QList& accounts, QWidget* parent) - : QDialog(parent), m_feedsModel(new AccountCheckModel(this)), m_rootItem(new RootItem()), + : QDialog(parent), m_feedsModel(new AccountCheckSortedModel(this)), m_rootItem(new RootItem()), m_accounts(accounts), m_reader(reader), m_loadingFilter(false) { m_ui.setupUi(this); @@ -51,10 +51,10 @@ FormMessageFiltersManager::FormMessageFiltersManager(FeedReader* reader, const Q connect(m_ui.m_cmbAccounts, static_cast(&QComboBox::currentIndexChanged), this, &FormMessageFiltersManager::onAccountChanged); - connect(m_ui.m_btnCheckAll, &QPushButton::clicked, m_feedsModel, &AccountCheckModel::checkAllItems); - connect(m_ui.m_btnUncheckAll, &QPushButton::clicked, m_feedsModel, &AccountCheckModel::uncheckAllItems); - connect(m_feedsModel, &AccountCheckModel::checkStateChanged, this, - &FormMessageFiltersManager::onFeedChecked); + connect(m_ui.m_btnCheckAll, &QPushButton::clicked, m_feedsModel->sourceModel(), &AccountCheckModel::checkAllItems); + connect(m_ui.m_btnUncheckAll, &QPushButton::clicked, m_feedsModel->sourceModel(), &AccountCheckModel::uncheckAllItems); + connect(m_feedsModel->sourceModel(), &AccountCheckModel::checkStateChanged, + this, &FormMessageFiltersManager::onFeedChecked); initializeTestingMessage(); loadFilters(); @@ -211,7 +211,7 @@ void FormMessageFiltersManager::loadFilterFeedAssignments(MessageFilter* filter, for (auto* feed : account->getSubTreeFeeds()) { if (feed->messageFilters().contains(filter)) { - m_feedsModel->setItemChecked(feed, Qt::CheckState::Checked); + m_feedsModel->sourceModel()->setItemChecked(feed, Qt::CheckState::Checked); } } diff --git a/src/librssguard/gui/dialogs/formmessagefiltersmanager.h b/src/librssguard/gui/dialogs/formmessagefiltersmanager.h index 4d4fbecfc..a2ca53646 100644 --- a/src/librssguard/gui/dialogs/formmessagefiltersmanager.h +++ b/src/librssguard/gui/dialogs/formmessagefiltersmanager.h @@ -9,7 +9,7 @@ #include "ui_formmessagefiltersmanager.h" -class AccountCheckModel; +class AccountCheckSortedModel; class MessageFilter; class FeedReader; @@ -51,7 +51,7 @@ class FormMessageFiltersManager : public QDialog { private: Ui::FormMessageFiltersManager m_ui; - AccountCheckModel* m_feedsModel; + AccountCheckSortedModel* m_feedsModel; RootItem* m_rootItem; QList m_accounts; FeedReader* m_reader; diff --git a/src/librssguard/miscellaneous/application.cpp b/src/librssguard/miscellaneous/application.cpp index 0d4e11522..714cc28d4 100755 --- a/src/librssguard/miscellaneous/application.cpp +++ b/src/librssguard/miscellaneous/application.cpp @@ -193,9 +193,6 @@ void Application::eliminateFirstRuns() { void Application::setFeedReader(FeedReader* feed_reader) { m_feedReader = feed_reader; - - connect(m_feedReader, &FeedReader::feedUpdatesStarted, this, &Application::onFeedUpdatesStarted); - connect(m_feedReader, &FeedReader::feedUpdatesProgress, this, &Application::onFeedUpdatesProgress); connect(m_feedReader, &FeedReader::feedUpdatesFinished, this, &Application::onFeedUpdatesFinished); } @@ -505,14 +502,6 @@ void Application::downloadRequested(QWebEngineDownloadItem* download_item) { #endif -void Application::onFeedUpdatesStarted() {} - -void Application::onFeedUpdatesProgress(const Feed* feed, int current, int total) { - Q_UNUSED(feed) - Q_UNUSED(current) - Q_UNUSED(total) -} - void Application::onFeedUpdatesFinished(const FeedDownloadResults& results) { if (!results.updatedFeeds().isEmpty()) { // Now, inform about results via GUI message/notification. diff --git a/src/librssguard/miscellaneous/application.h b/src/librssguard/miscellaneous/application.h index 4233d9370..1409b3530 100755 --- a/src/librssguard/miscellaneous/application.h +++ b/src/librssguard/miscellaneous/application.h @@ -133,8 +133,6 @@ class RSSGUARD_DLLSPEC Application : public QtSingleApplication { void downloadRequested(QWebEngineDownloadItem* download_item); #endif - void onFeedUpdatesStarted(); - void onFeedUpdatesProgress(const Feed* feed, int current, int total); void onFeedUpdatesFinished(const FeedDownloadResults& results); private: diff --git a/src/librssguard/services/abstract/accountcheckmodel.cpp b/src/librssguard/services/abstract/accountcheckmodel.cpp index 825964b21..d5fac5b04 100644 --- a/src/librssguard/services/abstract/accountcheckmodel.cpp +++ b/src/librssguard/services/abstract/accountcheckmodel.cpp @@ -280,3 +280,71 @@ bool AccountCheckModel::isItemChecked(RootItem* item) { bool AccountCheckModel::setItemChecked(RootItem* item, Qt::CheckState check) { return setData(indexForItem(item), check, Qt::CheckStateRole); } + +AccountCheckSortedModel::AccountCheckSortedModel(QObject* parent) + : QSortFilterProxyModel(parent), m_sourceModel(new AccountCheckModel(parent)) { + setDynamicSortFilter(false); + setSourceModel(m_sourceModel); + sort(0, Qt::SortOrder::AscendingOrder); +} + +bool AccountCheckSortedModel::lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const { + auto* lhs = m_sourceModel->itemForIndex(source_left); + auto* rhs = m_sourceModel->itemForIndex(source_right); + + if (lhs != nullptr && rhs != nullptr) { + QList priorities = { + RootItem::Kind::Category, + RootItem::Kind::Feed, + RootItem::Kind::Labels, + RootItem::Kind::Important, + RootItem::Kind::Bin + }; + + if (lhs->keepOnTop()) { + return sortOrder() == Qt::SortOrder::AscendingOrder; + } + else if (rhs->keepOnTop()) { + return sortOrder() == Qt::SortOrder::DescendingOrder; + } + + auto left_priority = priorities.indexOf(lhs->kind()); + auto right_priority = priorities.indexOf(rhs->kind()); + + if (left_priority == right_priority) { + return QString::localeAwareCompare(lhs->title().toLower(), rhs->title().toLower()) < 0; + } + else { + return sortOrder() == Qt::SortOrder::AscendingOrder + ? left_priority < right_priority + : right_priority < left_priority; + } + } + + return false; +} + +AccountCheckModel* AccountCheckSortedModel::sourceModel() const { + return m_sourceModel; +} + +void AccountCheckSortedModel::setRootItem(RootItem* root_item, bool delete_previous_root, bool with_layout_change) { + setSourceModel(nullptr); + m_sourceModel->setRootItem(root_item, delete_previous_root, with_layout_change); + setSourceModel(m_sourceModel); +} + +void AccountCheckSortedModel::checkAllItems() { + m_sourceModel->checkAllItems(); +} + +void AccountCheckSortedModel::uncheckAllItems() { + m_sourceModel->uncheckAllItems(); +} + +bool AccountCheckSortedModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const { + auto kind = m_sourceModel->itemForIndex(m_sourceModel->index(source_row, 0, source_parent))->kind(); + + return kind == RootItem::Kind::Root || kind == RootItem::Kind::ServiceRoot || + kind == RootItem::Kind::Category || kind == RootItem::Kind::Feed; +} diff --git a/src/librssguard/services/abstract/accountcheckmodel.h b/src/librssguard/services/abstract/accountcheckmodel.h index 4a8fdaa15..4c099334c 100644 --- a/src/librssguard/services/abstract/accountcheckmodel.h +++ b/src/librssguard/services/abstract/accountcheckmodel.h @@ -4,6 +4,7 @@ #define ACCOUNTCHECKMODEL_H #include +#include #include "services/abstract/rootitem.h" @@ -54,4 +55,26 @@ class AccountCheckModel : public QAbstractItemModel { bool m_recursiveChange; }; +class AccountCheckSortedModel : public QSortFilterProxyModel { + Q_OBJECT + + public: + explicit AccountCheckSortedModel(QObject* parent = nullptr); + virtual ~AccountCheckSortedModel() = default; + + AccountCheckModel* sourceModel() const; + void setRootItem(RootItem* root_item, bool delete_previous_root = true, bool with_layout_change = false); + + public slots: + void checkAllItems(); + void uncheckAllItems(); + + protected: + virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const; + virtual bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const; + + private: + AccountCheckModel* m_sourceModel; +}; + #endif // ACCOUNTCHECKMODEL_H diff --git a/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp b/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp index ed4edd07c..d9faf5b7b 100644 --- a/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp +++ b/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp @@ -16,13 +16,13 @@ #include FeedsImportExportModel::FeedsImportExportModel(QObject* parent) - : AccountCheckModel(parent), m_mode(Mode::Import) {} + : AccountCheckSortedModel(parent), m_mode(Mode::Import) {} FeedsImportExportModel::~FeedsImportExportModel() { - if (m_rootItem != nullptr && m_mode == Mode::Import) { + if (sourceModel() != nullptr && sourceModel()->rootItem() != nullptr && m_mode == Mode::Import) { // Delete all model items, but only if we are in import mode. Export mode shares // root item with main feed model, thus cannot be deleted from memory now. - delete m_rootItem; + delete sourceModel()->rootItem(); } } @@ -54,7 +54,7 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray& result) { QDomElement elem_opml_body = opml_document.createElement(QSL("body")); QStack items_to_process; - items_to_process.push(m_rootItem); + items_to_process.push(sourceModel()->rootItem()); QStack elements_to_use; elements_to_use.push(elem_opml_body); @@ -65,7 +65,7 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray& result) { RootItem* active_item = items_to_process.pop(); for (RootItem* child_item : active_item->childItems()) { - if (!isItemChecked(child_item)) { + if (!sourceModel()->isItemChecked(child_item)) { continue; } @@ -259,12 +259,13 @@ void FeedsImportExportModel::importAsOPML20(const QByteArray& data, bool fetch_m emit layoutAboutToBeChanged(); setRootItem(root_item); + emit layoutChanged(); emit parsingFinished(failed, succeded, false); } bool FeedsImportExportModel::exportToTxtURLPerLine(QByteArray& result) { - for (const Feed* const feed : m_rootItem->getSubTreeFeeds()) { + for (const Feed* const feed : sourceModel()->rootItem()->getSubTreeFeeds()) { result += feed->url() + QL1S("\n"); } diff --git a/src/librssguard/services/standard/standardfeedsimportexportmodel.h b/src/librssguard/services/standard/standardfeedsimportexportmodel.h index a5af0a59c..7968dea68 100644 --- a/src/librssguard/services/standard/standardfeedsimportexportmodel.h +++ b/src/librssguard/services/standard/standardfeedsimportexportmodel.h @@ -5,7 +5,7 @@ #include "services/abstract/accountcheckmodel.h" -class FeedsImportExportModel : public AccountCheckModel { +class FeedsImportExportModel : public AccountCheckSortedModel { Q_OBJECT public: diff --git a/src/librssguard/services/standard/standardserviceroot.cpp b/src/librssguard/services/standard/standardserviceroot.cpp index 85381f478..4a2590683 100644 --- a/src/librssguard/services/standard/standardserviceroot.cpp +++ b/src/librssguard/services/standard/standardserviceroot.cpp @@ -197,7 +197,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model, original_parents.push(target_root_node); QStack new_parents; - new_parents.push(model->rootItem()); + new_parents.push(model->sourceModel()->rootItem()); bool some_feed_category_error = false; // Iterate all new items we would like to merge into current model. @@ -206,7 +206,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model, RootItem* source_parent = new_parents.pop(); for (RootItem* source_item : source_parent->childItems()) { - if (!model->isItemChecked(source_item)) { + if (!model->sourceModel()->isItemChecked(source_item)) { // We can skip this item, because it is not checked and should not be imported. // NOTE: All descendants are thus skipped too. continue;