/* proto_tree_model.c * * Wireshark - Network traffic analyzer * By Gerald Combs * 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 */ #include "config.h" #include #include #include #include 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; gboolean resolv_forced; e_addr_resolve resolv_flags; }; #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 = (proto_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 = (proto_node *)iter->user_data; fi = PNODE_FINFO(node); /* dissection with an invisible proto tree? */ g_assert(fi); switch (column) { case 0: { g_value_init(value, G_TYPE_STRING); if (model->resolv_forced) { e_addr_resolve old_flags = gbl_resolv_flags; gbl_resolv_flags = model->resolv_flags; g_value_take_string(value, fi_get_string(fi)); gbl_resolv_flags = old_flags; } else 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 = (proto_node *)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 = (proto_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 = (proto_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 = (proto_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 = (proto_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; } void proto_tree_model_force_resolv(ProtoTreeModel *model, const e_addr_resolve *flags) { model->resolv_forced = TRUE; model->resolv_flags = *flags; } 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; model->resolv_forced = FALSE; return model; } /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 8 * tab-width: 8 * indent-tabs-mode: t * End: * * vi: set shiftwidth=8 tabstop=8 noexpandtab: * :indentSize=8:tabSize=8:noTabs=false: */