/* expert_info_model.cpp * Data model for Expert Info tap data. * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0+ */ #include "expert_info_model.h" #include #include "file.h" ExpertPacketItem::ExpertPacketItem(expert_info_t& expert_info, column_info *cinfo, ExpertPacketItem* parent) : packet_num_(expert_info.packet_num), group_(expert_info.group), severity_(expert_info.severity), hf_id_(expert_info.hf_index), protocol_(expert_info.protocol), summary_(expert_info.summary), parentItem_(parent) { if (cinfo) { info_ = col_get_text(cinfo, COL_INFO); } } ExpertPacketItem::~ExpertPacketItem() { } QString ExpertPacketItem::groupKey(bool group_by_summary, int severity, int group, QString protocol, int expert_hf) { QString key = QString("%1|%2|%3") .arg(severity) .arg(group) .arg(protocol); if (group_by_summary) { key += QString("|%1").arg(expert_hf); } return key; } QString ExpertPacketItem::groupKey(bool group_by_summary) { return groupKey(group_by_summary, severity_, group_, protocol_, hf_id_); } void ExpertPacketItem::appendChild(ExpertPacketItem* child, QString hash) { childItems_.append(child); hashChild_[hash] = child; } ExpertPacketItem* ExpertPacketItem::child(int row) { return childItems_.value(row); } ExpertPacketItem* ExpertPacketItem::child(QString hash) { return hashChild_[hash]; } int ExpertPacketItem::childCount() const { return childItems_.count(); } int ExpertPacketItem::row() const { if (parentItem_) return parentItem_->childItems_.indexOf(const_cast(this)); return 0; } ExpertPacketItem* ExpertPacketItem::parentItem() { return parentItem_; } ExpertInfoModel::ExpertInfoModel(CaptureFile& capture_file, QObject *parent) : QAbstractItemModel(parent), capture_file_(capture_file), group_by_summary_(true), root_(createRootItem()) { } void ExpertInfoModel::clear() { emit beginResetModel(); eventCounts_.clear(); delete root_; root_ = createRootItem(); emit endResetModel(); } ExpertPacketItem* ExpertInfoModel::createRootItem() { static const char* rootName = "ROOT"; static expert_info_t root_expert = { 0, -1, -1, -1, rootName, (gchar*)rootName, NULL }; return new ExpertPacketItem(root_expert, NULL, NULL); } int ExpertInfoModel::numEvents(enum ExpertSeverity severity) { return eventCounts_[severity]; } QModelIndex ExpertInfoModel::index(int row, int column, const QModelIndex& parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); ExpertPacketItem *parent_item, *child_item; if (!parent.isValid()) parent_item = root_; else parent_item = static_cast(parent.internalPointer()); Q_ASSERT(parent_item); if (group_by_summary_) { //don't allow group layer if (parent_item == root_) { int row_count = 0; ExpertPacketItem *grandchild_item; for (int subrow = 0; subrow < parent_item->childCount(); subrow++) { child_item = parent_item->child(subrow); //summary children are always stored in first child of group grandchild_item = child_item->child(0); if (row_count+grandchild_item->childCount() > row) { return createIndex(row, column, grandchild_item->child(row-row_count)); } row_count += grandchild_item->childCount(); } //shouldn't happen return QModelIndex(); } int root_level = 0; ExpertPacketItem *item = parent_item; while (item != root_) { root_level++; item = item->parentItem(); } if (root_level == 3) { child_item = parent_item->child(row); if (child_item) { return createIndex(row, column, child_item); } } } else { child_item = parent_item->child(row); if (child_item) { //only allow 2 levels deep if (((parent_item == root_) || (parent_item->parentItem() == root_))) return createIndex(row, column, child_item); } } return QModelIndex(); } QModelIndex ExpertInfoModel::parent(const QModelIndex& index) const { if (!index.isValid()) return QModelIndex(); ExpertPacketItem *item = static_cast(index.internalPointer()); ExpertPacketItem *parent_item = item->parentItem(); if (group_by_summary_) { //don't allow group layer int root_level = 0; item = parent_item; while ((item != root_) && (item != NULL)) { root_level++; item = item->parentItem(); } if (root_level == 3) return createIndex(parent_item->row(), 0, parent_item); } else { if (parent_item == root_) return QModelIndex(); return createIndex(parent_item->row(), 0, parent_item); } return QModelIndex(); } #if 0 Qt::ItemFlags ExpertInfoModel::flags(const QModelIndex &index) const { if (!index.isValid()) return 0; ExpertPacketItem* item = static_cast(index.internalPointer()); Qt::ItemFlags flags = QAbstractTableModel::flags(index); //collapse??? return flags; } #endif QVariant ExpertInfoModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || role != Qt::DisplayRole) return QVariant(); ExpertPacketItem* item = static_cast(index.internalPointer()); if (item == NULL) return QVariant(); switch ((enum ExpertColumn)index.column()) { case colSeverity: return QString(val_to_str_const(item->severity(), expert_severity_vals, "Unknown")); case colSummary: if (index.parent().isValid()) { if (group_by_summary_) return item->colInfo().simplified(); return item->summary().simplified(); } else { if (group_by_summary_) return item->summary().simplified(); } return QVariant(); case colGroup: return QString(val_to_str_const(item->group(), expert_group_vals, "Unknown")); case colProtocol: return item->protocol(); case colCount: if (!index.parent().isValid()) { return item->childCount(); } break; case colPacket: return item->packetNum(); case colHf: return item->hfId(); default: break; } return QVariant(); } //GUI helpers void ExpertInfoModel::setGroupBySummary(bool group_by_summary) { emit beginResetModel(); group_by_summary_ = group_by_summary; emit endResetModel(); } int ExpertInfoModel::rowCount(const QModelIndex &parent) const { ExpertPacketItem *parent_item; if (parent.column() > 0) return 0; if (!parent.isValid()) parent_item = root_; else parent_item = static_cast(parent.internalPointer()); if (group_by_summary_) { int row_count = 0; //don't allow group layer if (parent_item == root_) { ExpertPacketItem *child_item, *grandchild_item; for (int row = 0; row < parent_item->childCount(); row++) { child_item = parent_item->child(row); grandchild_item = child_item->child(0); row_count += grandchild_item->childCount(); } return row_count; } return parent_item->childCount(); } else { //only allow 2 levels deep if ((parent_item == root_) || (parent_item->parentItem() == root_)) return parent_item->childCount(); } return 0; } int ExpertInfoModel::columnCount(const QModelIndex& ) const { return colLast; } void ExpertInfoModel::addExpertInfo(struct expert_info_s& expert_info) { QString groupKey = ExpertPacketItem::groupKey(FALSE, expert_info.severity, expert_info.group, QString(expert_info.protocol), expert_info.hf_index); QString summaryKey = ExpertPacketItem::groupKey(TRUE, expert_info.severity, expert_info.group, QString(expert_info.protocol), expert_info.hf_index); ExpertPacketItem* expert_root = root_->child(groupKey); if (expert_root == NULL) { ExpertPacketItem *new_item = new ExpertPacketItem(expert_info, &(capture_file_.capFile()->cinfo), root_); root_->appendChild(new_item, groupKey); expert_root = new_item; } ExpertPacketItem *expert = new ExpertPacketItem(expert_info, &(capture_file_.capFile()->cinfo), expert_root); expert_root->appendChild(expert, groupKey); //add the summary children off of the first child of the root children ExpertPacketItem* summary_root = expert_root->child(0); //make a summary child ExpertPacketItem* expert_summary_root = summary_root->child(summaryKey); if (expert_summary_root == NULL) { ExpertPacketItem *new_summary = new ExpertPacketItem(expert_info, &(capture_file_.capFile()->cinfo), summary_root); summary_root->appendChild(new_summary, summaryKey); expert_summary_root = new_summary; } ExpertPacketItem *expert_summary = new ExpertPacketItem(expert_info, &(capture_file_.capFile()->cinfo), expert_summary_root); expert_summary_root->appendChild(expert_summary, summaryKey); } void ExpertInfoModel::tapReset(void *eid_ptr) { ExpertInfoModel *model = static_cast(eid_ptr); if (!model) return; model->clear(); } gboolean ExpertInfoModel::tapPacket(void *eid_ptr, struct _packet_info *pinfo, struct epan_dissect *, const void *data) { ExpertInfoModel *model = static_cast(eid_ptr); expert_info_t *expert_info = (expert_info_t *) data; gboolean draw_required = FALSE; if (!pinfo || !model || !expert_info) return FALSE; model->addExpertInfo(*expert_info); if (model->numEvents((enum ExpertSeverity)expert_info->severity) < 1) draw_required = TRUE; model->eventCounts_[(enum ExpertSeverity)expert_info->severity]++; return draw_required; } void ExpertInfoModel::tapDraw(void *eid_ptr) { ExpertInfoModel *model = static_cast(eid_ptr); if (!model) return; emit model->beginResetModel(); emit model->endResetModel(); } /* * Editor modelines * * Local Variables: * c-basic-offset: 4 * tab-width: 8 * indent-tabs-mode: nil * End: * * ex: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */