modernize: Use override instead of virtual
[quassel.git] / src / qtui / qtuimessageprocessor.h
1 /***************************************************************************
2  *   Copyright (C) 2005-2018 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 <QTimer>
25
26 #include "abstractmessageprocessor.h"
27 #include "expressionmatch.h"
28 #include "nickhighlightmatcher.h"
29
30 class QtUiMessageProcessor : public AbstractMessageProcessor
31 {
32     Q_OBJECT
33
34 public:
35     enum Mode {
36         TimerBased,
37         Concurrent
38     };
39
40     QtUiMessageProcessor(QObject *parent);
41
42     inline bool isProcessing() const { return _processing; }
43     inline Mode processMode() const { return _processMode; }
44
45     void reset() override;
46
47 public slots:
48     void process(Message &msg) override;
49     void process(QList<Message> &msgs) override;
50
51     /**
52      * Network removed from system
53      *
54      * Handles cleaning up cache from stale networks.
55      *
56      * @param id Network ID of removed network
57      */
58     inline void networkRemoved(NetworkId id) {
59         // Clean up nickname matching cache
60         _nickMatcher.removeNetwork(id);
61     }
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() {}
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,
91                       QString chanName)
92             : _contents(contents), _isRegEx(isRegEx), _isCaseSensitive(isCaseSensitive),
93               _isEnabled(isEnabled), _chanName(chanName)
94         {
95             _cacheInvalid = true;
96             // Cache expression matches on construction
97             //
98             // This provides immediate feedback on errors when loading the rule.  If profiling shows
99             // this as a performance bottleneck, this can be removed in deference to caching on
100             // first use.
101             //
102             // Inversely, if needed for validity checks, caching can be done on every update below
103             // instead of on first use.
104             determineExpressions();
105         }
106
107         /**
108          * Gets the message contents this rule matches
109          *
110          * NOTE: Use HighlightRule::contentsMatcher() for performing matches
111          *
112          * CAUTION: For legacy reasons, "contents" doubles as the identifier for the ignore rule.
113          * Duplicate entries are not allowed.
114          *
115          * @return String representing a phrase or expression to match
116          */
117         inline QString contents() const {
118             return _contents;
119         }
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             _contents = contents;
127             _cacheInvalid = true;
128         }
129
130         /**
131          * Gets if this is a regular expression rule
132          *
133          * @return True if regular expression, otherwise false
134          */
135         inline bool isRegEx() const {
136             return _isRegEx;
137         }
138         /**
139          * Sets if this rule is a regular expression rule
140          *
141          * @param isRegEx True if regular expression, otherwise false
142          */
143         inline void setIsRegEx(bool isRegEx) {
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 {
154             return _isCaseSensitive;
155         }
156         /**
157          * Sets if this rule is case sensitive
158          *
159          * @param isCaseSensitive True if case sensitive, otherwise false
160          */
161         inline void setIsCaseSensitive(bool isCaseSensitive) {
162             _isCaseSensitive = isCaseSensitive;
163             _cacheInvalid = true;
164         }
165
166         /**
167          * Gets if this rule is enabled and active
168          *
169          * @return True if enabled, otherwise false
170          */
171         inline bool isEnabled() const {
172             return _isEnabled;
173         }
174         /**
175          * Sets if this rule is enabled and active
176          *
177          * @param isEnabled True if enabled, otherwise false
178          */
179         inline void setIsEnabled(bool isEnabled) {
180             _isEnabled = isEnabled;
181         }
182
183         /**
184          * Gets the channel name this rule matches
185          *
186          * NOTE: Use HighlightRule::chanNameMatcher() for performing matches
187          *
188          * @return String representing a phrase or expression to match
189          */
190         inline QString chanName() const {
191             return _chanName;
192         }
193         /**
194          * Sets the channel name this rule matches
195          *
196          * @param chanName String representing a phrase or expression to match
197          */
198         inline void setChanName(const QString &chanName) {
199             _chanName = chanName;
200             _cacheInvalid = true;
201         }
202
203         /**
204          * Gets the expression matcher for the message contents, caching if needed
205          *
206          * @return Expression matcher to compare with message contents
207          */
208         inline ExpressionMatch contentsMatcher() const {
209             if (_cacheInvalid) {
210                 determineExpressions();
211             }
212             return _contentsMatch;
213         }
214
215         /**
216          * Gets the expression matcher for the channel name, caching if needed
217          *
218          * @return Expression matcher to compare with channel name
219          */
220         inline ExpressionMatch chanNameMatcher() const {
221             if (_cacheInvalid) {
222                 determineExpressions();
223             }
224             return _chanNameMatch;
225         }
226
227         bool operator!=(const LegacyHighlightRule &other) const;
228
229     private:
230         /**
231          * Update internal cache of expression matching if needed
232          */
233         void determineExpressions() const;
234
235         QString _contents = {};
236         bool _isRegEx = false;
237         bool _isCaseSensitive = false;
238         bool _isEnabled = true;
239         QString _chanName = {};
240
241         // These represent internal cache and should be safe to mutate in 'const' functions
242         // See https://stackoverflow.com/questions/3141087/what-is-meant-with-const-at-end-of-function-declaration
243         mutable bool _cacheInvalid = true;           ///< If true, match cache needs redone
244         mutable ExpressionMatch _contentsMatch = {}; ///< Expression match cache for message content
245         mutable ExpressionMatch _chanNameMatch = {}; ///< Expression match cache for channel name
246     };
247
248     using LegacyHighlightRuleList = QList<LegacyHighlightRule>;
249
250     void checkForHighlight(Message &msg);
251     void startProcessing();
252
253     using HighlightNickType = NotificationSettings::HighlightNickType;
254
255     LegacyHighlightRuleList _highlightRuleList; ///< Custom highlight rule list
256     NickHighlightMatcher _nickMatcher = {};     ///< Nickname highlight matcher
257
258     /// Nickname highlighting mode
259     HighlightNickType _highlightNick = HighlightNickType::CurrentNick;
260     bool _nicksCaseSensitive = false; ///< If true, match nicknames with exact case
261
262     QList<QList<Message> > _processQueue;
263     QList<Message> _currentBatch;
264     QTimer _processTimer;
265     bool _processing;
266     Mode _processMode;
267 };
268
269
270 #endif