Qt: Speed up ProtoTreeModel with lots of items

When creating a ProtoNode, count the (non-hidden) children and put
them in a QVector. This saves time having to iterate through all
of a node's children (or the parent's children) each time the
model or view wants to get the row or index number. Create and
delete the needed ProtoNodes when the root node is changed, instead
of recreating them on demand from the proto_nodes (since they're no
longer a thin wrapper.)

Fix #18625
This commit is contained in:
John Thacker 2022-11-12 22:27:42 -05:00
parent 52382b2592
commit b7ed46288a
8 changed files with 161 additions and 113 deletions

View File

@ -23,9 +23,15 @@
// - Add ProtoTreeModel to CaptureFile // - Add ProtoTreeModel to CaptureFile
ProtoTreeModel::ProtoTreeModel(QObject * parent) : ProtoTreeModel::ProtoTreeModel(QObject * parent) :
QAbstractItemModel(parent), QAbstractItemModel(parent)
root_node_(0) {
{} root_node_ = new ProtoNode(NULL);
}
ProtoTreeModel::~ProtoTreeModel()
{
delete root_node_;
}
Qt::ItemFlags ProtoTreeModel::flags(const QModelIndex &index) const Qt::ItemFlags ProtoTreeModel::flags(const QModelIndex &index) const
{ {
@ -39,44 +45,39 @@ Qt::ItemFlags ProtoTreeModel::flags(const QModelIndex &index) const
QModelIndex ProtoTreeModel::index(int row, int, const QModelIndex &parent) const QModelIndex ProtoTreeModel::index(int row, int, const QModelIndex &parent) const
{ {
ProtoNode parent_node(root_node_); ProtoNode *parent_node = root_node_;
if (parent.isValid()) { if (parent.isValid()) {
// index is not a top level item. // index is not a top level item.
parent_node = protoNodeFromIndex(parent); parent_node = protoNodeFromIndex(parent);
} }
if (! parent_node.isValid()) if (! parent_node->isValid())
return QModelIndex(); return QModelIndex();
int cur_row = 0; ProtoNode *child = parent_node->child(row);
ProtoNode::ChildIterator kids = parent_node.children(); if (! child) {
while (kids.element().isValid())
{
if (cur_row == row)
break;
cur_row++;
kids.next();
}
if (! kids.element().isValid()) {
return QModelIndex(); return QModelIndex();
} }
return createIndex(row, 0, static_cast<void *>(kids.element().protoNode())); return createIndex(row, 0, static_cast<void *>(child));
} }
QModelIndex ProtoTreeModel::parent(const QModelIndex &index) const QModelIndex ProtoTreeModel::parent(const QModelIndex &index) const
{ {
ProtoNode parent_node = protoNodeFromIndex(index).parentNode(); if (!index.isValid())
return QModelIndex();
ProtoNode *parent_node = protoNodeFromIndex(index)->parentNode();
return indexFromProtoNode(parent_node); return indexFromProtoNode(parent_node);
} }
int ProtoTreeModel::rowCount(const QModelIndex &parent) const int ProtoTreeModel::rowCount(const QModelIndex &parent) const
{ {
if (parent.isValid()) { if (parent.isValid()) {
return protoNodeFromIndex(parent).childrenCount(); return protoNodeFromIndex(parent)->childrenCount();
} }
return ProtoNode(root_node_).childrenCount(); return root_node_->childrenCount();
} }
// The QItemDelegate documentation says // The QItemDelegate documentation says
@ -87,15 +88,18 @@ int ProtoTreeModel::rowCount(const QModelIndex &parent) const
// We might want to move this to a delegate regardless. // We might want to move this to a delegate regardless.
QVariant ProtoTreeModel::data(const QModelIndex &index, int role) const QVariant ProtoTreeModel::data(const QModelIndex &index, int role) const
{ {
ProtoNode index_node = protoNodeFromIndex(index); if (!index.isValid())
FieldInformation finfo(index_node.protoNode()); return QVariant();
ProtoNode *index_node = protoNodeFromIndex(index);
FieldInformation finfo(index_node);
if (!finfo.isValid()) { if (!finfo.isValid()) {
return QVariant(); return QVariant();
} }
switch (role) { switch (role) {
case Qt::DisplayRole: case Qt::DisplayRole:
return index_node.labelText(); return index_node->labelText();
case Qt::BackgroundRole: case Qt::BackgroundRole:
{ {
switch(finfo.flag(PI_SEVERITY_MASK)) { switch(finfo.flag(PI_SEVERITY_MASK)) {
@ -148,45 +152,55 @@ QVariant ProtoTreeModel::data(const QModelIndex &index, int role) const
void ProtoTreeModel::setRootNode(proto_node *root_node) void ProtoTreeModel::setRootNode(proto_node *root_node)
{ {
beginResetModel(); beginResetModel();
root_node_ = root_node; delete root_node_;
root_node_ = new ProtoNode(root_node);
endResetModel(); endResetModel();
if (!root_node) return; if (!root_node) return;
int row_count = ProtoNode(root_node_).childrenCount(); int row_count = root_node_->childrenCount();
if (row_count < 1) return; if (row_count < 1) return;
beginInsertRows(QModelIndex(), 0, row_count - 1); beginInsertRows(QModelIndex(), 0, row_count - 1);
endInsertRows(); endInsertRows();
} }
ProtoNode ProtoTreeModel::protoNodeFromIndex(const QModelIndex &index) const ProtoNode* ProtoTreeModel::protoNodeFromIndex(const QModelIndex &index) const
{ {
return ProtoNode(static_cast<proto_node*>(index.internalPointer())); return static_cast<ProtoNode*>(index.internalPointer());
} }
QModelIndex ProtoTreeModel::indexFromProtoNode(ProtoNode &index_node) const QModelIndex ProtoTreeModel::indexFromProtoNode(ProtoNode *index_node) const
{ {
int row = index_node.row(); if (!index_node) {
if (!index_node.isValid() || row < 0) {
return QModelIndex(); return QModelIndex();
} }
return createIndex(row, 0, static_cast<void *>(index_node.protoNode())); 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_ { struct find_hfid_ {
int hfid; int hfid;
ProtoNode node; ProtoNode *node;
}; };
void ProtoTreeModel::foreachFindHfid(proto_node *node, gpointer find_hfid_ptr) bool ProtoTreeModel::foreachFindHfid(ProtoNode *node, gpointer find_hfid_ptr)
{ {
struct find_hfid_ *find_hfid = (struct find_hfid_ *) find_hfid_ptr; struct find_hfid_ *find_hfid = (struct find_hfid_ *) find_hfid_ptr;
if (PNODE_FINFO(node)->hfinfo->id == find_hfid->hfid) { if (PNODE_FINFO(node->protoNode())->hfinfo->id == find_hfid->hfid) {
find_hfid->node = ProtoNode(node); find_hfid->node = node;
return; return true;
} }
proto_tree_children_foreach(node, foreachFindHfid, find_hfid); 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) QModelIndex ProtoTreeModel::findFirstHfid(int hf_id)
@ -196,9 +210,7 @@ QModelIndex ProtoTreeModel::findFirstHfid(int hf_id)
struct find_hfid_ find_hfid; struct find_hfid_ find_hfid;
find_hfid.hfid = hf_id; find_hfid.hfid = hf_id;
proto_tree_children_foreach(root_node_, foreachFindHfid, &find_hfid); if (foreachFindHfid(root_node_, &find_hfid) && find_hfid.node->isValid()) {
if (find_hfid.node.isValid()) {
return indexFromProtoNode(find_hfid.node); return indexFromProtoNode(find_hfid.node);
} }
return QModelIndex(); return QModelIndex();
@ -206,17 +218,22 @@ QModelIndex ProtoTreeModel::findFirstHfid(int hf_id)
struct find_field_info_ { struct find_field_info_ {
field_info *fi; field_info *fi;
ProtoNode node; ProtoNode *node;
}; };
void ProtoTreeModel::foreachFindField(proto_node *node, gpointer find_finfo_ptr) bool ProtoTreeModel::foreachFindField(ProtoNode *node, gpointer find_finfo_ptr)
{ {
struct find_field_info_ *find_finfo = (struct find_field_info_ *) find_finfo_ptr; struct find_field_info_ *find_finfo = (struct find_field_info_ *) find_finfo_ptr;
if (PNODE_FINFO(node) == find_finfo->fi) { if (PNODE_FINFO(node->protoNode()) == find_finfo->fi) {
find_finfo->node = ProtoNode(node); find_finfo->node = node;
return; return true;
} }
proto_tree_children_foreach(node, foreachFindField, find_finfo); for (int i = 0; i < node->childrenCount(); i++) {
if (foreachFindField(node->child(i), &find_finfo)) {
return true;
}
}
return false;
} }
QModelIndex ProtoTreeModel::findFieldInformation(FieldInformation *finfo) QModelIndex ProtoTreeModel::findFieldInformation(FieldInformation *finfo)
@ -228,8 +245,7 @@ QModelIndex ProtoTreeModel::findFieldInformation(FieldInformation *finfo)
struct find_field_info_ find_finfo; struct find_field_info_ find_finfo;
find_finfo.fi = fi; find_finfo.fi = fi;
proto_tree_children_foreach(root_node_, foreachFindField, &find_finfo); if (foreachFindField(root_node_, &find_finfo) && find_finfo.node->isValid()) {
if (find_finfo.node.isValid()) {
return indexFromProtoNode(find_finfo.node); return indexFromProtoNode(find_finfo.node);
} }
return QModelIndex(); return QModelIndex();

View File

@ -10,6 +10,7 @@
#ifndef PROTO_TREE_MODEL_H #ifndef PROTO_TREE_MODEL_H
#define PROTO_TREE_MODEL_H #define PROTO_TREE_MODEL_H
#include <ui/qt/utils/field_information.h>
#include <ui/qt/utils/proto_node.h> #include <ui/qt/utils/proto_node.h>
#include <QAbstractItemModel> #include <QAbstractItemModel>
@ -21,6 +22,7 @@ class ProtoTreeModel : public QAbstractItemModel
public: public:
explicit ProtoTreeModel(QObject * parent = 0); explicit ProtoTreeModel(QObject * parent = 0);
~ProtoTreeModel();
virtual Qt::ItemFlags flags(const QModelIndex &index) const; virtual Qt::ItemFlags flags(const QModelIndex &index) const;
QModelIndex index(int row, int, const QModelIndex &parent = QModelIndex()) const; QModelIndex index(int row, int, const QModelIndex &parent = QModelIndex()) const;
@ -31,16 +33,16 @@ public:
// root_node can be NULL. // root_node can be NULL.
void setRootNode(proto_node *root_node); void setRootNode(proto_node *root_node);
ProtoNode protoNodeFromIndex(const QModelIndex &index) const; ProtoNode* protoNodeFromIndex(const QModelIndex &index) const;
QModelIndex indexFromProtoNode(ProtoNode &index_node) const; QModelIndex indexFromProtoNode(ProtoNode *index_node) const;
QModelIndex findFirstHfid(int hf_id); QModelIndex findFirstHfid(int hf_id);
QModelIndex findFieldInformation(FieldInformation *finfo); QModelIndex findFieldInformation(FieldInformation *finfo);
private: private:
proto_node* root_node_; ProtoNode *root_node_;
static void foreachFindHfid(proto_node *node, gpointer find_hfid_ptr); static bool foreachFindHfid(ProtoNode *node, gpointer find_hfid_ptr);
static void foreachFindField(proto_node *node, gpointer find_finfo_ptr); static bool foreachFindField(ProtoNode *node, gpointer find_finfo_ptr);
}; };
#endif // PROTO_TREE_MODEL_H #endif // PROTO_TREE_MODEL_H

View File

@ -134,7 +134,7 @@ void ProtoTree::ctxCopyVisibleItems()
void ProtoTree::ctxCopyAsFilter() void ProtoTree::ctxCopyAsFilter()
{ {
QModelIndex idx = selectionModel()->selectedIndexes().first(); QModelIndex idx = selectionModel()->selectedIndexes().first();
FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(idx).protoNode()); FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(idx));
if (finfo.isValid()) if (finfo.isValid())
{ {
epan_dissect_t *edt = cap_file_ ? cap_file_->edt : edt_; epan_dissect_t *edt = cap_file_ ? cap_file_->edt : edt_;
@ -156,7 +156,7 @@ void ProtoTree::ctxCopySelectedInfo()
val = send->property("field_type").toInt(); val = send->property("field_type").toInt();
QModelIndex idx = selectionModel()->selectedIndexes().first(); QModelIndex idx = selectionModel()->selectedIndexes().first();
FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(idx).protoNode()); FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(idx));
if (! finfo.isValid()) if (! finfo.isValid())
return; return;
@ -194,7 +194,7 @@ void ProtoTree::ctxOpenUrlWiki()
if (send && send->property("field_reference").isValid()) if (send && send->property("field_reference").isValid())
is_field_reference = send->property("field_reference").toBool(); is_field_reference = send->property("field_reference").toBool();
QModelIndex idx = selectionModel()->selectedIndexes().first(); QModelIndex idx = selectionModel()->selectedIndexes().first();
FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(idx).protoNode()); FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(idx));
int field_id = finfo.headerInfo().id; int field_id = finfo.headerInfo().id;
if (!proto_registrar_is_protocol(field_id) && (field_id != hf_text_only)) { if (!proto_registrar_is_protocol(field_id) && (field_id != hf_text_only)) {
@ -250,7 +250,7 @@ void ProtoTree::contextMenuEvent(QContextMenuEvent *event)
QAction *action; QAction *action;
bool have_subtree = false; bool have_subtree = false;
FieldInformation *finfo = new FieldInformation(proto_tree_model_->protoNodeFromIndex(index).protoNode(), ctx_menu); FieldInformation *finfo = new FieldInformation(proto_tree_model_->protoNodeFromIndex(index), ctx_menu);
field_info * fi = finfo->fieldInfo(); field_info * fi = finfo->fieldInfo();
bool is_selected = false; bool is_selected = false;
epan_dissect_t *edt = cap_file_ ? cap_file_->edt : edt_; epan_dissect_t *edt = cap_file_ ? cap_file_->edt : edt_;
@ -376,9 +376,10 @@ void ProtoTree::contextMenuEvent(QContextMenuEvent *event)
// The "text only" header field will not give preferences for the selected protocol. // The "text only" header field will not give preferences for the selected protocol.
// Use parent in this case. // Use parent in this case.
proto_node *node = proto_tree_model_->protoNodeFromIndex(index).protoNode(); ProtoNode *node = proto_tree_model_->protoNodeFromIndex(index);
while (node && node->finfo && node->finfo->hfinfo && node->finfo->hfinfo->id == hf_text_only) while (node && node->isValid() && node->protoNode()->finfo && node->protoNode()->finfo->hfinfo && node->protoNode()->finfo->hfinfo->id == hf_text_only) {
node = node->parent; node = node->parentNode();
}
FieldInformation pref_finfo(node); FieldInformation pref_finfo(node);
proto_prefs_menu_.setModule(pref_finfo.moduleName()); proto_prefs_menu_.setModule(pref_finfo.moduleName());
@ -438,13 +439,8 @@ void ProtoTree::foreachTreeNode(proto_node *node, gpointer proto_tree_ptr)
return; return;
} }
// Expanded state // Related frames - there might be hidden FT_FRAMENUM nodes, so do this
if (tree_expanded(node->finfo->tree_type)) { // for each proto_node and not just the ProtoNodes in the model
ProtoNode expand_node = ProtoNode(node);
tree_view->expand(model->indexFromProtoNode(expand_node));
}
// Related frames
if (node->finfo->hfinfo->type == FT_FRAMENUM) { if (node->finfo->hfinfo->type == FT_FRAMENUM) {
ft_framenum_type_t framenum_type = (ft_framenum_type_t)GPOINTER_TO_INT(node->finfo->hfinfo->strings); ft_framenum_type_t framenum_type = (ft_framenum_type_t)GPOINTER_TO_INT(node->finfo->hfinfo->strings);
tree_view->emitRelatedFrame(node->finfo->value.value.uinteger, framenum_type); tree_view->emitRelatedFrame(node->finfo->value.value.uinteger, framenum_type);
@ -453,6 +449,23 @@ void ProtoTree::foreachTreeNode(proto_node *node, gpointer proto_tree_ptr)
proto_tree_children_foreach(node, foreachTreeNode, proto_tree_ptr); proto_tree_children_foreach(node, foreachTreeNode, proto_tree_ptr);
} }
void ProtoTree::foreachExpand(const QModelIndex &index = QModelIndex()) {
// Restore expanded state. (Note QModelIndex() refers to the root node)
int children = proto_tree_model_->rowCount(index);
QModelIndex childIndex;
for (int child = 0; child < children; child++) {
childIndex = proto_tree_model_->index(child, 0, index);
if (childIndex.isValid()) {
ProtoNode *node = proto_tree_model_->protoNodeFromIndex(childIndex);
if (node && node->isValid() && tree_expanded(node->protoNode()->finfo->tree_type)) {
expand(childIndex);
}
foreachExpand(childIndex);
}
}
}
// setRootNode sets the new contents for the protocol tree and subsequently // setRootNode sets the new contents for the protocol tree and subsequently
// restores the previously expanded state. // restores the previously expanded state.
void ProtoTree::setRootNode(proto_node *root_node) { void ProtoTree::setRootNode(proto_node *root_node) {
@ -463,6 +476,7 @@ void ProtoTree::setRootNode(proto_node *root_node) {
disconnect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(syncExpanded(QModelIndex))); disconnect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(syncExpanded(QModelIndex)));
proto_tree_children_foreach(root_node, foreachTreeNode, this); proto_tree_children_foreach(root_node, foreachTreeNode, this);
foreachExpand();
connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(syncExpanded(QModelIndex))); connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(syncExpanded(QModelIndex)));
updateContentWidth(); updateContentWidth();
@ -505,14 +519,14 @@ void ProtoTree::selectionChanged(const QItemSelection &selected, const QItemSele
// Find and highlight the protocol bytes. select above won't call // Find and highlight the protocol bytes. select above won't call
// selectionChanged if the current and selected indexes are the same // selectionChanged if the current and selected indexes are the same
// so we do this here. // so we do this here.
FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(index).protoNode(), this); FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(index), this);
if (finfo.isValid()) { if (finfo.isValid()) {
QModelIndex parent = index; QModelIndex parent = index;
while (parent.isValid() && parent.parent().isValid()) { while (parent.isValid() && parent.parent().isValid()) {
parent = parent.parent(); parent = parent.parent();
} }
if (parent.isValid()) { if (parent.isValid()) {
FieldInformation parent_finfo(proto_tree_model_->protoNodeFromIndex(parent).protoNode()); FieldInformation parent_finfo(proto_tree_model_->protoNodeFromIndex(parent));
finfo.setParentField(parent_finfo.fieldInfo()); finfo.setParentField(parent_finfo.fieldInfo());
} }
emit fieldSelected(&finfo); emit fieldSelected(&finfo);
@ -520,7 +534,7 @@ void ProtoTree::selectionChanged(const QItemSelection &selected, const QItemSele
} }
void ProtoTree::syncExpanded(const QModelIndex &index) { void ProtoTree::syncExpanded(const QModelIndex &index) {
FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(index).protoNode()); FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(index));
if (!finfo.isValid()) return; if (!finfo.isValid()) return;
/* /*
@ -533,7 +547,7 @@ void ProtoTree::syncExpanded(const QModelIndex &index) {
} }
void ProtoTree::syncCollapsed(const QModelIndex &index) { void ProtoTree::syncCollapsed(const QModelIndex &index) {
FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(index).protoNode()); FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(index));
if (!finfo.isValid()) return; if (!finfo.isValid()) return;
/* /*
@ -612,7 +626,7 @@ void ProtoTree::itemClicked(const QModelIndex &index)
if (selectionModel()->selectedIndexes().isEmpty()) { if (selectionModel()->selectedIndexes().isEmpty()) {
emit fieldSelected(0); emit fieldSelected(0);
} else if (index == selectionModel()->selectedIndexes().first()) { } else if (index == selectionModel()->selectedIndexes().first()) {
FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(index).protoNode()); FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(index));
if (finfo.isValid()) { if (finfo.isValid()) {
emit fieldSelected(&finfo); emit fieldSelected(&finfo);
@ -622,7 +636,7 @@ void ProtoTree::itemClicked(const QModelIndex &index)
void ProtoTree::itemDoubleClicked(const QModelIndex &index) void ProtoTree::itemDoubleClicked(const QModelIndex &index)
{ {
FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(index).protoNode()); FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(index));
if (!finfo.isValid()) return; if (!finfo.isValid()) return;
if (finfo.headerInfo().type == FT_FRAMENUM) { if (finfo.headerInfo().type == FT_FRAMENUM) {
@ -679,7 +693,7 @@ void ProtoTree::saveSelectedField(QModelIndex &index)
selected_hfid_path_.clear(); selected_hfid_path_.clear();
QModelIndex save_index = index; QModelIndex save_index = index;
while (save_index.isValid()) { while (save_index.isValid()) {
FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(save_index).protoNode()); FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(save_index));
if (!finfo.isValid()) break; if (!finfo.isValid()) break;
selected_hfid_path_.prepend(QPair<int,int>(save_index.row(), finfo.headerInfo().id)); selected_hfid_path_.prepend(QPair<int,int>(save_index.row(), finfo.headerInfo().id));
save_index = save_index.parent(); save_index = save_index.parent();
@ -697,7 +711,7 @@ void ProtoTree::restoreSelectedField()
int row = path_entry.first; int row = path_entry.first;
int hf_id = path_entry.second; int hf_id = path_entry.second;
cur_index = proto_tree_model_->index(row, 0, cur_index); cur_index = proto_tree_model_->index(row, 0, cur_index);
FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(cur_index).protoNode()); FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(cur_index));
if (!finfo.isValid() || finfo.headerInfo().id != hf_id) { if (!finfo.isValid() || finfo.headerInfo().id != hf_id) {
// Did not find the selected hfid path in the selected packet // Did not find the selected hfid path in the selected packet
cur_index = QModelIndex(); cur_index = QModelIndex();
@ -780,7 +794,7 @@ bool ProtoTree::eventFilter(QObject * obj, QEvent * event)
> QApplication::startDragDistance()) > QApplication::startDragDistance())
{ {
QModelIndex idx = indexAt(drag_start_position_); QModelIndex idx = indexAt(drag_start_position_);
FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(idx).protoNode()); FieldInformation finfo(proto_tree_model_->protoNodeFromIndex(idx));
if (finfo.isValid()) if (finfo.isValid())
{ {
/* Hack to prevent QItemSelection taking the item which has been dragged over at start /* Hack to prevent QItemSelection taking the item which has been dragged over at start

View File

@ -71,6 +71,7 @@ private:
void saveSelectedField(QModelIndex &index); void saveSelectedField(QModelIndex &index);
static void foreachTreeNode(proto_node *node, gpointer proto_tree_ptr); static void foreachTreeNode(proto_node *node, gpointer proto_tree_ptr);
void foreachExpand(const QModelIndex &index);
signals: signals:
void fieldSelected(FieldInformation *); void fieldSelected(FieldInformation *);

View File

@ -18,12 +18,12 @@ FieldInformation::FieldInformation(field_info *fi, QObject * parent)
parent_fi_ = NULL; parent_fi_ = NULL;
} }
FieldInformation::FieldInformation(proto_node *node, QObject * parent) FieldInformation::FieldInformation(ProtoNode *node, QObject * parent)
:QObject(parent) :QObject(parent)
{ {
fi_ = NULL; fi_ = NULL;
if (node) { if (node && node->isValid()) {
fi_ = node->finfo; fi_ = node->protoNode()->finfo;
} }
parent_fi_ = NULL; parent_fi_ = NULL;
} }

View File

@ -14,6 +14,7 @@
#include <epan/proto.h> #include <epan/proto.h>
#include <ui/qt/utils/proto_node.h>
#include "data_printer.h" #include "data_printer.h"
#include <QObject> #include <QObject>
@ -43,7 +44,7 @@ public:
}; };
explicit FieldInformation(field_info * fi, QObject * parent = Q_NULLPTR); explicit FieldInformation(field_info * fi, QObject * parent = Q_NULLPTR);
explicit FieldInformation(proto_node * node, QObject * parent = Q_NULLPTR); explicit FieldInformation(ProtoNode * node, QObject * parent = Q_NULLPTR);
bool isValid() const; bool isValid() const;
bool isLink() const ; bool isLink() const ;

View File

@ -8,12 +8,35 @@
*/ */
#include <ui/qt/utils/proto_node.h> #include <ui/qt/utils/proto_node.h>
#include <ui/qt/utils/field_information.h>
#include <epan/prefs.h> #include <epan/prefs.h>
ProtoNode::ProtoNode(proto_node *node) : ProtoNode::ProtoNode(proto_node *node, ProtoNode *parent) :
node_(node) node_(node), parent_(parent)
{ {
if (node_) {
int num_children = 0;
for (proto_node *child = node_->first_child; child; child = child->next) {
if (!isHidden(child)) {
num_children++;
}
}
m_children.reserve(num_children);
for (proto_node *child = node_->first_child; child; child = child->next) {
if (!isHidden(child)) {
m_children.append(new ProtoNode(child, this));
}
}
}
}
ProtoNode::~ProtoNode()
{
qDeleteAll(m_children);
} }
bool ProtoNode::isValid() const bool ProtoNode::isValid() const
@ -26,12 +49,9 @@ bool ProtoNode::isChild() const
return node_ && node_->parent; return node_ && node_->parent;
} }
ProtoNode ProtoNode::parentNode() ProtoNode* ProtoNode::parentNode()
{ {
if (node_) { return parent_;
return ProtoNode(node_->parent);
}
return ProtoNode(NULL);
} }
QString ProtoNode::labelText() const QString ProtoNode::labelText() const
@ -71,15 +91,7 @@ int ProtoNode::childrenCount() const
{ {
if (!node_) return 0; if (!node_) return 0;
int row_count = 0; return (int)m_children.count();
ChildIterator kids = children();
while (kids.element().isValid())
{
row_count++;
kids.next();
}
return row_count;
} }
int ProtoNode::row() int ProtoNode::row()
@ -88,20 +100,7 @@ int ProtoNode::row()
return -1; return -1;
} }
int cur_row = 0; return (int)parent_->m_children.indexOf(const_cast<ProtoNode*>(this));
ProtoNode::ChildIterator kids = parentNode().children();
while (kids.element().isValid())
{
if (kids.element().protoNode() == node_) {
break;
}
cur_row++;
kids.next();
}
if (! kids.element().isValid()) {
return -1;
}
return cur_row;
} }
bool ProtoNode::isExpanded() const bool ProtoNode::isExpanded() const
@ -117,8 +116,17 @@ proto_node * ProtoNode::protoNode() const
return node_; return node_;
} }
ProtoNode* ProtoNode::child(int row)
{
if (row < 0 || row >= m_children.size())
return nullptr;
return m_children.at(row);
}
ProtoNode::ChildIterator ProtoNode::children() const ProtoNode::ChildIterator ProtoNode::children() const
{ {
/* XXX: Iterate over m_children instead?
* Somewhat faster as m_children already excludes any hidden items. */
proto_node *child = node_->first_child; proto_node *child = node_->first_child;
while (child && isHidden(child)) { while (child && isHidden(child)) {
child = child->next; child = child->next;

View File

@ -12,7 +12,9 @@
#include <config.h> #include <config.h>
#include <ui/qt/utils/field_information.h> #include <epan/proto.h>
#include <QObject>
class ProtoNode class ProtoNode
{ {
@ -32,16 +34,18 @@ public:
NodePtr node; NodePtr node;
}; };
explicit ProtoNode(proto_node * node = NULL); explicit ProtoNode(proto_node * node = NULL, ProtoNode *parent = nullptr);
~ProtoNode();
bool isValid() const; bool isValid() const;
bool isChild() const; bool isChild() const;
bool isExpanded() const; bool isExpanded() const;
proto_node *protoNode() const; proto_node *protoNode() const;
ProtoNode *child(int row);
int childrenCount() const; int childrenCount() const;
int row(); int row();
ProtoNode parentNode(); ProtoNode *parentNode();
QString labelText() const; QString labelText() const;
@ -49,6 +53,8 @@ public:
private: private:
proto_node * node_; proto_node * node_;
QVector<ProtoNode*>m_children;
ProtoNode *parent_;
static bool isHidden(proto_node * node); static bool isHidden(proto_node * node);
}; };