From 5d8fd251738d2453d6c0ce04f8d4c57d689f8c9d Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 1 Jul 2020 10:13:44 +0200 Subject: [PATCH] Work on filters dialog. --- resources/icons.qrc | 2 + src/librssguard/core/messagefilter.h | 2 +- .../gui/dialogs/formmessagefiltersmanager.cpp | 64 ++- .../gui/dialogs/formmessagefiltersmanager.h | 28 +- .../gui/dialogs/formmessagefiltersmanager.ui | 422 ++++++++++++------ src/librssguard/gui/guiutilities.cpp | 2 +- src/librssguard/miscellaneous/feedreader.cpp | 20 +- src/librssguard/miscellaneous/feedreader.h | 4 +- .../services/abstract/accountcheckmodel.cpp | 19 +- .../services/abstract/accountcheckmodel.h | 4 +- .../standard/gui/formstandardimportexport.cpp | 13 +- .../standardfeedsimportexportmodel.cpp | 11 +- .../standard/standardfeedsimportexportmodel.h | 5 +- .../services/standard/standardserviceroot.cpp | 4 +- src/rssguard/main.cpp | 2 +- 15 files changed, 424 insertions(+), 178 deletions(-) diff --git a/resources/icons.qrc b/resources/icons.qrc index 89037330a..2dd52cfb9 100644 --- a/resources/icons.qrc +++ b/resources/icons.qrc @@ -25,6 +25,7 @@ ./graphics/Faenza/actions/64/go-up.png ./graphics/Faenza/actions/64/gtk-edit.png ./graphics/Faenza/actions/64/help-about.png + ./graphics/Faenza/actions/64/help-contents.png ./graphics/Faenza/actions/64/insert-object.png ./graphics/Faenza/actions/64/list-add.png ./graphics/Faenza/actions/64/list-remove.png @@ -37,6 +38,7 @@ ./graphics/Faenza/actions/64/mail-message-new.png ./graphics/Faenza/actions/64/mail-send.png ./graphics/Faenza/actions/64/mail-sent.png + ./graphics/Faenza/actions/64/media-playback-start.png ./graphics/Faenza/actions/64/process-stop.png ./graphics/Faenza/actions/64/reload.png ./graphics/Faenza/actions/64/system-search.png diff --git a/src/librssguard/core/messagefilter.h b/src/librssguard/core/messagefilter.h index 204529697..ab96618dc 100755 --- a/src/librssguard/core/messagefilter.h +++ b/src/librssguard/core/messagefilter.h @@ -14,7 +14,7 @@ class MessageFilter : public QObject { Q_OBJECT public: - explicit MessageFilter(int id, QObject* parent = nullptr); + explicit MessageFilter(int id = -1, QObject* parent = nullptr); FilteringAction filterMessage(QJSEngine* engine); diff --git a/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp b/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp index 3bc77ed36..6a3eb27aa 100644 --- a/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp +++ b/src/librssguard/gui/dialogs/formmessagefiltersmanager.cpp @@ -2,21 +2,83 @@ #include "gui/dialogs/formmessagefiltersmanager.h" +#include "core/messagefilter.h" #include "gui/guiutilities.h" #include "miscellaneous/application.h" +#include "miscellaneous/feedreader.h" #include "miscellaneous/iconfactory.h" #include "network-web/webfactory.h" +#include "services/abstract/accountcheckmodel.h" -FormMessageFiltersManager::FormMessageFiltersManager(QWidget* parent) : QDialog(parent) { +FormMessageFiltersManager::FormMessageFiltersManager(FeedReader* reader, const QList& accounts, QWidget* parent) + : QDialog(parent), m_feedsModel(new AccountCheckModel(this)), m_rootItem(new RootItem()), + m_accounts(accounts), m_reader(reader) { m_ui.setupUi(this); GuiUtilities::applyDialogProperties(*this, qApp->icons()->fromTheme(QSL("view-list-details"))); m_ui.m_btnAddNew->setIcon(qApp->icons()->fromTheme(QSL("list-add"))); m_ui.m_btnRemoveSelected->setIcon(qApp->icons()->fromTheme(QSL("list-remove"))); + m_ui.m_btnTest->setIcon(qApp->icons()->fromTheme(QSL("media-playback-start"))); + m_ui.m_btnDetailedHelp->setIcon(qApp->icons()->fromTheme(QSL("help-contents"))); m_ui.m_txtScript->setFont(QFontDatabase::systemFont(QFontDatabase::SystemFont::FixedFont)); connect(m_ui.m_btnDetailedHelp, &QPushButton::clicked, this, []() { qApp->web()->openUrlInExternalBrowser(MSG_FILTERING_HELP); }); + connect(m_ui.m_listFilters, &QListWidget::currentRowChanged, + this, &FormMessageFiltersManager::loadFilter); + connect(m_ui.m_btnAddNew, &QPushButton::clicked, + this, &FormMessageFiltersManager::addNewFilter); } + +FormMessageFiltersManager::~FormMessageFiltersManager() { + delete m_rootItem; +} + +MessageFilter* FormMessageFiltersManager::selectedFilter() const { + if (m_ui.m_listFilters->selectedItems().isEmpty()) { + return nullptr; + } + else { + return m_ui.m_listFilters->selectedItems().at(0)->data(Qt::ItemDataRole::UserRole).value(); + } +} + +ServiceRoot* FormMessageFiltersManager::selectedAccount() const { + return nullptr; +} + +void FormMessageFiltersManager::addNewFilter() { + auto* fltr = m_reader->addMessageFilter( + tr("New message filter"), + QSL("function filterMessage() { return 1; }")); + auto* it = new QListWidgetItem(fltr->name(), m_ui.m_listFilters); + + it->setData(Qt::ItemDataRole::UserRole, QVariant::fromValue(fltr)); + + m_ui.m_listFilters->setCurrentRow(m_ui.m_listFilters->count() - 1); +} + +void FormMessageFiltersManager::loadFilter() { + auto* filter = selectedFilter(); + auto* acc = selectedAccount(); + + showFilter(filter); + updateFeedAssignments(filter, acc); +} + +void FormMessageFiltersManager::showFilter(MessageFilter* filter) { + if (filter == nullptr) { + m_ui.m_txtTitle->clear(); + m_ui.m_txtScript->clear(); + m_ui.m_gbDetails->setEnabled(false); + } + else { + m_ui.m_txtTitle->setText(filter->name()); + m_ui.m_txtScript->setPlainText(filter->script()); + m_ui.m_gbDetails->setEnabled(true); + } +} + +void FormMessageFiltersManager::updateFeedAssignments(MessageFilter* filter, ServiceRoot* account) {} diff --git a/src/librssguard/gui/dialogs/formmessagefiltersmanager.h b/src/librssguard/gui/dialogs/formmessagefiltersmanager.h index 174b05cd2..d8c4663ef 100644 --- a/src/librssguard/gui/dialogs/formmessagefiltersmanager.h +++ b/src/librssguard/gui/dialogs/formmessagefiltersmanager.h @@ -5,16 +5,40 @@ #include +#include "services/abstract/serviceroot.h" + #include "ui_formmessagefiltersmanager.h" +class AccountCheckModel; +class MessageFilter; +class FeedReader; + class FormMessageFiltersManager : public QDialog { - Q_OBJECT + Q_OBJECT public: - explicit FormMessageFiltersManager(QWidget *parent = nullptr); + explicit FormMessageFiltersManager(FeedReader* reader, const QList& accounts, QWidget* parent = nullptr); + virtual ~FormMessageFiltersManager(); + + MessageFilter* selectedFilter() const; + ServiceRoot* selectedAccount() const; + + private slots: + void addNewFilter(); + void loadFilter(); + + // Display filter title/contents. + void showFilter(MessageFilter* filter); + + // Load feeds/categories of the account, place checkmarks where filter is used. + void updateFeedAssignments(MessageFilter* filter, ServiceRoot* account); private: Ui::FormMessageFiltersManager m_ui; + AccountCheckModel* m_feedsModel; + RootItem* m_rootItem; + QList m_accounts; + FeedReader* m_reader; }; #endif // FORMMESSAGEFILTERSMANAGER_H diff --git a/src/librssguard/gui/dialogs/formmessagefiltersmanager.ui b/src/librssguard/gui/dialogs/formmessagefiltersmanager.ui index 739f18d1f..2f4ec1d78 100644 --- a/src/librssguard/gui/dialogs/formmessagefiltersmanager.ui +++ b/src/librssguard/gui/dialogs/formmessagefiltersmanager.ui @@ -6,144 +6,16 @@ 0 0 - 737 - 592 + 900 + 625 Message filters - - - - - - - - 0 - 1 - - - - Message filter details - - - - - - Title - - - m_txtTitle - - - - - - - - - Title of message filter - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - JavaScript code - - - m_txtScript - - - - - - - Errors - - - m_txtErrors - - - - - - - false - - - - 0 - 1 - - - - false - - - - - - - - - &Detailed help - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 0 - 2 - - - - Your JavaScript-based message filtering logic - - - - - - - - - @@ -171,8 +43,276 @@ + + + + + + + + + + 0 + 150 + + + + + + + + + + + Account + + + comboBox + + + + + + + + + Message filter details + + + + + + Title + + + m_txtTitle + + + + + + + + + + 0 + 0 + + + + + 300 + 16777215 + + + + Title of message filter + + + + + + + Qt::Horizontal + + + + + + + + + JavaScript code + + + m_txtScript + + + + + + + + + + 0 + 1 + + + + Your JavaScript-based message filtering logic + + + + + + + Sample message + + + + + + + + Read + + + + + + + Important + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Title + + + lineEdit + + + + + + + + + + URL + + + lineEdit_2 + + + + + + + + + + Author + + + lineEdit_3 + + + + + + + + + + Created on + + + lineEdit_4 + + + + + + + + + + Contents + + + plainTextEdit + + + + + + + + + + + + + + + + + &Test + + + + + + + &Detailed &help + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Test output + + + m_txtErrors + + + + + + + false + + + + 0 + 1 + + + + false + + + + + + @@ -189,12 +329,22 @@ - m_treeFilters - m_treeFeeds + m_listFilters m_btnAddNew m_btnRemoveSelected + comboBox + m_treeFeeds m_txtTitle m_txtScript + m_btnTest + m_btnDetailedHelp + checkBox + checkBox_2 + lineEdit + lineEdit_2 + lineEdit_3 + lineEdit_4 + plainTextEdit m_txtErrors @@ -206,8 +356,8 @@ accept() - 248 - 254 + 701 + 615 157 @@ -222,8 +372,8 @@ reject() - 316 - 260 + 769 + 615 286 diff --git a/src/librssguard/gui/guiutilities.cpp b/src/librssguard/gui/guiutilities.cpp index 33bc8fb37..0e6df13e3 100644 --- a/src/librssguard/gui/guiutilities.cpp +++ b/src/librssguard/gui/guiutilities.cpp @@ -22,7 +22,7 @@ void GuiUtilities::setLabelAsNotice(QLabel& label, bool is_warning) { } void GuiUtilities::applyDialogProperties(QWidget& widget, const QIcon& icon, const QString& title) { - widget.setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint); + widget.setWindowFlags(/*Qt::MSWindowsFixedSizeDialogHint | */ Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint); widget.setWindowIcon(icon); if (!title.isEmpty()) { diff --git a/src/librssguard/miscellaneous/feedreader.cpp b/src/librssguard/miscellaneous/feedreader.cpp index 7ba84e0fc..4da905c7f 100644 --- a/src/librssguard/miscellaneous/feedreader.cpp +++ b/src/librssguard/miscellaneous/feedreader.cpp @@ -7,10 +7,10 @@ #include "core/feedsproxymodel.h" #include "core/messagesmodel.h" #include "core/messagesproxymodel.h" +#include "gui/dialogs/formmessagefiltersmanager.h" #include "miscellaneous/application.h" #include "miscellaneous/databasequeries.h" #include "miscellaneous/mutex.h" -#include "gui/dialogs/formmessagefiltersmanager.h" #include "services/abstract/cacheforserviceroot.h" #include "services/abstract/serviceroot.h" #include "services/gmail/gmailentrypoint.h" @@ -97,7 +97,10 @@ void FeedReader::updateFeeds(const QList& feeds) { } void FeedReader::showMessageFiltersManager() { - FormMessageFiltersManager manager(qApp->mainFormWidget()); + FormMessageFiltersManager manager(qApp->feedReader(), + qApp->feedReader()->feedsModel()->serviceRoots(), + qApp->mainFormWidget()); + manager.exec(); } @@ -135,7 +138,7 @@ int FeedReader::autoUpdateInitialInterval() const { return m_globalAutoUpdateInitialInterval; } -void FeedReader::loadSaveMessageFilters() { +void FeedReader::loadSavedMessageFilters() { // Load all message filters from database. // All plugin services will hook active filters to // all feeds. @@ -148,6 +151,17 @@ void FeedReader::loadSaveMessageFilters() { } } +MessageFilter* FeedReader::addMessageFilter(const QString& title, const QString& script) { + auto* fltr = new MessageFilter(12, this); + + fltr->setName(title); + fltr->setScript(script); + + // TODO: Save into database, then return. + + return fltr; +} + void FeedReader::updateAllFeeds() { updateFeeds(m_feedsModel->rootItem()->getSubTreeFeeds()); } diff --git a/src/librssguard/miscellaneous/feedreader.h b/src/librssguard/miscellaneous/feedreader.h index 550b94439..2005efd08 100644 --- a/src/librssguard/miscellaneous/feedreader.h +++ b/src/librssguard/miscellaneous/feedreader.h @@ -52,9 +52,9 @@ class RSSGUARD_DLLSPEC FeedReader : public QObject { int autoUpdateRemainingInterval() const; int autoUpdateInitialInterval() const; - void loadSaveMessageFilters(); - + void loadSavedMessageFilters(); QList messageFilters() const; + MessageFilter* addMessageFilter(const QString& title, const QString& script); public slots: void updateAllFeeds(); diff --git a/src/librssguard/services/abstract/accountcheckmodel.cpp b/src/librssguard/services/abstract/accountcheckmodel.cpp index db8e8cd07..f35523c74 100644 --- a/src/librssguard/services/abstract/accountcheckmodel.cpp +++ b/src/librssguard/services/abstract/accountcheckmodel.cpp @@ -25,9 +25,7 @@ RootItem* AccountCheckModel::rootItem() const { } void AccountCheckModel::setRootItem(RootItem* root_item) { - delete m_rootItem; - m_rootItem = root_item; } @@ -161,23 +159,17 @@ QVariant AccountCheckModel::data(const QModelIndex& index, int role) const { } } else if (role == Qt::DecorationRole) { - switch (item->kind()) { - case RootItemKind::Category: - case RootItemKind::Bin: - case RootItemKind::Feed: - return item->icon(); + auto ic = item->icon(); - default: - return QVariant(); - } + return ic.isNull() ? QVariant() : ic; } else if (role == Qt::DisplayRole) { switch (item->kind()) { case RootItemKind::Category: - return QVariant(item->data(index.column(), role).toString() + tr(" (category)")); + return QVariant(item->data(index.column(), role).toString() + QSL(" ") + tr("(category)")); case RootItemKind::Feed: - return QVariant(item->data(index.column(), role).toString() + tr(" (feed)")); + return QVariant(item->data(index.column(), role).toString() + QSL(" ") + tr("(feed)")); default: return item->title(); @@ -243,7 +235,8 @@ bool AccountCheckModel::setData(const QModelIndex& index, const QVariant& value, } Qt::ItemFlags AccountCheckModel::flags(const QModelIndex& index) const { - if (!index.isValid() || itemForIndex(index)->kind() == RootItemKind::Bin) { + if (!index.isValid() || (itemForIndex(index)->kind() != RootItemKind::Kind::Category && + itemForIndex(index)->kind() != RootItemKind::Kind::Feed)) { return Qt::NoItemFlags; } diff --git a/src/librssguard/services/abstract/accountcheckmodel.h b/src/librssguard/services/abstract/accountcheckmodel.h index eb583d203..f96152c49 100644 --- a/src/librssguard/services/abstract/accountcheckmodel.h +++ b/src/librssguard/services/abstract/accountcheckmodel.h @@ -7,12 +7,12 @@ #include "services/abstract/rootitem.h" +// This is common model which displays only categories/feeds +// and allows user to place checkmarks. class AccountCheckModel : public QAbstractItemModel { Q_OBJECT public: - - // Constructors and destructors. explicit AccountCheckModel(QObject* parent = nullptr); virtual ~AccountCheckModel(); diff --git a/src/librssguard/services/standard/gui/formstandardimportexport.cpp b/src/librssguard/services/standard/gui/formstandardimportexport.cpp index 772be3da0..094ea04a3 100644 --- a/src/librssguard/services/standard/gui/formstandardimportexport.cpp +++ b/src/librssguard/services/standard/gui/formstandardimportexport.cpp @@ -40,7 +40,7 @@ void FormStandardImportExport::setMode(const FeedsImportExportModel::Mode& mode) m_ui->m_progressBar->setVisible(false); switch (mode) { - case FeedsImportExportModel::Export: { + case FeedsImportExportModel::Mode::Export: { m_model->setRootItem(m_serviceRoot); m_model->checkAllItems(); m_ui->m_treeFeeds->setModel(m_model); @@ -55,7 +55,7 @@ void FormStandardImportExport::setMode(const FeedsImportExportModel::Mode& mode) break; } - case FeedsImportExportModel::Import: { + case FeedsImportExportModel::Mode::Import: { m_ui->m_groupFile->setTitle(tr("Source file")); m_ui->m_groupFeeds->setTitle(tr("Target feeds && categories")); m_ui->m_groupFeeds->setDisabled(true); @@ -77,11 +77,11 @@ void FormStandardImportExport::setMode(const FeedsImportExportModel::Mode& mode) void FormStandardImportExport::selectFile() { switch (m_model->mode()) { - case FeedsImportExportModel::Import: + case FeedsImportExportModel::Mode::Import: selectImportFile(); break; - case FeedsImportExportModel::Export: { + case FeedsImportExportModel::Mode::Export: { selectExportFile(); break; } @@ -194,6 +194,7 @@ void FormStandardImportExport::selectImportFile() { QString(), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + parseImportFile(selected_file, answer == QMessageBox::Yes); } } @@ -227,11 +228,11 @@ void FormStandardImportExport::parseImportFile(const QString& file_name, bool fe void FormStandardImportExport::performAction() { switch (m_model->mode()) { - case FeedsImportExportModel::Import: + case FeedsImportExportModel::Mode::Import: importFeeds(); break; - case FeedsImportExportModel::Export: + case FeedsImportExportModel::Mode::Export: exportFeeds(); break; diff --git a/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp b/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp index a76070457..3f73891cb 100644 --- a/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp +++ b/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp @@ -16,10 +16,10 @@ #include FeedsImportExportModel::FeedsImportExportModel(QObject* parent) - : AccountCheckModel(parent), m_mode(Import) {} + : AccountCheckModel(parent), m_mode(Mode::Import) {} FeedsImportExportModel::~FeedsImportExportModel() { - if (m_rootItem != nullptr && m_mode == Import) { + if (m_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; @@ -52,10 +52,11 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray& result) { elem_opml_head.appendChild(elem_opml_created); opml_document.documentElement().appendChild(elem_opml_head); QDomElement elem_opml_body = opml_document.createElement(QSL("body")); - QStack items_to_process; + items_to_process.push(m_rootItem); QStack elements_to_use; + elements_to_use.push(elem_opml_body); // Process all unprocessed nodes. @@ -146,10 +147,11 @@ void FeedsImportExportModel::importAsOPML20(const QByteArray& data, bool fetch_m int completed = 0, total = 0, succeded = 0, failed = 0; auto* root_item = new StandardServiceRoot(); - QStack model_items; + model_items.push(root_item); QStack elements_to_process; + elements_to_process.push(opml_document.documentElement().elementsByTagName(QSL("body")).at(0).toElement()); while (!elements_to_process.isEmpty()) { @@ -276,7 +278,6 @@ void FeedsImportExportModel::importAsTxtURLPerLine(const QByteArray& data, bool emit layoutChanged(); int completed = 0, succeded = 0, failed = 0; auto* root_item = new StandardServiceRoot(); - QList urls = data.split('\n'); for (const QByteArray& url : urls) { diff --git a/src/librssguard/services/standard/standardfeedsimportexportmodel.h b/src/librssguard/services/standard/standardfeedsimportexportmodel.h index f1e7b2084..a5af0a59c 100644 --- a/src/librssguard/services/standard/standardfeedsimportexportmodel.h +++ b/src/librssguard/services/standard/standardfeedsimportexportmodel.h @@ -9,13 +9,12 @@ class FeedsImportExportModel : public AccountCheckModel { Q_OBJECT public: - enum Mode { + enum class Mode { Import, Export }; - // Constructors and destructors. - explicit FeedsImportExportModel(QObject* parent = 0); + explicit FeedsImportExportModel(QObject* parent = nullptr); virtual ~FeedsImportExportModel(); // Exports to OPML 2.0 diff --git a/src/librssguard/services/standard/standardserviceroot.cpp b/src/librssguard/services/standard/standardserviceroot.cpp index 5352eead9..6fcb45a4c 100644 --- a/src/librssguard/services/standard/standardserviceroot.cpp +++ b/src/librssguard/services/standard/standardserviceroot.cpp @@ -293,14 +293,14 @@ void StandardServiceRoot::addNewCategory() { void StandardServiceRoot::importFeeds() { QScopedPointer form(new FormStandardImportExport(this, qApp->mainFormWidget())); - form.data()->setMode(FeedsImportExportModel::Import); + form.data()->setMode(FeedsImportExportModel::Mode::Import); form.data()->exec(); } void StandardServiceRoot::exportFeeds() { QScopedPointer form(new FormStandardImportExport(this, qApp->mainFormWidget())); - form.data()->setMode(FeedsImportExportModel::Export); + form.data()->setMode(FeedsImportExportModel::Mode::Export); form.data()->exec(); } diff --git a/src/rssguard/main.cpp b/src/rssguard/main.cpp index db85bcb90..e77f8e717 100755 --- a/src/rssguard/main.cpp +++ b/src/rssguard/main.cpp @@ -77,7 +77,7 @@ int main(int argc, char* argv[]) { qApp->loadDynamicShortcuts(); qApp->hideOrShowMainForm(); - qApp->feedReader()->loadSaveMessageFilters(); + qApp->feedReader()->loadSavedMessageFilters(); qApp->feedReader()->feedsModel()->loadActivatedServiceAccounts(); qApp->showTrayIcon(); qApp->offerChanges();