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