1 // For license of this file, see <project-root-folder>/LICENSE.md.
2 
3 #include "gui/toolbars/messagestoolbar.h"
4 
5 #include "definitions/definitions.h"
6 #include "gui/reusable/baselineedit.h"
7 #include "miscellaneous/iconfactory.h"
8 #include "miscellaneous/settings.h"
9 
10 #include <chrono>
11 #include <QMenu>
12 #include <QTimer>
13 #include <QToolButton>
14 #include <QWidgetAction>
15 
16 using namespace std::chrono_literals;
17 
MessagesToolBar(const QString & title,QWidget * parent)18 MessagesToolBar::MessagesToolBar(const QString& title, QWidget* parent) : BaseToolBar(title, parent) {
19   initializeSearchBox();
20   initializeHighlighter();
21 }
22 
availableActions() const23 QList<QAction*> MessagesToolBar::availableActions() const {
24   QList<QAction*> available_actions = qApp->userActions();
25 
26   available_actions.append(m_actionSearchMessages);
27   available_actions.append(m_actionMessageHighlighter);
28 
29   return available_actions;
30 }
31 
activatedActions() const32 QList<QAction*> MessagesToolBar::activatedActions() const {
33   return actions();
34 }
35 
saveAndSetActions(const QStringList & actions)36 void MessagesToolBar::saveAndSetActions(const QStringList& actions) {
37   qApp->settings()->setValue(GROUP(GUI), GUI::MessagesToolbarDefaultButtons, actions.join(QSL(",")));
38   loadSpecificActions(convertActions(actions));
39 
40   // If user hidden search messages box, then remove the filter.
41   if (!activatedActions().contains(m_actionSearchMessages)) {
42     m_txtSearchMessages->clear();
43   }
44 }
45 
convertActions(const QStringList & actions)46 QList<QAction*> MessagesToolBar::convertActions(const QStringList& actions) {
47   QList<QAction*> available_actions = availableActions();
48   QList<QAction*> spec_actions;
49 
50   // Iterate action names and add respectable actions into the toolbar.
51   for (const QString& action_name : actions) {
52     auto* matching_action = findMatchingAction(action_name, available_actions);
53 
54     if (matching_action != nullptr) {
55       // Add existing standard action.
56       spec_actions.append(matching_action);
57     }
58     else if (action_name == QSL(SEPARATOR_ACTION_NAME)) {
59       // Add new separator.
60       auto* act = new QAction(this);
61 
62       act->setSeparator(true);
63       spec_actions.append(act);
64     }
65     else if (action_name == QSL(SEARCH_BOX_ACTION_NAME)) {
66       // Add search box.
67       spec_actions.append(m_actionSearchMessages);
68     }
69     else if (action_name == QSL(HIGHLIGHTER_ACTION_NAME)) {
70       // Add filter button.
71       spec_actions.append(m_actionMessageHighlighter);
72     }
73     else if (action_name == QSL(SPACER_ACTION_NAME)) {
74       // Add new spacer.
75       auto* spacer = new QWidget(this);
76 
77       spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
78       auto* action = new QWidgetAction(this);
79 
80       action->setDefaultWidget(spacer);
81       action->setIcon(qApp->icons()->fromTheme(QSL("go-jump")));
82       action->setProperty("type", SPACER_ACTION_NAME);
83       action->setProperty("name", tr("Toolbar spacer"));
84       spec_actions.append(action);
85     }
86   }
87 
88   return spec_actions;
89 }
90 
loadSpecificActions(const QList<QAction * > & actions,bool initial_load)91 void MessagesToolBar::loadSpecificActions(const QList<QAction*>& actions, bool initial_load) {
92   Q_UNUSED(initial_load)
93 
94   clear();
95 
96   for (QAction* act : actions) {
97     addAction(act);
98   }
99 }
100 
handleMessageHighlighterChange(QAction * action)101 void MessagesToolBar::handleMessageHighlighterChange(QAction* action) {
102   m_btnMessageHighlighter->setIcon(action->icon());
103   m_btnMessageHighlighter->setToolTip(action->text());
104   emit messageFilterChanged(action->data().value<MessagesModel::MessageHighlighter>());
105 }
106 
initializeSearchBox()107 void MessagesToolBar::initializeSearchBox() {
108   m_tmrSearchPattern = new QTimer(this);
109   m_tmrSearchPattern->setSingleShot(true);
110 
111   m_txtSearchMessages = new BaseLineEdit(this);
112   m_txtSearchMessages->setSizePolicy(QSizePolicy::Policy::Expanding, m_txtSearchMessages->sizePolicy().verticalPolicy());
113   m_txtSearchMessages->setPlaceholderText(tr("Search articles"));
114 
115   // Setup wrapping action for search box.
116   m_actionSearchMessages = new QWidgetAction(this);
117   m_actionSearchMessages->setDefaultWidget(m_txtSearchMessages);
118   m_actionSearchMessages->setIcon(qApp->icons()->fromTheme(QSL("system-search")));
119   m_actionSearchMessages->setProperty("type", SEARCH_BOX_ACTION_NAME);
120   m_actionSearchMessages->setProperty("name", tr("Article search box"));
121 
122   connect(m_txtSearchMessages, &BaseLineEdit::textChanged, this, &MessagesToolBar::onSearchPatternChanged);
123   connect(m_tmrSearchPattern, &QTimer::timeout, this, [this]() {
124     emit messageSearchPatternChanged(m_searchPattern);
125   });
126 }
127 
initializeHighlighter()128 void MessagesToolBar::initializeHighlighter() {
129   m_menuMessageHighlighter = new QMenu(tr("Menu for highlighting articles"), this);
130   m_menuMessageHighlighter->addAction(qApp->icons()->fromTheme(QSL("mail-mark-read")),
131                                       tr("No extra highlighting"))->setData(QVariant::fromValue(MessagesModel::MessageHighlighter::NoHighlighting));
132   m_menuMessageHighlighter->addAction(qApp->icons()->fromTheme(QSL("mail-mark-unread")),
133                                       tr("Highlight unread articles"))->setData(QVariant::fromValue(MessagesModel::MessageHighlighter::HighlightUnread));
134   m_menuMessageHighlighter->addAction(qApp->icons()->fromTheme(QSL("mail-mark-important")),
135                                       tr("Highlight important articles"))->setData(QVariant::fromValue(MessagesModel::MessageHighlighter::HighlightImportant));
136   m_btnMessageHighlighter = new QToolButton(this);
137   m_btnMessageHighlighter->setToolTip(tr("Display all articles"));
138   m_btnMessageHighlighter->setMenu(m_menuMessageHighlighter);
139   m_btnMessageHighlighter->setPopupMode(QToolButton::ToolButtonPopupMode::MenuButtonPopup);
140   m_btnMessageHighlighter->setIcon(qApp->icons()->fromTheme(QSL("mail-mark-read")));
141   m_actionMessageHighlighter = new QWidgetAction(this);
142   m_actionMessageHighlighter->setDefaultWidget(m_btnMessageHighlighter);
143   m_actionMessageHighlighter->setIcon(m_btnMessageHighlighter->icon());
144   m_actionMessageHighlighter->setProperty("type", HIGHLIGHTER_ACTION_NAME);
145   m_actionMessageHighlighter->setProperty("name", tr("Article highlighter"));
146 
147   connect(m_menuMessageHighlighter, &QMenu::triggered, this, &MessagesToolBar::handleMessageHighlighterChange);
148 }
149 
defaultActions() const150 QStringList MessagesToolBar::defaultActions() const {
151   return QString(GUI::MessagesToolbarDefaultButtonsDef).split(QL1C(','),
152 #if QT_VERSION >= 0x050F00 // Qt >= 5.15.0
153                                                               Qt::SplitBehaviorFlags::SkipEmptyParts);
154 #else
155                                                               QString::SplitBehavior::SkipEmptyParts);
156 #endif
157 }
158 
savedActions() const159 QStringList MessagesToolBar::savedActions() const {
160   return qApp->settings()->value(GROUP(GUI),
161                                  SETTING(GUI::MessagesToolbarDefaultButtons)).toString().split(QL1C(','),
162 #if QT_VERSION >= 0x050F00 // Qt >= 5.15.0
163                                                                                                Qt::SplitBehaviorFlags::SkipEmptyParts);
164 #else
165                                                                                                QString::SplitBehavior::SkipEmptyParts);
166 #endif
167 }
168 
onSearchPatternChanged(const QString & search_pattern)169 void MessagesToolBar::onSearchPatternChanged(const QString& search_pattern) {
170   m_searchPattern = search_pattern;
171   m_tmrSearchPattern->start(search_pattern.isEmpty() ? 0ms : 300ms);
172 }
173