cmake: avoid de-duplication of user's CXXFLAGS
[quassel.git] / src / qtui / qtuimessageprocessor.h
1 /***************************************************************************
2  *   Copyright (C) 2005-2020 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #ifndef QTUIMESSAGEPROCESSOR_H_
22 #define QTUIMESSAGEPROCESSOR_H_
23
24 #include <utility>
25
26 #include <QTimer>
27
28 #include "abstractmessageprocessor.h"
29 #include "expressionmatch.h"
30 #include "nickhighlightmatcher.h"
31
32 class QtUiMessageProcessor : public AbstractMessageProcessor
33 {
34     Q_OBJECT
35
36 public:
37     enum Mode
38     {
39         TimerBased,
40         Concurrent
41     };
42
43     QtUiMessageProcessor(QObject* parent);
44
45     inline bool isProcessing() const { return _processing; }
46     inline Mode processMode() const { return _processMode; }
47
48     void reset() override;
49
50 public slots:
51     void process(Message& msg) override;
52     void process(QList<Message>& msgs) override;
53
54     /**
55      * Network removed from system
56      *
57      * Handles cleaning up cache from stale networks.
58      *
59      * @param id Network ID of removed network
60      */
61     void networkRemoved(NetworkId id) override;
62
63 private slots:
64     void processNextMessage();
65     void nicksCaseSensitiveChanged(const QVariant& variant);
66     void highlightListChanged(const QVariant& variant);
67     void highlightNickChanged(const QVariant& variant);
68
69 private:
70     /**
71      * Individual highlight rule (legacy client-side version)
72      */
73     class LegacyHighlightRule
74     {
75     public:
76         /**
77          * Construct an empty highlight rule
78          */
79         LegacyHighlightRule() = default;
80
81         /**
82          * Construct a highlight rule with the given parameters
83          *
84          * @param contents         String representing a message contents expression to match
85          * @param isRegEx          True if regular expression, otherwise false
86          * @param isCaseSensitive  True if case sensitive, otherwise false
87          * @param isEnabled        True if enabled, otherwise false
88          * @param chanName         String representing a channel name expression to match
89          */
90         LegacyHighlightRule(QString contents, bool isRegEx, bool isCaseSensitive, bool isEnabled, QString chanName)
91             : _contents(std::move(contents))
92             , _isRegEx(isRegEx)
93             , _isCaseSensitive(isCaseSensitive)
94             , _isEnabled(isEnabled)
95             , _chanName(std::move(chanName))
96         {
97             _cacheInvalid = true;
98             // Cache expression matches on construction
99             //
100             // This provides immediate feedback on errors when loading the rule.  If profiling shows
101             // this as a performance bottleneck, this can be removed in deference to caching on
102             // first use.
103             //
104             // Inversely, if needed for validity checks, caching can be done on every update below
105             // instead of on first use.
106             determineExpressions();
107         }
108
109         /**
110          * Gets the message contents this rule matches
111          *
112          * NOTE: Use HighlightRule::contentsMatcher() for performing matches
113          *
114          * CAUTION: For legacy reasons, "contents" doubles as the identifier for the ignore rule.
115          * Duplicate entries are not allowed.
116          *
117          * @return String representing a phrase or expression to match
118          */
119         inline QString contents() const { return _contents; }
120         /**
121          * Sets the message contents this rule matches
122          *
123          * @param contents String representing a phrase or expression to match
124          */
125         inline void setContents(const QString& contents)
126         {
127             _contents = contents;
128             _cacheInvalid = true;
129         }
130
131         /**
132          * Gets if this is a regular expression rule
133          *
134          * @return True if regular expression, otherwise false
135          */
136         inline bool isRegEx() const { return _isRegEx; }
137         /**
138          * Sets if this rule is a regular expression rule
139          *
140          * @param isRegEx True if regular expression, otherwise false
141          */
142         inline void setIsRegEx(bool isRegEx)
143         {
144             _isRegEx = isRegEx;
145             _cacheInvalid = true;
146         }
147
148         /**
149          * Gets if this rule is case sensitive
150          *
151          * @return True if case sensitive, otherwise false
152          */
153         inline bool isCaseSensitive() const { return _isCaseSensitive; }
154         /**
155          * Sets if this rule is case sensitive
156          *
157          * @param isCaseSensitive True if case sensitive, otherwise false
158          */
159         inline void setIsCaseSensitive(bool isCaseSensitive)
160         {
161             _isCaseSensitive = isCaseSensitive;
162             _cacheInvalid = true;
163         }
164
165         /**
166          * Gets if this rule is enabled and active
167          *
168          * @return True if enabled, otherwise false
169          */
170         inline bool isEnabled() const { return _isEnabled; }
171         /**
172          * Sets if this rule is enabled and active
173          *
174          * @param isEnabled True if enabled, otherwise false
175          */
176         inline void setIsEnabled(bool isEnabled) { _isEnabled = isEnabled; }
177
178         /**
179          * Gets the channel name this rule matches
180          *
181          * NOTE: Use HighlightRule::chanNameMatcher() for performing matches
182          *
183          * @return String representing a phrase or expression to match
184          */
185         inline QString chanName() const { return _chanName; }
186         /**
187          * Sets the channel name this rule matches
188          *
189          * @param chanName String representing a phrase or expression to match
190          */
191         inline void setChanName(const QString& chanName)
192         {
193             _chanName = chanName;
194             _cacheInvalid = true;
195         }
196
197         /**
198          * Gets the expression matcher for the message contents, caching if needed
199          *
200          * @return Expression matcher to compare with message contents
201          */
202         inline ExpressionMatch contentsMatcher() const
203         {
204             if (_cacheInvalid) {
205                 determineExpressions();
206             }
207             return _contentsMatch;
208         }
209
210         /**
211          * Gets the expression matcher for the channel name, caching if needed
212          *
213          * @return Expression matcher to compare with channel name
214          */
215         inline ExpressionMatch chanNameMatcher() const
216         {
217             if (_cacheInvalid) {
218                 determineExpressions();
219             }
220             return _chanNameMatch;
221         }
222
223         bool operator!=(const LegacyHighlightRule& other) const;
224
225     private:
226         /**
227          * Update internal cache of expression matching if needed
228          */
229         void determineExpressions() const;
230
231         QString _contents = {};
232         bool _isRegEx = false;
233         bool _isCaseSensitive = false;
234         bool _isEnabled = true;
235         QString _chanName = {};
236
237         // These represent internal cache and should be safe to mutate in 'const' functions
238         // See https://stackoverflow.com/questions/3141087/what-is-meant-with-const-at-end-of-function-declaration
239         mutable bool _cacheInvalid = true;            ///< If true, match cache needs redone
240         mutable ExpressionMatch _contentsMatch = {};  ///< Expression match cache for message content
241         mutable ExpressionMatch _chanNameMatch = {};  ///< Expression match cache for channel name
242     };
243
244     using LegacyHighlightRuleList = QList<LegacyHighlightRule>;
245
246     void checkForHighlight(Message& msg);
247     void startProcessing();
248
249     using HighlightNickType = NotificationSettings::HighlightNickType;
250
251     LegacyHighlightRuleList _highlightRuleList;  ///< Custom highlight rule list
252     NickHighlightMatcher _nickMatcher = {};      ///< Nickname highlight matcher
253
254     /// Nickname highlighting mode
255     HighlightNickType _highlightNick = HighlightNickType::CurrentNick;
256     bool _nicksCaseSensitive = false;  ///< If true, match nicknames with exact case
257
258     QList<QList<Message>> _processQueue;
259     QList<Message> _currentBatch;
260     QTimer _processTimer;
261     bool _processing;
262     Mode _processMode;
263 };
264
265 #endif