![Michael Mann](/assets/img/avatar_default.png)
Models and children weren't deleted which leaked memory all over the place. Change-Id: I961016b2501ad8cc8c75cf5fa5b0c86756a29382 Reviewed-on: https://code.wireshark.org/review/24858 Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot Reviewed-by: Michael Mann <mmann78@netscape.net>
418 lines
11 KiB
C++
418 lines
11 KiB
C++
/* expert_info_model.cpp
|
|
* Data model for Expert Info tap data.
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
#include "expert_info_model.h"
|
|
#include <ui/qt/utils/color_utils.h>
|
|
|
|
#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()
|
|
{
|
|
for (int row = 0; row < childItems_.count(); row++)
|
|
{
|
|
delete childItems_.value(row);
|
|
}
|
|
|
|
childItems_.clear();
|
|
}
|
|
|
|
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<ExpertPacketItem*>(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())
|
|
{
|
|
}
|
|
|
|
ExpertInfoModel::~ExpertInfoModel()
|
|
{
|
|
delete root_;
|
|
}
|
|
|
|
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<ExpertPacketItem*>(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<ExpertPacketItem*>(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<ExpertPacketItem*>(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<ExpertPacketItem*>(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<ExpertPacketItem*>(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<ExpertInfoModel*>(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<ExpertInfoModel*>(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<ExpertInfoModel*>(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:
|
|
*/
|