aboutsummaryrefslogtreecommitdiffstats
path: root/ui/qt/models
diff options
context:
space:
mode:
authorMichael Mann <mmann78@netscape.net>2017-06-28 20:00:38 -0400
committerRoland Knall <rknall@gmail.com>2017-12-13 16:07:07 +0000
commitb0112e60ada68646b3e304f73f8321f5fb1ddc01 (patch)
tree4b7e3e2503ba90cbfda0c10ccddb783afe43143b /ui/qt/models
parentf945b85391976bc59da4b542fe84cb58033bd22e (diff)
Add a model to use for Expert Info dialog.
With the model (and proxy), the following features were added/fixed. 1. Expert severities can be filtered by type 2. Search filter expanded to include summary, protocol and column info 3. Expert info starts with all items collapsed. 4. Context menus for collapse/expand all Bug: 11753 Bug: 13831 Bug: 13842 Change-Id: I8e89c7be441e1f08e18915ef8805609e5c5d0bd1 Reviewed-on: https://code.wireshark.org/review/22458 Reviewed-by: Michael Mann <mmann78@netscape.net> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot Reviewed-by: Roland Knall <rknall@gmail.com>
Diffstat (limited to 'ui/qt/models')
-rw-r--r--ui/qt/models/expert_info_model.cpp406
-rw-r--r--ui/qt/models/expert_info_model.h140
-rw-r--r--ui/qt/models/expert_info_proxy_model.cpp278
-rw-r--r--ui/qt/models/expert_info_proxy_model.h73
4 files changed, 897 insertions, 0 deletions
diff --git a/ui/qt/models/expert_info_model.cpp b/ui/qt/models/expert_info_model.cpp
new file mode 100644
index 0000000000..326a369290
--- /dev/null
+++ b/ui/qt/models/expert_info_model.cpp
@@ -0,0 +1,406 @@
+/* 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()
+{
+}
+
+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())
+{
+}
+
+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:
+ */
diff --git a/ui/qt/models/expert_info_model.h b/ui/qt/models/expert_info_model.h
new file mode 100644
index 0000000000..471cd6700a
--- /dev/null
+++ b/ui/qt/models/expert_info_model.h
@@ -0,0 +1,140 @@
+/* expert_info_model.h
+ * 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+
+ */
+
+#ifndef EXPERT_INFO_MODEL_H
+#define EXPERT_INFO_MODEL_H
+
+#include <config.h>
+
+#include <QAbstractItemModel>
+#include <QList>
+#include <QMap>
+
+#include <ui/qt/capture_file.h>
+
+#include <epan/expert.h>
+#include <epan/column-utils.h>
+
+class ExpertPacketItem
+{
+public:
+ ExpertPacketItem(expert_info_t& expert_info, column_info *cinfo, ExpertPacketItem* parent);
+ virtual ~ExpertPacketItem();
+
+ unsigned int packetNum() const { return packet_num_; }
+ int group() const { return group_; }
+ int severity() const { return severity_; }
+ int hfId() const { return hf_id_; }
+ QString protocol() const { return protocol_; }
+ QString summary() const { return summary_; }
+ QString colInfo() const { return info_; }
+
+ static QString groupKey(bool group_by_summary, int severity, int group, QString protocol, int expert_hf);
+ QString groupKey(bool group_by_summary);
+
+ void appendChild(ExpertPacketItem* child, QString hash);
+ ExpertPacketItem* child(int row);
+ ExpertPacketItem* child(QString hash);
+ int childCount() const;
+ int row() const;
+ ExpertPacketItem* parentItem();
+
+private:
+ unsigned int packet_num_;
+ int group_;
+ int severity_;
+ int hf_id_;
+ // Half-hearted attempt at conserving memory. If this isn't sufficient,
+ // PacketListRecord interns column strings in a GStringChunk.
+ QByteArray protocol_;
+ QByteArray summary_;
+ QByteArray info_;
+
+ QList<ExpertPacketItem*> childItems_;
+ ExpertPacketItem* parentItem_;
+ QHash<QString, ExpertPacketItem*> hashChild_; //optimization for insertion
+};
+
+class ExpertInfoModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ ExpertInfoModel(CaptureFile& capture_file, QObject *parent = 0);
+
+ enum ExpertColumn {
+ colSeverity = 0,
+ colSummary,
+ colGroup,
+ colProtocol,
+ colCount,
+ colPacket,
+ colHf,
+ colLast
+ };
+
+ enum ExpertSeverity {
+ severityError = PI_ERROR,
+ severityWarn = PI_WARN,
+ severityNote = PI_NOTE,
+ severityChat = PI_CHAT,
+ severityComment = PI_COMMENT
+ };
+
+ QModelIndex index(int row, int column,
+ const QModelIndex & = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &) const;
+#if 0
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+#endif
+ QVariant data(const QModelIndex &index, int role) const;
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+ int numEvents(enum ExpertSeverity severity);
+
+ void clear();
+
+ //GUI helpers
+ void setGroupBySummary(bool group_by_summary);
+
+ // Called from tapPacket
+ void addExpertInfo(struct expert_info_s& expert_info);
+
+ // Callbacks for register_tap_listener
+ static void tapReset(void *eid_ptr);
+ static gboolean tapPacket(void *eid_ptr, struct _packet_info *pinfo, struct epan_dissect *, const void *data);
+ static void tapDraw(void *eid_ptr);
+
+private:
+ CaptureFile& capture_file_;
+
+ ExpertPacketItem* createRootItem();
+
+ bool group_by_summary_;
+ ExpertPacketItem* root_;
+
+ QHash<enum ExpertSeverity, int> eventCounts_;
+};
+#endif // EXPERT_INFO_MODEL_H
+
+/*
+ * 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:
+ */
diff --git a/ui/qt/models/expert_info_proxy_model.cpp b/ui/qt/models/expert_info_proxy_model.cpp
new file mode 100644
index 0000000000..68a1faf11f
--- /dev/null
+++ b/ui/qt/models/expert_info_proxy_model.cpp
@@ -0,0 +1,278 @@
+/* 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 <ui/qt/models/expert_info_model.h>
+#include <ui/qt/models/expert_info_proxy_model.h>
+#include <ui/qt/utils/color_utils.h>
+
+ExpertInfoProxyModel::ExpertInfoProxyModel(QObject *parent) : QSortFilterProxyModel(parent),
+ severityMode_(Group)
+{
+}
+
+bool ExpertInfoProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
+{
+ ExpertPacketItem *left_item,
+ *right_item;
+ QString leftStr, rightStr;
+ bool checkPacketNumber = false;
+ int compare_ret;
+
+ if (source_left.parent().isValid() && source_right.parent().isValid()) {
+ left_item = static_cast<ExpertPacketItem*>(source_left.parent().internalPointer());
+ right_item = static_cast<ExpertPacketItem*>(source_right.parent().internalPointer());
+ } else {
+ left_item = static_cast<ExpertPacketItem*>(source_left.internalPointer()),
+ right_item = static_cast<ExpertPacketItem*>(source_right.internalPointer());
+ }
+
+ if ((left_item != NULL) && (right_item != NULL)) {
+ switch (source_left.column())
+ {
+ case colProxySeverity:
+ if (left_item->severity() != right_item->severity()) {
+ return (left_item->severity() < right_item->severity());
+ }
+
+ checkPacketNumber = true;
+ break;
+ case colProxySummary:
+ compare_ret = left_item->summary().compare(right_item->summary());
+ if (compare_ret < 0)
+ return true;
+ if (compare_ret > 0)
+ return false;
+
+ checkPacketNumber = true;
+ break;
+ case colProxyGroup:
+ if (left_item->group() != right_item->group()) {
+ return (left_item->group() < right_item->group());
+ }
+
+ checkPacketNumber = true;
+ break;
+ case colProxyProtocol:
+ compare_ret = left_item->protocol().compare(right_item->protocol());
+ if (compare_ret < 0)
+ return true;
+ if (compare_ret > 0)
+ return false;
+
+ checkPacketNumber = true;
+ break;
+ case colProxyCount:
+ break;
+ default:
+ break;
+ }
+
+ if (checkPacketNumber) {
+ return (left_item->packetNum() < right_item->packetNum());
+ }
+ }
+
+ // fallback to string cmp on other fields
+ return QSortFilterProxyModel::lessThan(source_left, source_right);
+}
+
+QVariant ExpertInfoProxyModel::data(const QModelIndex &proxy_index, int role) const
+{
+ QModelIndex source_index;
+
+ switch (role)
+ {
+ case Qt::BackgroundRole:
+ {
+ source_index = mapToSource(proxy_index);
+
+ //only color base row
+ if (!source_index.isValid() || source_index.parent().isValid())
+ return QVariant();
+
+ ExpertPacketItem* item = static_cast<ExpertPacketItem*>(source_index.internalPointer());
+ if (item == NULL)
+ return QVariant();
+
+ // provide background color for groups
+ switch(item->severity()) {
+ case(PI_COMMENT):
+ return QBrush(ColorUtils::expert_color_comment);
+ case(PI_CHAT):
+ return QBrush(ColorUtils::expert_color_chat);
+ case(PI_NOTE):
+ return QBrush(ColorUtils::expert_color_note);
+ case(PI_WARN):
+ return QBrush(ColorUtils::expert_color_warn);
+ case(PI_ERROR):
+ return QBrush(ColorUtils::expert_color_error);
+ }
+ }
+ break;
+ case Qt::ForegroundRole:
+ // XXX Use plain colors until our users demand to be blinded.
+ return QBrush(ColorUtils::expert_color_foreground);
+ case Qt::TextAlignmentRole:
+ switch (proxy_index.column())
+ {
+ case colProxySeverity:
+ //packet number should be right aligned
+ if (source_index.parent().isValid())
+ return Qt::AlignRight;
+ break;
+ case colProxyCount:
+ return Qt::AlignRight;
+ default:
+ break;
+ }
+ return Qt::AlignLeft;
+
+ case Qt::DisplayRole:
+ source_index = mapToSource(proxy_index);
+
+ switch (proxy_index.column())
+ {
+ case colProxySeverity:
+ if (source_index.parent().isValid())
+ return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colPacket), role);
+
+ return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colSeverity), role);
+ case colProxySummary:
+ return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colSummary), role);
+ case colProxyGroup:
+ return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colGroup), role);
+ case colProxyProtocol:
+ return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colProtocol), role);
+ case colProxyCount:
+ //only show counts for parent
+ if (!source_index.parent().isValid()) {
+ //because of potential filtering, count is computed manually
+ unsigned int count = 0;
+ ExpertPacketItem *child_item,
+ *item = static_cast<ExpertPacketItem*>(source_index.internalPointer());
+ for (int row = 0; row < item->childCount(); row++) {
+ child_item = item->child(row);
+ if (child_item == NULL)
+ continue;
+ if (filterAcceptItem(*child_item))
+ count++;
+ }
+
+ return count;
+ }
+ }
+ break;
+ }
+
+ return QSortFilterProxyModel::data(proxy_index, role);
+}
+
+QVariant ExpertInfoProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+
+ switch ((enum ExpertProxyColumn)section) {
+ case colProxySeverity:
+ if (severityMode_ == Packet)
+ return tr("Packet");
+ else
+ return tr("Severity");
+ case colProxySummary:
+ return tr("Summary");
+ case colProxyGroup:
+ return tr("Group");
+ case colProxyProtocol:
+ return tr("Protocol");
+ case colProxyCount:
+ return tr("Count");
+ default:
+ break;
+ }
+ }
+ return QVariant();
+}
+
+int ExpertInfoProxyModel::columnCount(const QModelIndex& ) const
+{
+ return colProxyLast;
+}
+
+bool ExpertInfoProxyModel::filterAcceptItem(ExpertPacketItem& item) const
+{
+ if (hidden_severities_.contains(item.severity()))
+ return false;
+
+ if (!textFilter_.isEmpty()) {
+ QRegExp regex(textFilter_, Qt::CaseInsensitive);
+
+ if (item.protocol().contains(regex))
+ return true;
+
+ if (item.summary().contains(regex))
+ return true;
+
+ if (item.colInfo().contains(regex))
+ return true;
+
+ return false;
+ }
+
+ return true;
+}
+
+bool ExpertInfoProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+{
+ QModelIndex severityIdx = sourceModel()->index(sourceRow, ExpertInfoModel::colSeverity, sourceParent);
+ ExpertPacketItem* item = static_cast<ExpertPacketItem*>(severityIdx.internalPointer());
+ if (item == NULL)
+ return true;
+
+ return filterAcceptItem(*item);
+}
+
+//GUI helpers
+void ExpertInfoProxyModel::setSeverityMode(enum SeverityMode mode)
+{
+ severityMode_ = mode;
+ emit headerDataChanged(Qt::Vertical, 0, 1);
+}
+
+void ExpertInfoProxyModel::setSeverityFilter(int severity, bool hide)
+{
+ if (hide)
+ {
+ hidden_severities_ << severity;
+ }
+ else
+ {
+ hidden_severities_.removeOne(severity);
+ }
+
+ invalidateFilter();
+}
+
+void ExpertInfoProxyModel::setSummaryFilter(const QString &filter)
+{
+ textFilter_ = filter;
+ invalidateFilter();
+}
+
+
+/* * 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:
+ */
diff --git a/ui/qt/models/expert_info_proxy_model.h b/ui/qt/models/expert_info_proxy_model.h
new file mode 100644
index 0000000000..3926e0e9e5
--- /dev/null
+++ b/ui/qt/models/expert_info_proxy_model.h
@@ -0,0 +1,73 @@
+/* expert_info_model.h
+ * 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+
+ */
+
+#ifndef EXPERT_INFO_PROXY_MODEL_H
+#define EXPERT_INFO_PROXY_MODEL_H
+
+#include <config.h>
+
+#include <QSortFilterProxyModel>
+
+class ExpertPacketItem;
+
+class ExpertInfoProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+
+public:
+ ExpertInfoProxyModel(QObject *parent = 0);
+
+ enum SeverityMode { Group, Packet };
+ enum ExpertProxyColumn {
+ colProxySeverity = 0,
+ colProxySummary,
+ colProxyGroup,
+ colProxyProtocol,
+ colProxyCount,
+ colProxyLast
+ };
+
+ QVariant data(const QModelIndex &index, int role) const;
+ QVariant headerData(int section, Qt::Orientation orientation,
+ int role = Qt::DisplayRole) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+ virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+
+ //GUI helpers
+ void setSeverityMode(enum SeverityMode);
+ void setSeverityFilter(int severity, bool hide);
+ void setSummaryFilter(const QString &filter);
+
+protected:
+ bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const;
+ bool filterAcceptItem(ExpertPacketItem& item) const;
+
+ enum SeverityMode severityMode_;
+ QList<int> hidden_severities_;
+
+ QString textFilter_;
+
+};
+
+#endif // EXPERT_INFO_PROXY_MODEL_H
+
+/*
+ * 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:
+ */