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