1 /* proto_tree_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 <ui/qt/models/proto_tree_model.h>
11
12 #include <epan/prefs.h>
13 #include <wsutil/wslog.h>
14
15 #include <ui/qt/utils/color_utils.h>
16
17 #include <QApplication>
18 #include <QPalette>
19
20 // To do:
21 // - Add ProtoTreeDelegate
22 // - Add ProtoTreeModel to CaptureFile
23
ProtoTreeModel(QObject * parent)24 ProtoTreeModel::ProtoTreeModel(QObject * parent) :
25 QAbstractItemModel(parent),
26 root_node_(0)
27 {}
28
flags(const QModelIndex & index) const29 Qt::ItemFlags ProtoTreeModel::flags(const QModelIndex &index) const
30 {
31 Qt::ItemFlags item_flags = QAbstractItemModel::flags(index);
32 if (rowCount(index) < 1) {
33 item_flags |= Qt::ItemNeverHasChildren;
34 }
35
36 return item_flags;
37 }
38
index(int row,int,const QModelIndex & parent) const39 QModelIndex ProtoTreeModel::index(int row, int, const QModelIndex &parent) const
40 {
41 ProtoNode parent_node(root_node_);
42
43 if (parent.isValid()) {
44 // index is not a top level item.
45 parent_node = protoNodeFromIndex(parent);
46 }
47
48 if (! parent_node.isValid())
49 return QModelIndex();
50
51 int cur_row = 0;
52 ProtoNode::ChildIterator kids = parent_node.children();
53 while (kids.element().isValid())
54 {
55 if (cur_row == row)
56 break;
57 cur_row++;
58 kids.next();
59 }
60 if (! kids.element().isValid()) {
61 return QModelIndex();
62 }
63
64 return createIndex(row, 0, static_cast<void *>(kids.element().protoNode()));
65 }
66
parent(const QModelIndex & index) const67 QModelIndex ProtoTreeModel::parent(const QModelIndex &index) const
68 {
69 ProtoNode parent_node = protoNodeFromIndex(index).parentNode();
70 return indexFromProtoNode(parent_node);
71 }
72
rowCount(const QModelIndex & parent) const73 int ProtoTreeModel::rowCount(const QModelIndex &parent) const
74 {
75 if (parent.isValid()) {
76 return protoNodeFromIndex(parent).childrenCount();
77 }
78 return ProtoNode(root_node_).childrenCount();
79 }
80
81 // The QItemDelegate documentation says
82 // "When displaying items from a custom model in a standard view, it is
83 // often sufficient to simply ensure that the model returns appropriate
84 // data for each of the roles that determine the appearance of items in
85 // views."
86 // We might want to move this to a delegate regardless.
data(const QModelIndex & index,int role) const87 QVariant ProtoTreeModel::data(const QModelIndex &index, int role) const
88 {
89 ProtoNode index_node = protoNodeFromIndex(index);
90 FieldInformation finfo(index_node.protoNode());
91 if (!finfo.isValid()) {
92 return QVariant();
93 }
94
95 switch (role) {
96 case Qt::DisplayRole:
97 return index_node.labelText();
98 case Qt::BackgroundRole:
99 {
100 switch(finfo.flag(PI_SEVERITY_MASK)) {
101 case(0):
102 break;
103 case(PI_COMMENT):
104 return ColorUtils::expert_color_comment;
105 case(PI_CHAT):
106 return ColorUtils::expert_color_chat;
107 case(PI_NOTE):
108 return ColorUtils::expert_color_note;
109 case(PI_WARN):
110 return ColorUtils::expert_color_warn;
111 case(PI_ERROR):
112 return ColorUtils::expert_color_error;
113 default:
114 ws_warning("Unhandled severity flag: %u", finfo.flag(PI_SEVERITY_MASK));
115 }
116 if (finfo.headerInfo().type == FT_PROTOCOL) {
117 return QApplication::palette().window();
118 }
119 return QApplication::palette().base();
120 }
121 case Qt::ForegroundRole:
122 {
123 if (finfo.flag(PI_SEVERITY_MASK)) {
124 return ColorUtils::expert_color_foreground;
125 }
126 if (finfo.isLink()) {
127 return ColorUtils::themeLinkBrush();
128 }
129 if (finfo.headerInfo().type == FT_PROTOCOL) {
130 return QApplication::palette().windowText();
131 }
132 return QApplication::palette().text();
133 }
134 case Qt::FontRole:
135 if (finfo.isLink()) {
136 QFont font;
137 font.setUnderline(true);
138 return font;
139 }
140 default:
141 break;
142 }
143
144 return QVariant();
145 }
146
setRootNode(proto_node * root_node)147 void ProtoTreeModel::setRootNode(proto_node *root_node)
148 {
149 beginResetModel();
150 root_node_ = root_node;
151 endResetModel();
152 if (!root_node) return;
153
154 int row_count = ProtoNode(root_node_).childrenCount();
155 if (row_count < 1) return;
156 beginInsertRows(QModelIndex(), 0, row_count - 1);
157 endInsertRows();
158 }
159
protoNodeFromIndex(const QModelIndex & index) const160 ProtoNode ProtoTreeModel::protoNodeFromIndex(const QModelIndex &index) const
161 {
162 return ProtoNode(static_cast<proto_node*>(index.internalPointer()));
163 }
164
indexFromProtoNode(ProtoNode & index_node) const165 QModelIndex ProtoTreeModel::indexFromProtoNode(ProtoNode &index_node) const
166 {
167 int row = index_node.row();
168
169 if (!index_node.isValid() || row < 0) {
170 return QModelIndex();
171 }
172
173 return createIndex(row, 0, static_cast<void *>(index_node.protoNode()));
174 }
175
176 struct find_hfid_ {
177 int hfid;
178 ProtoNode node;
179 };
180
foreachFindHfid(proto_node * node,gpointer find_hfid_ptr)181 void ProtoTreeModel::foreachFindHfid(proto_node *node, gpointer find_hfid_ptr)
182 {
183 struct find_hfid_ *find_hfid = (struct find_hfid_ *) find_hfid_ptr;
184 if (PNODE_FINFO(node)->hfinfo->id == find_hfid->hfid) {
185 find_hfid->node = ProtoNode(node);
186 return;
187 }
188 proto_tree_children_foreach(node, foreachFindHfid, find_hfid);
189 }
190
findFirstHfid(int hf_id)191 QModelIndex ProtoTreeModel::findFirstHfid(int hf_id)
192 {
193 if (!root_node_ || hf_id < 0) return QModelIndex();
194
195 struct find_hfid_ find_hfid;
196 find_hfid.hfid = hf_id;
197
198 proto_tree_children_foreach(root_node_, foreachFindHfid, &find_hfid);
199
200 if (find_hfid.node.isValid()) {
201 return indexFromProtoNode(find_hfid.node);
202 }
203 return QModelIndex();
204 }
205
206 struct find_field_info_ {
207 field_info *fi;
208 ProtoNode node;
209 };
210
foreachFindField(proto_node * node,gpointer find_finfo_ptr)211 void ProtoTreeModel::foreachFindField(proto_node *node, gpointer find_finfo_ptr)
212 {
213 struct find_field_info_ *find_finfo = (struct find_field_info_ *) find_finfo_ptr;
214 if (PNODE_FINFO(node) == find_finfo->fi) {
215 find_finfo->node = ProtoNode(node);
216 return;
217 }
218 proto_tree_children_foreach(node, foreachFindField, find_finfo);
219 }
220
findFieldInformation(FieldInformation * finfo)221 QModelIndex ProtoTreeModel::findFieldInformation(FieldInformation *finfo)
222 {
223 if (!root_node_ || !finfo) return QModelIndex();
224 field_info * fi = finfo->fieldInfo();
225 if (!fi) return QModelIndex();
226
227 struct find_field_info_ find_finfo;
228 find_finfo.fi = fi;
229
230 proto_tree_children_foreach(root_node_, foreachFindField, &find_finfo);
231 if (find_finfo.node.isValid()) {
232 return indexFromProtoNode(find_finfo.node);
233 }
234 return QModelIndex();
235 }
236