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