aboutsummaryrefslogtreecommitdiffstats
path: root/ui/qt/proto_tree.cpp
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2017-03-31 01:06:07 +0200
committerPeter Wu <peter@lekensteyn.nl>2017-04-07 08:51:30 +0000
commitb9b5703a41a52d9494c0179e42bbf5c62c7dcb05 (patch)
tree9aaa5320880acd66b9a850ad49d94a561dafed2d /ui/qt/proto_tree.cpp
parent438459183bebf650ba05bf1c3b4aa69ba0b011e6 (diff)
Qt: Remember exact position of selected item in tree
When switching between packets, the first field at a level would be selected. This is annoying if you have similarly structured trees (like TLVs or text labels). Combined with something like bug 13533, this causes erratic jumping. Fix this by incorporating the level position in the path. Change-Id: I998853ce899fffc69dd4932902508141325c35a4 Ping-Bug: 13533 Reviewed-on: https://code.wireshark.org/review/20799 Petri-Dish: Peter Wu <peter@lekensteyn.nl> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Diffstat (limited to 'ui/qt/proto_tree.cpp')
-rw-r--r--ui/qt/proto_tree.cpp48
1 files changed, 45 insertions, 3 deletions
diff --git a/ui/qt/proto_tree.cpp b/ui/qt/proto_tree.cpp
index 32c73e4085..177383d616 100644
--- a/ui/qt/proto_tree.cpp
+++ b/ui/qt/proto_tree.cpp
@@ -603,16 +603,58 @@ void ProtoTree::selectField(field_info *fi)
}
}
+// Finds position item at a level, counting only similar fields.
+static unsigned indexOfField(QTreeWidgetItem *item, header_field_info *hfi)
+{
+ QTreeWidgetItem *parent = item->parent();
+ unsigned pos = 0;
+ if (!parent) {
+ // In case multiple top-level layers are present for the same protocol,
+ // try to find its position (this will likely be the first match, zero).
+ QTreeWidget *tree = item->treeWidget();
+ for (int i = 0; i < tree->topLevelItemCount(); i++) {
+ QTreeWidgetItem *current = tree->topLevelItem(i);
+ if (current == item) {
+ return pos;
+ }
+ if (hfi == VariantPointer<field_info>::asPtr(current->data(0, Qt::UserRole))->hfinfo) {
+ pos++;
+ }
+ }
+ } else {
+ QTreeWidgetItemIterator iter(parent);
+ while (*iter) {
+ QTreeWidgetItem *current = *iter;
+ if (current == item) {
+ return pos;
+ }
+ if (hfi == VariantPointer<field_info>::asPtr(current->data(0, Qt::UserRole))->hfinfo) {
+ pos++;
+ }
+ ++iter;
+ }
+ }
+ // should not happen (child is not found at parent?!)
+ return 0;
+}
+
+// Assume about 2^8 items in tree and 2^24 different registered fields.
+// If there are more of each, then a collision may occur, but since the full
+// path is matched this is unlikely to be a problem.
+#define POS_SHIFT 24
+#define POS_MASK (((unsigned)-1) << POS_SHIFT)
+
// Remember the currently focussed field based on:
// - current hf_id (obviously)
// - parent items (to avoid selecting a text item in a different tree)
-// - position within a tree if there are multiple items (wishlist)
+// - position within a tree if there are multiple items
static QList<int> serializeAsPath(QTreeWidgetItem *item)
{
QList<int> path;
do {
field_info *fi = VariantPointer<field_info>::asPtr(item->data(0, Qt::UserRole));
- path.prepend(fi->hfinfo->id);
+ unsigned pos = indexOfField(item, fi->hfinfo);
+ path.prepend((pos << POS_SHIFT) | (fi->hfinfo->id & ~POS_MASK));
} while ((item = item->parent()));
return path;
}
@@ -627,7 +669,7 @@ void ProtoTree::restoreSelectedField()
if (selected_field_path_.isEmpty()) {
return;
}
- int last_hf_id = selected_field_path_.last();
+ int last_hf_id = selected_field_path_.last() & ~POS_MASK;
QTreeWidgetItemIterator iter(this);
while (*iter) {
field_info *fi = VariantPointer<field_info>::asPtr((*iter)->data(0, Qt::UserRole));