replace SPDX identifier GPL-2.0+ with GPL-2.0-or-later.
[metze/wireshark/wip.git] / ui / qt / models / enabled_protocols_model.cpp
1 /* enabled_protocols_model.cpp
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  */
9
10 #include <QSortFilterProxyModel>
11
12 #include <ui/qt/models/enabled_protocols_model.h>
13 #include <epan/packet.h>
14 #include <epan/disabled_protos.h>
15
16 #include <ui/qt/utils/variant_pointer.h>
17 #include "wireshark_application.h"
18
19 class ProtocolTreeItem : public EnabledProtocolItem
20 {
21 public:
22     ProtocolTreeItem(protocol_t* proto, EnabledProtocolItem* parent)
23         : EnabledProtocolItem(proto_get_protocol_short_name(proto), proto_get_protocol_long_name(proto), proto_is_protocol_enabled(proto), parent),
24         proto_(proto)
25     {
26
27     }
28
29     virtual ~ProtocolTreeItem() {}
30
31 protected:
32     virtual void applyValuePrivate(gboolean value)
33     {
34         proto_set_decoding(proto_get_id(proto_), value);
35     }
36
37 private:
38     protocol_t* proto_;
39 };
40
41 class HeuristicTreeItem : public EnabledProtocolItem
42 {
43 public:
44     HeuristicTreeItem(heur_dtbl_entry_t *heuristic, EnabledProtocolItem* parent)
45         : EnabledProtocolItem(heuristic->short_name, heuristic->display_name, heuristic->enabled, parent),
46         heuristic_(heuristic)
47     {
48     }
49
50     virtual ~HeuristicTreeItem() {}
51
52 protected:
53     virtual void applyValuePrivate(gboolean value)
54     {
55         heuristic_->enabled = value;
56     }
57
58 private:
59     heur_dtbl_entry_t *heuristic_;
60 };
61
62
63 EnabledProtocolItem::EnabledProtocolItem(QString name, QString description, bool enabled, EnabledProtocolItem* parent) :
64     ModelHelperTreeItem<EnabledProtocolItem>(parent),
65     name_(name),
66     description_(description),
67     enabled_(enabled),
68     enabledInit_(enabled)
69 {
70 }
71
72 EnabledProtocolItem::~EnabledProtocolItem()
73 {
74 }
75
76 bool EnabledProtocolItem::applyValue()
77 {
78     if (enabledInit_ != enabled_) {
79         applyValuePrivate(enabled_);
80         return true;
81     }
82
83     return false;
84 }
85
86
87
88
89 EnabledProtocolsModel::EnabledProtocolsModel(QObject *parent) :
90     QAbstractItemModel(parent),
91     root_(new ProtocolTreeItem(NULL, NULL))
92 {
93 }
94
95 EnabledProtocolsModel::~EnabledProtocolsModel()
96 {
97     delete root_;
98 }
99
100 int EnabledProtocolsModel::rowCount(const QModelIndex &parent) const
101 {
102    EnabledProtocolItem *parent_item;
103     if (parent.column() > 0)
104         return 0;
105
106     if (!parent.isValid())
107         parent_item = root_;
108     else
109         parent_item = static_cast<EnabledProtocolItem*>(parent.internalPointer());
110
111     if (parent_item == NULL)
112         return 0;
113
114     return parent_item->childCount();
115 }
116
117 int EnabledProtocolsModel::columnCount(const QModelIndex&) const
118 {
119     return colLast;
120 }
121
122 QVariant EnabledProtocolsModel::headerData(int section, Qt::Orientation orientation, int role) const
123 {
124     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
125
126         switch ((enum EnabledProtocolsColumn)section) {
127         case colProtocol:
128             return tr("Protocol");
129         case colDescription:
130             return tr("Description");
131         default:
132             break;
133         }
134     }
135     return QVariant();
136 }
137
138 QModelIndex EnabledProtocolsModel::parent(const QModelIndex& index) const
139 {
140     if (!index.isValid())
141         return QModelIndex();
142
143     EnabledProtocolItem* item = static_cast<EnabledProtocolItem*>(index.internalPointer());
144     if (item != NULL) {
145         EnabledProtocolItem* parent_item = item->parentItem();
146         if (parent_item != NULL) {
147             if (parent_item == root_)
148                 return QModelIndex();
149
150             return createIndex(parent_item->row(), 0, parent_item);
151         }
152     }
153
154     return QModelIndex();
155 }
156
157 QModelIndex EnabledProtocolsModel::index(int row, int column, const QModelIndex& parent) const
158 {
159     if (!hasIndex(row, column, parent))
160         return QModelIndex();
161
162     EnabledProtocolItem *parent_item, *child_item;
163
164     if (!parent.isValid())
165         parent_item = root_;
166     else
167         parent_item = static_cast<EnabledProtocolItem*>(parent.internalPointer());
168
169     Q_ASSERT(parent_item);
170
171     child_item = parent_item->child(row);
172     if (child_item) {
173         return createIndex(row, column, child_item);
174     }
175
176     return QModelIndex();
177 }
178
179 Qt::ItemFlags EnabledProtocolsModel::flags(const QModelIndex &index) const
180 {
181     if (!index.isValid())
182         return 0;
183
184     Qt::ItemFlags flags = QAbstractItemModel::flags(index);
185     switch(index.column())
186     {
187     case colProtocol:
188         flags |= Qt::ItemIsUserCheckable;
189         break;
190     default:
191         break;
192     }
193
194     return flags;
195 }
196
197 QVariant EnabledProtocolsModel::data(const QModelIndex &index, int role) const
198 {
199     if (!index.isValid())
200         return QVariant();
201
202     EnabledProtocolItem* item = static_cast<EnabledProtocolItem*>(index.internalPointer());
203     if (item == NULL)
204         return QVariant();
205
206     switch (role)
207     {
208     case Qt::DisplayRole:
209         switch ((enum EnabledProtocolsColumn)index.column())
210         {
211         case colProtocol:
212             return item->name();
213         case colDescription:
214             return item->description();
215         default:
216             break;
217         }
218         break;
219     case Qt::CheckStateRole:
220         switch ((enum EnabledProtocolsColumn)index.column())
221         {
222         case colProtocol:
223             return item->enabled() ? Qt::Checked : Qt::Unchecked;
224         default:
225             break;
226         }
227         break;
228     }
229     return QVariant();
230 }
231
232 bool EnabledProtocolsModel::setData(const QModelIndex &index, const QVariant &value, int role)
233 {
234     if (!index.isValid())
235         return false;
236
237     if ((role != Qt::EditRole) &&
238         ((index.column() == colProtocol) && (role != Qt::CheckStateRole)))
239         return false;
240
241     if (data(index, role) == value) {
242         // Data appears unchanged, do not do additional checks.
243         return true;
244     }
245
246     EnabledProtocolItem* item = static_cast<EnabledProtocolItem*>(index.internalPointer());
247     if (item == NULL)
248         return false;
249
250     item->setEnabled(value == Qt::Checked ? true : false);
251
252     QVector<int> roles;
253     roles << role;
254
255     emit dataChanged(index, index
256 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
257                          , roles
258 #endif
259         );
260
261     return true;
262 }
263
264 static void addHeuristicItem(gpointer data, gpointer user_data)
265 {
266     heur_dtbl_entry_t* heur = (heur_dtbl_entry_t*)data;
267     ProtocolTreeItem* protocol_item = (ProtocolTreeItem*)user_data;
268
269     HeuristicTreeItem* heuristic_row = new HeuristicTreeItem(heur, protocol_item);
270     protocol_item->appendChild(heuristic_row);
271 }
272
273 void EnabledProtocolsModel::populate()
274 {
275     void *cookie;
276     protocol_t *protocol;
277
278     emit beginResetModel();
279
280     // Iterate over all the protocols
281     for (int i = proto_get_first_protocol(&cookie); i != -1; i = proto_get_next_protocol(&cookie))
282     {
283         if (proto_can_toggle_protocol(i))
284         {
285             protocol = find_protocol_by_id(i);
286             ProtocolTreeItem* protocol_row = new ProtocolTreeItem(protocol, root_);
287             root_->appendChild(protocol_row);
288
289             proto_heuristic_dissector_foreach(protocol, addHeuristicItem, protocol_row);
290         }
291     }
292
293     emit endResetModel();
294 }
295
296 void EnabledProtocolsModel::invertEnabled()
297 {
298     emit beginResetModel();
299
300     for (int proto_index = 0; proto_index < root_->childCount(); proto_index++) {
301         EnabledProtocolItem* proto = root_->child(proto_index);
302         proto->setEnabled(!proto->enabled());
303         for (int heur_index = 0; heur_index < proto->childCount(); heur_index++) {
304             EnabledProtocolItem* heur = proto->child(heur_index);
305             heur->setEnabled(!heur->enabled());
306         }
307     }
308
309     emit endResetModel();
310 }
311
312 void EnabledProtocolsModel::enableAll()
313 {
314     emit beginResetModel();
315
316     for (int proto_index = 0; proto_index < root_->childCount(); proto_index++) {
317         EnabledProtocolItem* proto = root_->child(proto_index);
318         proto->setEnabled(true);
319         for (int heur_index = 0; heur_index < proto->childCount(); heur_index++) {
320             EnabledProtocolItem* heur = proto->child(heur_index);
321             heur->setEnabled(true);
322         }
323     }
324
325     emit endResetModel();
326 }
327
328 void EnabledProtocolsModel::disableAll()
329 {
330     emit beginResetModel();
331
332     for (int proto_index = 0; proto_index < root_->childCount(); proto_index++) {
333         EnabledProtocolItem* proto = root_->child(proto_index);
334         proto->setEnabled(false);
335         for (int heur_index = 0; heur_index < proto->childCount(); heur_index++) {
336             EnabledProtocolItem* heur = proto->child(heur_index);
337             heur->setEnabled(false);
338         }
339     }
340
341     emit endResetModel();
342 }
343
344 void EnabledProtocolsModel::applyChanges(bool writeChanges)
345 {
346     bool redissect = false;
347
348     for (int proto_index = 0; proto_index < root_->childCount(); proto_index++) {
349         EnabledProtocolItem* proto = root_->child(proto_index);
350         redissect |= proto->applyValue();
351         for (int heur_index = 0; heur_index < proto->childCount(); heur_index++) {
352             EnabledProtocolItem* heur = proto->child(heur_index);
353             redissect |= heur->applyValue();
354         }
355     }
356
357     if (redissect) {
358         saveChanges(writeChanges);
359     }
360 }
361
362 void EnabledProtocolsModel::disableProtocol(struct _protocol *protocol)
363 {
364     ProtocolTreeItem disabled_proto(protocol, NULL);
365     disabled_proto.setEnabled(false);
366     if (disabled_proto.applyValue()) {
367         saveChanges();
368     }
369 }
370
371 void EnabledProtocolsModel::saveChanges(bool writeChanges)
372 {
373     if (writeChanges) {
374         save_enabled_and_disabled_lists();
375     }
376     wsApp->emitAppSignal(WiresharkApplication::PacketDissectionChanged);
377 }
378
379
380
381
382 EnabledProtocolsProxyModel::EnabledProtocolsProxyModel(QObject * parent)
383 : QSortFilterProxyModel(parent),
384 filter_()
385 {
386 }
387
388 bool EnabledProtocolsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
389 {
390     //Use EnabledProtocolItem directly for better performance
391     EnabledProtocolItem* left_item = static_cast<EnabledProtocolItem*>(left.internalPointer());
392     EnabledProtocolItem* right_item = static_cast<EnabledProtocolItem*>(right.internalPointer());
393
394     if ((left_item != NULL) && (right_item != NULL)) {
395
396         int compare_ret = 0;
397
398         if (left.column() == EnabledProtocolsModel::colProtocol )
399             compare_ret = left_item->name().compare(right_item->name(), Qt::CaseInsensitive);
400         else if ( left.column() == EnabledProtocolsModel::colDescription )
401             compare_ret = left_item->description().compare(right_item->description(), Qt::CaseInsensitive);
402
403         if (compare_ret < 0)
404             return true;
405     }
406
407     return false;
408 }
409
410 bool EnabledProtocolsProxyModel::filterAcceptItem(EnabledProtocolItem& item) const
411 {
412     QRegExp regex(filter_, Qt::CaseInsensitive);
413
414     if (item.name().contains(regex))
415         return true;
416
417     if (item.description().contains(regex))
418         return true;
419
420     return false;
421 }
422
423 bool EnabledProtocolsProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
424 {
425
426     QModelIndex nameIdx = sourceModel()->index(sourceRow, EnabledProtocolsModel::colProtocol, sourceParent);
427     EnabledProtocolItem* item = static_cast<EnabledProtocolItem*>(nameIdx.internalPointer());
428     if (item == NULL)
429         return true;
430
431     if (!filter_.isEmpty()) {
432         if (filterAcceptItem(*item))
433             return true;
434
435         if (!nameIdx.parent().isValid())
436         {
437             EnabledProtocolItem* child_item;
438             for (int row = 0; row < item->childCount(); row++)
439             {
440                 child_item = item->child(row);
441                 if ((child_item != NULL) && (filterAcceptItem(*child_item)))
442                     return true;
443             }
444         }
445
446         return false;
447     }
448
449     return true;
450 }
451
452 void EnabledProtocolsProxyModel::setFilter(const QString& filter)
453 {
454     filter_ = filter;
455     invalidateFilter();
456 }
457
458
459 /*
460  * Editor modelines
461  *
462  * Local Variables:
463  * c-basic-offset: 4
464  * tab-width: 8
465  * indent-tabs-mode: nil
466  * End:
467  *
468  * ex: set shiftwidth=4 tabstop=8 expandtab:
469  * :indentSize=4:tabSize=8:noTabs=true:
470  */