diff --git a/src/librssguard/CMakeLists.txt b/src/librssguard/CMakeLists.txt index fa5cce10e..e579601cf 100644 --- a/src/librssguard/CMakeLists.txt +++ b/src/librssguard/CMakeLists.txt @@ -37,6 +37,8 @@ set(SOURCES database/sqlitedriver.h definitions/definitions.h definitions/typedefs.h + definitions/globals.cpp + definitions/globals.h dynamic-shortcuts/dynamicshortcuts.cpp dynamic-shortcuts/dynamicshortcuts.h dynamic-shortcuts/dynamicshortcutswidget.cpp diff --git a/src/librssguard/core/messagesproxymodel.cpp b/src/librssguard/core/messagesproxymodel.cpp index 4156b0495..bf1713049 100644 --- a/src/librssguard/core/messagesproxymodel.cpp +++ b/src/librssguard/core/messagesproxymodel.cpp @@ -4,6 +4,7 @@ #include "core/messagesmodel.h" #include "core/messagesmodelcache.h" +#include "definitions/globals.h" #include "miscellaneous/application.h" #include "miscellaneous/regexfactory.h" #include "miscellaneous/settings.h" @@ -14,6 +15,8 @@ MessagesProxyModel::MessagesProxyModel(MessagesModel* source_model, QObject* par : QSortFilterProxyModel(parent), m_sourceModel(source_model), m_filter(MessageListFilter::NoFiltering) { setObjectName(QSL("MessagesProxyModel")); + initializeFilters(); + setSortRole(Qt::ItemDataRole::EditRole); setSortCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive); @@ -28,6 +31,82 @@ MessagesProxyModel::~MessagesProxyModel() { qDebugNN << LOGSEC_MESSAGEMODEL << "Destroying MessagesProxyModel instance."; } +void MessagesProxyModel::initializeFilters() { + m_filters[MessageListFilter::ShowUnread] = [](const Message& msg) { + return !msg.m_isRead; + }; + + m_filters[MessageListFilter::ShowImportant] = [](const Message& msg) { + return msg.m_isImportant; + }; + + m_filters[MessageListFilter::ShowToday] = [](const Message& msg) { + const QDateTime current_dt = QDateTime::currentDateTime(); + const QDate current_d = current_dt.date(); + + return current_d.startOfDay() <= msg.m_created && msg.m_created <= current_d.endOfDay(); + }; + + m_filters[MessageListFilter::ShowYesterday] = [](const Message& msg) { + const QDateTime current_dt = QDateTime::currentDateTime(); + const QDate current_d = current_dt.date(); + + return current_d.addDays(-1).startOfDay() <= msg.m_created && msg.m_created <= current_d.addDays(-1).endOfDay(); + }; + + m_filters[MessageListFilter::ShowLast24Hours] = [](const Message& msg) { + const QDateTime current_dt = QDateTime::currentDateTime(); + + return current_dt.addSecs(-24 * 60 * 60) <= msg.m_created && msg.m_created <= current_dt; + }; + + m_filters[MessageListFilter::ShowLast48Hours] = [](const Message& msg) { + const QDateTime current_dt = QDateTime::currentDateTime(); + + return current_dt.addSecs(-48 * 60 * 60) <= msg.m_created && msg.m_created <= current_dt; + }; + + m_filters[MessageListFilter::ShowThisWeek] = [](const Message& msg) { + const QDateTime current_dt = QDateTime::currentDateTime(); + const QDate current_d = current_dt.date(); + + return current_d.year() == msg.m_created.date().year() && + current_d.weekNumber() == msg.m_created.date().weekNumber(); + }; + + m_filters[MessageListFilter::ShowLastWeek] = [](const Message& msg) { + const QDateTime current_dt = QDateTime::currentDateTime(); + const QDate current_d = current_dt.date(); + + return current_d.addDays(-7).year() == msg.m_created.date().year() && + current_d.addDays(-7).weekNumber() == msg.m_created.date().weekNumber(); + }; + + m_filters[MessageListFilter::ShowOnlyWithAttachments] = [](const Message& msg) { + return msg.m_enclosures.size() > 0; + }; + + m_filters[MessageListFilter::ShowOnlyWithScore] = [](const Message& msg) { + return msg.m_score > MSG_SCORE_MIN; + }; + + m_filterKeys = m_filters.keys(); +} + +bool MessagesProxyModel::filterAcceptsMessage(const Message& msg) const { + if (m_filter == MessageListFilter::NoFiltering) { + return true; + } + + for (MessageListFilter val : m_filterKeys) { + if (Globals::hasFlag(m_filter, val) && m_filters[val](msg)) { + return true; + } + } + + return false; +} + QModelIndex MessagesProxyModel::getNextPreviousImportantItemIndex(int default_row) { const bool started_from_zero = default_row == 0; QModelIndex next_index = getNextImportantItemIndex(default_row, rowCount() - 1); @@ -95,76 +174,7 @@ bool MessagesProxyModel::lessThan(const QModelIndex& left, const QModelIndex& ri Q_UNUSED(left) Q_UNUSED(right) - // NOTE: Comparisons are done by SQL servers itself, not client-side. - return false; -} - -bool MessagesProxyModel::filterAcceptsMessage(const Message& current_message) const { - switch (m_filter) { - case MessageListFilter::NoFiltering: - return true; - - case MessageListFilter::ShowUnread: - return !current_message.m_isRead; - - case MessageListFilter::ShowImportant: - return current_message.m_isImportant; - - case MessageListFilter::ShowToday: { - const QDateTime currentDateTime = QDateTime::currentDateTime(); - const QDate currentDate = currentDateTime.date(); - - return currentDate.startOfDay() <= current_message.m_created && - current_message.m_created <= currentDate.endOfDay(); - } - - case MessageListFilter::ShowYesterday: { - const QDateTime currentDateTime = QDateTime::currentDateTime(); - const QDate currentDate = currentDateTime.date(); - - return currentDate.addDays(-1).startOfDay() <= current_message.m_created && - current_message.m_created <= currentDate.addDays(-1).endOfDay(); - } - - case MessageListFilter::ShowLast24Hours: { - const QDateTime currentDateTime = QDateTime::currentDateTime(); - - return currentDateTime.addSecs(-24 * 60 * 60) <= current_message.m_created && - current_message.m_created <= currentDateTime; - } - - case MessageListFilter::ShowLast48Hours: { - const QDateTime currentDateTime = QDateTime::currentDateTime(); - - return currentDateTime.addSecs(-48 * 60 * 60) <= current_message.m_created && - current_message.m_created <= currentDateTime; - } - - case MessageListFilter::ShowThisWeek: { - const QDateTime currentDateTime = QDateTime::currentDateTime(); - const QDate currentDate = currentDateTime.date(); - - return currentDate.year() == current_message.m_created.date().year() && - currentDate.weekNumber() == current_message.m_created.date().weekNumber(); - } - - case MessageListFilter::ShowLastWeek: { - const QDateTime currentDateTime = QDateTime::currentDateTime(); - const QDate currentDate = currentDateTime.date(); - - return currentDate.addDays(-7).year() == current_message.m_created.date().year() && - currentDate.addDays(-7).weekNumber() == current_message.m_created.date().weekNumber(); - } - - case MessageListFilter::ShowOnlyWithAttachments: { - return current_message.m_enclosures.size() > 0; - } - - case MessageListFilter::ShowOnlyWithScore: { - return current_message.m_score > MSG_SCORE_MIN; - } - } - + // NOTE: Comparisons are done by SQL server itself, not client-side. return false; } diff --git a/src/librssguard/core/messagesproxymodel.h b/src/librssguard/core/messagesproxymodel.h index 02efc1a32..27ec55104 100644 --- a/src/librssguard/core/messagesproxymodel.h +++ b/src/librssguard/core/messagesproxymodel.h @@ -15,17 +15,17 @@ class MessagesProxyModel : public QSortFilterProxyModel { // Enum which describes basic filtering schemes // for messages. enum class MessageListFilter { - NoFiltering = 100, - ShowUnread = 101, - ShowImportant = 102, - ShowToday = 103, - ShowYesterday = 104, - ShowLast24Hours = 105, - ShowLast48Hours = 106, - ShowThisWeek = 107, - ShowLastWeek = 108, - ShowOnlyWithAttachments = 109, - ShowOnlyWithScore = 110 + NoFiltering = 1, + ShowUnread = 2, + ShowImportant = 4, + ShowToday = 8, + ShowYesterday = 16, + ShowLast24Hours = 32, + ShowLast48Hours = 64, + ShowThisWeek = 128, + ShowLastWeek = 256, + ShowOnlyWithAttachments = 512, + ShowOnlyWithScore = 1024 }; explicit MessagesProxyModel(MessagesModel* source_model, QObject* parent = nullptr); @@ -51,10 +51,12 @@ class MessagesProxyModel : public QSortFilterProxyModel { virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); private: + void initializeFilters(); + QModelIndex getNextImportantItemIndex(int default_row, int max_row) const; QModelIndex getNextUnreadItemIndex(int default_row, int max_row) const; - bool filterAcceptsMessage(const Message& current_message) const; + bool filterAcceptsMessage(const Message& msg) const; virtual bool lessThan(const QModelIndex& left, const QModelIndex& right) const; virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const; @@ -62,6 +64,8 @@ class MessagesProxyModel : public QSortFilterProxyModel { // Source model pointer. MessagesModel* m_sourceModel; MessageListFilter m_filter; + QMap> m_filters; + QList m_filterKeys; }; Q_DECLARE_METATYPE(MessagesProxyModel::MessageListFilter) diff --git a/src/librssguard/definitions/globals.cpp b/src/librssguard/definitions/globals.cpp new file mode 100755 index 000000000..df8e36e2e --- /dev/null +++ b/src/librssguard/definitions/globals.cpp @@ -0,0 +1,5 @@ +// For license of this file, see /LICENSE.md. + +#include "definitions/globals.h" + +Globals::Globals() {} diff --git a/src/librssguard/definitions/globals.h b/src/librssguard/definitions/globals.h new file mode 100755 index 000000000..21202370d --- /dev/null +++ b/src/librssguard/definitions/globals.h @@ -0,0 +1,18 @@ +// For license of this file, see /LICENSE.md. + +#ifndef GLOBALS_H +#define GLOBALS_H + +class Globals { + public: + template static bool hasFlag(T lhs, T rhs); + + private: + Globals(); +}; + +template inline bool Globals::hasFlag(T lhs, T rhs) { + return (int(lhs) & int(rhs)) == int(rhs); +} + +#endif // GLOBALS_H diff --git a/src/librssguard/gui/toolbars/messagestoolbar.cpp b/src/librssguard/gui/toolbars/messagestoolbar.cpp index c73f53249..4f6287b66 100644 --- a/src/librssguard/gui/toolbars/messagestoolbar.cpp +++ b/src/librssguard/gui/toolbars/messagestoolbar.cpp @@ -2,6 +2,7 @@ #include "gui/toolbars/messagestoolbar.h" +#include "3rd-party/boolinq/boolinq.h" #include "definitions/definitions.h" #include "gui/reusable/baselineedit.h" #include "miscellaneous/iconfactory.h" @@ -107,16 +108,46 @@ void MessagesToolBar::loadSpecificActions(const QList& actions, bool i void MessagesToolBar::handleMessageHighlighterChange(QAction* action) { m_btnMessageHighlighter->setDefaultAction(action); - saveToolButtonSelection(HIGHLIGHTER_ACTION_NAME, action); + saveToolButtonSelection(HIGHLIGHTER_ACTION_NAME, {action}); emit messageHighlighterChanged(action->data().value()); } -void MessagesToolBar::handleMessageFilterChange(QAction* action) { - m_btnMessageFilter->setDefaultAction(action); - saveToolButtonSelection(FILTER_ACTION_NAME, action); +inline MessagesProxyModel::MessageListFilter operator|(MessagesProxyModel::MessageListFilter a, + MessagesProxyModel::MessageListFilter b) { + return static_cast(static_cast(a) | static_cast(b)); +} - emit messageFilterChanged(action->data().value()); +void MessagesToolBar::handleMessageFilterChange(QAction* action) { + MessagesProxyModel::MessageListFilter task = action->data().value(); + + m_btnMessageFilter->setDefaultAction(action); + + auto checked_tasks_std = boolinq::from(m_menuMessageFilter->actions()) + .where([](QAction* act) { + return act->isChecked(); + }) + .toStdList(); + + if (task == MessagesProxyModel::MessageListFilter::NoFiltering) { + // Uncheck everything. + m_menuMessageFilter->blockSignals(true); + + for (QAction* tsk : checked_tasks_std) { + tsk->setChecked(false); + } + + m_menuMessageFilter->blockSignals(false); + } + else { + for (QAction* tsk : checked_tasks_std) { + task = task | tsk->data().value(); + } + } + + saveToolButtonSelection(FILTER_ACTION_NAME, FROM_STD_LIST(QList, checked_tasks_std)); + + emit messageFilterChanged(task); } void MessagesToolBar::initializeSearchBox() { @@ -148,6 +179,7 @@ void MessagesToolBar::addActionToMenu(QMenu* menu, const QString& name) { QAction* action = menu->addAction(icon, title); + action->setCheckable(true); action->setData(value); action->setObjectName(name); } @@ -254,13 +286,19 @@ void MessagesToolBar::initializeHighlighter() { connect(m_menuMessageFilter, &QMenu::triggered, this, &MessagesToolBar::handleMessageFilterChange); } -void MessagesToolBar::saveToolButtonSelection(const QString& button_name, const QAction* action) const { +void MessagesToolBar::saveToolButtonSelection(const QString& button_name, const QList& actions) const { QStringList action_names = savedActions(); + auto opts_list = boolinq::from(actions) + .select([](const QAction* act) { + return act->objectName(); + }) + .toStdList(); + QStringList opts = FROM_STD_LIST(QStringList, opts_list); + for (QString& action_name : action_names) { if (action_name.startsWith(button_name)) { - action_name = - button_name + (action->objectName().isEmpty() ? "" : "[" + action->objectName().toStdString() + "]").c_str(); + action_name = button_name + QSL("[%1]").arg(opts.join(QL1C(';'))); } } @@ -272,14 +310,13 @@ void MessagesToolBar::activateAction(const QString& action_name, QWidgetAction* const int end = action_name.indexOf(']'); if (start != -1 && end != -1 && end == action_name.length() - 1) { - const QString menu_action_name = action_name.chopped(1).right(end - start - 1); - auto toolButton = qobject_cast(widget_action->defaultWidget()); + const QStringList menu_action_names = action_name.chopped(1).right(end - start - 1).split(QL1C(';')); + auto tool_btn = qobject_cast(widget_action->defaultWidget()); - for (QAction* action : toolButton->menu()->actions()) { - if (action->objectName() == menu_action_name) { - toolButton->setDefaultAction(action); + for (QAction* action : tool_btn->menu()->actions()) { + if (menu_action_names.contains(action->objectName())) { + // tool_btn->setDefaultAction(action); action->trigger(); - break; } } } diff --git a/src/librssguard/gui/toolbars/messagestoolbar.h b/src/librssguard/gui/toolbars/messagestoolbar.h index 22f872ace..5b8c17e9c 100644 --- a/src/librssguard/gui/toolbars/messagestoolbar.h +++ b/src/librssguard/gui/toolbars/messagestoolbar.h @@ -43,7 +43,7 @@ class MessagesToolBar : public BaseToolBar { void addActionToMenu(QMenu* menu, const QIcon& icon, const QString& title, const QVariant& value, const QString& name); void initializeHighlighter(); void activateAction(const QString& action_name, QWidgetAction* widget_action); - void saveToolButtonSelection(const QString& button_name, const QAction* action) const; + void saveToolButtonSelection(const QString& button_name, const QList &actions) const; private: QWidgetAction* m_actionMessageHighlighter;