initial fix for #468

This commit is contained in:
Martin Rotter 2023-02-02 14:25:14 +01:00
parent 92c00c0c8a
commit 6baa539480
7 changed files with 173 additions and 97 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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<MessageListFilter, std::function<bool(const Message&)>> m_filters;
QList<MessageListFilter> m_filterKeys;
};
Q_DECLARE_METATYPE(MessagesProxyModel::MessageListFilter)

View File

@ -0,0 +1,5 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "definitions/globals.h"
Globals::Globals() {}

View File

@ -0,0 +1,18 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef GLOBALS_H
#define GLOBALS_H
class Globals {
public:
template <typename T> static bool hasFlag(T lhs, T rhs);
private:
Globals();
};
template <typename T> inline bool Globals::hasFlag(T lhs, T rhs) {
return (int(lhs) & int(rhs)) == int(rhs);
}
#endif // GLOBALS_H

View File

@ -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<QAction*>& 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<MessagesModel::MessageHighlighter>());
}
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<MessagesProxyModel::MessageListFilter>(static_cast<int>(a) | static_cast<int>(b));
}
emit messageFilterChanged(action->data().value<MessagesProxyModel::MessageListFilter>());
void MessagesToolBar::handleMessageFilterChange(QAction* action) {
MessagesProxyModel::MessageListFilter task = action->data().value<MessagesProxyModel::MessageListFilter>();
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<MessagesProxyModel::MessageListFilter>();
}
}
saveToolButtonSelection(FILTER_ACTION_NAME, FROM_STD_LIST(QList<QAction*>, 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<QAction*>& 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<QToolButton*>(widget_action->defaultWidget());
const QStringList menu_action_names = action_name.chopped(1).right(end - start - 1).split(QL1C(';'));
auto tool_btn = qobject_cast<QToolButton*>(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;
}
}
}

View File

@ -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<QAction *> &actions) const;
private:
QWidgetAction* m_actionMessageHighlighter;