diff options
author | Jakub Zawadzki <darkjames-ws@darkjames.pl> | 2012-06-10 22:07:54 +0000 |
---|---|---|
committer | Jakub Zawadzki <darkjames-ws@darkjames.pl> | 2012-06-10 22:07:54 +0000 |
commit | f372010ee83aa3438f633d38c7d8e46516c1ab7b (patch) | |
tree | d72f197e9919300f5671b1fb734144c8c03639f8 /ui/gtk/proto_tree_model.c | |
parent | a2bb94c3b33d53f42534aceb7cc67aab1d1fb1f9 (diff) |
Custom model for packet details
Original patch tracked in bug #7224
svn path=/trunk/; revision=43189
Diffstat (limited to 'ui/gtk/proto_tree_model.c')
-rw-r--r-- | ui/gtk/proto_tree_model.c | 455 |
1 files changed, 455 insertions, 0 deletions
diff --git a/ui/gtk/proto_tree_model.c b/ui/gtk/proto_tree_model.c new file mode 100644 index 0000000000..66ecc0aacf --- /dev/null +++ b/ui/gtk/proto_tree_model.c @@ -0,0 +1,455 @@ +/* proto_tree_model.c + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +/* This code was originally based on the GTK+ Tree View tutorial at + * http://scentric.net/tutorial */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include <gtk/gtk.h> +#include <glib.h> + +#include <epan/proto.h> + +static GObjectClass *parent_class = NULL; + +typedef struct { + GObjectClass parent_class; + +} ProtoTreeModelClass; + +struct proto_tree_model { + GObject parent; /** MUST be first */ + + /** Random integer to check whether an iter belongs to our model. */ + gint stamp; + + proto_tree *protocol_tree; + int with_hidden; +}; + +#include "proto_tree_model.h" + +static GtkTreeModelFlags +proto_tree_model_get_flags(GtkTreeModel *tree_model) +{ + g_return_val_if_fail(PROTO_IS_TREE(tree_model), (GtkTreeModelFlags)0); + + return GTK_TREE_MODEL_ITERS_PERSIST; +} + +static gint +proto_tree_model_get_n_columns(GtkTreeModel *tree_model) +{ + g_return_val_if_fail(PROTO_IS_TREE(tree_model), 0); + + return 2; +} + +static GType +proto_tree_model_get_column_type(GtkTreeModel *tree_model, gint idx) +{ + g_return_val_if_fail(PROTO_IS_TREE(tree_model), G_TYPE_INVALID); + g_return_val_if_fail(idx == 0 || idx == 1, G_TYPE_INVALID); + + switch (idx) { + case 0: + return G_TYPE_STRING; + case 1: + return G_TYPE_POINTER; + } + /* never here */ + return G_TYPE_INVALID; +} + +static gboolean +proto_tree_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n) +{ + ProtoTreeModel *model; + proto_node *node; + + g_return_val_if_fail(PROTO_IS_TREE(tree_model), FALSE); + model = (ProtoTreeModel *) tree_model; + + if (parent) { + g_return_val_if_fail(parent->stamp == model->stamp, FALSE); + node = parent->user_data; + } else + node = model->protocol_tree; + + if (!node) + return FALSE; + + node = node->first_child; + while (node != NULL) { + if (model->with_hidden || !PROTO_ITEM_IS_HIDDEN(node)) { + if (!n) + break; + n--; + } + node = node->next; + } + + /* not found? */ + if (!node) + return FALSE; + + iter->stamp = model->stamp; + iter->user_data = node; + return TRUE; +} + +static gboolean +proto_tree_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path) +{ + gint *indices, depth; + + g_assert(PROTO_IS_TREE(tree_model)); + g_assert(path != NULL); + + indices = gtk_tree_path_get_indices(path); + depth = gtk_tree_path_get_depth(path); + + g_return_val_if_fail(depth > 0, FALSE); + + if (!proto_tree_model_iter_nth_child(tree_model, iter, NULL, indices[0])) + return FALSE; + + while (--depth) { + indices++; + if (!proto_tree_model_iter_nth_child(tree_model, iter, iter, *indices)) + return FALSE; + } + return TRUE; +} + +static char * +fi_get_string(field_info *fi) +{ + gchar label_str[ITEM_LABEL_LENGTH]; + gchar *label_ptr; + + if (!fi->rep) { + label_ptr = label_str; + proto_item_fill_label(fi, label_str); + } else + label_ptr = fi->rep->representation; + + if (FI_GET_FLAG(fi, FI_GENERATED)) { + if (FI_GET_FLAG(fi, FI_HIDDEN)) + label_ptr = g_strdup_printf("<[%s]>", label_ptr); + else + label_ptr = g_strdup_printf("[%s]", label_ptr); + + } else if (FI_GET_FLAG(fi, FI_HIDDEN)) + label_ptr = g_strdup_printf("<%s>", label_ptr); + else + label_ptr = g_strdup(label_ptr); + + return label_ptr; +} + +static void +proto_tree_model_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value) +{ + ProtoTreeModel *model; + proto_node *node; + field_info *fi; + + g_return_if_fail(PROTO_IS_TREE(tree_model)); + model = (ProtoTreeModel *) tree_model; + + g_return_if_fail(iter != NULL); + g_return_if_fail(iter->stamp == model->stamp); + g_return_if_fail(column == 0 || column == 1); + + node = iter->user_data; + fi = PNODE_FINFO(node); + + g_assert(fi && "dissection with an invisible proto tree?"); + + switch (column) { + case 0: + g_value_init(value, G_TYPE_STRING); + g_value_take_string(value, fi_get_string(fi)); + break; + + case 1: + g_value_init(value, G_TYPE_POINTER); + g_value_set_pointer(value, fi); + break; + } +} + +static gboolean +proto_tree_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter) +{ + ProtoTreeModel *model; + proto_node *current; + + g_return_val_if_fail(PROTO_IS_TREE(tree_model), FALSE); + model = (ProtoTreeModel *) tree_model; + + g_return_val_if_fail(iter->stamp == model->stamp, FALSE); + + current = iter->user_data; + current = current->next; + while (current) { + if (model->with_hidden || !PROTO_ITEM_IS_HIDDEN(current)) { + iter->user_data = current; + return TRUE; + } + current = current->next; + } + return FALSE; +} + +static gboolean +proto_tree_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) +{ + return proto_tree_model_iter_nth_child(tree_model, iter, parent, 0); +} + +static gint +proto_tree_model_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter) +{ + ProtoTreeModel *model; + proto_node *node; + gint count; + + g_return_val_if_fail(PROTO_IS_TREE(tree_model), 0); + model = (ProtoTreeModel *) tree_model; + + g_return_val_if_fail(iter == NULL || iter->user_data != NULL, 0); + + if (iter) { + g_return_val_if_fail(iter->stamp == model->stamp, 0); + node = iter->user_data; + } else + node = model->protocol_tree; + + if (!node) + return 0; + + count = 0; + node = node->first_child; + while (node != NULL) { + if (model->with_hidden || !PROTO_ITEM_IS_HIDDEN(node)) + count++; + node = node->next; + } + return count; +} + +static GtkTreePath * +proto_tree_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter) +{ + ProtoTreeModel *model; + GtkTreePath *path; + proto_node *node; + + g_return_val_if_fail(PROTO_IS_TREE(tree_model), NULL); + model = (ProtoTreeModel *) tree_model; + + g_return_val_if_fail(iter != NULL, NULL); + g_return_val_if_fail(iter->stamp == model->stamp, NULL); + + node = iter->user_data; + g_return_val_if_fail(node != model->protocol_tree, NULL); + + path = gtk_tree_path_new(); + do { + proto_node *cur = node; + proto_node *node_i; + int pos; + + node = node->parent; + + pos = 0; + for (node_i = node->first_child; node_i; node_i = node_i->next) { + if (model->with_hidden || !PROTO_ITEM_IS_HIDDEN(node_i)) { + if (node_i == cur) + break; + pos++; + } + } + + g_assert(node_i != NULL); + gtk_tree_path_prepend_index(path, pos); + } while (node != model->protocol_tree); + + return path; +} + +static gboolean +proto_tree_model_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter) +{ + /* optimized version of: + * return proto_tree_model_iter_n_children(tree_model, iter) != 0; + * synchronize when changed! + */ + ProtoTreeModel *model; + proto_node *node; + + g_return_val_if_fail(PROTO_IS_TREE(tree_model), FALSE); + model = (ProtoTreeModel *) tree_model; + + g_return_val_if_fail(iter == NULL || iter->user_data != NULL, FALSE); + + if (iter) { + g_return_val_if_fail(iter->stamp == model->stamp, FALSE); + node = iter->user_data; + } else + node = model->protocol_tree; + + if (!node) + return FALSE; + + node = node->first_child; + while (node != NULL) { + if (model->with_hidden || !PROTO_ITEM_IS_HIDDEN(node)) + return TRUE; + node = node->next; + } + return FALSE; +} + +static gboolean +proto_tree_model_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) +{ + ProtoTreeModel *model; + proto_node *node; + + g_return_val_if_fail(PROTO_IS_TREE(tree_model), FALSE); + model = (ProtoTreeModel *) tree_model; + + g_return_val_if_fail(iter != NULL, FALSE); + g_return_val_if_fail(child->stamp == model->stamp, FALSE); + + node = child->user_data; + if (node->parent == model->protocol_tree) + return FALSE; + g_return_val_if_fail(node->parent != NULL, FALSE); + iter->stamp = model->stamp; + iter->user_data = node->parent; + return TRUE; +} + +static void +proto_tree_model_tree_init(GtkTreeModelIface *iface) +{ + iface->get_flags = proto_tree_model_get_flags; + iface->get_n_columns = proto_tree_model_get_n_columns; + iface->get_column_type = proto_tree_model_get_column_type; + iface->get_iter = proto_tree_model_get_iter; + iface->get_path = proto_tree_model_get_path; + iface->get_value = proto_tree_model_get_value; + iface->iter_next = proto_tree_model_iter_next; + iface->iter_children = proto_tree_model_iter_children; + iface->iter_has_child = proto_tree_model_iter_has_child; + iface->iter_n_children = proto_tree_model_iter_n_children; + iface->iter_nth_child = proto_tree_model_iter_nth_child; + iface->iter_parent = proto_tree_model_iter_parent; +} + +static void +proto_tree_model_init(ProtoTreeModel *model) +{ + /* To check whether an iter belongs to our model. */ + model->stamp = g_random_int(); +} + +static void +_class_finalize(GObject *object) +{ + /* must chain up - finalize parent */ + (*parent_class->finalize)(object); +} + +static void +proto_tree_model_class_init(ProtoTreeModelClass *klass) +{ + GObjectClass *object_class; + + parent_class = (GObjectClass*) g_type_class_peek_parent(klass); + object_class = (GObjectClass*) klass; + + object_class->finalize = _class_finalize; +} + +GType +proto_tree_model_get_type(void) +{ + static GType proto_tree_type = 0; + + if (proto_tree_type == 0) { + static const GTypeInfo proto_tree_info = { + sizeof(ProtoTreeModelClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) proto_tree_model_class_init, + NULL, /* class finalize */ + NULL, /* class_data */ + sizeof(ProtoTreeModel), + 0, /* n_preallocs */ + (GInstanceInitFunc) proto_tree_model_init, + NULL /* value_table */ + }; + + static const GInterfaceInfo tree_model_info = { + (GInterfaceInitFunc) proto_tree_model_tree_init, + NULL, + NULL + }; + + /* Register the new derived type with the GObject type system */ + proto_tree_type = g_type_register_static(G_TYPE_OBJECT, + "ProtoTreeModel", + &proto_tree_info, + (GTypeFlags)0); + + g_type_add_interface_static(proto_tree_type, + GTK_TYPE_TREE_MODEL, + &tree_model_info); + } + return proto_tree_type; +} + +ProtoTreeModel * +proto_tree_model_new(proto_tree *protocol_tree, int display_hidden_proto_items) +{ + ProtoTreeModel *model; + + model = (ProtoTreeModel *) g_object_new(PROTO_TYPE_TREE, NULL); + + g_assert(model != NULL); + model->protocol_tree = protocol_tree; + model->with_hidden = display_hidden_proto_items; + + return model; +} |