]> Pileus Git - ~andy/gtk/blob - gtk/gtkliststore.c
remove validation idle
[~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 "gtktreednd.h"
26 #include <gobject/gvaluecollector.h>
27
28 #define G_SLIST(x) ((GSList *) x)
29
30 enum {
31   CHANGED,
32   INSERTED,
33   CHILD_TOGGLED,
34   DELETED,
35   LAST_SIGNAL
36 };
37
38 static guint list_store_signals[LAST_SIGNAL] = { 0 };
39
40 static void         gtk_list_store_init            (GtkListStore      *list_store);
41 static void         gtk_list_store_class_init      (GtkListStoreClass *class);
42 static void         gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
43 static void         gtk_list_store_drag_source_init(GtkTreeDragSourceIface *iface);
44 static void         gtk_list_store_drag_dest_init  (GtkTreeDragDestIface   *iface);
45 static guint        gtk_list_store_get_flags       (GtkTreeModel      *tree_model);
46 static gint         gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
47 static GType        gtk_list_store_get_column_type (GtkTreeModel      *tree_model,
48                                                     gint               index);
49 static gboolean     gtk_list_store_get_iter        (GtkTreeModel      *tree_model,
50                                                     GtkTreeIter       *iter,
51                                                     GtkTreePath       *path);
52 static GtkTreePath *gtk_list_store_get_path        (GtkTreeModel      *tree_model,
53                                                     GtkTreeIter       *iter);
54 static void         gtk_list_store_get_value       (GtkTreeModel      *tree_model,
55                                                     GtkTreeIter       *iter,
56                                                     gint               column,
57                                                     GValue            *value);
58 static gboolean     gtk_list_store_iter_next       (GtkTreeModel      *tree_model,
59                                                     GtkTreeIter       *iter);
60 static gboolean     gtk_list_store_iter_children   (GtkTreeModel      *tree_model,
61                                                     GtkTreeIter       *iter,
62                                                     GtkTreeIter       *parent);
63 static gboolean     gtk_list_store_iter_has_child  (GtkTreeModel      *tree_model,
64                                                     GtkTreeIter       *iter);
65 static gint         gtk_list_store_iter_n_children (GtkTreeModel      *tree_model,
66                                                     GtkTreeIter       *iter);
67 static gboolean     gtk_list_store_iter_nth_child  (GtkTreeModel      *tree_model,
68                                                     GtkTreeIter       *iter,
69                                                     GtkTreeIter       *parent,
70                                                     gint               n);
71 static gboolean     gtk_list_store_iter_parent     (GtkTreeModel      *tree_model,
72                                                     GtkTreeIter       *iter,
73                                                     GtkTreeIter       *child);
74
75 static gboolean gtk_list_store_drag_data_delete   (GtkTreeDragSource *drag_source,
76                                                    GtkTreePath       *path);
77 static gboolean gtk_list_store_drag_data_get      (GtkTreeDragSource *drag_source,
78                                                    GtkTreePath       *path,
79                                                    GtkSelectionData  *selection_data);
80 static gboolean gtk_list_store_drag_data_received (GtkTreeDragDest   *drag_dest,
81                                                    GtkTreePath       *dest,
82                                                    GtkSelectionData  *selection_data);
83 static gboolean gtk_list_store_row_drop_possible  (GtkTreeDragDest   *drag_dest,
84                                                    GtkTreeModel      *src_model,
85                                                    GtkTreePath       *src_path,
86                                                    GtkTreePath       *dest_path);
87 static void
88 validate_list_store (GtkListStore *list_store)
89 {
90   if (gtk_debug_flags & GTK_DEBUG_TREE)
91     {
92       g_assert (g_slist_length (list_store->root) == list_store->length);
93       
94       g_assert (g_slist_last (list_store->root) == list_store->tail);
95     }
96 }
97
98 GtkType
99 gtk_list_store_get_type (void)
100 {
101   static GtkType list_store_type = 0;
102
103   if (!list_store_type)
104     {
105       static const GTypeInfo list_store_info =
106       {
107         sizeof (GtkListStoreClass),
108         NULL,           /* base_init */
109         NULL,           /* base_finalize */
110         (GClassInitFunc) gtk_list_store_class_init,
111         NULL,           /* class_finalize */
112         NULL,           /* class_data */
113         sizeof (GtkListStore),
114         0,
115         (GInstanceInitFunc) gtk_list_store_init,
116       };
117
118       static const GInterfaceInfo tree_model_info =
119       {
120         (GInterfaceInitFunc) gtk_list_store_tree_model_init,
121         NULL,
122         NULL
123       };
124
125       static const GInterfaceInfo drag_source_info =
126       {
127         (GInterfaceInitFunc) gtk_list_store_drag_source_init,
128         NULL,
129         NULL
130       };
131
132       static const GInterfaceInfo drag_dest_info =
133       {
134         (GInterfaceInitFunc) gtk_list_store_drag_dest_init,
135         NULL,
136         NULL
137       };
138       
139       list_store_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkListStore", &list_store_info, 0);
140       g_type_add_interface_static (list_store_type,
141                                    GTK_TYPE_TREE_MODEL,
142                                    &tree_model_info);
143       g_type_add_interface_static (list_store_type,
144                                    GTK_TYPE_TREE_DRAG_SOURCE,
145                                    &drag_source_info);
146       g_type_add_interface_static (list_store_type,
147                                    GTK_TYPE_TREE_DRAG_DEST,
148                                    &drag_dest_info);
149     }
150
151   return list_store_type;
152 }
153
154 static void
155 gtk_list_store_class_init (GtkListStoreClass *class)
156 {
157   GtkObjectClass *object_class;
158
159   object_class = (GtkObjectClass*) class;
160
161   list_store_signals[CHANGED] =
162     gtk_signal_new ("changed",
163                     GTK_RUN_FIRST,
164                     GTK_CLASS_TYPE (object_class),
165                     GTK_SIGNAL_OFFSET (GtkListStoreClass, changed),
166                     gtk_marshal_VOID__BOXED_BOXED,
167                     G_TYPE_NONE, 2,
168                     GTK_TYPE_TREE_PATH,
169                     GTK_TYPE_TREE_ITER);
170   list_store_signals[INSERTED] =
171     gtk_signal_new ("inserted",
172                     GTK_RUN_FIRST,
173                     GTK_CLASS_TYPE (object_class),
174                     GTK_SIGNAL_OFFSET (GtkListStoreClass, inserted),
175                     gtk_marshal_VOID__BOXED_BOXED,
176                     G_TYPE_NONE, 2,
177                     GTK_TYPE_TREE_PATH,
178                     GTK_TYPE_TREE_ITER);
179   list_store_signals[CHILD_TOGGLED] =
180     gtk_signal_new ("child_toggled",
181                     GTK_RUN_FIRST,
182                     GTK_CLASS_TYPE (object_class),
183                     GTK_SIGNAL_OFFSET (GtkListStoreClass, child_toggled),
184                     gtk_marshal_VOID__BOXED_BOXED,
185                     G_TYPE_NONE, 2,
186                     GTK_TYPE_TREE_PATH,
187                     GTK_TYPE_TREE_ITER);
188   list_store_signals[DELETED] =
189     gtk_signal_new ("deleted",
190                     GTK_RUN_FIRST,
191                     GTK_CLASS_TYPE (object_class),
192                     GTK_SIGNAL_OFFSET (GtkListStoreClass, deleted),
193                     gtk_marshal_VOID__BOXED,
194                     G_TYPE_NONE, 1,
195                     GTK_TYPE_TREE_PATH);
196 }
197
198 static void
199 gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
200 {
201   iface->get_flags = gtk_list_store_get_flags;
202   iface->get_n_columns = gtk_list_store_get_n_columns;
203   iface->get_column_type = gtk_list_store_get_column_type;
204   iface->get_iter = gtk_list_store_get_iter;
205   iface->get_path = gtk_list_store_get_path;
206   iface->get_value = gtk_list_store_get_value;
207   iface->iter_next = gtk_list_store_iter_next;
208   iface->iter_children = gtk_list_store_iter_children;
209   iface->iter_has_child = gtk_list_store_iter_has_child;
210   iface->iter_n_children = gtk_list_store_iter_n_children;
211   iface->iter_nth_child = gtk_list_store_iter_nth_child;
212   iface->iter_parent = gtk_list_store_iter_parent;
213 }
214
215 static void
216 gtk_list_store_drag_source_init (GtkTreeDragSourceIface *iface)
217 {
218   iface->drag_data_delete = gtk_list_store_drag_data_delete;
219   iface->drag_data_get = gtk_list_store_drag_data_get;
220 }
221
222 static void
223 gtk_list_store_drag_dest_init   (GtkTreeDragDestIface   *iface)
224 {
225   iface->drag_data_received = gtk_list_store_drag_data_received;
226   iface->row_drop_possible = gtk_list_store_row_drop_possible;
227 }
228
229 static void
230 gtk_list_store_init (GtkListStore *list_store)
231 {
232   list_store->root = NULL;
233   list_store->tail = NULL;
234   list_store->stamp = g_random_int ();
235   list_store->length = 0;
236 }
237
238 /**
239  * gtk_list_store_new:
240  *
241  * Creates a new #GtkListStore. A #GtkListStore implements the
242  * #GtkTreeModel interface, and stores a linked list of
243  * rows; each row can have any number of columns. Columns are of uniform type,
244  * i.e. all cells in a column have the same type such as #G_TYPE_STRING or
245  * #GDK_TYPE_PIXBUF. Use #GtkListStore to store data to be displayed in a
246  * #GtkTreeView.
247  * 
248  * Return value: a new #GtkListStore
249  **/
250 GtkListStore *
251 gtk_list_store_new (void)
252 {
253   return GTK_LIST_STORE (gtk_type_new (gtk_list_store_get_type ()));
254 }
255
256 /**
257  * gtk_list_store_new_with_types:
258  * @n_columns: number of columns in the list store
259  * @Varargs: pairs of column number and #GType
260  *
261  * Creates a new list store as with gtk_list_store_new(),
262  * simultaneously setting up the columns and column types as with
263  * gtk_list_store_set_n_columns() and
264  * gtk_list_store_set_column_type().
265  * 
266  * 
267  * Return value: a new #GtkListStore
268  **/
269 GtkListStore *
270 gtk_list_store_new_with_types (gint n_columns,
271                                ...)
272 {
273   GtkListStore *retval;
274   va_list args;
275   gint i;
276
277   g_return_val_if_fail (n_columns > 0, NULL);
278
279   retval = gtk_list_store_new ();
280   gtk_list_store_set_n_columns (retval, n_columns);
281
282   va_start (args, n_columns);
283
284   for (i = 0; i < n_columns; i++)
285     gtk_list_store_set_column_type (retval, i, va_arg (args, GType));
286
287   va_end (args);
288
289   return retval;
290 }
291
292 /**
293  * gtk_list_store_set_n_columns:
294  * @store: a #GtkListStore
295  * @n_columns: number of columns
296  *
297  * Sets the number of columns in the #GtkListStore.
298  * 
299  **/
300 void
301 gtk_list_store_set_n_columns (GtkListStore *list_store,
302                               gint          n_columns)
303 {
304   GType *new_columns;
305
306   g_return_if_fail (list_store != NULL);
307   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
308   g_return_if_fail (n_columns > 0);
309
310   if (list_store->n_columns == n_columns)
311     return;
312
313   new_columns = g_new0 (GType, n_columns);
314   if (list_store->column_headers)
315     {
316       /* copy the old header orders over */
317       if (n_columns >= list_store->n_columns)
318         memcpy (new_columns, list_store->column_headers, list_store->n_columns * sizeof (gchar *));
319       else
320         memcpy (new_columns, list_store->column_headers, n_columns * sizeof (GType));
321
322       g_free (list_store->column_headers);
323     }
324
325   list_store->column_headers = new_columns;
326   list_store->n_columns = n_columns;
327 }
328
329 /**
330  * gtk_list_store_set_column_type:
331  * @store: a #GtkListStore
332  * @column: column number
333  * @type: type of the data stored in @column
334  *
335  * Supported types include: %G_TYPE_UINT, %G_TYPE_INT, %G_TYPE_UCHAR,
336  * %G_TYPE_CHAR, %G_TYPE_BOOLEAN, %G_TYPE_POINTER, %G_TYPE_FLOAT, %G_TYPE_STRING,
337  * %G_TYPE_OBJECT, and %G_TYPE_BOXED, along with subclasses of those types such
338  * as %GDK_TYPE_PIXBUF.
339  * 
340  **/
341 void
342 gtk_list_store_set_column_type (GtkListStore *list_store,
343                                 gint          column,
344                                 GType         type)
345 {
346   g_return_if_fail (list_store != NULL);
347   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
348   g_return_if_fail (column >=0 && column < list_store->n_columns);
349
350   list_store->column_headers[column] = type;
351 }
352
353 /* Fulfill the GtkTreeModel requirements */
354 static guint
355 gtk_list_store_get_flags (GtkTreeModel *tree_model)
356 {
357   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);
358
359   return GTK_TREE_MODEL_ITERS_PERSIST;
360 }
361
362 static gint
363 gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
364 {
365   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);
366
367   return GTK_LIST_STORE (tree_model)->n_columns;
368 }
369
370 static GType
371 gtk_list_store_get_column_type (GtkTreeModel *tree_model,
372                                 gint          index)
373 {
374   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), G_TYPE_INVALID);
375   g_return_val_if_fail (index < GTK_LIST_STORE (tree_model)->n_columns &&
376                         index >= 0, G_TYPE_INVALID);
377
378   return GTK_LIST_STORE (tree_model)->column_headers[index];
379 }
380
381 static gboolean
382 gtk_list_store_get_iter (GtkTreeModel *tree_model,
383                          GtkTreeIter  *iter,
384                          GtkTreePath  *path)
385 {
386   GSList *list;
387   gint i;
388   
389   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
390   g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);  
391
392   i = gtk_tree_path_get_indices (path)[0];
393
394   if (i >= GTK_LIST_STORE (tree_model)->length)
395     return FALSE;
396   
397   list = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root),
398                       i);
399
400   /* If this fails, list_store->length has gotten mangled. */
401   g_assert (list);
402   
403   iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
404   iter->user_data = list;
405   return TRUE;
406 }
407
408 static GtkTreePath *
409 gtk_list_store_get_path (GtkTreeModel *tree_model,
410                          GtkTreeIter  *iter)
411 {
412   GtkTreePath *retval;
413   GSList *list;
414   gint i = 0;
415
416   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), NULL);
417   g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, NULL);
418
419   for (list = G_SLIST (GTK_LIST_STORE (tree_model)->root); list; list = list->next)
420     {
421       if (list == G_SLIST (iter->user_data))
422         break;
423       i++;
424     }
425   if (list == NULL)
426     return NULL;
427
428   retval = gtk_tree_path_new ();
429   gtk_tree_path_append_index (retval, i);
430   return retval;
431 }
432
433 static void
434 gtk_list_store_get_value (GtkTreeModel *tree_model,
435                           GtkTreeIter  *iter,
436                           gint          column,
437                           GValue       *value)
438 {
439   GtkTreeDataList *list;
440   gint tmp_column = column;
441
442   g_return_if_fail (GTK_IS_LIST_STORE (tree_model));
443   g_return_if_fail (column < GTK_LIST_STORE (tree_model)->n_columns);
444   g_return_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp);
445
446   list = G_SLIST (iter->user_data)->data;
447
448   while (tmp_column-- > 0 && list)
449     list = list->next;
450
451   if (list == NULL)
452     g_value_init (value, GTK_LIST_STORE (tree_model)->column_headers[column]);
453   else
454     _gtk_tree_data_list_node_to_value (list,
455                                        GTK_LIST_STORE (tree_model)->column_headers[column],
456                                        value);
457 }
458
459 static gboolean
460 gtk_list_store_iter_next (GtkTreeModel  *tree_model,
461                           GtkTreeIter   *iter)
462 {
463   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
464   g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE);
465
466   if (G_SLIST (iter->user_data)->next)
467     {
468       iter->user_data = G_SLIST (iter->user_data)->next;
469       return TRUE;
470     }
471   else
472     return FALSE;
473 }
474
475 static gboolean
476 gtk_list_store_iter_children (GtkTreeModel *tree_model,
477                               GtkTreeIter  *iter,
478                               GtkTreeIter  *parent)
479 {
480   /* this is a list, nodes have no children */
481   if (parent)
482     return FALSE;
483
484   /* but if parent == NULL we return the list itself as children of the
485    * "root"
486    */
487   
488   if (GTK_LIST_STORE (tree_model)->root)
489     {
490       iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
491       iter->user_data = GTK_LIST_STORE (tree_model)->root;
492       return TRUE;
493     }
494   else
495     return FALSE;
496 }
497
498 static gboolean
499 gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
500                                GtkTreeIter  *iter)
501 {
502   return FALSE;
503 }
504
505 static gint
506 gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
507                                 GtkTreeIter  *iter)
508 {
509   if (iter == NULL)
510     return GTK_LIST_STORE (tree_model)->length;
511   else
512     return 0;
513 }
514
515 static gboolean
516 gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
517                                GtkTreeIter  *iter,
518                                GtkTreeIter  *parent,
519                                gint          n)
520 {
521   GSList *child;
522   
523   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
524
525   if (parent)
526     return FALSE;
527
528   child = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root), n);
529
530   if (child)
531     {
532       iter->user_data = child;
533       iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
534       return TRUE;
535     }
536   else
537     return FALSE;
538 }
539
540 static gboolean
541 gtk_list_store_iter_parent (GtkTreeModel *tree_model,
542                             GtkTreeIter  *iter,
543                             GtkTreeIter  *child)
544 {
545   return FALSE;
546 }
547
548 /* Public accessors */
549 /* This is a somewhat inelegant function that does a lot of list
550  * manipulations on it's own.
551  */
552
553 /**
554  * gtk_list_store_set_cell:
555  * @store: a #GtkListStore
556  * @iter: iterator for the row you're modifying
557  * @column: column number to modify
558  * @value: new value for the cell
559  *
560  * Sets the data in the cell specified by @iter and @column.
561  * The type of @value must be convertible to the type of the
562  * column.
563  * 
564  **/
565 void
566 gtk_list_store_set_cell (GtkListStore *list_store,
567                          GtkTreeIter  *iter,
568                          gint          column,
569                          GValue       *value)
570 {
571   GtkTreeDataList *list;
572   GtkTreeDataList *prev;
573
574   g_return_if_fail (list_store != NULL);
575   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
576   g_return_if_fail (iter != NULL);
577   g_return_if_fail (column >= 0 && column < list_store->n_columns);
578
579   prev = list = G_SLIST (iter->user_data)->data;
580
581   while (list != NULL)
582     {
583       if (column == 0)
584         {
585           _gtk_tree_data_list_value_to_node (list, value);
586           gtk_signal_emit_by_name (GTK_OBJECT (list_store),
587                                    "changed",
588                                    NULL, iter);
589           return;
590         }
591
592       column--;
593       prev = list;
594       list = list->next;
595     }
596
597   if (G_SLIST (iter->user_data)->data == NULL)
598     {
599       G_SLIST (iter->user_data)->data = list = _gtk_tree_data_list_alloc ();
600       list->next = NULL;
601     }
602   else
603     {
604       list = prev->next = _gtk_tree_data_list_alloc ();
605       list->next = NULL;
606     }
607
608   while (column != 0)
609     {
610       list->next = _gtk_tree_data_list_alloc ();
611       list = list->next;
612       list->next = NULL;
613       column --;
614     }
615   _gtk_tree_data_list_value_to_node (list, value);
616   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
617                            "changed",
618                            NULL, iter);
619 }
620
621 /**
622  * gtk_list_store_set_valist:
623  * @list_store: a #GtkListStore
624  * @iter: row to set data for
625  * @var_args: va_list of column/value pairs
626  *
627  * See gtk_list_store_set(); this version takes a va_list for
628  * use by language bindings.
629  * 
630  **/
631 void
632 gtk_list_store_set_valist (GtkListStore *list_store,
633                            GtkTreeIter  *iter,
634                            va_list       var_args)
635 {
636   gint column;
637
638   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
639
640   column = va_arg (var_args, gint);
641
642   while (column != -1)
643     {
644       GValue value = { 0, };
645       gchar *error = NULL;
646
647       if (column >= list_store->n_columns)
648         {
649           g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
650           break;
651         }
652       g_value_init (&value, list_store->column_headers[column]);
653
654       G_VALUE_COLLECT (&value, var_args, &error);
655       if (error)
656         {
657           g_warning ("%s: %s", G_STRLOC, error);
658           g_free (error);
659
660           /* we purposely leak the value here, it might not be
661            * in a sane state if an error condition occoured
662            */
663           break;
664         }
665
666       gtk_list_store_set_cell (list_store,
667                                iter,
668                                column,
669                                &value);
670
671       g_value_unset (&value);
672
673       column = va_arg (var_args, gint);
674     }
675 }
676
677 /**
678  * gtk_list_store_set:
679  * @list_store: a #GtkListStore
680  * @iter: row iterator
681  * @Varargs: pairs of column number and value, terminated with -1
682  * 
683  * Sets the value of one or more cells in the row referenced by @iter.
684  * The variable argument list should contain integer column numbers,
685  * each column number followed by the value to be set.
686  * The list is terminated by a -1. For example, to set column 0 with type
687  * %G_TYPE_STRING to "Foo", you would write gtk_list_store_set (store, iter,
688  * 0, "Foo", -1).
689  **/
690 void
691 gtk_list_store_set (GtkListStore *list_store,
692                     GtkTreeIter  *iter,
693                     ...)
694 {
695   va_list var_args;
696
697   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
698
699   va_start (var_args, iter);
700   gtk_list_store_set_valist (list_store, iter, var_args);
701   va_end (var_args);
702 }
703
704 /**
705  * gtk_list_store_get_valist:
706  * @list_store: a #GtkListStore
707  * @iter: a row in @list_store
708  * @var_args: va_list of column/return location pairs
709  *
710  * See gtk_list_store_get(), this version takes a va_list for
711  * language bindings to use.
712  * 
713  **/
714 void
715 gtk_list_store_get_valist (GtkListStore *list_store,
716                            GtkTreeIter  *iter,
717                            va_list      var_args)
718 {
719   gint column;
720
721   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
722
723   column = va_arg (var_args, gint);
724
725   while (column != -1)
726     {
727       GValue value = { 0, };
728       gchar *error = NULL;
729
730       if (column >= list_store->n_columns)
731         {
732           g_warning ("%s: Invalid column number %d accessed (remember to end your list of columns with a -1)", G_STRLOC, column);
733           break;
734         }
735
736       gtk_list_store_get_value (GTK_TREE_MODEL (list_store), iter, column, &value);
737
738       G_VALUE_LCOPY (&value, var_args, &error);
739       if (error)
740         {
741           g_warning ("%s: %s", G_STRLOC, error);
742           g_free (error);
743
744           /* we purposely leak the value here, it might not be
745            * in a sane state if an error condition occoured
746            */
747           break;
748         }
749
750       g_value_unset (&value);
751
752       column = va_arg (var_args, gint);
753     }
754 }
755
756 /**
757  * gtk_list_store_get:
758  * @list_store: a #GtkListStore
759  * @iter: a row in @list_store
760  * @Varargs: pairs of column number and value return locations, terminated by -1
761  *
762  * Gets the value of one or more cells in the row referenced by @iter.
763  * The variable argument list should contain integer column numbers,
764  * each column number followed by a place to store the value being
765  * retrieved.  The list is terminated by a -1. For example, to get a
766  * value from column 0 with type %G_TYPE_STRING, you would
767  * write: gtk_list_store_set (store, iter, 0, &place_string_here, -1),
768  * where place_string_here is a gchar* to be filled with the string.
769  * If appropriate, the returned values have to be freed or unreferenced.
770  * 
771  **/
772 void
773 gtk_list_store_get (GtkListStore *list_store,
774                     GtkTreeIter  *iter,
775                     ...)
776 {
777   va_list var_args;
778
779   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
780
781   va_start (var_args, iter);
782   gtk_list_store_get_valist (list_store, iter, var_args);
783   va_end (var_args);
784 }
785
786 static GSList*
787 remove_link_saving_prev (GSList  *list,
788                          GSList  *link,
789                          GSList **prevp)
790 {
791   GSList *tmp;
792   GSList *prev;
793
794   prev = NULL;
795   tmp = list;
796
797   while (tmp)
798     {
799       if (tmp == link)
800         {
801           if (prev)
802             prev->next = link->next;
803
804           if (list == link)
805             list = list->next;
806
807           link->next = NULL;
808           break;
809         }
810
811       prev = tmp;
812       tmp = tmp->next;
813     }
814
815   *prevp = prev;
816   
817   return list;
818 }
819
820 static void
821 gtk_list_store_remove_silently (GtkListStore *list_store,
822                                 GtkTreeIter  *iter,
823                                 GtkTreePath  *path)
824 {
825   if (G_SLIST (iter->user_data)->data)
826     {
827       _gtk_tree_data_list_free ((GtkTreeDataList *) G_SLIST (iter->user_data)->data,
828                                 list_store->column_headers);
829       G_SLIST (iter->user_data)->data = NULL;
830     }
831
832   {
833     GSList *prev = NULL;
834     
835     list_store->root = remove_link_saving_prev (G_SLIST (list_store->root),
836                                                 G_SLIST (iter->user_data),
837                                                 &prev);
838
839     list_store->length -= 1;
840     
841     if (iter->user_data == list_store->tail)
842       list_store->tail = prev;
843   }
844   
845   list_store->stamp ++;
846 }
847
848 /**
849  * gtk_list_store_remove:
850  * @store: a #GtkListStore
851  * @iter: a row in @list_store
852  *
853  * Removes the given row from the list store, emitting the
854  * "deleted" signal on #GtkTreeModel.
855  * 
856  **/
857 void
858 gtk_list_store_remove (GtkListStore *list_store,
859                        GtkTreeIter  *iter)
860 {
861   GtkTreePath *path;
862
863   g_return_if_fail (list_store != NULL);
864   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
865   g_return_if_fail (iter->user_data != NULL);  
866
867   path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
868
869   validate_list_store (list_store);
870   
871   gtk_list_store_remove_silently (list_store, iter, path);
872
873   validate_list_store (list_store);  
874   
875   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
876                            "deleted",
877                            path);
878   gtk_tree_path_free (path);
879 }
880
881 static void
882 insert_after (GtkListStore *list_store,
883               GSList       *sibling,
884               GSList       *new_list)
885 {
886   g_return_if_fail (sibling != NULL);
887   g_return_if_fail (new_list != NULL);
888   
889   /* insert new node after list */
890   new_list->next = sibling->next;
891   sibling->next = new_list;
892
893   /* if list was the tail, the new node is the new tail */
894   if (sibling == list_store->tail)
895     list_store->tail = new_list;
896
897   list_store->length += 1;
898 }
899
900 /**
901  * gtk_list_store_insert:
902  * @store: a #GtkListStore
903  * @iter: iterator to initialize with the new row
904  * @position: position to insert the new row
905  *
906  * Creates a new row at @position, initializing @iter to point to the
907  * new row, and emitting the "inserted" signal from the #GtkTreeModel
908  * interface.
909  * 
910  **/
911 void
912 gtk_list_store_insert (GtkListStore *list_store,
913                        GtkTreeIter  *iter,
914                        gint          position)
915 {
916   GSList *list;
917   GtkTreePath *path;
918   GSList *new_list;
919   
920   g_return_if_fail (list_store != NULL);
921   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
922   g_return_if_fail (iter != NULL);
923   g_return_if_fail (position >= 0);
924
925   if (position == 0)
926     {
927       gtk_list_store_prepend (list_store, iter);
928       return;
929     }
930
931   new_list = g_slist_alloc ();
932
933   list = g_slist_nth (G_SLIST (list_store->root), position - 1);
934
935   if (list == NULL)
936     {
937       g_warning ("%s: position %d is off the end of the list\n", G_STRLOC, position);
938       return;
939     }
940
941   insert_after (list_store, list, new_list);
942   
943   iter->stamp = list_store->stamp;
944   iter->user_data = new_list;
945
946   validate_list_store (list_store);
947   
948   path = gtk_tree_path_new ();
949   gtk_tree_path_append_index (path, position);
950   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
951                            "inserted",
952                            path, iter);
953   gtk_tree_path_free (path);
954 }
955
956 /**
957  * gtk_list_store_insert_before:
958  * @store: a #GtkListStore
959  * @iter: iterator to initialize with the new row
960  * @sibling: an existing row
961  *
962  * Inserts a new row before @sibling, initializing @iter to point to
963  * the new row, and emitting the "inserted" signal from the
964  * #GtkTreeModel interface.
965  * 
966  **/
967 void
968 gtk_list_store_insert_before (GtkListStore *list_store,
969                               GtkTreeIter  *iter,
970                               GtkTreeIter  *sibling)
971 {
972   GtkTreePath *path;
973   GSList *list, *prev, *new_list;
974   gint i = 0;
975
976   g_return_if_fail (list_store != NULL);
977   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
978   g_return_if_fail (iter != NULL);
979
980   if (sibling == NULL)
981     {
982       gtk_list_store_append (list_store, iter);
983       return;
984     }
985   
986   new_list = g_slist_alloc ();
987
988   prev = NULL;
989   list = list_store->root;
990   while (list && list != sibling->user_data)
991     {
992       prev = list;
993       list = list->next;
994       i++;
995     }
996
997   if (list != sibling->user_data)
998     {
999       g_warning ("%s: sibling iterator invalid? not found in the list", G_STRLOC);
1000       return;
1001     }
1002
1003   /* if there are no nodes, we become the list tail, otherwise we
1004    * are inserting before any existing nodes so we can't change
1005    * the tail
1006    */
1007
1008   if (list_store->root == NULL)
1009     list_store->tail = new_list;
1010   
1011   if (prev)
1012     {
1013       new_list->next = prev->next;
1014       prev->next = new_list;
1015     }
1016   else
1017     {
1018       new_list->next = list_store->root;
1019       list_store->root = new_list;
1020     }
1021
1022   iter->stamp = list_store->stamp;
1023   iter->user_data = new_list;
1024
1025   list_store->length += 1;
1026
1027   validate_list_store (list_store);
1028   
1029   path = gtk_tree_path_new ();
1030   gtk_tree_path_append_index (path, i);
1031   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
1032                            "inserted",
1033                            path, iter);
1034   gtk_tree_path_free (path);
1035 }
1036
1037 /**
1038  * gtk_list_store_insert_after:
1039  * @store: a #GtkListStore
1040  * @iter: iterator to initialize with the new row
1041  * @sibling: an existing row
1042  *
1043  * Inserts a new row after @sibling, initializing @iter to point to
1044  * the new row, and emitting the "inserted" signal from the
1045  * #GtkTreeModel interface.
1046  * 
1047  **/
1048 void
1049 gtk_list_store_insert_after (GtkListStore *list_store,
1050                              GtkTreeIter  *iter,
1051                              GtkTreeIter  *sibling)
1052 {
1053   GtkTreePath *path;
1054   GSList *list, *new_list;
1055   gint i = 0;
1056
1057   g_return_if_fail (list_store != NULL);
1058   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1059   g_return_if_fail (iter != NULL);
1060   if (sibling)
1061     g_return_if_fail (sibling->stamp == list_store->stamp);
1062
1063   if (sibling == NULL)
1064     {
1065       gtk_list_store_prepend (list_store, iter);
1066       return;
1067     }
1068
1069   for (list = list_store->root; list && list != sibling->user_data; list = list->next)
1070     i++;
1071
1072   g_return_if_fail (list == sibling->user_data);
1073
1074   new_list = g_slist_alloc ();
1075
1076   insert_after (list_store, list, new_list);
1077   
1078   iter->stamp = list_store->stamp;
1079   iter->user_data = new_list;
1080
1081   validate_list_store (list_store);
1082   
1083   path = gtk_tree_path_new ();
1084   gtk_tree_path_append_index (path, i);
1085   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
1086                            "inserted",
1087                            path, iter);
1088   gtk_tree_path_free (path);
1089 }
1090
1091 /**
1092  * gtk_list_store_prepend:
1093  * @store: a #GtkListStore
1094  * @iter: iterator to initialize with new row
1095  *
1096  * Prepends a row to @store, initializing @iter to point to the
1097  * new row, and emitting the "inserted" signal on the #GtkTreeModel
1098  * interface for the @store.
1099  * 
1100  **/
1101 void
1102 gtk_list_store_prepend (GtkListStore *list_store,
1103                         GtkTreeIter  *iter)
1104 {
1105   GtkTreePath *path;
1106
1107   g_return_if_fail (list_store != NULL);
1108   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1109   g_return_if_fail (iter != NULL);
1110
1111   iter->stamp = list_store->stamp;
1112   iter->user_data = g_slist_alloc ();
1113
1114   if (list_store->root == NULL)
1115     list_store->tail = iter->user_data;
1116   
1117   G_SLIST (iter->user_data)->next = G_SLIST (list_store->root);
1118   list_store->root = iter->user_data;
1119
1120   list_store->length += 1;
1121
1122   validate_list_store (list_store);
1123   
1124   path = gtk_tree_path_new ();
1125   gtk_tree_path_append_index (path, 0);
1126   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
1127                            "inserted",
1128                            path, iter);
1129   gtk_tree_path_free (path);
1130 }
1131
1132 /**
1133  * gtk_list_store_append:
1134  * @store: a #GtkListStore
1135  * @iter: iterator to initialize with the new row
1136  *
1137  * Appends a row to @store, initializing @iter to point to the
1138  * new row, and emitting the "inserted" signal on the #GtkTreeModel
1139  * interface for the @store.
1140  * 
1141  **/
1142 void
1143 gtk_list_store_append (GtkListStore *list_store,
1144                        GtkTreeIter  *iter)
1145 {
1146   GtkTreePath *path;
1147   gint i = 0;
1148
1149   g_return_if_fail (list_store != NULL);
1150   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1151   g_return_if_fail (iter != NULL);
1152
1153   iter->stamp = list_store->stamp;
1154   iter->user_data = g_slist_alloc ();
1155
1156   if (list_store->tail)
1157     list_store->tail->next = iter->user_data;
1158   else
1159     list_store->root = iter->user_data;
1160
1161   list_store->tail = iter->user_data;
1162
1163   list_store->length += 1;
1164
1165   validate_list_store (list_store);
1166   
1167   path = gtk_tree_path_new ();
1168   gtk_tree_path_append_index (path, i);
1169   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
1170                            "inserted",
1171                            path, iter);
1172   gtk_tree_path_free (path);
1173 }
1174
1175 static gboolean
1176 gtk_list_store_drag_data_delete (GtkTreeDragSource *drag_source,
1177                                  GtkTreePath       *path)
1178 {
1179   GtkTreeIter iter;
1180   g_return_val_if_fail (GTK_IS_LIST_STORE (drag_source), FALSE);
1181   
1182   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source),
1183                                &iter,
1184                                path))
1185     {
1186       gtk_list_store_remove (GTK_LIST_STORE (drag_source),
1187                              &iter);
1188       return TRUE;
1189     }
1190   else
1191     {
1192       return FALSE;
1193     }
1194 }
1195
1196 static gboolean
1197 gtk_list_store_drag_data_get (GtkTreeDragSource *drag_source,
1198                               GtkTreePath       *path,
1199                               GtkSelectionData  *selection_data)
1200 {
1201   g_return_val_if_fail (GTK_IS_LIST_STORE (drag_source), FALSE);
1202
1203   /* Note that we don't need to handle the GTK_TREE_MODEL_ROW
1204    * target, because the default handler does it for us, but
1205    * we do anyway for the convenience of someone maybe overriding the
1206    * default handler.
1207    */
1208
1209   if (gtk_selection_data_set_tree_row (selection_data,
1210                                        GTK_TREE_MODEL (drag_source),
1211                                        path))
1212     {
1213       return TRUE;
1214     }
1215   else
1216     {
1217       /* FIXME handle text targets at least. */
1218     }
1219
1220   return FALSE;
1221 }
1222
1223 static gboolean
1224 gtk_list_store_drag_data_received (GtkTreeDragDest   *drag_dest,
1225                                    GtkTreePath       *dest,
1226                                    GtkSelectionData  *selection_data)
1227 {
1228   GtkTreeModel *tree_model;
1229   GtkListStore *list_store;
1230   GtkTreeModel *src_model = NULL;
1231   GtkTreePath *src_path = NULL;
1232   gboolean retval = FALSE;
1233   
1234   g_return_val_if_fail (GTK_IS_LIST_STORE (drag_dest), FALSE);
1235
1236   tree_model = GTK_TREE_MODEL (drag_dest);
1237   list_store = GTK_LIST_STORE (drag_dest);
1238   
1239   if (gtk_selection_data_get_tree_row (selection_data,
1240                                        &src_model,
1241                                        &src_path) &&
1242       src_model == tree_model)
1243     {
1244       /* Copy the given row to a new position */
1245       GtkTreeIter src_iter;
1246       GtkTreeIter dest_iter;
1247       GtkTreePath *prev;
1248       
1249       if (!gtk_tree_model_get_iter (src_model,
1250                                     &src_iter,
1251                                     src_path))
1252         {
1253           goto out;
1254         }
1255
1256       /* Get the path to insert _after_ (dest is the path to insert _before_) */
1257       prev = gtk_tree_path_copy (dest);
1258
1259       if (!gtk_tree_path_prev (prev))
1260         {
1261           /* dest was the first spot in the list; which means we are supposed
1262            * to prepend.
1263            */
1264           gtk_list_store_prepend (GTK_LIST_STORE (tree_model),
1265                                   &dest_iter);
1266           
1267           retval = TRUE;
1268         }
1269       else
1270         {
1271           if (gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_model),
1272                                        &dest_iter,
1273                                        prev))
1274             {
1275               GtkTreeIter tmp_iter = dest_iter;
1276               gtk_list_store_insert_after (GTK_LIST_STORE (tree_model),
1277                                            &dest_iter,
1278                                            &tmp_iter);
1279               retval = TRUE;
1280             }
1281         }
1282
1283       gtk_tree_path_free (prev);
1284       
1285       /* If we succeeded in creating dest_iter, copy data from src
1286        */
1287       if (retval)
1288         {
1289           GtkTreeDataList *dl = G_SLIST (src_iter.user_data)->data;
1290           GtkTreeDataList *copy_head = NULL;
1291           GtkTreeDataList *copy_prev = NULL;
1292           GtkTreeDataList *copy_iter = NULL;
1293           gint col;
1294
1295           col = 0;
1296           while (dl)
1297             {
1298               copy_iter = _gtk_tree_data_list_node_copy (dl,
1299                                                          list_store->column_headers[col]);
1300               
1301               if (copy_head == NULL)
1302                 copy_head = copy_iter;
1303
1304               if (copy_prev)
1305                 copy_prev->next = copy_iter;
1306
1307               copy_prev = copy_iter;
1308
1309               dl = dl->next;
1310               ++col;
1311             }
1312           
1313           G_SLIST (dest_iter.user_data)->data = copy_head;
1314           
1315           gtk_signal_emit_by_name (GTK_OBJECT (tree_model),
1316                                    "changed",
1317                                    NULL, &dest_iter);
1318         }
1319     }
1320   else
1321     {
1322       /* FIXME maybe add some data targets eventually, or handle text
1323        * targets in the simple case.
1324        */
1325     }
1326
1327  out:
1328   
1329   if (src_path)
1330     gtk_tree_path_free (src_path);
1331   
1332   return retval;  
1333 }
1334
1335 static gboolean
1336 gtk_list_store_row_drop_possible (GtkTreeDragDest *drag_dest,
1337                                   GtkTreeModel    *src_model,
1338                                   GtkTreePath     *src_path,
1339                                   GtkTreePath     *dest_path)
1340 {
1341   gint *indices;
1342   
1343   g_return_val_if_fail (GTK_IS_LIST_STORE (drag_dest), FALSE);
1344
1345   if (src_model != GTK_TREE_MODEL (drag_dest))
1346     return FALSE;
1347   
1348   if (gtk_tree_path_get_depth (dest_path) != 1)
1349     return FALSE;
1350
1351   /* can drop before any existing node, or before one past any existing. */
1352
1353   indices = gtk_tree_path_get_indices (dest_path);
1354
1355   if (indices[0] <= GTK_LIST_STORE (drag_dest)->length)
1356     return TRUE;
1357   else
1358     return FALSE;
1359 }