summaryrefslogtreecommitdiffstats
path: root/ui/qt/models/proto_tree_model.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ui/qt/models/proto_tree_model.cpp')
-rw-r--r--ui/qt/models/proto_tree_model.cpp252
1 files changed, 252 insertions, 0 deletions
diff --git a/ui/qt/models/proto_tree_model.cpp b/ui/qt/models/proto_tree_model.cpp
new file mode 100644
index 00000000..3ededffd
--- /dev/null
+++ b/ui/qt/models/proto_tree_model.cpp
@@ -0,0 +1,252 @@
+/* proto_tree_model.cpp
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <ui/qt/models/proto_tree_model.h>
+
+#include <epan/prefs.h>
+#include <wsutil/wslog.h>
+
+#include <ui/qt/utils/color_utils.h>
+
+#include <QApplication>
+#include <QPalette>
+#include <QFont>
+
+// To do:
+// - Add ProtoTreeDelegate
+// - Add ProtoTreeModel to CaptureFile
+
+ProtoTreeModel::ProtoTreeModel(QObject * parent) :
+ QAbstractItemModel(parent)
+{
+ root_node_ = new ProtoNode(NULL);
+}
+
+ProtoTreeModel::~ProtoTreeModel()
+{
+ delete root_node_;
+}
+
+Qt::ItemFlags ProtoTreeModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags item_flags = QAbstractItemModel::flags(index);
+ if (rowCount(index) < 1) {
+ item_flags |= Qt::ItemNeverHasChildren;
+ }
+
+ return item_flags;
+}
+
+QModelIndex ProtoTreeModel::index(int row, int, const QModelIndex &parent) const
+{
+ ProtoNode *parent_node = root_node_;
+
+ if (parent.isValid()) {
+ // index is not a top level item.
+ parent_node = protoNodeFromIndex(parent);
+ }
+
+ if (! parent_node->isValid())
+ return QModelIndex();
+
+ ProtoNode *child = parent_node->child(row);
+ if (! child) {
+ return QModelIndex();
+ }
+
+ return createIndex(row, 0, static_cast<void *>(child));
+}
+
+QModelIndex ProtoTreeModel::parent(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QModelIndex();
+
+ ProtoNode *parent_node = protoNodeFromIndex(index)->parentNode();
+ return indexFromProtoNode(parent_node);
+}
+
+int ProtoTreeModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid()) {
+ return protoNodeFromIndex(parent)->childrenCount();
+ }
+ return root_node_->childrenCount();
+}
+
+// The QItemDelegate documentation says
+// "When displaying items from a custom model in a standard view, it is
+// often sufficient to simply ensure that the model returns appropriate
+// data for each of the roles that determine the appearance of items in
+// views."
+// We might want to move this to a delegate regardless.
+QVariant ProtoTreeModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ ProtoNode *index_node = protoNodeFromIndex(index);
+ FieldInformation finfo(index_node);
+ if (!finfo.isValid()) {
+ return QVariant();
+ }
+
+ switch (role) {
+ case Qt::DisplayRole:
+ return index_node->labelText();
+ case Qt::BackgroundRole:
+ {
+ switch(finfo.flag(PI_SEVERITY_MASK)) {
+ case(0):
+ break;
+ case(PI_COMMENT):
+ return ColorUtils::expert_color_comment;
+ case(PI_CHAT):
+ return ColorUtils::expert_color_chat;
+ case(PI_NOTE):
+ return ColorUtils::expert_color_note;
+ case(PI_WARN):
+ return ColorUtils::expert_color_warn;
+ case(PI_ERROR):
+ return ColorUtils::expert_color_error;
+ default:
+ ws_warning("Unhandled severity flag: %u", finfo.flag(PI_SEVERITY_MASK));
+ }
+ if (finfo.headerInfo().type == FT_PROTOCOL) {
+ return QApplication::palette().window();
+ }
+ return QApplication::palette().base();
+ }
+ case Qt::ForegroundRole:
+ {
+ if (finfo.flag(PI_SEVERITY_MASK)) {
+ return ColorUtils::expert_color_foreground;
+ }
+ if (finfo.isLink()) {
+ return ColorUtils::themeLinkBrush();
+ }
+ if (finfo.headerInfo().type == FT_PROTOCOL) {
+ return QApplication::palette().windowText();
+ }
+ return QApplication::palette().text();
+ }
+ case Qt::FontRole:
+ if (finfo.isLink()) {
+ QFont font;
+ font.setUnderline(true);
+ return font;
+ }
+ default:
+ break;
+ }
+
+ return QVariant();
+}
+
+void ProtoTreeModel::setRootNode(proto_node *root_node)
+{
+ beginResetModel();
+ delete root_node_;
+ root_node_ = new ProtoNode(root_node);
+ endResetModel();
+ if (!root_node) return;
+
+ int row_count = root_node_->childrenCount();
+ if (row_count < 1) return;
+ beginInsertRows(QModelIndex(), 0, row_count - 1);
+ endInsertRows();
+}
+
+ProtoNode* ProtoTreeModel::protoNodeFromIndex(const QModelIndex &index) const
+{
+ return static_cast<ProtoNode*>(index.internalPointer());
+}
+
+QModelIndex ProtoTreeModel::indexFromProtoNode(ProtoNode *index_node) const
+{
+ if (!index_node) {
+ return QModelIndex();
+ }
+
+ int row = index_node->row();
+
+ if (!index_node->isValid() || row < 0) {
+ return QModelIndex();
+ }
+
+ return createIndex(row, 0, static_cast<void *>(index_node));
+}
+
+struct find_hfid_ {
+ int hfid;
+ ProtoNode *node;
+};
+
+bool ProtoTreeModel::foreachFindHfid(ProtoNode *node, gpointer find_hfid_ptr)
+{
+ struct find_hfid_ *find_hfid = (struct find_hfid_ *) find_hfid_ptr;
+ if (PNODE_FINFO(node->protoNode()) && PNODE_FINFO(node->protoNode())->hfinfo->id == find_hfid->hfid) {
+ find_hfid->node = node;
+ return true;
+ }
+ for (int i = 0; i < node->childrenCount(); i++) {
+ if (foreachFindHfid(node->child(i), find_hfid)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+QModelIndex ProtoTreeModel::findFirstHfid(int hf_id)
+{
+ if (!root_node_ || hf_id < 0) return QModelIndex();
+
+ struct find_hfid_ find_hfid;
+ find_hfid.hfid = hf_id;
+
+ if (foreachFindHfid(root_node_, &find_hfid) && find_hfid.node->isValid()) {
+ return indexFromProtoNode(find_hfid.node);
+ }
+ return QModelIndex();
+}
+
+struct find_field_info_ {
+ field_info *fi;
+ ProtoNode *node;
+};
+
+bool ProtoTreeModel::foreachFindField(ProtoNode *node, gpointer find_finfo_ptr)
+{
+ struct find_field_info_ *find_finfo = (struct find_field_info_ *) find_finfo_ptr;
+ if (PNODE_FINFO(node->protoNode()) == find_finfo->fi) {
+ find_finfo->node = node;
+ return true;
+ }
+ for (int i = 0; i < node->childrenCount(); i++) {
+ if (foreachFindField(node->child(i), find_finfo)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+QModelIndex ProtoTreeModel::findFieldInformation(FieldInformation *finfo)
+{
+ if (!root_node_ || !finfo) return QModelIndex();
+ field_info * fi = finfo->fieldInfo();
+ if (!fi) return QModelIndex();
+
+ struct find_field_info_ find_finfo;
+ find_finfo.fi = fi;
+
+ if (foreachFindField(root_node_, &find_finfo) && find_finfo.node->isValid()) {
+ return indexFromProtoNode(find_finfo.node);
+ }
+ return QModelIndex();
+}