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 "expert_info_model.h" 12 13 #include "file.h" 14 15 ExpertPacketItem::ExpertPacketItem(const expert_info_t& expert_info, column_info *cinfo, ExpertPacketItem* parent) : 16 packet_num_(expert_info.packet_num), 17 group_(expert_info.group), 18 severity_(expert_info.severity), 19 hf_id_(expert_info.hf_index), 20 protocol_(expert_info.protocol), 21 summary_(expert_info.summary), 22 parentItem_(parent) 23 { 24 if (cinfo) { 25 info_ = col_get_text(cinfo, COL_INFO); 26 } 27 } 28 29 ExpertPacketItem::~ExpertPacketItem() 30 { 31 for (int row = 0; row < childItems_.count(); row++) 32 { 33 delete childItems_.value(row); 34 } 35 36 childItems_.clear(); 37 } 38 39 QString ExpertPacketItem::groupKey(bool group_by_summary, int severity, int group, QString protocol, int expert_hf) 40 { 41 QString key = QString("%1|%2|%3") 42 .arg(severity) 43 .arg(group) 44 .arg(protocol); 45 if (group_by_summary) { 46 key += QString("|%1").arg(expert_hf); 47 } 48 return key; 49 } 50 51 QString ExpertPacketItem::groupKey(bool group_by_summary) { 52 return groupKey(group_by_summary, severity_, group_, protocol_, hf_id_); 53 } 54 55 void ExpertPacketItem::appendChild(ExpertPacketItem* child, QString hash) 56 { 57 childItems_.append(child); 58 hashChild_[hash] = child; 59 } 60 61 ExpertPacketItem* ExpertPacketItem::child(int row) 62 { 63 return childItems_.value(row); 64 } 65 66 ExpertPacketItem* ExpertPacketItem::child(QString hash) 67 { 68 return hashChild_[hash]; 69 } 70 71 int ExpertPacketItem::childCount() const 72 { 73 return childItems_.count(); 74 } 75 76 int ExpertPacketItem::row() const 77 { 78 if (parentItem_) 79 return parentItem_->childItems_.indexOf(const_cast<ExpertPacketItem*>(this)); 80 81 return 0; 82 } 83 84 ExpertPacketItem* ExpertPacketItem::parentItem() 85 { 86 return parentItem_; 87 } 88 89 90 91 92 ExpertInfoModel::ExpertInfoModel(CaptureFile& capture_file, QObject *parent) : 93 QAbstractItemModel(parent), 94 capture_file_(capture_file), 95 group_by_summary_(true), 96 root_(createRootItem()) 97 { 98 } 99 100 ExpertInfoModel::~ExpertInfoModel() 101 { 102 delete root_; 103 } 104 105 void ExpertInfoModel::clear() 106 { 107 emit beginResetModel(); 108 109 eventCounts_.clear(); 110 delete root_; 111 root_ = createRootItem(); 112 113 emit endResetModel(); 114 } 115 116 ExpertPacketItem* ExpertInfoModel::createRootItem() 117 { 118 static const char* rootName = "ROOT"; 119 DIAG_OFF_CAST_AWAY_CONST 120 static expert_info_t root_expert = { 0, -1, -1, -1, rootName, (gchar*)rootName, NULL }; 121 DIAG_ON_CAST_AWAY_CONST 122 123 return new ExpertPacketItem(root_expert, NULL, NULL); 124 } 125 126 127 128 int ExpertInfoModel::numEvents(enum ExpertSeverity severity) 129 { 130 return eventCounts_[severity]; 131 } 132 133 QModelIndex ExpertInfoModel::index(int row, int column, const QModelIndex& parent) const 134 { 135 if (!hasIndex(row, column, parent)) 136 return QModelIndex(); 137 138 ExpertPacketItem *parent_item, *child_item; 139 140 if (!parent.isValid()) 141 parent_item = root_; 142 else 143 parent_item = static_cast<ExpertPacketItem*>(parent.internalPointer()); 144 145 Q_ASSERT(parent_item); 146 if (group_by_summary_) { 147 //don't allow group layer 148 if (parent_item == root_) { 149 int row_count = 0; 150 ExpertPacketItem *grandchild_item; 151 152 for (int subrow = 0; subrow < parent_item->childCount(); subrow++) { 153 child_item = parent_item->child(subrow); 154 //summary children are always stored in first child of group 155 grandchild_item = child_item->child(0); 156 157 if (row_count+grandchild_item->childCount() > row) { 158 return createIndex(row, column, grandchild_item->child(row-row_count)); 159 } 160 row_count += grandchild_item->childCount(); 161 } 162 163 //shouldn't happen 164 return QModelIndex(); 165 } 166 167 int root_level = 0; 168 ExpertPacketItem *item = parent_item; 169 while (item != root_) 170 { 171 root_level++; 172 item = item->parentItem(); 173 } 174 175 if (root_level == 3) { 176 child_item = parent_item->child(row); 177 if (child_item) { 178 return createIndex(row, column, child_item); 179 } 180 } 181 182 } else { 183 child_item = parent_item->child(row); 184 if (child_item) { 185 //only allow 2 levels deep 186 if (((parent_item == root_) || (parent_item->parentItem() == root_))) 187 return createIndex(row, column, child_item); 188 } 189 } 190 return QModelIndex(); 191 } 192 193 QModelIndex ExpertInfoModel::parent(const QModelIndex& index) const 194 { 195 if (!index.isValid()) 196 return QModelIndex(); 197 198 ExpertPacketItem *item = static_cast<ExpertPacketItem*>(index.internalPointer()); 199 ExpertPacketItem *parent_item = item->parentItem(); 200 201 if (group_by_summary_) 202 { 203 //don't allow group layer 204 int root_level = 0; 205 item = parent_item; 206 while ((item != root_) && (item != NULL)) 207 { 208 root_level++; 209 item = item->parentItem(); 210 } 211 212 if (root_level == 3) 213 return createIndex(parent_item->row(), 0, parent_item); 214 215 } else { 216 if (parent_item == root_) 217 return QModelIndex(); 218 219 return createIndex(parent_item->row(), 0, parent_item); 220 } 221 222 return QModelIndex(); 223 } 224 225 #if 0 226 Qt::ItemFlags ExpertInfoModel::flags(const QModelIndex &index) const 227 { 228 if (!index.isValid()) 229 return 0; 230 231 ExpertPacketItem* item = static_cast<ExpertPacketItem*>(index.internalPointer()); 232 Qt::ItemFlags flags = QAbstractTableModel::flags(index); 233 234 //collapse??? 235 return flags; 236 } 237 #endif 238 239 QVariant ExpertInfoModel::data(const QModelIndex &index, int role) const 240 { 241 if (!index.isValid() || role != Qt::DisplayRole) 242 return QVariant(); 243 244 ExpertPacketItem* item = static_cast<ExpertPacketItem*>(index.internalPointer()); 245 if (item == NULL) 246 return QVariant(); 247 248 switch ((enum ExpertColumn)index.column()) { 249 case colSeverity: 250 return QString(val_to_str_const(item->severity(), expert_severity_vals, "Unknown")); 251 case colSummary: 252 if (index.parent().isValid()) 253 { 254 if (item->severity() == PI_COMMENT) 255 return item->summary().simplified(); 256 if (group_by_summary_) 257 return item->colInfo().simplified(); 258 259 return item->summary().simplified(); 260 } 261 else 262 { 263 if (group_by_summary_) 264 { 265 if (item->severity() == PI_COMMENT) 266 return "Packet comments listed below."; 267 return item->summary().simplified(); 268 } 269 } 270 return QVariant(); 271 case colGroup: 272 return QString(val_to_str_const(item->group(), expert_group_vals, "Unknown")); 273 case colProtocol: 274 return item->protocol(); 275 case colCount: 276 if (!index.parent().isValid()) 277 { 278 return item->childCount(); 279 } 280 break; 281 case colPacket: 282 return item->packetNum(); 283 case colHf: 284 return item->hfId(); 285 default: 286 break; 287 } 288 289 return QVariant(); 290 } 291 292 //GUI helpers 293 void ExpertInfoModel::setGroupBySummary(bool group_by_summary) 294 { 295 emit beginResetModel(); 296 group_by_summary_ = group_by_summary; 297 emit endResetModel(); 298 } 299 300 int ExpertInfoModel::rowCount(const QModelIndex &parent) const 301 { 302 ExpertPacketItem *parent_item; 303 if (parent.column() > 0) 304 return 0; 305 306 if (!parent.isValid()) 307 parent_item = root_; 308 else 309 parent_item = static_cast<ExpertPacketItem*>(parent.internalPointer()); 310 311 if (group_by_summary_) { 312 int row_count = 0; 313 314 //don't allow group layer 315 if (parent_item == root_) { 316 ExpertPacketItem *child_item, *grandchild_item; 317 318 for (int row = 0; row < parent_item->childCount(); row++) { 319 child_item = parent_item->child(row); 320 grandchild_item = child_item->child(0); 321 row_count += grandchild_item->childCount(); 322 } 323 324 return row_count; 325 } 326 327 return parent_item->childCount(); 328 329 } else { 330 //only allow 2 levels deep 331 if ((parent_item == root_) || (parent_item->parentItem() == root_)) 332 return parent_item->childCount(); 333 } 334 335 return 0; 336 } 337 338 int ExpertInfoModel::columnCount(const QModelIndex&) const 339 { 340 return colLast; 341 } 342 343 void ExpertInfoModel::addExpertInfo(const struct expert_info_s& expert_info) 344 { 345 QString groupKey = ExpertPacketItem::groupKey(FALSE, expert_info.severity, expert_info.group, QString(expert_info.protocol), expert_info.hf_index); 346 QString summaryKey = ExpertPacketItem::groupKey(TRUE, expert_info.severity, expert_info.group, QString(expert_info.protocol), expert_info.hf_index); 347 348 ExpertPacketItem* expert_root = root_->child(groupKey); 349 if (expert_root == NULL) { 350 ExpertPacketItem *new_item = new ExpertPacketItem(expert_info, &(capture_file_.capFile()->cinfo), root_); 351 352 root_->appendChild(new_item, groupKey); 353 354 expert_root = new_item; 355 } 356 357 ExpertPacketItem *expert = new ExpertPacketItem(expert_info, &(capture_file_.capFile()->cinfo), expert_root); 358 expert_root->appendChild(expert, groupKey); 359 360 //add the summary children off of the first child of the root children 361 ExpertPacketItem* summary_root = expert_root->child(0); 362 363 //make a summary child 364 ExpertPacketItem* expert_summary_root = summary_root->child(summaryKey); 365 if (expert_summary_root == NULL) { 366 ExpertPacketItem *new_summary = new ExpertPacketItem(expert_info, &(capture_file_.capFile()->cinfo), summary_root); 367 368 summary_root->appendChild(new_summary, summaryKey); 369 expert_summary_root = new_summary; 370 } 371 372 ExpertPacketItem *expert_summary = new ExpertPacketItem(expert_info, &(capture_file_.capFile()->cinfo), expert_summary_root); 373 expert_summary_root->appendChild(expert_summary, summaryKey); 374 } 375 376 void ExpertInfoModel::tapReset(void *eid_ptr) 377 { 378 ExpertInfoModel *model = static_cast<ExpertInfoModel*>(eid_ptr); 379 if (!model) 380 return; 381 382 model->clear(); 383 } 384 385 tap_packet_status ExpertInfoModel::tapPacket(void *eid_ptr, struct _packet_info *pinfo, struct epan_dissect *, const void *data) 386 { 387 ExpertInfoModel *model = static_cast<ExpertInfoModel*>(eid_ptr); 388 const expert_info_t *expert_info = (const expert_info_t *) data; 389 tap_packet_status status = TAP_PACKET_DONT_REDRAW; 390 391 if (!pinfo || !model || !expert_info) 392 return TAP_PACKET_DONT_REDRAW; 393 394 model->addExpertInfo(*expert_info); 395 396 if (model->numEvents((enum ExpertSeverity)expert_info->severity) < 1) 397 status = TAP_PACKET_REDRAW; 398 399 model->eventCounts_[(enum ExpertSeverity)expert_info->severity]++; 400 401 return status; 402 } 403 404 void ExpertInfoModel::tapDraw(void *eid_ptr) 405 { 406 ExpertInfoModel *model = static_cast<ExpertInfoModel*>(eid_ptr); 407 if (!model) 408 return; 409 410 emit model->beginResetModel(); 411 emit model->endResetModel(); 412 } 413