]> Pileus Git - ~andy/gtk/blob - gtk/gtktreemodel.c
Not sure how this ever worked. Fixed it to use new iter stuff, and added
[~andy/gtk] / gtk / gtktreemodel.c
1 /* gtktreemodel.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include "gtktreemodel.h"
24
25 struct _GtkTreePath
26 {
27   gint depth;
28   gint *indices;
29 };
30
31 GtkType
32 gtk_tree_model_get_type (void)
33 {
34   static GtkType tree_model_type = 0;
35
36   if (!tree_model_type)
37     {
38       static const GTypeInfo tree_model_info =
39       {
40         sizeof (GtkTreeModelIface), /* class_size */
41         NULL,           /* base_init */
42         NULL,           /* base_finalize */
43       };
44
45       tree_model_type = g_type_register_static (G_TYPE_INTERFACE, "GtkTreeModel", &tree_model_info, 0);
46     }
47
48   return tree_model_type;
49 }
50
51 /**
52  * gtk_tree_path_new:
53  * @void: 
54  * 
55  * Creates a new #GtkTreePath.
56  * 
57  * Return value: A newly created #GtkTreePath.
58  **/
59 /* GtkTreePath Operations */
60 GtkTreePath *
61 gtk_tree_path_new (void)
62 {
63   GtkTreePath *retval;
64   retval = (GtkTreePath *) g_new (GtkTreePath, 1);
65   retval->depth = 0;
66   retval->indices = NULL;
67
68   return retval;
69 }
70
71 /**
72  * gtk_tree_path_new_from_string:
73  * @path: The string representation of a path.
74  * 
75  * Creates a new #GtkTreePath initialized to @path.  @path is expected to be a
76  * colon separated list of numbers.  For example, the string "10:4:0" would
77  * create a path of depth 3.
78  * 
79  * Return value: A newly created #GtkTreePath.
80  **/
81 GtkTreePath *
82 gtk_tree_path_new_from_string (gchar *path)
83 {
84   GtkTreePath *retval;
85   gchar *ptr;
86   gint i;
87
88   g_return_val_if_fail (path != NULL, gtk_tree_path_new ());
89
90   retval = gtk_tree_path_new ();
91
92   while (1)
93     {
94       i = strtol (path, &ptr, 10);
95       gtk_tree_path_append_index (retval, i);
96
97       if (*ptr == '\000')
98         break;
99       /* FIXME: should we error out if this is not a ':', or should we be tolerant? */
100       path = ptr + 1;
101     }
102
103   return retval;
104 }
105
106 /**
107  * gtk_tree_path_to_string:
108  * @path: A #GtkTreePath
109  * 
110  * Generates a string representation of the path.  This string is a ':'
111  * separated list of numbers.  For example, "4:10:0:3" would be an acceptable return value for this string.
112  * 
113  * Return value: A newly allocated string.  Must be freed with #g_free.
114  **/
115 gchar *
116 gtk_tree_path_to_string (GtkTreePath *path)
117 {
118   gchar *retval, *ptr;
119   gint i;
120
121   if (path->depth == 0)
122     return NULL;
123
124   ptr = retval = (gchar *) g_new0 (char *, path->depth*8);
125   sprintf (retval, "%d", path->indices[0]);
126   while (*ptr != '\000')
127     ptr++;
128
129   for (i = 1; i < path->depth; i++)
130     {
131       sprintf (ptr, ":%d", path->indices[i]);
132       while (*ptr != '\000')
133         ptr++;
134     }
135
136   return retval;
137 }
138
139 /**
140  * gtk_tree_path_new_root:
141  * @void: 
142  * 
143  * Creates a new root #GtkTreePath.  The string representation of this path is
144  * "0"
145  * 
146  * Return value: A new #GtkTreePath.
147  **/
148 GtkTreePath *
149 gtk_tree_path_new_root (void)
150 {
151   GtkTreePath *retval;
152
153   retval = gtk_tree_path_new ();
154   gtk_tree_path_append_index (retval, 0);
155
156   return retval;
157 }
158
159 /**
160  * gtk_tree_path_append_index:
161  * @path: A #GtkTreePath.
162  * @index: The index.
163  * 
164  * Appends a new index to a path.  As a result, the depth of the path is
165  * increased.
166  **/
167 void
168 gtk_tree_path_append_index (GtkTreePath *path,
169                             gint         index)
170 {
171   gint *new_indices;
172
173   g_return_if_fail (path != NULL);
174   g_return_if_fail (index >= 0);
175
176   new_indices = g_new (gint, ++path->depth);
177   if (path->indices == NULL)
178     {
179       path->indices = new_indices;
180       path->indices[0] = index;
181       return;
182     }
183
184   memcpy (new_indices, path->indices, (path->depth - 1)*sizeof (gint));
185   g_free (path->indices);
186   path->indices = new_indices;
187   path->indices[path->depth - 1] = index;
188 }
189
190 /**
191  * gtk_tree_path_prepend_index:
192  * @path: A #GtkTreePath.
193  * @index: The index.
194  * 
195  * Prepends a new index to a path.  As a result, the depth of the path is
196  * increased.
197  **/
198 void
199 gtk_tree_path_prepend_index (GtkTreePath *path,
200                              gint       index)
201 {
202   gint *new_indices = g_new (gint, ++path->depth);
203   if (path->indices == NULL)
204     {
205       path->indices = new_indices;
206       path->indices[0] = index;
207       return;
208     }
209   memcpy (new_indices + 1, path->indices, (path->depth - 1)*sizeof (gint));
210   g_free (path->indices);
211   path->indices = new_indices;
212   path->indices[0] = index;
213 }
214
215 /**
216  * gtk_tree_path_get_depth:
217  * @path: A #GtkTreePath.
218  * 
219  * Returns the current depth of @path.
220  * 
221  * Return value: The depth of @path
222  **/
223 gint
224 gtk_tree_path_get_depth (GtkTreePath *path)
225 {
226   g_return_val_if_fail (path != NULL, 0);
227
228   return path->depth;
229 }
230
231 /**
232  * gtk_tree_path_get_indices:
233  * @path: A #GtkTreePath.
234  * 
235  * Returns the current indices of @path.  This is an array of integers, each
236  * representing a node in a tree.
237  * 
238  * Return value: The current indices, or NULL.
239  **/
240 gint *
241 gtk_tree_path_get_indices (GtkTreePath *path)
242 {
243   g_return_val_if_fail (path != NULL, NULL);
244
245   return path->indices;
246 }
247
248 /**
249  * gtk_tree_path_free:
250  * @path: A #GtkTreePath.
251  * 
252  * Frees @path.
253  **/
254 void
255 gtk_tree_path_free (GtkTreePath *path)
256 {
257   g_free (path->indices);
258   g_free (path);
259 }
260
261 /**
262  * gtk_tree_path_copy:
263  * @path: A #GtkTreePath.
264  * 
265  * Creates a new #GtkTreePath based upon @path.
266  * 
267  * Return value: A new #GtkTreePath.
268  **/
269 GtkTreePath *
270 gtk_tree_path_copy (GtkTreePath *path)
271 {
272   GtkTreePath *retval;
273
274   retval = g_new (GtkTreePath, 1);
275   retval->depth = path->depth;
276   retval->indices = g_new (gint, path->depth);
277   memcpy (retval->indices, path->indices, path->depth * sizeof (gint));
278   return retval;
279 }
280
281 /**
282  * gtk_tree_path_compare:
283  * @a: A #GtkTreePath.
284  * @b: A #GtkTreePath to compare with.
285  * 
286  * Compares two paths.  If @a appears before @b in a tree, then 1, is returned.
287  * If @b appears before @a, then -1 is returned.  If the two nodes are equal,
288  * then 0 is returned.
289  * 
290  * Return value: The relative positions of @a and @b
291  **/
292 gint
293 gtk_tree_path_compare (const GtkTreePath *a,
294                        const GtkTreePath *b)
295 {
296   gint p = 0, q = 0;
297
298   g_return_val_if_fail (a != NULL, 0);
299   g_return_val_if_fail (b != NULL, 0);
300   g_return_val_if_fail (a->depth > 0, 0);
301   g_return_val_if_fail (b->depth > 0, 0);
302
303   do
304     {
305       if (a->indices[p] == b->indices[q])
306         continue;
307       return (a->indices[p] < b->indices[q]?1:-1);
308     }
309   while (++p < a->depth && ++q < b->depth);
310   if (a->depth == b->depth)
311     return 0;
312   return (a->depth < b->depth?1:-1);
313 }
314
315 /**
316  * gtk_tree_path_next:
317  * @path: A #GtkTreePath.
318  * 
319  * Moves the @path to point to the next node at the current depth.
320  **/
321 void
322 gtk_tree_path_next (GtkTreePath *path)
323 {
324   g_return_if_fail (path != NULL);
325   g_return_if_fail (path->depth > 0);
326
327   path->indices[path->depth - 1] ++;
328 }
329
330 /**
331  * gtk_tree_path_prev:
332  * @path: A #GtkTreePath.
333  * 
334  * Moves the @path to point to the previous node at the current depth, if it exists.
335  **/
336 gint
337 gtk_tree_path_prev (GtkTreePath *path)
338 {
339   g_return_val_if_fail (path != NULL, FALSE);
340
341   if (path->indices[path->depth] == 0)
342     return FALSE;
343
344   path->indices[path->depth - 1] --;
345
346   return TRUE;
347 }
348
349 /**
350  * gtk_tree_path_up:
351  * @path: A #GtkTreePath.
352  * 
353  * Moves the @path to point to it's parent node, if it has a parent.
354  * 
355  * Return value: TRUE if @path has a parent, and the move was made.
356  **/
357 gint
358 gtk_tree_path_up (GtkTreePath *path)
359 {
360   g_return_val_if_fail (path != NULL, FALSE);
361
362   if (path->depth == 1)
363     return FALSE;
364
365   path->depth--;
366
367   return TRUE;
368 }
369
370 /**
371  * gtk_tree_path_down:
372  * @path: A #GtkTreePath.
373  * 
374  * Moves @path to point to the first child of the current path.
375  **/
376 void
377 gtk_tree_path_down (GtkTreePath *path)
378 {
379   g_return_if_fail (path != NULL);
380
381   gtk_tree_path_append_index (path, 0);
382 }
383
384 /**
385  * gtk_tree_model_get_n_columns:
386  * @tree_model: A #GtkTreeModel.
387  * 
388  * Returns the number of columns supported by the #tree_model
389  * 
390  * Return value: The number of columns.
391  **/
392 gint
393 gtk_tree_model_get_n_columns (GtkTreeModel *tree_model)
394 {
395   g_return_val_if_fail (tree_model != NULL, 0);
396   g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), 0);
397   g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->get_n_columns != NULL, 0);
398
399   return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->get_n_columns) (tree_model);
400 }
401
402 /**
403  * gtk_tree_model_get_iter:
404  * @tree_model: A #GtkTreeModel.
405  * @iter: The uninitialized #GtkTreeIter.
406  * @path: The #GtkTreePath.
407  * 
408  * Sets @iter to a valid iterator pointing to @path.  If the model does not
409  * provide an implementation of this function, it is implemented in terms of
410  * @gtk_tree_model_iter_nth_child.
411  * 
412  * Return value: TRUE, if @iter was set.
413  **/
414 gboolean
415 gtk_tree_model_get_iter (GtkTreeModel *tree_model,
416                          GtkTreeIter  *iter,
417                          GtkTreePath  *path)
418 {
419   GtkTreeIter parent;
420   gint *indices;
421   gint depth, i;
422
423   g_return_val_if_fail (tree_model != NULL, FALSE);
424   g_return_val_if_fail (iter != NULL, FALSE);
425   g_return_val_if_fail (path != NULL, FALSE);
426   g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
427
428   if (GTK_TREE_MODEL_GET_IFACE (tree_model)->get_iter != NULL)
429     return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->get_iter) (tree_model, iter, path);
430
431   indices = gtk_tree_path_get_indices (path);
432   depth = gtk_tree_path_get_depth (path);
433
434   g_return_val_if_fail (depth > 0, FALSE);
435
436   if (! gtk_tree_model_iter_nth_child (tree_model, iter, NULL, indices[0]))
437     return FALSE;
438
439   for (i = 1; i < depth; i++)
440     {
441       parent = *iter;
442       if (! gtk_tree_model_iter_nth_child (tree_model, iter, &parent, indices[i]))
443         return FALSE;
444     }
445
446   return TRUE;
447 }
448
449 /**
450  * gtk_tree_model_get_path:
451  * @tree_model: A #GtkTreeModel.
452  * @iter: The #GtkTreeIter.
453  * 
454  * Returns a newly created #GtkTreePath referenced by @iter.  This path should
455  * be freed with #gtk_tree_path_free.
456  * 
457  * Return value: a newly created #GtkTreePath.
458  **/
459 GtkTreePath *
460 gtk_tree_model_get_path (GtkTreeModel *tree_model,
461                          GtkTreeIter  *iter)
462 {
463   g_return_val_if_fail (tree_model != NULL, NULL);
464   g_return_val_if_fail (iter != NULL, NULL);
465   g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), NULL);
466   g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->get_path != NULL, NULL);
467
468   return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->get_path) (tree_model, iter);
469 }
470
471 /**
472  * gtk_tree_model_get_value:
473  * @tree_model: A #GtkTreeModel.
474  * @iter: The #GtkTreeIter.
475  * @column: The column to lookup the value at.
476  * @value: An empty #GValue to set.
477  * 
478  * Sets initializes and sets @value to that at @column.  When done with value,
479  * #g_value_unset needs to be called on it.
480  **/
481 void
482 gtk_tree_model_get_value (GtkTreeModel *tree_model,
483                           GtkTreeIter  *iter,
484                           gint          column,
485                           GValue       *value)
486 {
487   g_return_if_fail (tree_model != NULL);
488   g_return_if_fail (iter != NULL);
489   g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
490   g_return_if_fail (value != NULL);
491   g_return_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->get_value != NULL);
492
493   (* GTK_TREE_MODEL_GET_IFACE (tree_model)->get_value) (tree_model, iter, column, value);
494 }
495
496 /**
497  * gtk_tree_model_iter_next:
498  * @tree_model: A #GtkTreeModel.
499  * @iter: The #GtkTreeIter.
500  * 
501  * Sets @iter to point to the node following it at the current level.  If there
502  * is no next @iter, FALSE is returned and @iter is set to be invalid.
503  * 
504  * Return value: TRUE if @iter has been changed to the next node.
505  **/
506 gboolean
507 gtk_tree_model_iter_next (GtkTreeModel  *tree_model,
508                           GtkTreeIter   *iter)
509 {
510   g_return_val_if_fail (tree_model != NULL, FALSE);
511   g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
512   g_return_val_if_fail (iter != NULL, FALSE);
513   g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_next != NULL, FALSE);
514
515   return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_next) (tree_model, iter);
516 }
517
518 /**
519  * gtk_tree_model_iter_children:
520  * @tree_model: A #GtkTreeModel.
521  * @iter: The #GtkTreeIter.
522  * @child: The new #GtkTreeIter.
523  * 
524  * Sets @iter to point to the first child of @parent.  If @parent has no children,
525  * FALSE is returned and @iter is set to be invalid.  @parent will remain a valid
526  * node after this function has been called.
527  * 
528  * Return value: TRUE, if @child has been set to the first child.
529  **/
530 gboolean
531 gtk_tree_model_iter_children (GtkTreeModel *tree_model,
532                               GtkTreeIter  *iter,
533                               GtkTreeIter  *parent)
534 {
535   g_return_val_if_fail (tree_model != NULL, FALSE);
536   g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
537   g_return_val_if_fail (iter != NULL, FALSE);
538   g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_children != NULL, FALSE);
539
540   return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_children) (tree_model, iter, parent);
541 }
542
543 /**
544  * gtk_tree_model_iter_has_child:
545  * @tree_model: A #GtkTreeModel.
546  * @iter: The #GtkTreeIter to test for children.
547  * 
548  * Returns TRUE if @iter has children, FALSE otherwise.
549  * 
550  * Return value: TRUE if @iter has children.
551  **/
552 gboolean
553 gtk_tree_model_iter_has_child (GtkTreeModel *tree_model,
554                                GtkTreeIter  *iter)
555 {
556   g_return_val_if_fail (tree_model != NULL, FALSE);
557   g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
558   g_return_val_if_fail (iter != NULL, FALSE);
559   g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_has_child != NULL, FALSE);
560
561   return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_has_child) (tree_model, iter);
562 }
563
564 /**
565  * gtk_tree_model_iter_n_children:
566  * @tree_model: A #GtkTreeModel.
567  * @iter: The #GtkTreeIter.
568  * 
569  * Returns the number of children that @iter has.
570  * 
571  * Return value: The number of children of @iter.
572  **/
573 gint
574 gtk_tree_model_iter_n_children (GtkTreeModel *tree_model,
575                                 GtkTreeIter  *iter)
576 {
577   g_return_val_if_fail (tree_model != NULL, 0);
578   g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), 0);
579   g_return_val_if_fail (iter != NULL, 0);
580   g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_n_children != NULL, 0);
581
582   return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_n_children) (tree_model, iter);
583 }
584
585 /**
586  * gtk_tree_model_iter_nth_child:
587  * @tree_model: A #GtkTreeModel.
588  * @iter: The #GtkTreeIter to set to the nth child.
589  * @parent: The #GtkTreeIter to get the child from, or NULL.
590  * @n: Then index of the desired child.
591  * 
592  * Sets @iter to be the child of @parent, using the given index.  The first index
593  * is 0.  If the index is too big, or @parent has no children, @iter is set to an
594  * invalid iterator and FALSE is returned.  @parent will remain a valid node after
595  * this function has been called.  If @parent is NULL, then the root node is assumed.
596  * 
597  * Return value: TRUE, if @parent has an nth child.
598  **/
599 gboolean
600 gtk_tree_model_iter_nth_child (GtkTreeModel *tree_model,
601                                GtkTreeIter  *iter,
602                                GtkTreeIter  *parent,
603                                gint          n)
604 {
605   g_return_val_if_fail (tree_model != NULL, FALSE);
606   g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
607   g_return_val_if_fail (iter != NULL, FALSE);
608   g_return_val_if_fail (n >= 0, FALSE);
609   g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_nth_child != NULL, FALSE);
610
611   return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_nth_child) (tree_model, iter, parent, n);
612 }
613
614 /**
615  * gtk_tree_model_iter_parent:
616  * @tree_model: A #GtkTreeModel
617  * @iter: The #GtkTreeIter.
618  * @parent: The #GtkTreeIter to set to the parent
619  * 
620  * Sets @iter to be the parent of @child.  If @child is at the toplevel, and
621  * doesn't have a parent, then @iter is set to an invalid iterator and FALSE
622  * is returned.  @child will remain a valid node after this function has been
623  * called.
624  * 
625  * Return value: TRUE, if @iter is set to the parent of @child.
626  **/
627 gboolean
628 gtk_tree_model_iter_parent (GtkTreeModel *tree_model,
629                             GtkTreeIter  *iter,
630                             GtkTreeIter  *child)
631 {
632   g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_parent != NULL, FALSE);
633
634   return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_parent) (tree_model, iter, child);
635 }
636