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