]> Pileus Git - ~andy/gtk/blob - gtk/gtkliststore.c
Hide GtkTreeViewColumn buttons when header_window is not visible
[~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 "config.h"
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <gobject/gvaluecollector.h>
25 #include "gtktreemodel.h"
26 #include "gtkliststore.h"
27 #include "gtktreedatalist.h"
28 #include "gtktreednd.h"
29 #include "gtkintl.h"
30 #include "gtkbuildable.h"
31 #include "gtkbuilderprivate.h"
32
33
34 struct _GtkListStorePrivate
35 {
36   GtkSortType order;
37   GtkTreeIterCompareFunc default_sort_func;
38
39   GDestroyNotify default_sort_destroy;
40   GList *sort_list;
41   GType *column_headers;
42
43   gint stamp;
44   gint n_columns;
45   gint sort_column_id;
46   gint length;
47
48   guint columns_dirty : 1;
49
50   gpointer default_sort_data;
51   gpointer seq;         /* head of the list */
52 };
53
54 #define GTK_LIST_STORE_IS_SORTED(list) (((GtkListStore*)(list))->priv->sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
55 #define VALID_ITER(iter, list_store) ((iter)!= NULL && (iter)->user_data != NULL && list_store->priv->stamp == (iter)->stamp && !g_sequence_iter_is_end ((iter)->user_data) && g_sequence_iter_get_sequence ((iter)->user_data) == list_store->priv->seq)
56
57 static void         gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
58 static void         gtk_list_store_drag_source_init(GtkTreeDragSourceIface *iface);
59 static void         gtk_list_store_drag_dest_init  (GtkTreeDragDestIface   *iface);
60 static void         gtk_list_store_sortable_init   (GtkTreeSortableIface   *iface);
61 static void         gtk_list_store_buildable_init  (GtkBuildableIface      *iface);
62 static void         gtk_list_store_finalize        (GObject           *object);
63 static GtkTreeModelFlags gtk_list_store_get_flags  (GtkTreeModel      *tree_model);
64 static gint         gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
65 static GType        gtk_list_store_get_column_type (GtkTreeModel      *tree_model,
66                                                     gint               index);
67 static gboolean     gtk_list_store_get_iter        (GtkTreeModel      *tree_model,
68                                                     GtkTreeIter       *iter,
69                                                     GtkTreePath       *path);
70 static GtkTreePath *gtk_list_store_get_path        (GtkTreeModel      *tree_model,
71                                                     GtkTreeIter       *iter);
72 static void         gtk_list_store_get_value       (GtkTreeModel      *tree_model,
73                                                     GtkTreeIter       *iter,
74                                                     gint               column,
75                                                     GValue            *value);
76 static gboolean     gtk_list_store_iter_next       (GtkTreeModel      *tree_model,
77                                                     GtkTreeIter       *iter);
78 static gboolean     gtk_list_store_iter_children   (GtkTreeModel      *tree_model,
79                                                     GtkTreeIter       *iter,
80                                                     GtkTreeIter       *parent);
81 static gboolean     gtk_list_store_iter_has_child  (GtkTreeModel      *tree_model,
82                                                     GtkTreeIter       *iter);
83 static gint         gtk_list_store_iter_n_children (GtkTreeModel      *tree_model,
84                                                     GtkTreeIter       *iter);
85 static gboolean     gtk_list_store_iter_nth_child  (GtkTreeModel      *tree_model,
86                                                     GtkTreeIter       *iter,
87                                                     GtkTreeIter       *parent,
88                                                     gint               n);
89 static gboolean     gtk_list_store_iter_parent     (GtkTreeModel      *tree_model,
90                                                     GtkTreeIter       *iter,
91                                                     GtkTreeIter       *child);
92
93
94 static void gtk_list_store_set_n_columns   (GtkListStore *list_store,
95                                             gint          n_columns);
96 static void gtk_list_store_set_column_type (GtkListStore *list_store,
97                                             gint          column,
98                                             GType         type);
99
100 static void gtk_list_store_increment_stamp (GtkListStore *list_store);
101
102
103 /* Drag and Drop */
104 static gboolean real_gtk_list_store_row_draggable (GtkTreeDragSource *drag_source,
105                                                    GtkTreePath       *path);
106 static gboolean gtk_list_store_drag_data_delete   (GtkTreeDragSource *drag_source,
107                                                    GtkTreePath       *path);
108 static gboolean gtk_list_store_drag_data_get      (GtkTreeDragSource *drag_source,
109                                                    GtkTreePath       *path,
110                                                    GtkSelectionData  *selection_data);
111 static gboolean gtk_list_store_drag_data_received (GtkTreeDragDest   *drag_dest,
112                                                    GtkTreePath       *dest,
113                                                    GtkSelectionData  *selection_data);
114 static gboolean gtk_list_store_row_drop_possible  (GtkTreeDragDest   *drag_dest,
115                                                    GtkTreePath       *dest_path,
116                                                    GtkSelectionData  *selection_data);
117
118
119 /* sortable */
120 static void     gtk_list_store_sort                  (GtkListStore           *list_store);
121 static void     gtk_list_store_sort_iter_changed     (GtkListStore           *list_store,
122                                                       GtkTreeIter            *iter,
123                                                       gint                    column);
124 static gboolean gtk_list_store_get_sort_column_id    (GtkTreeSortable        *sortable,
125                                                       gint                   *sort_column_id,
126                                                       GtkSortType            *order);
127 static void     gtk_list_store_set_sort_column_id    (GtkTreeSortable        *sortable,
128                                                       gint                    sort_column_id,
129                                                       GtkSortType             order);
130 static void     gtk_list_store_set_sort_func         (GtkTreeSortable        *sortable,
131                                                       gint                    sort_column_id,
132                                                       GtkTreeIterCompareFunc  func,
133                                                       gpointer                data,
134                                                       GDestroyNotify          destroy);
135 static void     gtk_list_store_set_default_sort_func (GtkTreeSortable        *sortable,
136                                                       GtkTreeIterCompareFunc  func,
137                                                       gpointer                data,
138                                                       GDestroyNotify          destroy);
139 static gboolean gtk_list_store_has_default_sort_func (GtkTreeSortable        *sortable);
140
141
142 /* buildable */
143 static gboolean gtk_list_store_buildable_custom_tag_start (GtkBuildable  *buildable,
144                                                            GtkBuilder    *builder,
145                                                            GObject       *child,
146                                                            const gchar   *tagname,
147                                                            GMarkupParser *parser,
148                                                            gpointer      *data);
149 static void     gtk_list_store_buildable_custom_tag_end (GtkBuildable *buildable,
150                                                          GtkBuilder   *builder,
151                                                          GObject      *child,
152                                                          const gchar  *tagname,
153                                                          gpointer     *data);
154
155 G_DEFINE_TYPE_WITH_CODE (GtkListStore, gtk_list_store, G_TYPE_OBJECT,
156                          G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
157                                                 gtk_list_store_tree_model_init)
158                          G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
159                                                 gtk_list_store_drag_source_init)
160                          G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST,
161                                                 gtk_list_store_drag_dest_init)
162                          G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
163                                                 gtk_list_store_sortable_init)
164                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
165                                                 gtk_list_store_buildable_init))
166
167
168 static void
169 gtk_list_store_class_init (GtkListStoreClass *class)
170 {
171   GObjectClass *object_class;
172
173   object_class = (GObjectClass*) class;
174
175   object_class->finalize = gtk_list_store_finalize;
176
177   g_type_class_add_private (class, sizeof (GtkListStorePrivate));
178 }
179
180 static void
181 gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
182 {
183   iface->get_flags = gtk_list_store_get_flags;
184   iface->get_n_columns = gtk_list_store_get_n_columns;
185   iface->get_column_type = gtk_list_store_get_column_type;
186   iface->get_iter = gtk_list_store_get_iter;
187   iface->get_path = gtk_list_store_get_path;
188   iface->get_value = gtk_list_store_get_value;
189   iface->iter_next = gtk_list_store_iter_next;
190   iface->iter_children = gtk_list_store_iter_children;
191   iface->iter_has_child = gtk_list_store_iter_has_child;
192   iface->iter_n_children = gtk_list_store_iter_n_children;
193   iface->iter_nth_child = gtk_list_store_iter_nth_child;
194   iface->iter_parent = gtk_list_store_iter_parent;
195 }
196
197 static void
198 gtk_list_store_drag_source_init (GtkTreeDragSourceIface *iface)
199 {
200   iface->row_draggable = real_gtk_list_store_row_draggable;
201   iface->drag_data_delete = gtk_list_store_drag_data_delete;
202   iface->drag_data_get = gtk_list_store_drag_data_get;
203 }
204
205 static void
206 gtk_list_store_drag_dest_init (GtkTreeDragDestIface *iface)
207 {
208   iface->drag_data_received = gtk_list_store_drag_data_received;
209   iface->row_drop_possible = gtk_list_store_row_drop_possible;
210 }
211
212 static void
213 gtk_list_store_sortable_init (GtkTreeSortableIface *iface)
214 {
215   iface->get_sort_column_id = gtk_list_store_get_sort_column_id;
216   iface->set_sort_column_id = gtk_list_store_set_sort_column_id;
217   iface->set_sort_func = gtk_list_store_set_sort_func;
218   iface->set_default_sort_func = gtk_list_store_set_default_sort_func;
219   iface->has_default_sort_func = gtk_list_store_has_default_sort_func;
220 }
221
222 void
223 gtk_list_store_buildable_init (GtkBuildableIface *iface)
224 {
225   iface->custom_tag_start = gtk_list_store_buildable_custom_tag_start;
226   iface->custom_tag_end = gtk_list_store_buildable_custom_tag_end;
227 }
228
229 static void
230 gtk_list_store_init (GtkListStore *list_store)
231 {
232   GtkListStorePrivate *priv;
233
234   list_store->priv = G_TYPE_INSTANCE_GET_PRIVATE (list_store,
235                                                   GTK_TYPE_LIST_STORE,
236                                                   GtkListStorePrivate);
237   priv = list_store->priv;
238
239   priv->seq = g_sequence_new (NULL);
240   priv->sort_list = NULL;
241   priv->stamp = g_random_int ();
242   priv->sort_column_id = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
243   priv->columns_dirty = FALSE;
244   priv->length = 0;
245 }
246
247 /**
248  * gtk_list_store_new:
249  * @n_columns: number of columns in the list store
250  * @Varargs: all #GType types for the columns, from first to last
251  *
252  * Creates a new list store as with @n_columns columns each of the types passed
253  * in.  Note that only types derived from standard GObject fundamental types 
254  * are supported. 
255  *
256  * As an example, <literal>gtk_tree_store_new (3, G_TYPE_INT, G_TYPE_STRING,
257  * GDK_TYPE_PIXBUF);</literal> will create a new #GtkListStore with three columns, of type
258  * int, string and #GdkPixbuf respectively.
259  *
260  * Return value: a new #GtkListStore
261  **/
262 GtkListStore *
263 gtk_list_store_new (gint n_columns,
264                     ...)
265 {
266   GtkListStore *retval;
267   va_list args;
268   gint i;
269
270   g_return_val_if_fail (n_columns > 0, NULL);
271
272   retval = g_object_new (GTK_TYPE_LIST_STORE, NULL);
273   gtk_list_store_set_n_columns (retval, n_columns);
274
275   va_start (args, n_columns);
276
277   for (i = 0; i < n_columns; i++)
278     {
279       GType type = va_arg (args, GType);
280       if (! _gtk_tree_data_list_check_type (type))
281         {
282           g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
283           g_object_unref (retval);
284           return NULL;
285         }
286
287       gtk_list_store_set_column_type (retval, i, type);
288     }
289
290   va_end (args);
291
292   return retval;
293 }
294
295
296 /**
297  * gtk_list_store_newv:
298  * @n_columns: number of columns in the list store
299  * @types: (array length=n_columns): an array of #GType types for the columns, from first to last
300  *
301  * Non-vararg creation function.  Used primarily by language bindings.
302  *
303  * Return value: (transfer none): a new #GtkListStore
304  **/
305 GtkListStore *
306 gtk_list_store_newv (gint   n_columns,
307                      GType *types)
308 {
309   GtkListStore *retval;
310   gint i;
311
312   g_return_val_if_fail (n_columns > 0, NULL);
313
314   retval = g_object_new (GTK_TYPE_LIST_STORE, NULL);
315   gtk_list_store_set_n_columns (retval, n_columns);
316
317   for (i = 0; i < n_columns; i++)
318     {
319       if (! _gtk_tree_data_list_check_type (types[i]))
320         {
321           g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
322           g_object_unref (retval);
323           return NULL;
324         }
325
326       gtk_list_store_set_column_type (retval, i, types[i]);
327     }
328
329   return retval;
330 }
331
332 /**
333  * gtk_list_store_set_column_types:
334  * @list_store: A #GtkListStore
335  * @n_columns: Number of columns for the list store
336  * @types: (array length=n_columns): An array length n of #GTypes
337  *
338  * This function is meant primarily for #GObjects that inherit from #GtkListStore,
339  * and should only be used when constructing a new #GtkListStore.  It will not
340  * function after a row has been added, or a method on the #GtkTreeModel
341  * interface is called.
342  **/
343 void
344 gtk_list_store_set_column_types (GtkListStore *list_store,
345                                  gint          n_columns,
346                                  GType        *types)
347 {
348   GtkListStorePrivate *priv;
349   gint i;
350
351   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
352
353   priv = list_store->priv;
354
355   g_return_if_fail (priv->columns_dirty == 0);
356
357   gtk_list_store_set_n_columns (list_store, n_columns);
358   for (i = 0; i < n_columns; i++)
359     {
360       if (! _gtk_tree_data_list_check_type (types[i]))
361         {
362           g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
363           continue;
364         }
365       gtk_list_store_set_column_type (list_store, i, types[i]);
366     }
367 }
368
369 static void
370 gtk_list_store_set_n_columns (GtkListStore *list_store,
371                               gint          n_columns)
372 {
373   GtkListStorePrivate *priv = list_store->priv;
374   int i;
375
376   if (priv->n_columns == n_columns)
377     return;
378
379   priv->column_headers = g_renew (GType, priv->column_headers, n_columns);
380   for (i = priv->n_columns; i < n_columns; i++)
381     priv->column_headers[i] = G_TYPE_INVALID;
382   priv->n_columns = n_columns;
383
384   if (priv->sort_list)
385     _gtk_tree_data_list_header_free (priv->sort_list);
386   priv->sort_list = _gtk_tree_data_list_header_new (n_columns, priv->column_headers);
387 }
388
389 static void
390 gtk_list_store_set_column_type (GtkListStore *list_store,
391                                 gint          column,
392                                 GType         type)
393 {
394   GtkListStorePrivate *priv = list_store->priv;
395
396   if (!_gtk_tree_data_list_check_type (type))
397     {
398       g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
399       return;
400     }
401
402   priv->column_headers[column] = type;
403 }
404
405 static void
406 gtk_list_store_finalize (GObject *object)
407 {
408   GtkListStore *list_store = GTK_LIST_STORE (object);
409   GtkListStorePrivate *priv = list_store->priv;
410
411   g_sequence_foreach (priv->seq,
412                       (GFunc) _gtk_tree_data_list_free, priv->column_headers);
413
414   g_sequence_free (priv->seq);
415
416   _gtk_tree_data_list_header_free (priv->sort_list);
417   g_free (priv->column_headers);
418
419   if (priv->default_sort_destroy)
420     {
421       GDestroyNotify d = priv->default_sort_destroy;
422
423       priv->default_sort_destroy = NULL;
424       d (priv->default_sort_data);
425       priv->default_sort_data = NULL;
426     }
427
428   G_OBJECT_CLASS (gtk_list_store_parent_class)->finalize (object);
429 }
430
431 /* Fulfill the GtkTreeModel requirements */
432 static GtkTreeModelFlags
433 gtk_list_store_get_flags (GtkTreeModel *tree_model)
434 {
435   return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
436 }
437
438 static gint
439 gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
440 {
441   GtkListStore *list_store = GTK_LIST_STORE (tree_model);
442   GtkListStorePrivate *priv = list_store->priv;
443
444   priv->columns_dirty = TRUE;
445
446   return priv->n_columns;
447 }
448
449 static GType
450 gtk_list_store_get_column_type (GtkTreeModel *tree_model,
451                                 gint          index)
452 {
453   GtkListStore *list_store = GTK_LIST_STORE (tree_model);
454   GtkListStorePrivate *priv = list_store->priv;
455
456   g_return_val_if_fail (index < priv->n_columns, G_TYPE_INVALID);
457
458   priv->columns_dirty = TRUE;
459
460   return priv->column_headers[index];
461 }
462
463 static gboolean
464 gtk_list_store_get_iter (GtkTreeModel *tree_model,
465                          GtkTreeIter  *iter,
466                          GtkTreePath  *path)
467 {
468   GtkListStore *list_store = GTK_LIST_STORE (tree_model);
469   GtkListStorePrivate *priv = list_store->priv;
470   GSequence *seq;
471   gint i;
472
473   priv->columns_dirty = TRUE;
474
475   seq = priv->seq;
476
477   i = gtk_tree_path_get_indices (path)[0];
478
479   if (i >= g_sequence_get_length (seq))
480     return FALSE;
481
482   iter->stamp = priv->stamp;
483   iter->user_data = g_sequence_get_iter_at_pos (seq, i);
484
485   return TRUE;
486 }
487
488 static GtkTreePath *
489 gtk_list_store_get_path (GtkTreeModel *tree_model,
490                          GtkTreeIter  *iter)
491 {
492   GtkListStore *list_store = GTK_LIST_STORE (tree_model);
493   GtkListStorePrivate *priv = list_store->priv;
494   GtkTreePath *path;
495
496   g_return_val_if_fail (iter->stamp == priv->stamp, NULL);
497
498   if (g_sequence_iter_is_end (iter->user_data))
499     return NULL;
500         
501   path = gtk_tree_path_new ();
502   gtk_tree_path_append_index (path, g_sequence_iter_get_position (iter->user_data));
503   
504   return path;
505 }
506
507 static void
508 gtk_list_store_get_value (GtkTreeModel *tree_model,
509                           GtkTreeIter  *iter,
510                           gint          column,
511                           GValue       *value)
512 {
513   GtkListStore *list_store = GTK_LIST_STORE (tree_model);
514   GtkListStorePrivate *priv = list_store->priv;
515   GtkTreeDataList *list;
516   gint tmp_column = column;
517
518   g_return_if_fail (column < priv->n_columns);
519   g_return_if_fail (VALID_ITER (iter, list_store));
520                     
521   list = g_sequence_get (iter->user_data);
522
523   while (tmp_column-- > 0 && list)
524     list = list->next;
525
526   if (list == NULL)
527     g_value_init (value, priv->column_headers[column]);
528   else
529     _gtk_tree_data_list_node_to_value (list,
530                                        priv->column_headers[column],
531                                        value);
532 }
533
534 static gboolean
535 gtk_list_store_iter_next (GtkTreeModel  *tree_model,
536                           GtkTreeIter   *iter)
537 {
538   GtkListStore *list_store = GTK_LIST_STORE (tree_model);
539   GtkListStorePrivate *priv = list_store->priv;
540   gboolean retval;
541
542   g_return_val_if_fail (priv->stamp == iter->stamp, FALSE);
543   iter->user_data = g_sequence_iter_next (iter->user_data);
544
545   retval = g_sequence_iter_is_end (iter->user_data);
546   if (retval)
547     iter->stamp = 0;
548
549   return !retval;
550 }
551
552 static gboolean
553 gtk_list_store_iter_children (GtkTreeModel *tree_model,
554                               GtkTreeIter  *iter,
555                               GtkTreeIter  *parent)
556 {
557   GtkListStore *list_store = (GtkListStore *) tree_model;
558   GtkListStorePrivate *priv = list_store->priv;
559
560   /* this is a list, nodes have no children */
561   if (parent)
562     {
563       iter->stamp = 0;
564       return FALSE;
565     }
566
567   if (g_sequence_get_length (priv->seq) > 0)
568     {
569       iter->stamp = priv->stamp;
570       iter->user_data = g_sequence_get_begin_iter (priv->seq);
571       return TRUE;
572     }
573   else
574     {
575       iter->stamp = 0;
576       return FALSE;
577     }
578 }
579
580 static gboolean
581 gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
582                                GtkTreeIter  *iter)
583 {
584   return FALSE;
585 }
586
587 static gint
588 gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
589                                 GtkTreeIter  *iter)
590 {
591   GtkListStore *list_store = GTK_LIST_STORE (tree_model);
592   GtkListStorePrivate *priv = list_store->priv;
593
594   if (iter == NULL)
595     return g_sequence_get_length (priv->seq);
596
597   g_return_val_if_fail (priv->stamp == iter->stamp, -1);
598
599   return 0;
600 }
601
602 static gboolean
603 gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
604                                GtkTreeIter  *iter,
605                                GtkTreeIter  *parent,
606                                gint          n)
607 {
608   GtkListStore *list_store = GTK_LIST_STORE (tree_model);
609   GtkListStorePrivate *priv = list_store->priv;
610   GSequenceIter *child;
611
612   iter->stamp = 0;
613
614   if (parent)
615     return FALSE;
616
617   child = g_sequence_get_iter_at_pos (priv->seq, n);
618
619   if (g_sequence_iter_is_end (child))
620     return FALSE;
621
622   iter->stamp = priv->stamp;
623   iter->user_data = child;
624
625   return TRUE;
626 }
627
628 static gboolean
629 gtk_list_store_iter_parent (GtkTreeModel *tree_model,
630                             GtkTreeIter  *iter,
631                             GtkTreeIter  *child)
632 {
633   iter->stamp = 0;
634   return FALSE;
635 }
636
637 static gboolean
638 gtk_list_store_real_set_value (GtkListStore *list_store,
639                                GtkTreeIter  *iter,
640                                gint          column,
641                                GValue       *value,
642                                gboolean      sort)
643 {
644   GtkListStorePrivate *priv = list_store->priv;
645   GtkTreeDataList *list;
646   GtkTreeDataList *prev;
647   gint old_column = column;
648   GValue real_value = {0, };
649   gboolean converted = FALSE;
650   gboolean retval = FALSE;
651
652   if (! g_type_is_a (G_VALUE_TYPE (value), priv->column_headers[column]))
653     {
654       if (! (g_value_type_compatible (G_VALUE_TYPE (value), priv->column_headers[column]) &&
655              g_value_type_compatible (priv->column_headers[column], G_VALUE_TYPE (value))))
656         {
657           g_warning ("%s: Unable to convert from %s to %s\n",
658                      G_STRLOC,
659                      g_type_name (G_VALUE_TYPE (value)),
660                      g_type_name (priv->column_headers[column]));
661           return retval;
662         }
663       if (!g_value_transform (value, &real_value))
664         {
665           g_warning ("%s: Unable to make conversion from %s to %s\n",
666                      G_STRLOC,
667                      g_type_name (G_VALUE_TYPE (value)),
668                      g_type_name (priv->column_headers[column]));
669           g_value_unset (&real_value);
670           return retval;
671         }
672       converted = TRUE;
673     }
674
675   prev = list = g_sequence_get (iter->user_data);
676
677   while (list != NULL)
678     {
679       if (column == 0)
680         {
681           if (converted)
682             _gtk_tree_data_list_value_to_node (list, &real_value);
683           else
684             _gtk_tree_data_list_value_to_node (list, value);
685           retval = TRUE;
686           if (converted)
687             g_value_unset (&real_value);
688          if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
689             gtk_list_store_sort_iter_changed (list_store, iter, old_column);
690           return retval;
691         }
692
693       column--;
694       prev = list;
695       list = list->next;
696     }
697
698   if (g_sequence_get (iter->user_data) == NULL)
699     {
700       list = _gtk_tree_data_list_alloc();
701       g_sequence_set (iter->user_data, list);
702       list->next = NULL;
703     }
704   else
705     {
706       list = prev->next = _gtk_tree_data_list_alloc ();
707       list->next = NULL;
708     }
709
710   while (column != 0)
711     {
712       list->next = _gtk_tree_data_list_alloc ();
713       list = list->next;
714       list->next = NULL;
715       column --;
716     }
717
718   if (converted)
719     _gtk_tree_data_list_value_to_node (list, &real_value);
720   else
721     _gtk_tree_data_list_value_to_node (list, value);
722
723   retval = TRUE;
724   if (converted)
725     g_value_unset (&real_value);
726
727   if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
728     gtk_list_store_sort_iter_changed (list_store, iter, old_column);
729
730   return retval;
731 }
732
733
734 /**
735  * gtk_list_store_set_value:
736  * @list_store: A #GtkListStore
737  * @iter: A valid #GtkTreeIter for the row being modified
738  * @column: column number to modify
739  * @value: new value for the cell
740  *
741  * Sets the data in the cell specified by @iter and @column.
742  * The type of @value must be convertible to the type of the
743  * column.
744  *
745  **/
746 void
747 gtk_list_store_set_value (GtkListStore *list_store,
748                           GtkTreeIter  *iter,
749                           gint          column,
750                           GValue       *value)
751 {
752   GtkListStorePrivate *priv = list_store->priv;
753
754   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
755   g_return_if_fail (VALID_ITER (iter, list_store));
756   g_return_if_fail (G_IS_VALUE (value));
757   priv = list_store->priv;
758   g_return_if_fail (column >= 0 && column < priv->n_columns);
759
760   if (gtk_list_store_real_set_value (list_store, iter, column, value, TRUE))
761     {
762       GtkTreePath *path;
763
764       path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
765       gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
766       gtk_tree_path_free (path);
767     }
768 }
769
770 static GtkTreeIterCompareFunc
771 gtk_list_store_get_compare_func (GtkListStore *list_store)
772 {
773   GtkListStorePrivate *priv = list_store->priv;
774   GtkTreeIterCompareFunc func = NULL;
775
776   if (GTK_LIST_STORE_IS_SORTED (list_store))
777     {
778       if (priv->sort_column_id != -1)
779         {
780           GtkTreeDataSortHeader *header;
781           header = _gtk_tree_data_list_get_header (priv->sort_list,
782                                                    priv->sort_column_id);
783           g_return_val_if_fail (header != NULL, NULL);
784           g_return_val_if_fail (header->func != NULL, NULL);
785           func = header->func;
786         }
787       else
788         {
789           func = priv->default_sort_func;
790         }
791     }
792
793   return func;
794 }
795
796 static void
797 gtk_list_store_set_vector_internal (GtkListStore *list_store,
798                                     GtkTreeIter  *iter,
799                                     gboolean     *emit_signal,
800                                     gboolean     *maybe_need_sort,
801                                     gint         *columns,
802                                     GValue       *values,
803                                     gint          n_values)
804 {
805   GtkListStorePrivate *priv = list_store->priv;
806   gint i;
807   GtkTreeIterCompareFunc func = NULL;
808
809   func = gtk_list_store_get_compare_func (list_store);
810   if (func != _gtk_tree_data_list_compare_func)
811     *maybe_need_sort = TRUE;
812
813   for (i = 0; i < n_values; i++)
814     {
815       *emit_signal = gtk_list_store_real_set_value (list_store, 
816                                                iter, 
817                                                columns[i],
818                                                &values[i],
819                                                FALSE) || *emit_signal;
820
821       if (func == _gtk_tree_data_list_compare_func &&
822           columns[i] == priv->sort_column_id)
823         *maybe_need_sort = TRUE;
824     }
825 }
826
827 static void
828 gtk_list_store_set_valist_internal (GtkListStore *list_store,
829                                     GtkTreeIter  *iter,
830                                     gboolean     *emit_signal,
831                                     gboolean     *maybe_need_sort,
832                                     va_list       var_args)
833 {
834   GtkListStorePrivate *priv = list_store->priv;
835   gint column;
836   GtkTreeIterCompareFunc func = NULL;
837
838   column = va_arg (var_args, gint);
839
840   func = gtk_list_store_get_compare_func (list_store);
841   if (func != _gtk_tree_data_list_compare_func)
842     *maybe_need_sort = TRUE;
843
844   while (column != -1)
845     {
846       GValue value = { 0, };
847       gchar *error = NULL;
848
849       if (column < 0 || column >= priv->n_columns)
850         {
851           g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
852           break;
853         }
854       g_value_init (&value, priv->column_headers[column]);
855
856       G_VALUE_COLLECT (&value, var_args, 0, &error);
857       if (error)
858         {
859           g_warning ("%s: %s", G_STRLOC, error);
860           g_free (error);
861
862           /* we purposely leak the value here, it might not be
863            * in a sane state if an error condition occoured
864            */
865           break;
866         }
867
868       /* FIXME: instead of calling this n times, refactor with above */
869       *emit_signal = gtk_list_store_real_set_value (list_store,
870                                                     iter,
871                                                     column,
872                                                     &value,
873                                                     FALSE) || *emit_signal;
874       
875       if (func == _gtk_tree_data_list_compare_func &&
876           column == priv->sort_column_id)
877         *maybe_need_sort = TRUE;
878
879       g_value_unset (&value);
880
881       column = va_arg (var_args, gint);
882     }
883 }
884
885 /**
886  * gtk_list_store_set_valuesv:
887  * @list_store: A #GtkListStore
888  * @iter: A valid #GtkTreeIter for the row being modified
889  * @columns: (array length=n_values): an array of column numbers
890  * @values: (array length=n_values): an array of GValues
891  * @n_values: the length of the @columns and @values arrays
892  *
893  * A variant of gtk_list_store_set_valist() which
894  * takes the columns and values as two arrays, instead of
895  * varargs. This function is mainly intended for 
896  * language-bindings and in case the number of columns to
897  * change is not known until run-time.
898  *
899  * Since: 2.12
900  */
901 void
902 gtk_list_store_set_valuesv (GtkListStore *list_store,
903                             GtkTreeIter  *iter,
904                             gint         *columns,
905                             GValue       *values,
906                             gint          n_values)
907 {
908   GtkListStorePrivate *priv;
909   gboolean emit_signal = FALSE;
910   gboolean maybe_need_sort = FALSE;
911
912   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
913   g_return_if_fail (VALID_ITER (iter, list_store));
914
915   priv = list_store->priv;
916
917   gtk_list_store_set_vector_internal (list_store, iter,
918                                       &emit_signal,
919                                       &maybe_need_sort,
920                                       columns, values, n_values);
921
922   if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
923     gtk_list_store_sort_iter_changed (list_store, iter, priv->sort_column_id);
924
925   if (emit_signal)
926     {
927       GtkTreePath *path;
928
929       path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
930       gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
931       gtk_tree_path_free (path);
932     }
933 }
934
935 /**
936  * gtk_list_store_set_valist:
937  * @list_store: A #GtkListStore
938  * @iter: A valid #GtkTreeIter for the row being modified
939  * @var_args: va_list of column/value pairs
940  *
941  * See gtk_list_store_set(); this version takes a va_list for use by language
942  * bindings.
943  *
944  **/
945 void
946 gtk_list_store_set_valist (GtkListStore *list_store,
947                            GtkTreeIter  *iter,
948                            va_list       var_args)
949 {
950   GtkListStorePrivate *priv;
951   gboolean emit_signal = FALSE;
952   gboolean maybe_need_sort = FALSE;
953
954   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
955   g_return_if_fail (VALID_ITER (iter, list_store));
956
957   priv = list_store->priv;
958
959   gtk_list_store_set_valist_internal (list_store, iter, 
960                                       &emit_signal, 
961                                       &maybe_need_sort,
962                                       var_args);
963
964   if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
965     gtk_list_store_sort_iter_changed (list_store, iter, priv->sort_column_id);
966
967   if (emit_signal)
968     {
969       GtkTreePath *path;
970
971       path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
972       gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
973       gtk_tree_path_free (path);
974     }
975 }
976
977 /**
978  * gtk_list_store_set:
979  * @list_store: a #GtkListStore
980  * @iter: row iterator
981  * @Varargs: pairs of column number and value, terminated with -1
982  *
983  * Sets the value of one or more cells in the row referenced by @iter.
984  * The variable argument list should contain integer column numbers,
985  * each column number followed by the value to be set.
986  * The list is terminated by a -1. For example, to set column 0 with type
987  * %G_TYPE_STRING to "Foo", you would write <literal>gtk_list_store_set (store, iter,
988  * 0, "Foo", -1)</literal>.
989  *
990  * The value will be referenced by the store if it is a %G_TYPE_OBJECT, and it
991  * will be copied if it is a %G_TYPE_STRING or %G_TYPE_BOXED.
992  **/
993 void
994 gtk_list_store_set (GtkListStore *list_store,
995                     GtkTreeIter  *iter,
996                     ...)
997 {
998   va_list var_args;
999
1000   va_start (var_args, iter);
1001   gtk_list_store_set_valist (list_store, iter, var_args);
1002   va_end (var_args);
1003 }
1004
1005 /**
1006  * gtk_list_store_remove:
1007  * @list_store: A #GtkListStore
1008  * @iter: A valid #GtkTreeIter
1009  *
1010  * Removes the given row from the list store.  After being removed, 
1011  * @iter is set to be the next valid row, or invalidated if it pointed 
1012  * to the last row in @list_store.
1013  *
1014  * Return value: %TRUE if @iter is valid, %FALSE if not.
1015  **/
1016 gboolean
1017 gtk_list_store_remove (GtkListStore *list_store,
1018                        GtkTreeIter  *iter)
1019 {
1020   GtkListStorePrivate *priv;
1021   GtkTreePath *path;
1022   GSequenceIter *ptr, *next;
1023
1024   g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), FALSE);
1025   g_return_val_if_fail (VALID_ITER (iter, list_store), FALSE);
1026
1027   priv = list_store->priv;
1028
1029   path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
1030
1031   ptr = iter->user_data;
1032   next = g_sequence_iter_next (ptr);
1033   
1034   _gtk_tree_data_list_free (g_sequence_get (ptr), priv->column_headers);
1035   g_sequence_remove (iter->user_data);
1036
1037   priv->length--;
1038   
1039   gtk_tree_model_row_deleted (GTK_TREE_MODEL (list_store), path);
1040   gtk_tree_path_free (path);
1041
1042   if (g_sequence_iter_is_end (next))
1043     {
1044       iter->stamp = 0;
1045       return FALSE;
1046     }
1047   else
1048     {
1049       iter->stamp = priv->stamp;
1050       iter->user_data = next;
1051       return TRUE;
1052     }
1053 }
1054
1055 /**
1056  * gtk_list_store_insert:
1057  * @list_store: A #GtkListStore
1058  * @iter: (out): An unset #GtkTreeIter to set to the new row
1059  * @position: position to insert the new row
1060  *
1061  * Creates a new row at @position.  @iter will be changed to point to this new
1062  * row.  If @position is larger than the number of rows on the list, then the
1063  * new row will be appended to the list. The row will be empty after this
1064  * function is called.  To fill in values, you need to call 
1065  * gtk_list_store_set() or gtk_list_store_set_value().
1066  *
1067  **/
1068 void
1069 gtk_list_store_insert (GtkListStore *list_store,
1070                        GtkTreeIter  *iter,
1071                        gint          position)
1072 {
1073   GtkListStorePrivate *priv;
1074   GtkTreePath *path;
1075   GSequence *seq;
1076   GSequenceIter *ptr;
1077   gint length;
1078
1079   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1080   g_return_if_fail (iter != NULL);
1081   g_return_if_fail (position >= 0);
1082
1083   priv = list_store->priv;
1084
1085   priv->columns_dirty = TRUE;
1086
1087   seq = priv->seq;
1088
1089   length = g_sequence_get_length (seq);
1090   if (position > length)
1091     position = length;
1092
1093   ptr = g_sequence_get_iter_at_pos (seq, position);
1094   ptr = g_sequence_insert_before (ptr, NULL);
1095
1096   iter->stamp = priv->stamp;
1097   iter->user_data = ptr;
1098
1099   g_assert (VALID_ITER (iter, list_store));
1100
1101   priv->length++;
1102   
1103   path = gtk_tree_path_new ();
1104   gtk_tree_path_append_index (path, position);
1105   gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter);
1106   gtk_tree_path_free (path);
1107 }
1108
1109 /**
1110  * gtk_list_store_insert_before:
1111  * @list_store: A #GtkListStore
1112  * @iter: (out): An unset #GtkTreeIter to set to the new row
1113  * @sibling: (allow-none): A valid #GtkTreeIter, or %NULL
1114  *
1115  * Inserts a new row before @sibling. If @sibling is %NULL, then the row will 
1116  * be appended to the end of the list. @iter will be changed to point to this 
1117  * new row. The row will be empty after this function is called. To fill in 
1118  * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1119  *
1120  **/
1121 void
1122 gtk_list_store_insert_before (GtkListStore *list_store,
1123                               GtkTreeIter  *iter,
1124                               GtkTreeIter  *sibling)
1125 {
1126   GtkListStorePrivate *priv;
1127   GSequenceIter *after;
1128   
1129   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1130   g_return_if_fail (iter != NULL);
1131
1132   priv = list_store->priv;
1133
1134   if (sibling)
1135     g_return_if_fail (VALID_ITER (sibling, list_store));
1136
1137   if (!sibling)
1138     after = g_sequence_get_end_iter (priv->seq);
1139   else
1140     after = sibling->user_data;
1141
1142   gtk_list_store_insert (list_store, iter, g_sequence_iter_get_position (after));
1143 }
1144
1145 /**
1146  * gtk_list_store_insert_after:
1147  * @list_store: A #GtkListStore
1148  * @iter: (out): An unset #GtkTreeIter to set to the new row
1149  * @sibling: (allow-none): A valid #GtkTreeIter, or %NULL
1150  *
1151  * Inserts a new row after @sibling. If @sibling is %NULL, then the row will be
1152  * prepended to the beginning of the list. @iter will be changed to point to
1153  * this new row. The row will be empty after this function is called. To fill
1154  * in values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1155  *
1156  **/
1157 void
1158 gtk_list_store_insert_after (GtkListStore *list_store,
1159                              GtkTreeIter  *iter,
1160                              GtkTreeIter  *sibling)
1161 {
1162   GtkListStorePrivate *priv;
1163   GSequenceIter *after;
1164
1165   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1166   g_return_if_fail (iter != NULL);
1167
1168   priv = list_store->priv;
1169
1170   if (sibling)
1171     g_return_if_fail (VALID_ITER (sibling, list_store));
1172
1173   if (!sibling)
1174     after = g_sequence_get_begin_iter (priv->seq);
1175   else
1176     after = g_sequence_iter_next (sibling->user_data);
1177
1178   gtk_list_store_insert (list_store, iter, g_sequence_iter_get_position (after));
1179 }
1180
1181 /**
1182  * gtk_list_store_prepend:
1183  * @list_store: A #GtkListStore
1184  * @iter: (out): An unset #GtkTreeIter to set to the prepend row
1185  *
1186  * Prepends a new row to @list_store. @iter will be changed to point to this new
1187  * row. The row will be empty after this function is called. To fill in
1188  * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1189  *
1190  **/
1191 void
1192 gtk_list_store_prepend (GtkListStore *list_store,
1193                         GtkTreeIter  *iter)
1194 {
1195   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1196   g_return_if_fail (iter != NULL);
1197
1198   gtk_list_store_insert (list_store, iter, 0);
1199 }
1200
1201 /**
1202  * gtk_list_store_append:
1203  * @list_store: A #GtkListStore
1204  * @iter: (out): An unset #GtkTreeIter to set to the appended row
1205  *
1206  * Appends a new row to @list_store.  @iter will be changed to point to this new
1207  * row.  The row will be empty after this function is called.  To fill in
1208  * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1209  *
1210  **/
1211 void
1212 gtk_list_store_append (GtkListStore *list_store,
1213                        GtkTreeIter  *iter)
1214 {
1215   GtkListStorePrivate *priv;
1216
1217   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1218   g_return_if_fail (iter != NULL);
1219
1220   priv = list_store->priv;
1221
1222   gtk_list_store_insert (list_store, iter, g_sequence_get_length (priv->seq));
1223 }
1224
1225 static void
1226 gtk_list_store_increment_stamp (GtkListStore *list_store)
1227 {
1228   GtkListStorePrivate *priv = list_store->priv;
1229
1230   do
1231     {
1232       priv->stamp++;
1233     }
1234   while (priv->stamp == 0);
1235 }
1236
1237 /**
1238  * gtk_list_store_clear:
1239  * @list_store: a #GtkListStore.
1240  *
1241  * Removes all rows from the list store.  
1242  *
1243  **/
1244 void
1245 gtk_list_store_clear (GtkListStore *list_store)
1246 {
1247   GtkListStorePrivate *priv;
1248   GtkTreeIter iter;
1249
1250   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1251
1252   priv = list_store->priv;
1253
1254   while (g_sequence_get_length (priv->seq) > 0)
1255     {
1256       iter.stamp = priv->stamp;
1257       iter.user_data = g_sequence_get_begin_iter (priv->seq);
1258       gtk_list_store_remove (list_store, &iter);
1259     }
1260
1261   gtk_list_store_increment_stamp (list_store);
1262 }
1263
1264 /**
1265  * gtk_list_store_iter_is_valid:
1266  * @list_store: A #GtkListStore.
1267  * @iter: A #GtkTreeIter.
1268  *
1269  * <warning>This function is slow. Only use it for debugging and/or testing
1270  * purposes.</warning>
1271  *
1272  * Checks if the given iter is a valid iter for this #GtkListStore.
1273  *
1274  * Return value: %TRUE if the iter is valid, %FALSE if the iter is invalid.
1275  *
1276  * Since: 2.2
1277  **/
1278 gboolean
1279 gtk_list_store_iter_is_valid (GtkListStore *list_store,
1280                               GtkTreeIter  *iter)
1281 {
1282   GtkListStorePrivate *priv;
1283
1284   g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), FALSE);
1285   g_return_val_if_fail (iter != NULL, FALSE);
1286
1287   priv = list_store->priv;
1288
1289   if (!VALID_ITER (iter, list_store))
1290     return FALSE;
1291
1292   if (g_sequence_iter_get_sequence (iter->user_data) != priv->seq)
1293     return FALSE;
1294
1295   return TRUE;
1296 }
1297
1298 static gboolean real_gtk_list_store_row_draggable (GtkTreeDragSource *drag_source,
1299                                                    GtkTreePath       *path)
1300 {
1301   return TRUE;
1302 }
1303   
1304 static gboolean
1305 gtk_list_store_drag_data_delete (GtkTreeDragSource *drag_source,
1306                                  GtkTreePath       *path)
1307 {
1308   GtkTreeIter iter;
1309
1310   if (gtk_list_store_get_iter (GTK_TREE_MODEL (drag_source),
1311                                &iter,
1312                                path))
1313     {
1314       gtk_list_store_remove (GTK_LIST_STORE (drag_source), &iter);
1315       return TRUE;
1316     }
1317   return FALSE;
1318 }
1319
1320 static gboolean
1321 gtk_list_store_drag_data_get (GtkTreeDragSource *drag_source,
1322                               GtkTreePath       *path,
1323                               GtkSelectionData  *selection_data)
1324 {
1325   /* Note that we don't need to handle the GTK_TREE_MODEL_ROW
1326    * target, because the default handler does it for us, but
1327    * we do anyway for the convenience of someone maybe overriding the
1328    * default handler.
1329    */
1330
1331   if (gtk_tree_set_row_drag_data (selection_data,
1332                                   GTK_TREE_MODEL (drag_source),
1333                                   path))
1334     {
1335       return TRUE;
1336     }
1337   else
1338     {
1339       /* FIXME handle text targets at least. */
1340     }
1341
1342   return FALSE;
1343 }
1344
1345 static gboolean
1346 gtk_list_store_drag_data_received (GtkTreeDragDest   *drag_dest,
1347                                    GtkTreePath       *dest,
1348                                    GtkSelectionData  *selection_data)
1349 {
1350   GtkTreeModel *tree_model = GTK_TREE_MODEL (drag_dest);
1351   GtkListStore *list_store = GTK_LIST_STORE (tree_model);
1352   GtkListStorePrivate *priv = list_store->priv;
1353   GtkTreeModel *src_model = NULL;
1354   GtkTreePath *src_path = NULL;
1355   gboolean retval = FALSE;
1356
1357   if (gtk_tree_get_row_drag_data (selection_data,
1358                                   &src_model,
1359                                   &src_path) &&
1360       src_model == tree_model)
1361     {
1362       /* Copy the given row to a new position */
1363       GtkTreeIter src_iter;
1364       GtkTreeIter dest_iter;
1365       GtkTreePath *prev;
1366
1367       if (!gtk_list_store_get_iter (src_model,
1368                                     &src_iter,
1369                                     src_path))
1370         {
1371           goto out;
1372         }
1373
1374       /* Get the path to insert _after_ (dest is the path to insert _before_) */
1375       prev = gtk_tree_path_copy (dest);
1376
1377       if (!gtk_tree_path_prev (prev))
1378         {
1379           /* dest was the first spot in the list; which means we are supposed
1380            * to prepend.
1381            */
1382           gtk_list_store_prepend (list_store, &dest_iter);
1383
1384           retval = TRUE;
1385         }
1386       else
1387         {
1388           if (gtk_list_store_get_iter (tree_model, &dest_iter, prev))
1389             {
1390               GtkTreeIter tmp_iter = dest_iter;
1391
1392               gtk_list_store_insert_after (list_store, &dest_iter, &tmp_iter);
1393
1394               retval = TRUE;
1395             }
1396         }
1397
1398       gtk_tree_path_free (prev);
1399
1400       /* If we succeeded in creating dest_iter, copy data from src
1401        */
1402       if (retval)
1403         {
1404           GtkTreeDataList *dl = g_sequence_get (src_iter.user_data);
1405           GtkTreeDataList *copy_head = NULL;
1406           GtkTreeDataList *copy_prev = NULL;
1407           GtkTreeDataList *copy_iter = NULL;
1408           GtkTreePath *path;
1409           gint col;
1410
1411           col = 0;
1412           while (dl)
1413             {
1414               copy_iter = _gtk_tree_data_list_node_copy (dl,
1415                                                          priv->column_headers[col]);
1416
1417               if (copy_head == NULL)
1418                 copy_head = copy_iter;
1419
1420               if (copy_prev)
1421                 copy_prev->next = copy_iter;
1422
1423               copy_prev = copy_iter;
1424
1425               dl = dl->next;
1426               ++col;
1427             }
1428
1429           dest_iter.stamp = priv->stamp;
1430           g_sequence_set (dest_iter.user_data, copy_head);
1431
1432           path = gtk_list_store_get_path (tree_model, &dest_iter);
1433           gtk_tree_model_row_changed (tree_model, path, &dest_iter);
1434           gtk_tree_path_free (path);
1435         }
1436     }
1437   else
1438     {
1439       /* FIXME maybe add some data targets eventually, or handle text
1440        * targets in the simple case.
1441        */
1442     }
1443
1444  out:
1445
1446   if (src_path)
1447     gtk_tree_path_free (src_path);
1448
1449   return retval;
1450 }
1451
1452 static gboolean
1453 gtk_list_store_row_drop_possible (GtkTreeDragDest  *drag_dest,
1454                                   GtkTreePath      *dest_path,
1455                                   GtkSelectionData *selection_data)
1456 {
1457   gint *indices;
1458   GtkTreeModel *src_model = NULL;
1459   GtkTreePath *src_path = NULL;
1460   gboolean retval = FALSE;
1461
1462   /* don't accept drops if the list has been sorted */
1463   if (GTK_LIST_STORE_IS_SORTED (drag_dest))
1464     return FALSE;
1465
1466   if (!gtk_tree_get_row_drag_data (selection_data,
1467                                    &src_model,
1468                                    &src_path))
1469     goto out;
1470
1471   if (src_model != GTK_TREE_MODEL (drag_dest))
1472     goto out;
1473
1474   if (gtk_tree_path_get_depth (dest_path) != 1)
1475     goto out;
1476
1477   /* can drop before any existing node, or before one past any existing. */
1478
1479   indices = gtk_tree_path_get_indices (dest_path);
1480
1481   if (indices[0] <= g_sequence_get_length (GTK_LIST_STORE (drag_dest)->priv->seq))
1482     retval = TRUE;
1483
1484  out:
1485   if (src_path)
1486     gtk_tree_path_free (src_path);
1487   
1488   return retval;
1489 }
1490
1491 /* Sorting and reordering */
1492
1493 /* Reordering */
1494 static gint
1495 gtk_list_store_reorder_func (GSequenceIter *a,
1496                              GSequenceIter *b,
1497                              gpointer       user_data)
1498 {
1499   GHashTable *new_positions = user_data;
1500   gint apos = GPOINTER_TO_INT (g_hash_table_lookup (new_positions, a));
1501   gint bpos = GPOINTER_TO_INT (g_hash_table_lookup (new_positions, b));
1502
1503   if (apos < bpos)
1504     return -1;
1505   if (apos > bpos)
1506     return 1;
1507   return 0;
1508 }
1509   
1510 /**
1511  * gtk_list_store_reorder:
1512  * @store: A #GtkListStore.
1513  * @new_order: an array of integers mapping the new position of each child
1514  *      to its old position before the re-ordering,
1515  *      i.e. @new_order<literal>[newpos] = oldpos</literal>.
1516  *
1517  * Reorders @store to follow the order indicated by @new_order. Note that
1518  * this function only works with unsorted stores.
1519  *
1520  * Since: 2.2
1521  **/
1522 void
1523 gtk_list_store_reorder (GtkListStore *store,
1524                         gint         *new_order)
1525 {
1526   GtkListStorePrivate *priv;
1527   gint i;
1528   GtkTreePath *path;
1529   GHashTable *new_positions;
1530   GSequenceIter *ptr;
1531   gint *order;
1532   
1533   g_return_if_fail (GTK_IS_LIST_STORE (store));
1534   g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1535   g_return_if_fail (new_order != NULL);
1536
1537   priv = store->priv;
1538
1539   order = g_new (gint, g_sequence_get_length (priv->seq));
1540   for (i = 0; i < g_sequence_get_length (priv->seq); i++)
1541     order[new_order[i]] = i;
1542   
1543   new_positions = g_hash_table_new (g_direct_hash, g_direct_equal);
1544
1545   ptr = g_sequence_get_begin_iter (priv->seq);
1546   i = 0;
1547   while (!g_sequence_iter_is_end (ptr))
1548     {
1549       g_hash_table_insert (new_positions, ptr, GINT_TO_POINTER (order[i++]));
1550
1551       ptr = g_sequence_iter_next (ptr);
1552     }
1553   g_free (order);
1554   
1555   g_sequence_sort_iter (priv->seq, gtk_list_store_reorder_func, new_positions);
1556
1557   g_hash_table_destroy (new_positions);
1558   
1559   /* emit signal */
1560   path = gtk_tree_path_new ();
1561   gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store),
1562                                  path, NULL, new_order);
1563   gtk_tree_path_free (path);
1564 }
1565
1566 static GHashTable *
1567 save_positions (GSequence *seq)
1568 {
1569   GHashTable *positions = g_hash_table_new (g_direct_hash, g_direct_equal);
1570   GSequenceIter *ptr;
1571
1572   ptr = g_sequence_get_begin_iter (seq);
1573   while (!g_sequence_iter_is_end (ptr))
1574     {
1575       g_hash_table_insert (positions, ptr,
1576                            GINT_TO_POINTER (g_sequence_iter_get_position (ptr)));
1577       ptr = g_sequence_iter_next (ptr);
1578     }
1579
1580   return positions;
1581 }
1582
1583 static int *
1584 generate_order (GSequence *seq,
1585                 GHashTable *old_positions)
1586 {
1587   GSequenceIter *ptr;
1588   int *order = g_new (int, g_sequence_get_length (seq));
1589   int i;
1590
1591   i = 0;
1592   ptr = g_sequence_get_begin_iter (seq);
1593   while (!g_sequence_iter_is_end (ptr))
1594     {
1595       int old_pos = GPOINTER_TO_INT (g_hash_table_lookup (old_positions, ptr));
1596       order[i++] = old_pos;
1597       ptr = g_sequence_iter_next (ptr);
1598     }
1599
1600   g_hash_table_destroy (old_positions);
1601
1602   return order;
1603 }
1604
1605 /**
1606  * gtk_list_store_swap:
1607  * @store: A #GtkListStore.
1608  * @a: A #GtkTreeIter.
1609  * @b: Another #GtkTreeIter.
1610  *
1611  * Swaps @a and @b in @store. Note that this function only works with
1612  * unsorted stores.
1613  *
1614  * Since: 2.2
1615  **/
1616 void
1617 gtk_list_store_swap (GtkListStore *store,
1618                      GtkTreeIter  *a,
1619                      GtkTreeIter  *b)
1620 {
1621   GtkListStorePrivate *priv;
1622   GHashTable *old_positions;
1623   gint *order;
1624   GtkTreePath *path;
1625
1626   g_return_if_fail (GTK_IS_LIST_STORE (store));
1627   g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1628   g_return_if_fail (VALID_ITER (a, store));
1629   g_return_if_fail (VALID_ITER (b, store));
1630
1631   priv = store->priv;
1632
1633   if (a->user_data == b->user_data)
1634     return;
1635
1636   old_positions = save_positions (priv->seq);
1637   
1638   g_sequence_swap (a->user_data, b->user_data);
1639
1640   order = generate_order (priv->seq, old_positions);
1641   path = gtk_tree_path_new ();
1642   
1643   gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store),
1644                                  path, NULL, order);
1645
1646   gtk_tree_path_free (path);
1647   g_free (order);
1648 }
1649
1650 static void
1651 gtk_list_store_move_to (GtkListStore *store,
1652                         GtkTreeIter  *iter,
1653                         gint          new_pos)
1654 {
1655   GtkListStorePrivate *priv = store->priv;
1656   GHashTable *old_positions;
1657   GtkTreePath *path;
1658   gint *order;
1659
1660   old_positions = save_positions (priv->seq);
1661
1662   g_sequence_move (iter->user_data, g_sequence_get_iter_at_pos (priv->seq, new_pos));
1663
1664   order = generate_order (priv->seq, old_positions);
1665
1666   path = gtk_tree_path_new ();
1667   gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store),
1668                                  path, NULL, order);
1669   gtk_tree_path_free (path);
1670   g_free (order);
1671 }
1672
1673 /**
1674  * gtk_list_store_move_before:
1675  * @store: A #GtkListStore.
1676  * @iter: A #GtkTreeIter.
1677  * @position: (allow-none): A #GtkTreeIter, or %NULL.
1678  *
1679  * Moves @iter in @store to the position before @position. Note that this
1680  * function only works with unsorted stores. If @position is %NULL, @iter
1681  * will be moved to the end of the list.
1682  *
1683  * Since: 2.2
1684  **/
1685 void
1686 gtk_list_store_move_before (GtkListStore *store,
1687                             GtkTreeIter  *iter,
1688                             GtkTreeIter  *position)
1689 {
1690   gint pos;
1691   
1692   g_return_if_fail (GTK_IS_LIST_STORE (store));
1693   g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1694   g_return_if_fail (VALID_ITER (iter, store));
1695   if (position)
1696     g_return_if_fail (VALID_ITER (position, store));
1697
1698   if (position)
1699     pos = g_sequence_iter_get_position (position->user_data);
1700   else
1701     pos = -1;
1702   
1703   gtk_list_store_move_to (store, iter, pos);
1704 }
1705
1706 /**
1707  * gtk_list_store_move_after:
1708  * @store: A #GtkListStore.
1709  * @iter: A #GtkTreeIter.
1710  * @position: (allow-none): A #GtkTreeIter or %NULL.
1711  *
1712  * Moves @iter in @store to the position after @position. Note that this
1713  * function only works with unsorted stores. If @position is %NULL, @iter
1714  * will be moved to the start of the list.
1715  *
1716  * Since: 2.2
1717  **/
1718 void
1719 gtk_list_store_move_after (GtkListStore *store,
1720                            GtkTreeIter  *iter,
1721                            GtkTreeIter  *position)
1722 {
1723   gint pos;
1724   
1725   g_return_if_fail (GTK_IS_LIST_STORE (store));
1726   g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1727   g_return_if_fail (VALID_ITER (iter, store));
1728   if (position)
1729     g_return_if_fail (VALID_ITER (position, store));
1730
1731   if (position)
1732     pos = g_sequence_iter_get_position (position->user_data) + 1;
1733   else
1734     pos = 0;
1735   
1736   gtk_list_store_move_to (store, iter, pos);
1737 }
1738     
1739 /* Sorting */
1740 static gint
1741 gtk_list_store_compare_func (GSequenceIter *a,
1742                              GSequenceIter *b,
1743                              gpointer      user_data)
1744 {
1745   GtkListStore *list_store = user_data;
1746   GtkListStorePrivate *priv = list_store->priv;
1747   GtkTreeIter iter_a;
1748   GtkTreeIter iter_b;
1749   gint retval;
1750   GtkTreeIterCompareFunc func;
1751   gpointer data;
1752
1753   if (priv->sort_column_id != -1)
1754     {
1755       GtkTreeDataSortHeader *header;
1756
1757       header = _gtk_tree_data_list_get_header (priv->sort_list,
1758                                                priv->sort_column_id);
1759       g_return_val_if_fail (header != NULL, 0);
1760       g_return_val_if_fail (header->func != NULL, 0);
1761
1762       func = header->func;
1763       data = header->data;
1764     }
1765   else
1766     {
1767       g_return_val_if_fail (priv->default_sort_func != NULL, 0);
1768       func = priv->default_sort_func;
1769       data = priv->default_sort_data;
1770     }
1771
1772   iter_a.stamp = priv->stamp;
1773   iter_a.user_data = (gpointer)a;
1774   iter_b.stamp = priv->stamp;
1775   iter_b.user_data = (gpointer)b;
1776
1777   g_assert (VALID_ITER (&iter_a, list_store));
1778   g_assert (VALID_ITER (&iter_b, list_store));
1779   
1780   retval = (* func) (GTK_TREE_MODEL (list_store), &iter_a, &iter_b, data);
1781
1782   if (priv->order == GTK_SORT_DESCENDING)
1783     {
1784       if (retval > 0)
1785         retval = -1;
1786       else if (retval < 0)
1787         retval = 1;
1788     }
1789
1790   return retval;
1791 }
1792
1793 static void
1794 gtk_list_store_sort (GtkListStore *list_store)
1795 {
1796   GtkListStorePrivate *priv = list_store->priv;
1797   gint *new_order;
1798   GtkTreePath *path;
1799   GHashTable *old_positions;
1800
1801   if (!GTK_LIST_STORE_IS_SORTED (list_store) ||
1802       g_sequence_get_length (priv->seq) <= 1)
1803     return;
1804
1805   old_positions = save_positions (priv->seq);
1806
1807   g_sequence_sort_iter (priv->seq, gtk_list_store_compare_func, list_store);
1808
1809   /* Let the world know about our new order */
1810   new_order = generate_order (priv->seq, old_positions);
1811
1812   path = gtk_tree_path_new ();
1813   gtk_tree_model_rows_reordered (GTK_TREE_MODEL (list_store),
1814                                  path, NULL, new_order);
1815   gtk_tree_path_free (path);
1816   g_free (new_order);
1817 }
1818
1819 static gboolean
1820 iter_is_sorted (GtkListStore *list_store,
1821                 GtkTreeIter  *iter)
1822 {
1823   GSequenceIter *cmp;
1824
1825   if (!g_sequence_iter_is_begin (iter->user_data))
1826     {
1827       cmp = g_sequence_iter_prev (iter->user_data);
1828       if (gtk_list_store_compare_func (cmp, iter->user_data, list_store) > 0)
1829         return FALSE;
1830     }
1831
1832   cmp = g_sequence_iter_next (iter->user_data);
1833   if (!g_sequence_iter_is_end (cmp))
1834     {
1835       if (gtk_list_store_compare_func (iter->user_data, cmp, list_store) > 0)
1836         return FALSE;
1837     }
1838   
1839   return TRUE;
1840 }
1841
1842 static void
1843 gtk_list_store_sort_iter_changed (GtkListStore *list_store,
1844                                   GtkTreeIter  *iter,
1845                                   gint          column)
1846
1847 {
1848   GtkListStorePrivate *priv = list_store->priv;
1849   GtkTreePath *path;
1850
1851   path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
1852   gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
1853   gtk_tree_path_free (path);
1854
1855   if (!iter_is_sorted (list_store, iter))
1856     {
1857       GHashTable *old_positions;
1858       gint *order;
1859
1860       old_positions = save_positions (priv->seq);
1861       g_sequence_sort_changed_iter (iter->user_data,
1862                                     gtk_list_store_compare_func,
1863                                     list_store);
1864       order = generate_order (priv->seq, old_positions);
1865       path = gtk_tree_path_new ();
1866       gtk_tree_model_rows_reordered (GTK_TREE_MODEL (list_store),
1867                                      path, NULL, order);
1868       gtk_tree_path_free (path);
1869       g_free (order);
1870     }
1871 }
1872
1873 static gboolean
1874 gtk_list_store_get_sort_column_id (GtkTreeSortable  *sortable,
1875                                    gint             *sort_column_id,
1876                                    GtkSortType      *order)
1877 {
1878   GtkListStore *list_store = GTK_LIST_STORE (sortable);
1879   GtkListStorePrivate *priv = list_store->priv;
1880
1881   if (sort_column_id)
1882     * sort_column_id = priv->sort_column_id;
1883   if (order)
1884     * order = priv->order;
1885
1886   if (priv->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID ||
1887       priv->sort_column_id == GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
1888     return FALSE;
1889
1890   return TRUE;
1891 }
1892
1893 static void
1894 gtk_list_store_set_sort_column_id (GtkTreeSortable  *sortable,
1895                                    gint              sort_column_id,
1896                                    GtkSortType       order)
1897 {
1898   GtkListStore *list_store = GTK_LIST_STORE (sortable);
1899   GtkListStorePrivate *priv = list_store->priv;
1900
1901   if ((priv->sort_column_id == sort_column_id) &&
1902       (priv->order == order))
1903     return;
1904
1905   if (sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
1906     {
1907       if (sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
1908         {
1909           GtkTreeDataSortHeader *header = NULL;
1910
1911           header = _gtk_tree_data_list_get_header (priv->sort_list, 
1912                                                    sort_column_id);
1913
1914           /* We want to make sure that we have a function */
1915           g_return_if_fail (header != NULL);
1916           g_return_if_fail (header->func != NULL);
1917         }
1918       else
1919         {
1920           g_return_if_fail (priv->default_sort_func != NULL);
1921         }
1922     }
1923
1924
1925   priv->sort_column_id = sort_column_id;
1926   priv->order = order;
1927
1928   gtk_tree_sortable_sort_column_changed (sortable);
1929
1930   gtk_list_store_sort (list_store);
1931 }
1932
1933 static void
1934 gtk_list_store_set_sort_func (GtkTreeSortable        *sortable,
1935                               gint                    sort_column_id,
1936                               GtkTreeIterCompareFunc  func,
1937                               gpointer                data,
1938                               GDestroyNotify          destroy)
1939 {
1940   GtkListStore *list_store = GTK_LIST_STORE (sortable);
1941   GtkListStorePrivate *priv = list_store->priv;
1942
1943   priv->sort_list = _gtk_tree_data_list_set_header (priv->sort_list, 
1944                                                           sort_column_id, 
1945                                                           func, data, destroy);
1946
1947   if (priv->sort_column_id == sort_column_id)
1948     gtk_list_store_sort (list_store);
1949 }
1950
1951 static void
1952 gtk_list_store_set_default_sort_func (GtkTreeSortable        *sortable,
1953                                       GtkTreeIterCompareFunc  func,
1954                                       gpointer                data,
1955                                       GDestroyNotify          destroy)
1956 {
1957   GtkListStore *list_store = GTK_LIST_STORE (sortable);
1958   GtkListStorePrivate *priv = list_store->priv;
1959
1960   if (priv->default_sort_destroy)
1961     {
1962       GDestroyNotify d = priv->default_sort_destroy;
1963
1964       priv->default_sort_destroy = NULL;
1965       d (priv->default_sort_data);
1966     }
1967
1968   priv->default_sort_func = func;
1969   priv->default_sort_data = data;
1970   priv->default_sort_destroy = destroy;
1971
1972   if (priv->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
1973     gtk_list_store_sort (list_store);
1974 }
1975
1976 static gboolean
1977 gtk_list_store_has_default_sort_func (GtkTreeSortable *sortable)
1978 {
1979   GtkListStore *list_store = GTK_LIST_STORE (sortable);
1980   GtkListStorePrivate *priv = list_store->priv;
1981
1982   return (priv->default_sort_func != NULL);
1983 }
1984
1985
1986 /**
1987  * gtk_list_store_insert_with_values:
1988  * @list_store: A #GtkListStore
1989  * @iter: (out) (allow-none): An unset #GtkTreeIter to set to the new row, or %NULL.
1990  * @position: position to insert the new row
1991  * @Varargs: pairs of column number and value, terminated with -1
1992  *
1993  * Creates a new row at @position.  @iter will be changed to point to this new
1994  * row.  If @position is larger than the number of rows on the list, then the
1995  * new row will be appended to the list. The row will be filled with the 
1996  * values given to this function. 
1997  * 
1998  * Calling
1999  * <literal>gtk_list_store_insert_with_values(list_store, iter, position...)</literal> 
2000  * has the same effect as calling 
2001  * |[
2002  * gtk_list_store_insert (list_store, iter, position);
2003  * gtk_list_store_set (list_store, iter, ...);
2004  * ]|
2005  * with the difference that the former will only emit a row_inserted signal,
2006  * while the latter will emit row_inserted, row_changed and, if the list store
2007  * is sorted, rows_reordered. Since emitting the rows_reordered signal
2008  * repeatedly can affect the performance of the program, 
2009  * gtk_list_store_insert_with_values() should generally be preferred when
2010  * inserting rows in a sorted list store.
2011  *
2012  * Since: 2.6
2013  */
2014 void
2015 gtk_list_store_insert_with_values (GtkListStore *list_store,
2016                                    GtkTreeIter  *iter,
2017                                    gint          position,
2018                                    ...)
2019 {
2020   GtkListStorePrivate *priv;
2021   GtkTreePath *path;
2022   GSequence *seq;
2023   GSequenceIter *ptr;
2024   GtkTreeIter tmp_iter;
2025   gint length;
2026   gboolean changed = FALSE;
2027   gboolean maybe_need_sort = FALSE;
2028   va_list var_args;
2029
2030   /* FIXME: refactor to reduce overlap with gtk_list_store_set() */
2031   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
2032
2033   priv = list_store->priv;
2034
2035   if (!iter)
2036     iter = &tmp_iter;
2037
2038   priv->columns_dirty = TRUE;
2039
2040   seq = priv->seq;
2041
2042   length = g_sequence_get_length (seq);
2043   if (position > length)
2044     position = length;
2045
2046   ptr = g_sequence_get_iter_at_pos (seq, position);
2047   ptr = g_sequence_insert_before (ptr, NULL);
2048
2049   iter->stamp = priv->stamp;
2050   iter->user_data = ptr;
2051
2052   g_assert (VALID_ITER (iter, list_store));
2053
2054   priv->length++;
2055
2056   va_start (var_args, position);
2057   gtk_list_store_set_valist_internal (list_store, iter, 
2058                                       &changed, &maybe_need_sort,
2059                                       var_args);
2060   va_end (var_args);
2061
2062   /* Don't emit rows_reordered here */
2063   if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
2064     g_sequence_sort_changed_iter (iter->user_data,
2065                                   gtk_list_store_compare_func,
2066                                   list_store);
2067
2068   /* Just emit row_inserted */
2069   path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
2070   gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter);
2071   gtk_tree_path_free (path);
2072 }
2073
2074
2075 /**
2076  * gtk_list_store_insert_with_valuesv:
2077  * @list_store: A #GtkListStore
2078  * @iter: (out) (allow-none): An unset #GtkTreeIter to set to the new row, or %NULL.
2079  * @position: position to insert the new row
2080  * @columns: an array of column numbers
2081  * @values: an array of GValues 
2082  * @n_values: the length of the @columns and @values arrays
2083  * 
2084  * A variant of gtk_list_store_insert_with_values() which
2085  * takes the columns and values as two arrays, instead of
2086  * varargs. This function is mainly intended for 
2087  * language-bindings.
2088  *
2089  * Since: 2.6
2090  */
2091 void
2092 gtk_list_store_insert_with_valuesv (GtkListStore *list_store,
2093                                     GtkTreeIter  *iter,
2094                                     gint          position,
2095                                     gint         *columns, 
2096                                     GValue       *values,
2097                                     gint          n_values)
2098 {
2099   GtkListStorePrivate *priv;
2100   GtkTreePath *path;
2101   GSequence *seq;
2102   GSequenceIter *ptr;
2103   GtkTreeIter tmp_iter;
2104   gint length;
2105   gboolean changed = FALSE;
2106   gboolean maybe_need_sort = FALSE;
2107
2108   /* FIXME refactor to reduce overlap with 
2109    * gtk_list_store_insert_with_values() 
2110    */
2111   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
2112
2113   priv = list_store->priv;
2114
2115   if (!iter)
2116     iter = &tmp_iter;
2117
2118   priv->columns_dirty = TRUE;
2119
2120   seq = priv->seq;
2121
2122   length = g_sequence_get_length (seq);
2123   if (position > length)
2124     position = length;
2125
2126   ptr = g_sequence_get_iter_at_pos (seq, position);
2127   ptr = g_sequence_insert_before (ptr, NULL);
2128
2129   iter->stamp = priv->stamp;
2130   iter->user_data = ptr;
2131
2132   g_assert (VALID_ITER (iter, list_store));
2133
2134   priv->length++;  
2135
2136   gtk_list_store_set_vector_internal (list_store, iter,
2137                                       &changed, &maybe_need_sort,
2138                                       columns, values, n_values);
2139
2140   /* Don't emit rows_reordered here */
2141   if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
2142     g_sequence_sort_changed_iter (iter->user_data,
2143                                   gtk_list_store_compare_func,
2144                                   list_store);
2145
2146   /* Just emit row_inserted */
2147   path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
2148   gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter);
2149   gtk_tree_path_free (path);
2150 }
2151
2152 /* GtkBuildable custom tag implementation
2153  *
2154  * <columns>
2155  *   <column type="..."/>
2156  *   <column type="..."/>
2157  * </columns>
2158  */
2159 typedef struct {
2160   gboolean translatable;
2161   gchar *context;
2162   int id;
2163 } ColInfo;
2164
2165 typedef struct {
2166   GtkBuilder *builder;
2167   GObject *object;
2168   GSList *column_type_names;
2169   GType *column_types;
2170   GValue *values;
2171   gint *colids;
2172   ColInfo **columns;
2173   gint last_row;
2174   gint n_columns;
2175   gint row_column;
2176   GQuark error_quark;
2177   gboolean is_data;
2178   const gchar *domain;
2179 } SubParserData;
2180
2181 static void
2182 list_store_start_element (GMarkupParseContext *context,
2183                           const gchar         *element_name,
2184                           const gchar        **names,
2185                           const gchar        **values,
2186                           gpointer             user_data,
2187                           GError             **error)
2188 {
2189   guint i;
2190   SubParserData *data = (SubParserData*)user_data;
2191
2192   if (strcmp (element_name, "col") == 0)
2193     {
2194       int i, id = -1;
2195       gchar *context = NULL;
2196       gboolean translatable = FALSE;
2197       ColInfo *info;
2198
2199       if (data->row_column >= data->n_columns)
2200         {
2201           g_set_error (error, data->error_quark, 0,
2202                        "Too many columns, maximum is %d\n", data->n_columns - 1);
2203           return;
2204         }
2205
2206       for (i = 0; names[i]; i++)
2207         if (strcmp (names[i], "id") == 0)
2208           {
2209             errno = 0;
2210             id = atoi (values[i]);
2211             if (errno)
2212               {
2213                 g_set_error (error, data->error_quark, 0,
2214                              "the id tag %s could not be converted to an integer",
2215                              values[i]);
2216                 return;
2217               }
2218             if (id < 0 || id >= data->n_columns)
2219               {
2220                 g_set_error (error, data->error_quark, 0,
2221                              "id value %d out of range", id);
2222                 return;
2223               }
2224           }
2225         else if (strcmp (names[i], "translatable") == 0)
2226           {
2227             if (!_gtk_builder_boolean_from_string (values[i], &translatable,
2228                                                    error))
2229               return;
2230           }
2231         else if (strcmp (names[i], "comments") == 0)
2232           {
2233             /* do nothing, comments are for translators */
2234           }
2235         else if (strcmp (names[i], "context") == 0) 
2236           {
2237             context = g_strdup (values[i]);
2238           }
2239
2240       if (id == -1)
2241         {
2242           g_set_error (error, data->error_quark, 0,
2243                        "<col> needs an id attribute");
2244           return;
2245         }
2246       
2247       info = g_slice_new0 (ColInfo);
2248       info->translatable = translatable;
2249       info->context = context;
2250       info->id = id;
2251
2252       data->colids[data->row_column] = id;
2253       data->columns[data->row_column] = info;
2254       data->row_column++;
2255       data->is_data = TRUE;
2256     }
2257   else if (strcmp (element_name, "row") == 0)
2258     ;
2259   else if (strcmp (element_name, "column") == 0)
2260     for (i = 0; names[i]; i++)
2261       if (strcmp (names[i], "type") == 0)
2262         data->column_type_names = g_slist_prepend (data->column_type_names,
2263                                                    g_strdup (values[i]));
2264   else if (strcmp (element_name, "columns") == 0)
2265     ;
2266   else if (strcmp (element_name, "data") == 0)
2267     ;
2268   else
2269     g_set_error (error, data->error_quark, 0,
2270                  "Unknown start tag: %s", element_name);
2271 }
2272
2273 static void
2274 list_store_end_element (GMarkupParseContext *context,
2275                         const gchar         *element_name,
2276                         gpointer             user_data,
2277                         GError             **error)
2278 {
2279   SubParserData *data = (SubParserData*)user_data;
2280
2281   g_assert (data->builder);
2282   
2283   if (strcmp (element_name, "row") == 0)
2284     {
2285       GtkTreeIter iter;
2286       int i;
2287
2288       gtk_list_store_insert_with_valuesv (GTK_LIST_STORE (data->object),
2289                                           &iter,
2290                                           data->last_row,
2291                                           data->colids,
2292                                           data->values,
2293                                           data->row_column);
2294       for (i = 0; i < data->row_column; i++)
2295         {
2296           ColInfo *info = data->columns[i];
2297           g_free (info->context);
2298           g_slice_free (ColInfo, info);
2299           data->columns[i] = NULL;
2300           g_value_unset (&data->values[i]);
2301         }
2302       g_free (data->values);
2303       data->values = g_new0 (GValue, data->n_columns);
2304       data->last_row++;
2305       data->row_column = 0;
2306     }
2307   else if (strcmp (element_name, "columns") == 0)
2308     {
2309       GType *column_types;
2310       GSList *l;
2311       int i;
2312       GType type;
2313
2314       data->column_type_names = g_slist_reverse (data->column_type_names);
2315       column_types = g_new0 (GType, g_slist_length (data->column_type_names));
2316
2317       for (l = data->column_type_names, i = 0; l; l = l->next, i++)
2318         {
2319           type = gtk_builder_get_type_from_name (data->builder, l->data);
2320           if (type == G_TYPE_INVALID)
2321             {
2322               g_warning ("Unknown type %s specified in treemodel %s",
2323                          (const gchar*)l->data,
2324                          gtk_buildable_get_name (GTK_BUILDABLE (data->object)));
2325               continue;
2326             }
2327           column_types[i] = type;
2328
2329           g_free (l->data);
2330         }
2331
2332       gtk_list_store_set_column_types (GTK_LIST_STORE (data->object), i,
2333                                        column_types);
2334
2335       g_free (column_types);
2336     }
2337   else if (strcmp (element_name, "col") == 0)
2338     data->is_data = FALSE;
2339   else if (strcmp (element_name, "data") == 0)
2340     ;
2341   else if (strcmp (element_name, "column") == 0)
2342     ;
2343   else
2344     g_set_error (error, data->error_quark, 0,
2345                  "Unknown end tag: %s", element_name);
2346 }
2347
2348 static void
2349 list_store_text (GMarkupParseContext *context,
2350                  const gchar         *text,
2351                  gsize                text_len,
2352                  gpointer             user_data,
2353                  GError             **error)
2354 {
2355   SubParserData *data = (SubParserData*)user_data;
2356   gint i;
2357   GError *tmp_error = NULL;
2358   gchar *string;
2359   ColInfo *info;
2360   
2361   if (!data->is_data)
2362     return;
2363
2364   i = data->row_column - 1;
2365   info = data->columns[i];
2366
2367   string = g_strndup (text, text_len);
2368   if (info->translatable && text_len)
2369     {
2370       gchar *translated;
2371
2372       /* FIXME: This will not use the domain set in the .ui file,
2373        * since the parser is not telling the builder about the domain.
2374        * However, it will work for gtk_builder_set_translation_domain() calls.
2375        */
2376       translated = _gtk_builder_parser_translate (data->domain,
2377                                                   info->context,
2378                                                   string);
2379       g_free (string);
2380       string = translated;
2381     }
2382
2383   if (!gtk_builder_value_from_string_type (data->builder,
2384                                            data->column_types[info->id],
2385                                            string,
2386                                            &data->values[i],
2387                                            &tmp_error))
2388     {
2389       g_set_error (error,
2390                    tmp_error->domain,
2391                    tmp_error->code,
2392                    "Could not convert '%s' to type %s: %s\n",
2393                    text, g_type_name (data->column_types[info->id]),
2394                    tmp_error->message);
2395       g_error_free (tmp_error);
2396     }
2397   g_free (string);
2398 }
2399
2400 static const GMarkupParser list_store_parser =
2401   {
2402     list_store_start_element,
2403     list_store_end_element,
2404     list_store_text
2405   };
2406
2407 static gboolean
2408 gtk_list_store_buildable_custom_tag_start (GtkBuildable  *buildable,
2409                                            GtkBuilder    *builder,
2410                                            GObject       *child,
2411                                            const gchar   *tagname,
2412                                            GMarkupParser *parser,
2413                                            gpointer      *data)
2414 {
2415   SubParserData *parser_data;
2416
2417   if (child)
2418     return FALSE;
2419
2420   if (strcmp (tagname, "columns") == 0)
2421     {
2422
2423       parser_data = g_slice_new0 (SubParserData);
2424       parser_data->builder = builder;
2425       parser_data->object = G_OBJECT (buildable);
2426       parser_data->column_type_names = NULL;
2427
2428       *parser = list_store_parser;
2429       *data = parser_data;
2430       return TRUE;
2431     }
2432   else if (strcmp (tagname, "data") == 0)
2433     {
2434       gint n_columns = gtk_list_store_get_n_columns (GTK_TREE_MODEL (buildable));
2435       if (n_columns == 0)
2436         g_error ("Cannot append data to an empty model");
2437
2438       parser_data = g_slice_new0 (SubParserData);
2439       parser_data->builder = builder;
2440       parser_data->object = G_OBJECT (buildable);
2441       parser_data->values = g_new0 (GValue, n_columns);
2442       parser_data->colids = g_new0 (gint, n_columns);
2443       parser_data->columns = g_new0 (ColInfo*, n_columns);
2444       parser_data->column_types = GTK_LIST_STORE (buildable)->priv->column_headers;
2445       parser_data->n_columns = n_columns;
2446       parser_data->last_row = 0;
2447       parser_data->error_quark = g_quark_from_static_string ("GtkListStore");
2448       parser_data->domain = gtk_builder_get_translation_domain (builder);
2449       
2450       *parser = list_store_parser;
2451       *data = parser_data;
2452       return TRUE;
2453     }
2454   else
2455     g_warning ("Unknown custom list store tag: %s", tagname);
2456   
2457   return FALSE;
2458 }
2459
2460 static void
2461 gtk_list_store_buildable_custom_tag_end (GtkBuildable *buildable,
2462                                          GtkBuilder   *builder,
2463                                          GObject      *child,
2464                                          const gchar  *tagname,
2465                                          gpointer     *data)
2466 {
2467   SubParserData *sub = (SubParserData*)data;
2468   
2469   if (strcmp (tagname, "columns") == 0)
2470     {
2471       g_slist_free (sub->column_type_names);
2472       g_slice_free (SubParserData, sub);
2473     }
2474   else if (strcmp (tagname, "data") == 0)
2475     {
2476       int i;
2477       for (i = 0; i < sub->n_columns; i++)
2478         {
2479           ColInfo *info = sub->columns[i];
2480           if (info)
2481             {
2482               g_free (info->context);
2483               g_slice_free (ColInfo, info);
2484             }
2485         }
2486       g_free (sub->colids);
2487       g_free (sub->columns);
2488       g_free (sub->values);
2489       g_slice_free (SubParserData, sub);
2490     }
2491   else
2492     g_warning ("Unknown custom list store tag: %s", tagname);
2493 }