ast-model.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. /*
  2. * ast-model.c
  3. *
  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 >
  7. *
  8. * Copyright (C) 2010 Christopher Li
  9. */
  10. #include "ast-model.h"
  11. #include "stdint.h"
  12. /* boring declarations of local functions */
  13. static void ast_init(AstNode *pkg_tree);
  14. static void ast_class_init(AstNodeClass *klass);
  15. static void ast_tree_model_init(GtkTreeModelIface *iface);
  16. static void ast_finalize(GObject *object);
  17. static GtkTreeModelFlags ast_get_flags(GtkTreeModel *tree_model);
  18. static gint ast_get_n_columns(GtkTreeModel *tree_model);
  19. static GType ast_get_column_type(GtkTreeModel *tree_model, gint index);
  20. static gboolean ast_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter,
  21. GtkTreePath *path);
  22. static GtkTreePath *ast_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter);
  23. static void ast_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter,
  24. gint column, GValue *value);
  25. static gboolean ast_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter);
  26. static gboolean ast_iter_children(GtkTreeModel *tree_model,
  27. GtkTreeIter *iter,
  28. GtkTreeIter *parent);
  29. static gboolean ast_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter);
  30. static gint ast_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter);
  31. static gboolean ast_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter,
  32. GtkTreeIter *parent, gint n);
  33. static gboolean ast_iter_parent(GtkTreeModel *tree_model,
  34. GtkTreeIter *iter,
  35. GtkTreeIter *child);
  36. static GObjectClass *parent_class = NULL; /* GObject stuff - nothing to worry about */
  37. static inline
  38. void inspect_child_node(AstNode *node)
  39. {
  40. if (node->inspect) {
  41. node->inspect(node);
  42. node->inspect = NULL;
  43. }
  44. }
  45. static inline
  46. AstNode* ast_nth_child(AstNode *node, int n)
  47. {
  48. if (!node)
  49. return NULL;
  50. inspect_child_node(node);
  51. if (n >= node->childnodes->len)
  52. return NULL;
  53. return g_array_index(node->childnodes, AstNode *, n);
  54. }
  55. static inline
  56. gboolean ast_set_iter(GtkTreeIter *iter, AstNode *node)
  57. {
  58. iter->user_data = node;
  59. iter->user_data2 = iter->user_data3 = NULL;
  60. return node != NULL;
  61. }
  62. /*****************************************************************************
  63. *
  64. * ast_get_type: here we register our new type and its interfaces
  65. * with the type system. If you want to implement
  66. * additional interfaces like GtkTreeSortable, you
  67. * will need to do it here.
  68. *
  69. *****************************************************************************/
  70. GType
  71. ast_get_type (void)
  72. {
  73. static GType ast_type = 0;
  74. static const GTypeInfo ast_info = {
  75. sizeof (AstNodeClass),
  76. NULL, /* base_init */
  77. NULL, /* base_finalize */
  78. (GClassInitFunc) ast_class_init,
  79. NULL, /* class finalize */
  80. NULL, /* class_data */
  81. sizeof (AstNode),
  82. 0, /* n_preallocs */
  83. (GInstanceInitFunc) ast_init
  84. };
  85. static const GInterfaceInfo tree_model_info = {
  86. (GInterfaceInitFunc) ast_tree_model_init,
  87. NULL,
  88. NULL
  89. };
  90. if (ast_type)
  91. return ast_type;
  92. /* Some boilerplate type registration stuff */
  93. ast_type = g_type_register_static(G_TYPE_OBJECT, "AstNode",
  94. &ast_info, (GTypeFlags)0);
  95. /* Here we register our GtkTreeModel interface with the type system */
  96. g_type_add_interface_static(ast_type, GTK_TYPE_TREE_MODEL, &tree_model_info);
  97. return ast_type;
  98. }
  99. /*****************************************************************************
  100. *
  101. * ast_class_init: more boilerplate GObject/GType stuff.
  102. * Init callback for the type system,
  103. * called once when our new class is created.
  104. *
  105. *****************************************************************************/
  106. static void
  107. ast_class_init (AstNodeClass *klass)
  108. {
  109. GObjectClass *object_class;
  110. parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
  111. object_class = (GObjectClass*) klass;
  112. object_class->finalize = ast_finalize;
  113. }
  114. /*****************************************************************************
  115. *
  116. * ast_tree_model_init: init callback for the interface registration
  117. * in ast_get_type. Here we override
  118. * the GtkTreeModel interface functions that
  119. * we implement.
  120. *
  121. *****************************************************************************/
  122. static void
  123. ast_tree_model_init (GtkTreeModelIface *iface)
  124. {
  125. iface->get_flags = ast_get_flags;
  126. iface->get_n_columns = ast_get_n_columns;
  127. iface->get_column_type = ast_get_column_type;
  128. iface->get_iter = ast_get_iter;
  129. iface->get_path = ast_get_path;
  130. iface->get_value = ast_get_value;
  131. iface->iter_next = ast_iter_next;
  132. iface->iter_children = ast_iter_children;
  133. iface->iter_has_child = ast_iter_has_child;
  134. iface->iter_n_children = ast_iter_n_children;
  135. iface->iter_nth_child = ast_iter_nth_child;
  136. iface->iter_parent = ast_iter_parent;
  137. }
  138. /*****************************************************************************
  139. *
  140. * ast_init: this is called every time a new ast node object
  141. * instance is created (we do that in ast_new).
  142. * Initialise the list structure's fields here.
  143. *
  144. *****************************************************************************/
  145. static void
  146. ast_init (AstNode *node)
  147. {
  148. node->childnodes = g_array_new(FALSE, TRUE, sizeof(AstNode *));
  149. node->stamp = g_random_int(); /* Random int to check whether iters belong to out model */
  150. }
  151. /*****************************************************************************
  152. *
  153. * ast_finalize: this is called just before an ast node is
  154. * destroyed. Free dynamically allocated memory here.
  155. *
  156. *****************************************************************************/
  157. static void
  158. ast_finalize (GObject *object)
  159. {
  160. /* AstNode *node = AST_NODE(object); */
  161. /* FIXME: free all node memory */
  162. /* must chain up - finalize parent */
  163. (* parent_class->finalize) (object);
  164. }
  165. /*****************************************************************************
  166. *
  167. * ast_get_flags: tells the rest of the world whether our tree model
  168. * has any special characteristics. In our case,
  169. * we have a list model (instead of a tree), and each
  170. * tree iter is valid as long as the row in question
  171. * exists, as it only contains a pointer to our struct.
  172. *
  173. *****************************************************************************/
  174. static GtkTreeModelFlags
  175. ast_get_flags(GtkTreeModel *tree_model)
  176. {
  177. return (GTK_TREE_MODEL_ITERS_PERSIST);
  178. }
  179. /*****************************************************************************
  180. *
  181. * ast_get_n_columns: tells the rest of the world how many data
  182. * columns we export via the tree model interface
  183. *
  184. *****************************************************************************/
  185. static gint
  186. ast_get_n_columns(GtkTreeModel *tree_model)
  187. {
  188. return 1;
  189. }
  190. /*****************************************************************************
  191. *
  192. * ast_get_column_type: tells the rest of the world which type of
  193. * data an exported model column contains
  194. *
  195. *****************************************************************************/
  196. static GType
  197. ast_get_column_type(GtkTreeModel *tree_model,
  198. gint index)
  199. {
  200. return G_TYPE_STRING;
  201. }
  202. /*****************************************************************************
  203. *
  204. * ast_get_iter: converts a tree path (physical position) into a
  205. * tree iter structure (the content of the iter
  206. * fields will only be used internally by our model).
  207. * We simply store a pointer to our AstNodeItem
  208. * structure that represents that row in the tree iter.
  209. *
  210. *****************************************************************************/
  211. static gboolean
  212. ast_get_iter(GtkTreeModel *tree_model,
  213. GtkTreeIter *iter,
  214. GtkTreePath *path)
  215. {
  216. AstNode *node;
  217. gint *indices, depth;
  218. int i;
  219. node = AST_NODE(tree_model);
  220. indices = gtk_tree_path_get_indices(path);
  221. depth = gtk_tree_path_get_depth(path);
  222. for (i = 0; i < depth; i++)
  223. node = ast_nth_child(node, indices[i]);
  224. return ast_set_iter(iter, node);
  225. }
  226. /*****************************************************************************
  227. *
  228. * ast_get_path: converts a tree iter into a tree path (ie. the
  229. * physical position of that row in the list).
  230. *
  231. *****************************************************************************/
  232. static GtkTreePath *
  233. ast_get_path(GtkTreeModel *tree_model,
  234. GtkTreeIter *iter)
  235. {
  236. GtkTreePath *path;
  237. AstNode *root = AST_NODE(tree_model);
  238. AstNode *node = AST_NODE(iter->user_data);
  239. path = gtk_tree_path_new();
  240. while (node != root) {
  241. gtk_tree_path_prepend_index(path, node->index);
  242. node = node->parent;
  243. }
  244. return path;
  245. }
  246. /*****************************************************************************
  247. *
  248. * ast_get_value: Returns a row's exported data columns
  249. * (_get_value is what gtk_tree_model_get uses)
  250. *
  251. *****************************************************************************/
  252. static void
  253. ast_get_value(GtkTreeModel *tree_model,
  254. GtkTreeIter *iter,
  255. gint column,
  256. GValue *value)
  257. {
  258. AstNode *node = iter->user_data;
  259. g_assert(AST_IS_NODE(tree_model));
  260. if (column != 1)
  261. return;
  262. inspect_child_node(node);
  263. g_value_init(value, G_TYPE_STRING);
  264. g_value_set_string(value, node->text);
  265. return;
  266. }
  267. /*****************************************************************************
  268. *
  269. * ast_iter_next: Takes an iter structure and sets it to point
  270. * to the next row.
  271. *
  272. *****************************************************************************/
  273. static gboolean
  274. ast_iter_next(GtkTreeModel *tree_model,
  275. GtkTreeIter *iter)
  276. {
  277. AstNode *node = iter->user_data;
  278. g_assert(AST_IS_NODE (tree_model));
  279. node = ast_nth_child(node->parent, node->index + 1);
  280. return ast_set_iter(iter, node);
  281. }
  282. /*****************************************************************************
  283. *
  284. * ast_iter_children: Returns TRUE or FALSE depending on whether
  285. * the row specified by 'parent' has any children.
  286. * If it has children, then 'iter' is set to
  287. * point to the first child. Special case: if
  288. * 'parent' is NULL, then the first top-level
  289. * row should be returned if it exists.
  290. *
  291. *****************************************************************************/
  292. static gboolean
  293. ast_iter_children(GtkTreeModel *tree_model,
  294. GtkTreeIter *iter,
  295. GtkTreeIter *parent)
  296. {
  297. return ast_iter_nth_child(tree_model, iter, parent, 0);
  298. }
  299. /*****************************************************************************
  300. *
  301. * ast_iter_has_child: Returns TRUE or FALSE depending on whether
  302. * the row specified by 'iter' has any children.
  303. * We only have a list and thus no children.
  304. *
  305. *****************************************************************************/
  306. static gboolean
  307. ast_iter_has_child (GtkTreeModel *tree_model,
  308. GtkTreeIter *iter)
  309. {
  310. AstNode *node = iter->user_data;
  311. inspect_child_node(node);
  312. return node->childnodes->len > 0;
  313. }
  314. /*****************************************************************************
  315. *
  316. * ast_iter_n_children: Returns the number of children the row
  317. * specified by 'iter' has. This is usually 0,
  318. * as we only have a list and thus do not have
  319. * any children to any rows. A special case is
  320. * when 'iter' is NULL, in which case we need
  321. * to return the number of top-level node,
  322. * ie. the number of rows in our list.
  323. *
  324. *****************************************************************************/
  325. static gint
  326. ast_iter_n_children (GtkTreeModel *tree_model,
  327. GtkTreeIter *iter)
  328. {
  329. AstNode *node = iter ? iter->user_data
  330. : AST_NODE(tree_model);
  331. inspect_child_node(node);
  332. return node->childnodes->len;
  333. }
  334. /*****************************************************************************
  335. *
  336. * ast_iter_nth_child: If the row specified by 'parent' has any
  337. * children, set 'iter' to the n-th child and
  338. * return TRUE if it exists, otherwise FALSE.
  339. * A special case is when 'parent' is NULL, in
  340. * which case we need to set 'iter' to the n-th
  341. * row if it exists.
  342. *
  343. *****************************************************************************/
  344. static gboolean
  345. ast_iter_nth_child(GtkTreeModel *tree_model,
  346. GtkTreeIter *iter,
  347. GtkTreeIter *parent,
  348. gint n)
  349. {
  350. AstNode *node = parent ? parent->user_data : (AstNode*) tree_model;
  351. GArray *array = node->childnodes;
  352. if (n >= array->len)
  353. return FALSE;
  354. iter->user_data = g_array_index(array, AstNode *, n);
  355. return TRUE;
  356. }
  357. /*****************************************************************************
  358. *
  359. * ast_iter_parent: Point 'iter' to the parent node of 'child'. As
  360. * we have a list and thus no children and no
  361. * parents of children, we can just return FALSE.
  362. *
  363. *****************************************************************************/
  364. static gboolean
  365. ast_iter_parent (GtkTreeModel *tree_model,
  366. GtkTreeIter *iter,
  367. GtkTreeIter *child)
  368. {
  369. AstNode *node = (AstNode *) child->user_data;
  370. iter->user_data = node->parent;
  371. return node->parent != NULL;
  372. }
  373. AstNode *
  374. ast_new (AstNode *parent, int index, const char *text, void *ptr, void (*inspect)(AstNode*))
  375. {
  376. AstNode *node = (AstNode*) g_object_new (AST_TYPE_NODE, NULL);
  377. g_assert(node != NULL);
  378. node->parent = parent;
  379. node->index = index;
  380. node->text = text;
  381. node->inspect = inspect;
  382. node->ptr = ptr;
  383. return node;
  384. }