extra: fix values_fit_type()
[smatch.git] / ast-model.c
blob704c487806770cf374cb9f5a09eb8b730741155f
1 /*
2 * ast-model.c
4 * A custom tree model to simplify viewing of AST objects.
5 * Modify from the Gtk+ tree view tutorial, custom-list.c
6 * by Tim-Philipp Mueller < tim at centricular dot net >
8 * Copyright (C) 2010 Christopher Li
9 */
12 #include "ast-model.h"
13 #include "stdint.h"
15 /* boring declarations of local functions */
17 static void ast_init(AstNode *pkg_tree);
18 static void ast_class_init(AstNodeClass *klass);
19 static void ast_tree_model_init(GtkTreeModelIface *iface);
20 static void ast_finalize(GObject *object);
21 static GtkTreeModelFlags ast_get_flags(GtkTreeModel *tree_model);
22 static gint ast_get_n_columns(GtkTreeModel *tree_model);
23 static GType ast_get_column_type(GtkTreeModel *tree_model, gint index);
24 static gboolean ast_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter,
25 GtkTreePath *path);
26 static GtkTreePath *ast_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter);
27 static void ast_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter,
28 gint column, GValue *value);
29 static gboolean ast_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter);
30 static gboolean ast_iter_children(GtkTreeModel *tree_model,
31 GtkTreeIter *iter,
32 GtkTreeIter *parent);
33 static gboolean ast_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter);
34 static gint ast_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter);
35 static gboolean ast_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter,
36 GtkTreeIter *parent, gint n);
37 static gboolean ast_iter_parent(GtkTreeModel *tree_model,
38 GtkTreeIter *iter,
39 GtkTreeIter *child);
41 static GObjectClass *parent_class = NULL; /* GObject stuff - nothing to worry about */
43 static inline
44 void inspect_child_node(AstNode *node)
46 if (node->inspect) {
47 node->inspect(node);
48 node->inspect = NULL;
53 static inline
54 AstNode* ast_nth_child(AstNode *node, int n)
56 if (!node)
57 return NULL;
59 inspect_child_node(node);
61 if (n >= node->childnodes->len)
62 return FALSE;
63 return g_array_index(node->childnodes, AstNode *, n);
67 static inline
68 gboolean ast_set_iter(GtkTreeIter *iter, AstNode *node)
70 iter->user_data = node;
71 iter->user_data2 = iter->user_data3 = NULL;
72 return node != NULL;
76 /*****************************************************************************
78 * ast_get_type: here we register our new type and its interfaces
79 * with the type system. If you want to implement
80 * additional interfaces like GtkTreeSortable, you
81 * will need to do it here.
83 *****************************************************************************/
85 GType
86 ast_get_type (void)
88 static GType ast_type = 0;
89 static const GTypeInfo ast_info = {
90 sizeof (AstNodeClass),
91 NULL, /* base_init */
92 NULL, /* base_finalize */
93 (GClassInitFunc) ast_class_init,
94 NULL, /* class finalize */
95 NULL, /* class_data */
96 sizeof (AstNode),
97 0, /* n_preallocs */
98 (GInstanceInitFunc) ast_init
100 static const GInterfaceInfo tree_model_info = {
101 (GInterfaceInitFunc) ast_tree_model_init,
102 NULL,
103 NULL
108 if (ast_type)
109 return ast_type;
111 /* Some boilerplate type registration stuff */
112 ast_type = g_type_register_static(G_TYPE_OBJECT, "AstNode",
113 &ast_info, (GTypeFlags)0);
115 /* Here we register our GtkTreeModel interface with the type system */
116 g_type_add_interface_static(ast_type, GTK_TYPE_TREE_MODEL, &tree_model_info);
118 return ast_type;
122 /*****************************************************************************
124 * ast_class_init: more boilerplate GObject/GType stuff.
125 * Init callback for the type system,
126 * called once when our new class is created.
128 *****************************************************************************/
130 static void
131 ast_class_init (AstNodeClass *klass)
133 GObjectClass *object_class;
135 parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
136 object_class = (GObjectClass*) klass;
138 object_class->finalize = ast_finalize;
141 /*****************************************************************************
143 * ast_tree_model_init: init callback for the interface registration
144 * in ast_get_type. Here we override
145 * the GtkTreeModel interface functions that
146 * we implement.
148 *****************************************************************************/
150 static void
151 ast_tree_model_init (GtkTreeModelIface *iface)
153 iface->get_flags = ast_get_flags;
154 iface->get_n_columns = ast_get_n_columns;
155 iface->get_column_type = ast_get_column_type;
156 iface->get_iter = ast_get_iter;
157 iface->get_path = ast_get_path;
158 iface->get_value = ast_get_value;
159 iface->iter_next = ast_iter_next;
160 iface->iter_children = ast_iter_children;
161 iface->iter_has_child = ast_iter_has_child;
162 iface->iter_n_children = ast_iter_n_children;
163 iface->iter_nth_child = ast_iter_nth_child;
164 iface->iter_parent = ast_iter_parent;
168 /*****************************************************************************
170 * ast_init: this is called every time a new ast node object
171 * instance is created (we do that in ast_new).
172 * Initialise the list structure's fields here.
174 *****************************************************************************/
176 static void
177 ast_init (AstNode *node)
179 node->childnodes = g_array_new(FALSE, TRUE, sizeof(AstNode *));
180 node->stamp = g_random_int(); /* Random int to check whether iters belong to out model */
184 /*****************************************************************************
186 * ast_finalize: this is called just before an ast node is
187 * destroyed. Free dynamically allocated memory here.
189 *****************************************************************************/
191 static void
192 ast_finalize (GObject *object)
194 /* AstNode *node = AST_NODE(object); */
196 /* FIXME: free all node memory */
198 /* must chain up - finalize parent */
199 (* parent_class->finalize) (object);
203 /*****************************************************************************
205 * ast_get_flags: tells the rest of the world whether our tree model
206 * has any special characteristics. In our case,
207 * we have a list model (instead of a tree), and each
208 * tree iter is valid as long as the row in question
209 * exists, as it only contains a pointer to our struct.
211 *****************************************************************************/
213 static GtkTreeModelFlags
214 ast_get_flags(GtkTreeModel *tree_model)
216 return (GTK_TREE_MODEL_ITERS_PERSIST);
220 /*****************************************************************************
222 * ast_get_n_columns: tells the rest of the world how many data
223 * columns we export via the tree model interface
225 *****************************************************************************/
227 static gint
228 ast_get_n_columns(GtkTreeModel *tree_model)
230 return 1;
234 /*****************************************************************************
236 * ast_get_column_type: tells the rest of the world which type of
237 * data an exported model column contains
239 *****************************************************************************/
241 static GType
242 ast_get_column_type(GtkTreeModel *tree_model,
243 gint index)
245 return G_TYPE_STRING;
249 /*****************************************************************************
251 * ast_get_iter: converts a tree path (physical position) into a
252 * tree iter structure (the content of the iter
253 * fields will only be used internally by our model).
254 * We simply store a pointer to our AstNodeItem
255 * structure that represents that row in the tree iter.
257 *****************************************************************************/
259 static gboolean
260 ast_get_iter(GtkTreeModel *tree_model,
261 GtkTreeIter *iter,
262 GtkTreePath *path)
264 AstNode *node;
265 gint *indices, depth;
266 int i;
268 node = AST_NODE(tree_model);
269 indices = gtk_tree_path_get_indices(path);
270 depth = gtk_tree_path_get_depth(path);
272 for (i = 0; i < depth; i++)
273 node = ast_nth_child(node, indices[i]);
275 return ast_set_iter(iter, node);
279 /*****************************************************************************
281 * ast_get_path: converts a tree iter into a tree path (ie. the
282 * physical position of that row in the list).
284 *****************************************************************************/
286 static GtkTreePath *
287 ast_get_path(GtkTreeModel *tree_model,
288 GtkTreeIter *iter)
290 GtkTreePath *path;
291 AstNode *root = AST_NODE(tree_model);
292 AstNode *node = AST_NODE(iter->user_data);
294 path = gtk_tree_path_new();
295 while (node != root) {
296 gtk_tree_path_prepend_index(path, node->index);
297 node = node->parent;
299 return path;
303 /*****************************************************************************
305 * ast_get_value: Returns a row's exported data columns
306 * (_get_value is what gtk_tree_model_get uses)
308 *****************************************************************************/
310 static void
311 ast_get_value(GtkTreeModel *tree_model,
312 GtkTreeIter *iter,
313 gint column,
314 GValue *value)
316 AstNode *node = iter->user_data;
318 g_assert(AST_IS_NODE(tree_model));
319 if (column != 1)
320 return;
322 inspect_child_node(node);
324 g_value_init(value, G_TYPE_STRING);
325 g_value_set_string(value, node->text);
326 return;
330 /*****************************************************************************
332 * ast_iter_next: Takes an iter structure and sets it to point
333 * to the next row.
335 *****************************************************************************/
337 static gboolean
338 ast_iter_next(GtkTreeModel *tree_model,
339 GtkTreeIter *iter)
341 AstNode *node = iter->user_data;
343 g_assert(AST_IS_NODE (tree_model));
345 node = ast_nth_child(node->parent, node->index + 1);
346 return ast_set_iter(iter, node);
350 /*****************************************************************************
352 * ast_iter_children: Returns TRUE or FALSE depending on whether
353 * the row specified by 'parent' has any children.
354 * If it has children, then 'iter' is set to
355 * point to the first child. Special case: if
356 * 'parent' is NULL, then the first top-level
357 * row should be returned if it exists.
359 *****************************************************************************/
361 static gboolean
362 ast_iter_children(GtkTreeModel *tree_model,
363 GtkTreeIter *iter,
364 GtkTreeIter *parent)
366 return ast_iter_nth_child(tree_model, iter, parent, 0);
370 /*****************************************************************************
372 * ast_iter_has_child: Returns TRUE or FALSE depending on whether
373 * the row specified by 'iter' has any children.
374 * We only have a list and thus no children.
376 *****************************************************************************/
378 static gboolean
379 ast_iter_has_child (GtkTreeModel *tree_model,
380 GtkTreeIter *iter)
382 AstNode *node = iter->user_data;
383 inspect_child_node(node);
384 return node->childnodes->len > 0;
388 /*****************************************************************************
390 * ast_iter_n_children: Returns the number of children the row
391 * specified by 'iter' has. This is usually 0,
392 * as we only have a list and thus do not have
393 * any children to any rows. A special case is
394 * when 'iter' is NULL, in which case we need
395 * to return the number of top-level node,
396 * ie. the number of rows in our list.
398 *****************************************************************************/
400 static gint
401 ast_iter_n_children (GtkTreeModel *tree_model,
402 GtkTreeIter *iter)
404 AstNode *node = iter->user_data;
406 inspect_child_node(node);
407 return node->childnodes->len;
411 /*****************************************************************************
413 * ast_iter_nth_child: If the row specified by 'parent' has any
414 * children, set 'iter' to the n-th child and
415 * return TRUE if it exists, otherwise FALSE.
416 * A special case is when 'parent' is NULL, in
417 * which case we need to set 'iter' to the n-th
418 * row if it exists.
420 *****************************************************************************/
422 static gboolean
423 ast_iter_nth_child(GtkTreeModel *tree_model,
424 GtkTreeIter *iter,
425 GtkTreeIter *parent,
426 gint n)
428 AstNode *node = parent ? parent->user_data : (AstNode*) tree_model;
429 GArray *array = node->childnodes;
430 if (n >= array->len)
431 return FALSE;
432 iter->user_data = g_array_index(array, AstNode *, n);
433 return TRUE;
437 /*****************************************************************************
439 * ast_iter_parent: Point 'iter' to the parent node of 'child'. As
440 * we have a list and thus no children and no
441 * parents of children, we can just return FALSE.
443 *****************************************************************************/
445 static gboolean
446 ast_iter_parent (GtkTreeModel *tree_model,
447 GtkTreeIter *iter,
448 GtkTreeIter *child)
450 AstNode *node = (AstNode *) child->user_data;
451 iter->user_data = node->parent;
452 return node->parent != NULL;
456 AstNode *
457 ast_new (AstNode *parent, int index, const char *text, void *ptr, void (*inspect)(AstNode*))
459 AstNode *node = (AstNode*) g_object_new (AST_TYPE_NODE, NULL);
460 g_assert(node != NULL);
461 node->parent = parent;
462 node->index = index;
463 node->text = text;
464 node->inspect = inspect;
465 node->ptr = ptr;
466 return node;