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
12 #include "ast-model.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
,
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
,
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
,
41 static GObjectClass
*parent_class
= NULL
; /* GObject stuff - nothing to worry about */
44 void inspect_child_node(AstNode
*node
)
54 AstNode
* ast_nth_child(AstNode
*node
, int n
)
59 inspect_child_node(node
);
61 if (n
>= node
->childnodes
->len
)
63 return g_array_index(node
->childnodes
, AstNode
*, n
);
68 gboolean
ast_set_iter(GtkTreeIter
*iter
, AstNode
*node
)
70 iter
->user_data
= node
;
71 iter
->user_data2
= iter
->user_data3
= 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 *****************************************************************************/
88 static GType ast_type
= 0;
89 static const GTypeInfo ast_info
= {
90 sizeof (AstNodeClass
),
92 NULL
, /* base_finalize */
93 (GClassInitFunc
) ast_class_init
,
94 NULL
, /* class finalize */
95 NULL
, /* class_data */
98 (GInstanceInitFunc
) ast_init
100 static const GInterfaceInfo tree_model_info
= {
101 (GInterfaceInitFunc
) ast_tree_model_init
,
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
);
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 *****************************************************************************/
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
148 *****************************************************************************/
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 *****************************************************************************/
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 *****************************************************************************/
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 *****************************************************************************/
228 ast_get_n_columns(GtkTreeModel
*tree_model
)
234 /*****************************************************************************
236 * ast_get_column_type: tells the rest of the world which type of
237 * data an exported model column contains
239 *****************************************************************************/
242 ast_get_column_type(GtkTreeModel
*tree_model
,
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 *****************************************************************************/
260 ast_get_iter(GtkTreeModel
*tree_model
,
265 gint
*indices
, depth
;
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 *****************************************************************************/
287 ast_get_path(GtkTreeModel
*tree_model
,
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
);
303 /*****************************************************************************
305 * ast_get_value: Returns a row's exported data columns
306 * (_get_value is what gtk_tree_model_get uses)
308 *****************************************************************************/
311 ast_get_value(GtkTreeModel
*tree_model
,
316 AstNode
*node
= iter
->user_data
;
318 g_assert(AST_IS_NODE(tree_model
));
322 inspect_child_node(node
);
324 g_value_init(value
, G_TYPE_STRING
);
325 g_value_set_string(value
, node
->text
);
330 /*****************************************************************************
332 * ast_iter_next: Takes an iter structure and sets it to point
335 *****************************************************************************/
338 ast_iter_next(GtkTreeModel
*tree_model
,
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 *****************************************************************************/
362 ast_iter_children(GtkTreeModel
*tree_model
,
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 *****************************************************************************/
379 ast_iter_has_child (GtkTreeModel
*tree_model
,
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 *****************************************************************************/
401 ast_iter_n_children (GtkTreeModel
*tree_model
,
404 AstNode
*node
= iter
? iter
->user_data
405 : AST_NODE(tree_model
);
407 inspect_child_node(node
);
408 return node
->childnodes
->len
;
412 /*****************************************************************************
414 * ast_iter_nth_child: If the row specified by 'parent' has any
415 * children, set 'iter' to the n-th child and
416 * return TRUE if it exists, otherwise FALSE.
417 * A special case is when 'parent' is NULL, in
418 * which case we need to set 'iter' to the n-th
421 *****************************************************************************/
424 ast_iter_nth_child(GtkTreeModel
*tree_model
,
429 AstNode
*node
= parent
? parent
->user_data
: (AstNode
*) tree_model
;
430 GArray
*array
= node
->childnodes
;
433 iter
->user_data
= g_array_index(array
, AstNode
*, n
);
438 /*****************************************************************************
440 * ast_iter_parent: Point 'iter' to the parent node of 'child'. As
441 * we have a list and thus no children and no
442 * parents of children, we can just return FALSE.
444 *****************************************************************************/
447 ast_iter_parent (GtkTreeModel
*tree_model
,
451 AstNode
*node
= (AstNode
*) child
->user_data
;
452 iter
->user_data
= node
->parent
;
453 return node
->parent
!= NULL
;
458 ast_new (AstNode
*parent
, int index
, const char *text
, void *ptr
, void (*inspect
)(AstNode
*))
460 AstNode
*node
= (AstNode
*) g_object_new (AST_TYPE_NODE
, NULL
);
461 g_assert(node
!= NULL
);
462 node
->parent
= parent
;
465 node
->inspect
= inspect
;