clazy: Convert many old-style connects into function pointer based
[quassel.git] / src / qtui / settingspages / ignorelistmodel.cpp
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 #include "ignorelistmodel.h"
22
23 #include <QDebug>
24 #include <QStringList>
25 #include <QPushButton>
26
27 #include "client.h"
28 #include "signalproxy.h"
29
30 IgnoreListModel::IgnoreListModel(QObject *parent)
31     : QAbstractItemModel(parent)
32 {
33     // we need this signal for future connects to reset the data;
34     connect(Client::instance(), &Client::connected, this, &IgnoreListModel::clientConnected);
35     connect(Client::instance(), &Client::disconnected, this, &IgnoreListModel::clientDisconnected);
36
37     if (Client::isConnected())
38         clientConnected();
39     else
40         emit modelReady(false);
41 }
42
43
44 QVariant IgnoreListModel::data(const QModelIndex &index, int role) const
45 {
46     if (!_modelReady)
47         return QVariant();
48
49     if (!index.isValid() || index.row() >= rowCount() || index.column() >= columnCount())
50         return QVariant();
51
52     switch (role) {
53     case Qt::ToolTipRole:
54         switch (index.column()) {
55         /*
56       case 0: return "<b>Type:</b><br />"
57     "<i><u>BySender:</u></i><br />"
58       "The ignore rule is matched against the <i>nick!ident@host.mask</i> sender-string.<br />"
59     "<i><u>ByMessage:</u></i><br />"
60       "The ignore rule is matched against the message content.";
61       case 1:
62         return "<b>Strictness:</b><br />"
63     "<i><u>Dynamic:</u></i><br />"
64           "Messages are hidden but still get stored in the database.<br />Deactivate or delete an ignore rule to show the messages again<br />"
65     "<i><u>Permanent:</u></i><br />"
66            "Messages are never stored or shown anywhere.";
67     */
68         case 0:
69             return tr("<b>Enable / Disable:</b><br />"
70                       "Only enabled rules are filtered.<br />"
71                       "For dynamic rules, disabling actually shows the filtered messages again");
72         case 2:
73             return tr("<b>Ignore rule:</b><br />"
74                       "Depending on the type of the rule, the text is matched against either:<br /><br />"
75                       "- <u>the message content:</u><br />"
76                       "<i>Example:<i><br />"
77                       "    \"*foobar*\" matches any text containing the word \"foobar\"<br /><br />"
78                       "- <u>the sender string <i>nick!ident@host.name<i></u><br />"
79                       "<i>Example:</i><br />"
80                       "    \"*@foobar.com\" matches any sender from host foobar.com<br />"
81                       "    \"stupid!.+\" (RegEx) matches any sender with nickname \"stupid\" from any host<br />");
82         default:
83             return QVariant();
84         }
85     case Qt::DisplayRole:
86         switch (index.column()) {
87         case 1:
88             if (ignoreListManager()[index.row()].type() == IgnoreListManager::SenderIgnore)
89                 return tr("By Sender");
90             else
91                 return tr("By Message");
92         }
93         // Intentional fallthrough
94     case Qt::EditRole:
95         switch (index.column()) {
96         case 0:
97             return ignoreListManager()[index.row()].isEnabled();
98         case 1:
99             return ignoreListManager()[index.row()].type();
100         case 2:
101             return ignoreListManager()[index.row()].contents();
102         default:
103             return QVariant();
104         }
105     default:
106         return QVariant();
107     }
108 }
109
110
111 bool IgnoreListModel::setData(const QModelIndex &index, const QVariant &value, int role)
112 {
113     if (!_modelReady)
114         return false;
115
116     if (!index.isValid() || index.row() >= rowCount() || index.column() >= columnCount() || role != Qt::EditRole)
117         return false;
118
119     QVariant newValue = value;
120     if (newValue.isNull())
121         return false;
122
123     switch (index.column()) {
124     case 0:
125         cloneIgnoreListManager()[index.row()].setIsEnabled(newValue.toBool());
126         return true;
127     case 1:
128         cloneIgnoreListManager()[index.row()].setType(
129                     (IgnoreListManager::IgnoreType)newValue.toInt());
130         return true;
131     case 2:
132         if (ignoreListManager().contains(newValue.toString())) {
133             return false;
134         }
135         else {
136             cloneIgnoreListManager()[index.row()].setContents(newValue.toString());
137             return true;
138         }
139     default:
140         return false;
141     }
142 }
143
144
145 bool IgnoreListModel::newIgnoreRule(const IgnoreListManager::IgnoreListItem &item)
146 {
147     IgnoreListManager &manager = cloneIgnoreListManager();
148     if (manager.contains(item.contents()))
149         return false;
150     beginInsertRows(QModelIndex(), rowCount(), rowCount());
151     // manager.addIgnoreListItem(item);
152     manager.addIgnoreListItem(item.type(), item.contents(), item.isRegEx(), item.strictness(),
153                               item.scope(), item.scopeRule(), item.isEnabled());
154     endInsertRows();
155     return true;
156 }
157
158
159 void IgnoreListModel::loadDefaults()
160 {
161     /*if(!_modelReady)
162       return;
163
164     IgnoreListManager &manager = cloneIgnoreListManager();
165
166     if(!manager.isEmpty()) {
167       beginRemoveRows(QModelIndex(), 0, rowCount() - 1);
168       for(int i = rowCount() - 1; i >= 0; i--)
169         manager.removeAt(i);
170       endRemoveRows();
171     }
172
173     IgnoreListManager::IgnoreList defaults = IgnoreListModel::defaults();
174     beginInsertRows(QModelIndex(), 0, defaults.count() - 1);
175     foreach(IgnoreListManager::IgnoreListItem item, defaults) {
176       manager.addIgnoreListItem(item.contents(), item.isRegEx(), item.strictness(), item.scope(),
177                                 item.scopeRule());
178     }
179     endInsertRows();*/
180 }
181
182
183 void IgnoreListModel::removeIgnoreRule(int index)
184 {
185     if (index < 0 || index >= rowCount())
186         return;
187
188     IgnoreListManager &manager = cloneIgnoreListManager();
189     beginRemoveRows(QModelIndex(), index, index);
190     manager.removeAt(index);
191     endRemoveRows();
192 }
193
194
195 Qt::ItemFlags IgnoreListModel::flags(const QModelIndex &index) const
196 {
197     if (!index.isValid()) {
198         return Qt::ItemIsDropEnabled;
199     }
200     else {
201         return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
202     }
203 }
204
205
206 QVariant IgnoreListModel::headerData(int section, Qt::Orientation orientation, int role) const
207 {
208     QStringList header;
209     header << tr("Enabled")
210            << tr("Type")
211            << tr("Ignore Rule");
212
213     if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
214         return header[section];
215
216     return QVariant();
217 }
218
219
220 QModelIndex IgnoreListModel::index(int row, int column, const QModelIndex &parent) const
221 {
222     Q_UNUSED(parent);
223     if (row >= rowCount() || column >= columnCount())
224         return {};
225
226     return createIndex(row, column);
227 }
228
229
230 const IgnoreListManager &IgnoreListModel::ignoreListManager() const
231 {
232     if (_configChanged)
233         return _clonedIgnoreListManager;
234     else
235         return *Client::ignoreListManager();
236 }
237
238
239 IgnoreListManager &IgnoreListModel::ignoreListManager()
240 {
241     if (_configChanged)
242         return _clonedIgnoreListManager;
243     else
244         return *Client::ignoreListManager();
245 }
246
247
248 IgnoreListManager &IgnoreListModel::cloneIgnoreListManager()
249 {
250     if (!_configChanged) {
251         _clonedIgnoreListManager = *Client::ignoreListManager();
252         _configChanged = true;
253         emit configChanged(true);
254     }
255     return _clonedIgnoreListManager;
256 }
257
258
259 void IgnoreListModel::revert()
260 {
261     if (!_configChanged)
262         return;
263
264     _configChanged = false;
265     emit configChanged(false);
266     beginResetModel();
267     endResetModel();
268 }
269
270
271 void IgnoreListModel::commit()
272 {
273     if (!_configChanged)
274         return;
275
276     Client::ignoreListManager()->requestUpdate(_clonedIgnoreListManager.toVariantMap());
277     revert();
278 }
279
280
281 void IgnoreListModel::initDone()
282 {
283     _modelReady = true;
284     beginResetModel();
285     endResetModel();
286     emit modelReady(true);
287 }
288
289
290 void IgnoreListModel::clientConnected()
291 {
292     connect(Client::ignoreListManager(), SIGNAL(updated()), SLOT(revert()));
293     if (Client::ignoreListManager()->isInitialized())
294         initDone();
295     else
296         connect(Client::ignoreListManager(), &SyncableObject::initDone, this, &IgnoreListModel::initDone);
297 }
298
299
300 void IgnoreListModel::clientDisconnected()
301 {
302     // clear
303     _clonedIgnoreListManager = ClientIgnoreListManager();
304     _modelReady = false;
305     beginResetModel();
306     endResetModel();
307     emit modelReady(false);
308 }
309
310
311 const IgnoreListManager::IgnoreListItem &IgnoreListModel::ignoreListItemAt(int row) const
312 {
313     return ignoreListManager()[row];
314 }
315
316
317 // FIXME use QModelIndex?
318 void IgnoreListModel::setIgnoreListItemAt(int row, const IgnoreListManager::IgnoreListItem &item)
319 {
320     cloneIgnoreListManager()[row] = item;
321     emit dataChanged(createIndex(row, 0), createIndex(row, 2));
322 }
323
324
325 const QModelIndex IgnoreListModel::indexOf(const QString &rule)
326 {
327     return createIndex(ignoreListManager().indexOf(rule), 2);
328 }