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