1 /* expert_info_model.cpp
2 * Data model for Expert Info tap data.
3 *
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include <ui/qt/models/expert_info_model.h>
12 #include <ui/qt/models/expert_info_proxy_model.h>
13 #include <ui/qt/utils/color_utils.h>
14
ExpertInfoProxyModel(QObject * parent)15 ExpertInfoProxyModel::ExpertInfoProxyModel(QObject *parent) : QSortFilterProxyModel(parent),
16 severityMode_(Group)
17 {
18 }
19
lessThan(const QModelIndex & source_left,const QModelIndex & source_right) const20 bool ExpertInfoProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
21 {
22 ExpertPacketItem *left_item,
23 *right_item;
24 QString leftStr, rightStr;
25 bool checkPacketNumber = false;
26 int compare_ret;
27
28 if (source_left.parent().isValid() && source_right.parent().isValid()) {
29 left_item = static_cast<ExpertPacketItem*>(source_left.parent().internalPointer());
30 right_item = static_cast<ExpertPacketItem*>(source_right.parent().internalPointer());
31 } else {
32 left_item = static_cast<ExpertPacketItem*>(source_left.internalPointer());
33 right_item = static_cast<ExpertPacketItem*>(source_right.internalPointer());
34 }
35
36 if ((left_item != NULL) && (right_item != NULL)) {
37 switch (source_left.column())
38 {
39 case colProxySeverity:
40 if (left_item->severity() != right_item->severity()) {
41 return (left_item->severity() < right_item->severity());
42 }
43
44 checkPacketNumber = true;
45 break;
46 case colProxySummary:
47 compare_ret = left_item->summary().compare(right_item->summary());
48 if (compare_ret < 0)
49 return true;
50 if (compare_ret > 0)
51 return false;
52
53 checkPacketNumber = true;
54 break;
55 case colProxyGroup:
56 if (left_item->group() != right_item->group()) {
57 return (left_item->group() < right_item->group());
58 }
59
60 checkPacketNumber = true;
61 break;
62 case colProxyProtocol:
63 compare_ret = left_item->protocol().compare(right_item->protocol());
64 if (compare_ret < 0)
65 return true;
66 if (compare_ret > 0)
67 return false;
68
69 checkPacketNumber = true;
70 break;
71 case colProxyCount:
72 break;
73 default:
74 break;
75 }
76
77 if (checkPacketNumber) {
78 return (left_item->packetNum() < right_item->packetNum());
79 }
80 }
81
82 // fallback to string cmp on other fields
83 return QSortFilterProxyModel::lessThan(source_left, source_right);
84 }
85
data(const QModelIndex & proxy_index,int role) const86 QVariant ExpertInfoProxyModel::data(const QModelIndex &proxy_index, int role) const
87 {
88 QModelIndex source_index;
89
90 switch (role)
91 {
92 case Qt::BackgroundRole:
93 {
94 source_index = mapToSource(proxy_index);
95
96 // only color base row
97 if (!source_index.isValid() || source_index.parent().isValid())
98 return QVariant();
99
100 ExpertPacketItem* item = static_cast<ExpertPacketItem*>(source_index.internalPointer());
101 if (item == NULL)
102 return QVariant();
103
104 // provide background color for groups
105 switch(item->severity()) {
106 case(PI_COMMENT):
107 return QBrush(ColorUtils::expert_color_comment);
108 case(PI_CHAT):
109 return QBrush(ColorUtils::expert_color_chat);
110 case(PI_NOTE):
111 return QBrush(ColorUtils::expert_color_note);
112 case(PI_WARN):
113 return QBrush(ColorUtils::expert_color_warn);
114 case(PI_ERROR):
115 return QBrush(ColorUtils::expert_color_error);
116 }
117 }
118 break;
119 case Qt::ForegroundRole:
120 {
121 source_index = mapToSource(proxy_index);
122
123 // only color base row
124 if (!source_index.isValid() || source_index.parent().isValid())
125 return QVariant();
126
127 ExpertPacketItem* item = static_cast<ExpertPacketItem*>(source_index.internalPointer());
128 if (item == NULL)
129 return QVariant();
130
131 // provide foreground color for groups
132 switch(item->severity()) {
133 case(PI_COMMENT):
134 case(PI_CHAT):
135 case(PI_NOTE):
136 case(PI_WARN):
137 case(PI_ERROR):
138 return QBrush(ColorUtils::expert_color_foreground);
139 }
140 }
141 break;
142 case Qt::TextAlignmentRole:
143 switch (proxy_index.column())
144 {
145 case colProxySeverity:
146 //packet number should be right aligned
147 if (source_index.parent().isValid())
148 return Qt::AlignRight;
149 break;
150 case colProxyCount:
151 return Qt::AlignRight;
152 default:
153 break;
154 }
155 return Qt::AlignLeft;
156
157 case Qt::DisplayRole:
158 source_index = mapToSource(proxy_index);
159
160 switch (proxy_index.column())
161 {
162 case colProxySeverity:
163 if (source_index.parent().isValid())
164 return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colPacket), role);
165
166 return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colSeverity), role);
167 case colProxySummary:
168 return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colSummary), role);
169 case colProxyGroup:
170 return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colGroup), role);
171 case colProxyProtocol:
172 return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colProtocol), role);
173 case colProxyCount:
174 //only show counts for parent
175 if (!source_index.parent().isValid()) {
176 //because of potential filtering, count is computed manually
177 unsigned int count = 0;
178 ExpertPacketItem *child_item,
179 *item = static_cast<ExpertPacketItem*>(source_index.internalPointer());
180 for (int row = 0; row < item->childCount(); row++) {
181 child_item = item->child(row);
182 if (child_item == NULL)
183 continue;
184 if (filterAcceptItem(*child_item))
185 count++;
186 }
187
188 return count;
189 }
190 }
191 break;
192 }
193
194 return QSortFilterProxyModel::data(proxy_index, role);
195 }
196
headerData(int section,Qt::Orientation orientation,int role) const197 QVariant ExpertInfoProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
198 {
199 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
200
201 switch ((enum ExpertProxyColumn)section) {
202 case colProxySeverity:
203 if (severityMode_ == Packet)
204 return tr("Packet");
205 else
206 return tr("Severity");
207 case colProxySummary:
208 return tr("Summary");
209 case colProxyGroup:
210 return tr("Group");
211 case colProxyProtocol:
212 return tr("Protocol");
213 case colProxyCount:
214 return tr("Count");
215 default:
216 break;
217 }
218 }
219 return QVariant();
220 }
221
columnCount(const QModelIndex &) const222 int ExpertInfoProxyModel::columnCount(const QModelIndex&) const
223 {
224 return colProxyLast;
225 }
226
filterAcceptItem(ExpertPacketItem & item) const227 bool ExpertInfoProxyModel::filterAcceptItem(ExpertPacketItem& item) const
228 {
229 if (hidden_severities_.contains(item.severity()))
230 return false;
231
232 if (!textFilter_.isEmpty()) {
233 QRegExp regex(textFilter_, Qt::CaseInsensitive);
234
235 if (item.protocol().contains(regex))
236 return true;
237
238 if (item.summary().contains(regex))
239 return true;
240
241 if (item.colInfo().contains(regex))
242 return true;
243
244 return false;
245 }
246
247 return true;
248 }
249
filterAcceptsRow(int sourceRow,const QModelIndex & sourceParent) const250 bool ExpertInfoProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
251 {
252 QModelIndex severityIdx = sourceModel()->index(sourceRow, ExpertInfoModel::colSeverity, sourceParent);
253 ExpertPacketItem* item = static_cast<ExpertPacketItem*>(severityIdx.internalPointer());
254 if (item == NULL)
255 return true;
256
257 return filterAcceptItem(*item);
258 }
259
260 //GUI helpers
setSeverityMode(enum SeverityMode mode)261 void ExpertInfoProxyModel::setSeverityMode(enum SeverityMode mode)
262 {
263 severityMode_ = mode;
264 emit headerDataChanged(Qt::Vertical, 0, 1);
265 }
266
setSeverityFilter(int severity,bool hide)267 void ExpertInfoProxyModel::setSeverityFilter(int severity, bool hide)
268 {
269 if (hide)
270 {
271 hidden_severities_ << severity;
272 }
273 else
274 {
275 hidden_severities_.removeOne(severity);
276 }
277
278 invalidateFilter();
279 }
280
setSummaryFilter(const QString & filter)281 void ExpertInfoProxyModel::setSummaryFilter(const QString &filter)
282 {
283 textFilter_ = filter;
284 invalidateFilter();
285 }
286