]> Pileus Git - ~andy/gtk/blob - gtk/gtkliststore.c
hack on this some
[~andy/gtk] / gtk / gtkliststore.c
1 /* gtkliststore.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 <string.h>
21 #include "gtktreemodel.h"
22 #include "gtkliststore.h"
23 #include "gtktreedatalist.h"
24 #include "gtksignal.h"
25 #include <gobject/gvaluecollector.h>
26
27 #define G_SLIST(x) ((GSList *) x)
28
29 enum {
30   CHANGED,
31   INSERTED,
32   CHILD_TOGGLED,
33   DELETED,
34   LAST_SIGNAL
35 };
36
37 static guint list_store_signals[LAST_SIGNAL] = { 0 };
38
39 static void         gtk_list_store_init            (GtkListStore      *list_store);
40 static void         gtk_list_store_class_init      (GtkListStoreClass *class);
41 static void         gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
42 static guint        gtk_list_store_get_flags       (GtkTreeModel      *tree_model);
43 static gint         gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
44 static GType        gtk_list_store_get_column_type (GtkTreeModel      *tree_model,
45                                                     gint               index);
46 static gboolean     gtk_list_store_get_iter        (GtkTreeModel      *tree_model,
47                                                     GtkTreeIter       *iter,
48                                                     GtkTreePath       *path);
49 static GtkTreePath *gtk_list_store_get_path        (GtkTreeModel      *tree_model,
50                                                     GtkTreeIter       *iter);
51 static void         gtk_list_store_get_value       (GtkTreeModel      *tree_model,
52                                                     GtkTreeIter       *iter,
53                                                     gint               column,
54                                                     GValue            *value);
55 static gboolean     gtk_list_store_iter_next       (GtkTreeModel      *tree_model,
56                                                     GtkTreeIter       *iter);
57 static gboolean     gtk_list_store_iter_children   (GtkTreeModel      *tree_model,
58                                                     GtkTreeIter       *iter,
59                                                     GtkTreeIter       *parent);
60 static gboolean     gtk_list_store_iter_has_child  (GtkTreeModel      *tree_model,
61                                                     GtkTreeIter       *iter);
62 static gint         gtk_list_store_iter_n_children (GtkTreeModel      *tree_model,
63                                                     GtkTreeIter       *iter);
64 static gboolean     gtk_list_store_iter_nth_child  (GtkTreeModel      *tree_model,
65                                                     GtkTreeIter       *iter,
66                                                     GtkTreeIter       *parent,
67                                                     gint               n);
68 static gboolean     gtk_list_store_iter_parent     (GtkTreeModel      *tree_model,
69                                                     GtkTreeIter       *iter,
70                                                     GtkTreeIter       *child);
71
72
73 GtkType
74 gtk_list_store_get_type (void)
75 {
76   static GtkType list_store_type = 0;
77
78   if (!list_store_type)
79     {
80       static const GTypeInfo list_store_info =
81       {
82         sizeof (GtkListStoreClass),
83         NULL,           /* base_init */
84         NULL,           /* base_finalize */
85         (GClassInitFunc) gtk_list_store_class_init,
86         NULL,           /* class_finalize */
87         NULL,           /* class_data */
88         sizeof (GtkListStore),
89         0,
90         (GInstanceInitFunc) gtk_list_store_init,
91       };
92
93       static const GInterfaceInfo tree_model_info =
94       {
95         (GInterfaceInitFunc) gtk_list_store_tree_model_init,
96         NULL,
97         NULL
98       };
99
100       list_store_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkListStore", &list_store_info, 0);
101       g_type_add_interface_static (list_store_type,
102                                    GTK_TYPE_TREE_MODEL,
103                                    &tree_model_info);
104     }
105
106   return list_store_type;
107 }
108
109 static void
110 gtk_list_store_class_init (GtkListStoreClass *class)
111 {
112   GtkObjectClass *object_class;
113
114   object_class = (GtkObjectClass*) class;
115
116   list_store_signals[CHANGED] =
117     gtk_signal_new ("changed",
118                     GTK_RUN_FIRST,
119                     GTK_CLASS_TYPE (object_class),
120                     GTK_SIGNAL_OFFSET (GtkListStoreClass, changed),
121                     gtk_marshal_VOID__BOXED_BOXED,
122                     G_TYPE_NONE, 2,
123                     GTK_TYPE_TREE_PATH,
124                     GTK_TYPE_TREE_ITER);
125   list_store_signals[INSERTED] =
126     gtk_signal_new ("inserted",
127                     GTK_RUN_FIRST,
128                     GTK_CLASS_TYPE (object_class),
129                     GTK_SIGNAL_OFFSET (GtkListStoreClass, inserted),
130                     gtk_marshal_VOID__BOXED_BOXED,
131                     G_TYPE_NONE, 2,
132                     GTK_TYPE_TREE_PATH,
133                     GTK_TYPE_TREE_ITER);
134   list_store_signals[CHILD_TOGGLED] =
135     gtk_signal_new ("child_toggled",
136                     GTK_RUN_FIRST,
137                     GTK_CLASS_TYPE (object_class),
138                     GTK_SIGNAL_OFFSET (GtkListStoreClass, child_toggled),
139                     gtk_marshal_VOID__BOXED_BOXED,
140                     G_TYPE_NONE, 2,
141                     GTK_TYPE_TREE_PATH,
142                     GTK_TYPE_TREE_ITER);
143   list_store_signals[DELETED] =
144     gtk_signal_new ("deleted",
145                     GTK_RUN_FIRST,
146                     GTK_CLASS_TYPE (object_class),
147                     GTK_SIGNAL_OFFSET (GtkListStoreClass, deleted),
148                     gtk_marshal_VOID__BOXED,
149                     G_TYPE_NONE, 1,
150                     GTK_TYPE_TREE_PATH);
151 }
152
153 static void
154 gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
155 {
156   iface->get_flags = gtk_list_store_get_flags;
157   iface->get_n_columns = gtk_list_store_get_n_columns;
158   iface->get_column_type = gtk_list_store_get_column_type;
159   iface->get_iter = gtk_list_store_get_iter;
160   iface->get_path = gtk_list_store_get_path;
161   iface->get_value = gtk_list_store_get_value;
162   iface->iter_next = gtk_list_store_iter_next;
163   iface->iter_children = gtk_list_store_iter_children;
164   iface->iter_has_child = gtk_list_store_iter_has_child;
165   iface->iter_n_children = gtk_list_store_iter_n_children;
166   iface->iter_nth_child = gtk_list_store_iter_nth_child;
167   iface->iter_parent = gtk_list_store_iter_parent;
168 }
169
170 static void
171 gtk_list_store_init (GtkListStore *list_store)
172 {
173   list_store->root = NULL;
174   list_store->stamp = g_random_int ();
175 }
176
177 GtkListStore *
178 gtk_list_store_new (void)
179 {
180   return GTK_LIST_STORE (gtk_type_new (gtk_list_store_get_type ()));
181 }
182
183 GtkListStore *
184 gtk_list_store_new_with_types (gint n_columns,
185                                ...)
186 {
187   GtkListStore *retval;
188   va_list args;
189   gint i;
190
191   g_return_val_if_fail (n_columns > 0, NULL);
192
193   retval = gtk_list_store_new ();
194   gtk_list_store_set_n_columns (retval, n_columns);
195
196   va_start (args, n_columns);
197
198   for (i = 0; i < n_columns; i++)
199     gtk_list_store_set_column_type (retval, i, va_arg (args, GType));
200
201   va_end (args);
202
203   return retval;
204 }
205
206 void
207 gtk_list_store_set_n_columns (GtkListStore *list_store,
208                               gint          n_columns)
209 {
210   GType *new_columns;
211
212   g_return_if_fail (list_store != NULL);
213   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
214   g_return_if_fail (n_columns > 0);
215
216   if (list_store->n_columns == n_columns)
217     return;
218
219   new_columns = g_new0 (GType, n_columns);
220   if (list_store->column_headers)
221     {
222       /* copy the old header orders over */
223       if (n_columns >= list_store->n_columns)
224         memcpy (new_columns, list_store->column_headers, list_store->n_columns * sizeof (gchar *));
225       else
226         memcpy (new_columns, list_store->column_headers, n_columns * sizeof (GType));
227
228       g_free (list_store->column_headers);
229     }
230
231   list_store->column_headers = new_columns;
232   list_store->n_columns = n_columns;
233 }
234
235 void
236 gtk_list_store_set_column_type (GtkListStore *list_store,
237                                 gint          column,
238                                 GType         type)
239 {
240   g_return_if_fail (list_store != NULL);
241   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
242   g_return_if_fail (column >=0 && column < list_store->n_columns);
243
244   list_store->column_headers[column] = type;
245 }
246
247 /* Fulfill the GtkTreeModel requirements */
248 static guint
249 gtk_list_store_get_flags (GtkTreeModel *tree_model)
250 {
251   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);
252
253   return GTK_TREE_MODEL_ITERS_PERSIST;
254 }
255
256 static gint
257 gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
258 {
259   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);
260
261   return GTK_LIST_STORE (tree_model)->n_columns;
262 }
263
264 static GType
265 gtk_list_store_get_column_type (GtkTreeModel *tree_model,
266                                 gint          index)
267 {
268   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), G_TYPE_INVALID);
269   g_return_val_if_fail (index < GTK_LIST_STORE (tree_model)->n_columns &&
270                         index >= 0, G_TYPE_INVALID);
271
272   return GTK_LIST_STORE (tree_model)->column_headers[index];
273 }
274
275 static gboolean
276 gtk_list_store_get_iter (GtkTreeModel *tree_model,
277                          GtkTreeIter  *iter,
278                          GtkTreePath  *path)
279 {
280   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
281   g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
282   
283   iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
284   iter->user_data = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root),
285                                  gtk_tree_path_get_indices (path)[0]);
286
287   return iter->user_data != NULL;
288 }
289
290 static GtkTreePath *
291 gtk_list_store_get_path (GtkTreeModel *tree_model,
292                          GtkTreeIter  *iter)
293 {
294   GtkTreePath *retval;
295   GSList *list;
296   gint i = 0;
297
298   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), NULL);
299   g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, NULL);
300
301   for (list = G_SLIST (GTK_LIST_STORE (tree_model)->root); list; list = list->next)
302     {
303       if (list == G_SLIST (iter->user_data))
304         break;
305       i++;
306     }
307   if (list == NULL)
308     return NULL;
309
310   retval = gtk_tree_path_new ();
311   gtk_tree_path_append_index (retval, i);
312   return retval;
313 }
314
315 static void
316 gtk_list_store_get_value (GtkTreeModel *tree_model,
317                           GtkTreeIter  *iter,
318                           gint          column,
319                           GValue       *value)
320 {
321   GtkTreeDataList *list;
322   gint tmp_column = column;
323
324   g_return_if_fail (GTK_IS_LIST_STORE (tree_model));
325   g_return_if_fail (column < GTK_LIST_STORE (tree_model)->n_columns);
326   g_return_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp);
327
328   list = G_SLIST (iter->user_data)->data;
329
330   while (tmp_column-- > 0 && list)
331     list = list->next;
332
333   if (list == NULL)
334     g_value_init (value, GTK_LIST_STORE (tree_model)->column_headers[column]);
335   else
336     _gtk_tree_data_list_node_to_value (list,
337                                        GTK_LIST_STORE (tree_model)->column_headers[column],
338                                        value);
339 }
340
341 static gboolean
342 gtk_list_store_iter_next (GtkTreeModel  *tree_model,
343                           GtkTreeIter   *iter)
344 {
345   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
346   g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE);
347
348   iter->user_data = G_SLIST (iter->user_data)->next;
349
350   return (iter->user_data != NULL);
351 }
352
353 static gboolean
354 gtk_list_store_iter_children (GtkTreeModel *tree_model,
355                               GtkTreeIter  *iter,
356                               GtkTreeIter  *parent)
357 {
358   iter->stamp = 0;
359   iter->user_data = NULL;
360
361   return FALSE;
362 }
363
364 static gboolean
365 gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
366                                GtkTreeIter  *iter)
367 {
368   return FALSE;
369 }
370
371 static gint
372 gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
373                                 GtkTreeIter  *iter)
374 {
375   if (iter == NULL)
376     return g_slist_length (G_SLIST (GTK_LIST_STORE (tree_model)->root));
377
378   return 0;
379 }
380
381 static gboolean
382 gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
383                                GtkTreeIter  *iter,
384                                GtkTreeIter  *parent,
385                                gint          n)
386 {
387   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
388
389   if (parent)
390     {
391       g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, FALSE);
392       iter->stamp = 0;
393       iter->user_data = NULL;
394
395       return FALSE;
396     }
397
398   iter->user_data = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root), n);
399   if (iter->user_data)
400     iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
401   else
402     iter->stamp = 0;
403
404   return (iter->user_data != NULL);
405 }
406
407 static gboolean
408 gtk_list_store_iter_parent (GtkTreeModel *tree_model,
409                             GtkTreeIter  *iter,
410                             GtkTreeIter  *child)
411 {
412   iter->stamp = 0;
413   iter->user_data = NULL;
414
415   return FALSE;
416 }
417
418 /* Public accessors */
419 /* This is a somewhat inelegant function that does a lot of list
420  * manipulations on it's own.
421  */
422 void
423 gtk_list_store_set_cell (GtkListStore *list_store,
424                          GtkTreeIter  *iter,
425                          gint          column,
426                          GValue       *value)
427 {
428   GtkTreeDataList *list;
429   GtkTreeDataList *prev;
430
431   g_return_if_fail (list_store != NULL);
432   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
433   g_return_if_fail (iter != NULL);
434   g_return_if_fail (column >= 0 && column < list_store->n_columns);
435
436   prev = list = G_SLIST (iter->user_data)->data;
437
438   while (list != NULL)
439     {
440       if (column == 0)
441         {
442           _gtk_tree_data_list_value_to_node (list, value);
443           gtk_signal_emit_by_name (GTK_OBJECT (list_store),
444                                    "changed",
445                                    NULL, iter);
446           return;
447         }
448
449       column--;
450       prev = list;
451       list = list->next;
452     }
453
454   if (G_SLIST (iter->user_data)->data == NULL)
455     {
456       G_SLIST (iter->user_data)->data = list = _gtk_tree_data_list_alloc ();
457       list->next = NULL;
458     }
459   else
460     {
461       list = prev->next = _gtk_tree_data_list_alloc ();
462       list->next = NULL;
463     }
464
465   while (column != 0)
466     {
467       list->next = _gtk_tree_data_list_alloc ();
468       list = list->next;
469       list->next = NULL;
470       column --;
471     }
472   _gtk_tree_data_list_value_to_node (list, value);
473   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
474                            "changed",
475                            NULL, iter);
476 }
477
478 void
479 gtk_list_store_set_valist (GtkListStore *list_store,
480                            GtkTreeIter  *iter,
481                            va_list      var_args)
482 {
483   gint column;
484
485   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
486
487   column = va_arg (var_args, gint);
488
489   while (column != -1)
490     {
491       GValue value = { 0, };
492       gchar *error = NULL;
493
494       if (column >= list_store->n_columns)
495         {
496           g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
497           break;
498         }
499       g_value_init (&value, list_store->column_headers[column]);
500
501       G_VALUE_COLLECT (&value, var_args, &error);
502       if (error)
503         {
504           g_warning ("%s: %s", G_STRLOC, error);
505           g_free (error);
506
507           /* we purposely leak the value here, it might not be
508            * in a sane state if an error condition occoured
509            */
510           break;
511         }
512
513       gtk_list_store_set_cell (list_store,
514                                iter,
515                                column,
516                                &value);
517
518       g_value_unset (&value);
519
520       column = va_arg (var_args, gint);
521     }
522 }
523
524 /**
525  * gtk_list_store_set:
526  * @list_store: a #GtkListStore
527  * @iter: row iterator
528  * @Varargs: pairs of column number and value, terminated with -1
529  * 
530  * Sets the value of one or more cells in the row referenced by @iter.
531  * The variable argument list should contain integer column numbers,
532  * each column number followed by the value to be set. For example,
533  * The list is terminated by a -1. For example, to set column 0 with type
534  * %G_TYPE_STRING to "Foo", you would write gtk_list_store_set (store, iter,
535  * 0, "Foo", -1).
536  **/
537 void
538 gtk_list_store_set (GtkListStore *list_store,
539                     GtkTreeIter  *iter,
540                     ...)
541 {
542   va_list var_args;
543
544   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
545
546   va_start (var_args, iter);
547   gtk_list_store_set_valist (list_store, iter, var_args);
548   va_end (var_args);
549 }
550
551 void
552 gtk_list_store_get_valist (GtkListStore *list_store,
553                            GtkTreeIter  *iter,
554                            va_list      var_args)
555 {
556   gint column;
557
558   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
559
560   column = va_arg (var_args, gint);
561
562   while (column != -1)
563     {
564       GValue value = { 0, };
565       gchar *error = NULL;
566
567       if (column >= list_store->n_columns)
568         {
569           g_warning ("%s: Invalid column number %d accessed (remember to end your list of columns with a -1)", G_STRLOC, column);
570           break;
571         }
572
573       gtk_list_store_get_value (GTK_TREE_MODEL (list_store), iter, column, &value);
574
575       G_VALUE_LCOPY (&value, var_args, &error);
576       if (error)
577         {
578           g_warning ("%s: %s", G_STRLOC, error);
579           g_free (error);
580
581           /* we purposely leak the value here, it might not be
582            * in a sane state if an error condition occoured
583            */
584           break;
585         }
586
587       g_value_unset (&value);
588
589       column = va_arg (var_args, gint);
590     }
591 }
592
593 void
594 gtk_list_store_get (GtkListStore *list_store,
595                     GtkTreeIter  *iter,
596                     ...)
597 {
598   va_list var_args;
599
600   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
601
602   va_start (var_args, iter);
603   gtk_list_store_get_valist (list_store, iter, var_args);
604   va_end (var_args);
605 }
606
607 void
608 gtk_list_store_remove (GtkListStore *list_store,
609                        GtkTreeIter  *iter)
610 {
611   GtkTreePath *path;
612
613   g_return_if_fail (list_store != NULL);
614   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
615
616   if (G_SLIST (iter->user_data)->data)
617     _gtk_tree_data_list_free ((GtkTreeDataList *) G_SLIST (iter->user_data)->data,
618                               list_store->column_headers);
619
620   path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
621   list_store->root = g_slist_remove_link (G_SLIST (list_store->root),
622                                           G_SLIST (iter->user_data));
623   list_store->stamp ++;
624   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
625                            "deleted",
626                            path);
627   gtk_tree_path_free (path);
628 }
629
630 void
631 gtk_list_store_insert (GtkListStore *list_store,
632                        GtkTreeIter  *iter,
633                        gint          position)
634 {
635   GSList *list;
636   GtkTreePath *path;
637
638   g_return_if_fail (list_store != NULL);
639   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
640   g_return_if_fail (iter != NULL);
641   g_return_if_fail (position < 0);
642
643   if (position == 0)
644     {
645       gtk_list_store_prepend (list_store, iter);
646       return;
647     }
648
649   iter->stamp = list_store->stamp;
650   iter->user_data = g_slist_alloc ();
651
652   list = g_slist_nth (G_SLIST (list_store->root), position - 1);
653   if (list)
654     {
655       G_SLIST (iter->user_data)->next = list->next;
656       list->next = G_SLIST (iter->user_data)->next;
657     }
658   path = gtk_tree_path_new ();
659   gtk_tree_path_append_index (path, position);
660   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
661                            "inserted",
662                            path, iter);
663   gtk_tree_path_free (path);
664 }
665
666 void
667 gtk_list_store_insert_before (GtkListStore *list_store,
668                               GtkTreeIter  *iter,
669                               GtkTreeIter  *sibling)
670 {
671   GtkTreePath *path;
672   GSList *list, *prev;
673   gint i = 0;
674
675   g_return_if_fail (list_store != NULL);
676   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
677   g_return_if_fail (iter != NULL);
678   g_return_if_fail (G_SLIST (iter)->next == NULL);
679
680   if (sibling == NULL)
681     {
682       gtk_list_store_append (list_store, iter);
683       return;
684     }
685
686   iter->stamp = list_store->stamp;
687   iter->user_data = g_slist_alloc ();
688
689   prev = list = list_store->root;
690   while (list && list != sibling->user_data)
691     {
692       prev = list;
693       list = list->next;
694       i++;
695     }
696   
697   if (prev)
698     {
699       prev->next = iter->user_data;
700     }
701   else
702     {
703       G_SLIST (iter->user_data)->next = list_store->root;
704       list_store->root = iter->user_data;
705     }
706
707   path = gtk_tree_path_new ();
708   gtk_tree_path_append_index (path, i);
709   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
710                            "inserted",
711                            path, iter);
712   gtk_tree_path_free (path);
713 }
714
715 void
716 gtk_list_store_insert_after (GtkListStore *list_store,
717                              GtkTreeIter  *iter,
718                              GtkTreeIter  *sibling)
719 {
720   GtkTreePath *path;
721   GSList *list;
722   gint i = 0;
723
724   g_return_if_fail (list_store != NULL);
725   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
726   g_return_if_fail (iter == NULL);
727   if (sibling)
728     g_return_if_fail (sibling->stamp == list_store->stamp);
729
730   if (sibling == NULL)
731     {
732       gtk_list_store_prepend (list_store, iter);
733       return;
734     }
735
736   for (list = list_store->root; list && list != sibling->user_data; list = list->next)
737     i++;
738
739   g_return_if_fail (list != NULL);
740
741   iter->stamp = list_store->stamp;
742   iter->user_data = g_slist_alloc ();
743
744   G_SLIST (iter->user_data)->next = G_SLIST (sibling->user_data)->next;
745   G_SLIST (sibling)->next = G_SLIST (iter);
746
747   path = gtk_tree_path_new ();
748   gtk_tree_path_append_index (path, i);
749   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
750                            "inserted",
751                            path, iter);
752   gtk_tree_path_free (path);
753 }
754
755 void
756 gtk_list_store_prepend (GtkListStore *list_store,
757                         GtkTreeIter  *iter)
758 {
759   GtkTreePath *path;
760
761   g_return_if_fail (list_store != NULL);
762   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
763   g_return_if_fail (iter != NULL);
764
765   iter->stamp = list_store->stamp;
766   iter->user_data = g_slist_alloc ();
767
768   G_SLIST (iter->user_data)->next = G_SLIST (list_store->root);
769   list_store->root = iter->user_data;
770
771   path = gtk_tree_path_new ();
772   gtk_tree_path_append_index (path, 0);
773   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
774                            "inserted",
775                            path, iter);
776   gtk_tree_path_free (path);
777 }
778
779 void
780 gtk_list_store_append (GtkListStore *list_store,
781                        GtkTreeIter  *iter)
782 {
783   GtkTreePath *path;
784   GSList *list, *prev;
785   gint i = 0;
786
787   g_return_if_fail (list_store != NULL);
788   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
789   g_return_if_fail (iter != NULL);
790
791   iter->stamp = list_store->stamp;
792   iter->user_data = g_slist_alloc ();
793
794   prev = list = list_store->root;
795   while (list)
796     {
797       prev = list;
798       list = list->next;
799       i++;
800     }
801   
802   if (prev)
803     prev->next = iter->user_data;
804   else
805     list_store->root = iter->user_data;
806
807   path = gtk_tree_path_new ();
808   gtk_tree_path_append_index (path, i);
809   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
810                            "inserted",
811                            path, iter);
812   gtk_tree_path_free (path);
813 }