]> Pileus Git - ~andy/gtk/blob - gtk/gtkliststore.c
Restore length field; PyGTK and maybe others use it directly.
[~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 <string.h>
22 #include <gobject/gvaluecollector.h>
23 #include "gtkalias.h"
24 #include "gtktreemodel.h"
25 #include "gtkliststore.h"
26 #include "gtktreedatalist.h"
27 #include "gtktreednd.h"
28 #include "gtksequence.h"
29
30 #define GTK_LIST_STORE_IS_SORTED(list) (GTK_LIST_STORE (list)->sort_column_id != -2)
31 #define VALID_ITER(iter, list_store) ((iter)!= NULL && (iter)->user_data != NULL && list_store->stamp == (iter)->stamp && !_gtk_sequence_ptr_is_end ((iter)->user_data) && _gtk_sequence_ptr_get_sequence ((iter)->user_data) == list_store->seq)
32
33 static void         gtk_list_store_init            (GtkListStore      *list_store);
34 static void         gtk_list_store_class_init      (GtkListStoreClass *class);
35 static void         gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
36 static void         gtk_list_store_drag_source_init(GtkTreeDragSourceIface *iface);
37 static void         gtk_list_store_drag_dest_init  (GtkTreeDragDestIface   *iface);
38 static void         gtk_list_store_sortable_init   (GtkTreeSortableIface   *iface);
39 static void         gtk_list_store_finalize        (GObject           *object);
40 static GtkTreeModelFlags gtk_list_store_get_flags  (GtkTreeModel      *tree_model);
41 static gint         gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
42 static GType        gtk_list_store_get_column_type (GtkTreeModel      *tree_model,
43                                                     gint               index);
44 static gboolean     gtk_list_store_get_iter        (GtkTreeModel      *tree_model,
45                                                     GtkTreeIter       *iter,
46                                                     GtkTreePath       *path);
47 static GtkTreePath *gtk_list_store_get_path        (GtkTreeModel      *tree_model,
48                                                     GtkTreeIter       *iter);
49 static void         gtk_list_store_get_value       (GtkTreeModel      *tree_model,
50                                                     GtkTreeIter       *iter,
51                                                     gint               column,
52                                                     GValue            *value);
53 static gboolean     gtk_list_store_iter_next       (GtkTreeModel      *tree_model,
54                                                     GtkTreeIter       *iter);
55 static gboolean     gtk_list_store_iter_children   (GtkTreeModel      *tree_model,
56                                                     GtkTreeIter       *iter,
57                                                     GtkTreeIter       *parent);
58 static gboolean     gtk_list_store_iter_has_child  (GtkTreeModel      *tree_model,
59                                                     GtkTreeIter       *iter);
60 static gint         gtk_list_store_iter_n_children (GtkTreeModel      *tree_model,
61                                                     GtkTreeIter       *iter);
62 static gboolean     gtk_list_store_iter_nth_child  (GtkTreeModel      *tree_model,
63                                                     GtkTreeIter       *iter,
64                                                     GtkTreeIter       *parent,
65                                                     gint               n);
66 static gboolean     gtk_list_store_iter_parent     (GtkTreeModel      *tree_model,
67                                                     GtkTreeIter       *iter,
68                                                     GtkTreeIter       *child);
69
70
71 static void gtk_list_store_set_n_columns   (GtkListStore *list_store,
72                                             gint          n_columns);
73 static void gtk_list_store_set_column_type (GtkListStore *list_store,
74                                             gint          column,
75                                             GType         type);
76
77
78 /* Drag and Drop */
79 static gboolean real_gtk_list_store_row_draggable (GtkTreeDragSource *drag_source,
80                                                    GtkTreePath       *path);
81 static gboolean gtk_list_store_drag_data_delete   (GtkTreeDragSource *drag_source,
82                                                    GtkTreePath       *path);
83 static gboolean gtk_list_store_drag_data_get      (GtkTreeDragSource *drag_source,
84                                                    GtkTreePath       *path,
85                                                    GtkSelectionData  *selection_data);
86 static gboolean gtk_list_store_drag_data_received (GtkTreeDragDest   *drag_dest,
87                                                    GtkTreePath       *dest,
88                                                    GtkSelectionData  *selection_data);
89 static gboolean gtk_list_store_row_drop_possible  (GtkTreeDragDest   *drag_dest,
90                                                    GtkTreePath       *dest_path,
91                                                    GtkSelectionData  *selection_data);
92
93
94 /* sortable */
95 static void     gtk_list_store_sort                  (GtkListStore           *list_store);
96 static void     gtk_list_store_sort_iter_changed     (GtkListStore           *list_store,
97                                                       GtkTreeIter            *iter,
98                                                       gint                    column);
99 static gboolean gtk_list_store_get_sort_column_id    (GtkTreeSortable        *sortable,
100                                                       gint                   *sort_column_id,
101                                                       GtkSortType            *order);
102 static void     gtk_list_store_set_sort_column_id    (GtkTreeSortable        *sortable,
103                                                       gint                    sort_column_id,
104                                                       GtkSortType             order);
105 static void     gtk_list_store_set_sort_func         (GtkTreeSortable        *sortable,
106                                                       gint                    sort_column_id,
107                                                       GtkTreeIterCompareFunc  func,
108                                                       gpointer                data,
109                                                       GtkDestroyNotify        destroy);
110 static void     gtk_list_store_set_default_sort_func (GtkTreeSortable        *sortable,
111                                                       GtkTreeIterCompareFunc  func,
112                                                       gpointer                data,
113                                                       GtkDestroyNotify        destroy);
114 static gboolean gtk_list_store_has_default_sort_func (GtkTreeSortable        *sortable);
115
116
117 static GObjectClass *parent_class = NULL;
118
119 GType
120 gtk_list_store_get_type (void)
121 {
122   static GType list_store_type = 0;
123
124   if (!list_store_type)
125     {
126       static const GTypeInfo list_store_info =
127       {
128         sizeof (GtkListStoreClass),
129         NULL,           /* base_init */
130         NULL,           /* base_finalize */
131         (GClassInitFunc) gtk_list_store_class_init,
132         NULL,           /* class_finalize */
133         NULL,           /* class_data */
134         sizeof (GtkListStore),
135         0,
136         (GInstanceInitFunc) gtk_list_store_init,
137       };
138
139       static const GInterfaceInfo tree_model_info =
140       {
141         (GInterfaceInitFunc) gtk_list_store_tree_model_init,
142         NULL,
143         NULL
144       };
145
146       static const GInterfaceInfo drag_source_info =
147       {
148         (GInterfaceInitFunc) gtk_list_store_drag_source_init,
149         NULL,
150         NULL
151       };
152
153       static const GInterfaceInfo drag_dest_info =
154       {
155         (GInterfaceInitFunc) gtk_list_store_drag_dest_init,
156         NULL,
157         NULL
158       };
159
160       static const GInterfaceInfo sortable_info =
161       {
162         (GInterfaceInitFunc) gtk_list_store_sortable_init,
163         NULL,
164         NULL
165       };
166
167       list_store_type = g_type_register_static (G_TYPE_OBJECT, "GtkListStore",
168                                                 &list_store_info, 0);
169
170       g_type_add_interface_static (list_store_type,
171                                    GTK_TYPE_TREE_MODEL,
172                                    &tree_model_info);
173       g_type_add_interface_static (list_store_type,
174                                    GTK_TYPE_TREE_DRAG_SOURCE,
175                                    &drag_source_info);
176       g_type_add_interface_static (list_store_type,
177                                    GTK_TYPE_TREE_DRAG_DEST,
178                                    &drag_dest_info);
179       g_type_add_interface_static (list_store_type,
180                                    GTK_TYPE_TREE_SORTABLE,
181                                    &sortable_info);
182     }
183
184   return list_store_type;
185 }
186
187 static void
188 gtk_list_store_class_init (GtkListStoreClass *class)
189 {
190   GObjectClass *object_class;
191
192   parent_class = g_type_class_peek_parent (class);
193   object_class = (GObjectClass*) class;
194
195   object_class->finalize = gtk_list_store_finalize;
196 }
197
198 static void
199 gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
200 {
201   iface->get_flags = gtk_list_store_get_flags;
202   iface->get_n_columns = gtk_list_store_get_n_columns;
203   iface->get_column_type = gtk_list_store_get_column_type;
204   iface->get_iter = gtk_list_store_get_iter;
205   iface->get_path = gtk_list_store_get_path;
206   iface->get_value = gtk_list_store_get_value;
207   iface->iter_next = gtk_list_store_iter_next;
208   iface->iter_children = gtk_list_store_iter_children;
209   iface->iter_has_child = gtk_list_store_iter_has_child;
210   iface->iter_n_children = gtk_list_store_iter_n_children;
211   iface->iter_nth_child = gtk_list_store_iter_nth_child;
212   iface->iter_parent = gtk_list_store_iter_parent;
213 }
214
215 static void
216 gtk_list_store_drag_source_init (GtkTreeDragSourceIface *iface)
217 {
218   iface->row_draggable = real_gtk_list_store_row_draggable;
219   iface->drag_data_delete = gtk_list_store_drag_data_delete;
220   iface->drag_data_get = gtk_list_store_drag_data_get;
221 }
222
223 static void
224 gtk_list_store_drag_dest_init (GtkTreeDragDestIface *iface)
225 {
226   iface->drag_data_received = gtk_list_store_drag_data_received;
227   iface->row_drop_possible = gtk_list_store_row_drop_possible;
228 }
229
230 static void
231 gtk_list_store_sortable_init (GtkTreeSortableIface *iface)
232 {
233   iface->get_sort_column_id = gtk_list_store_get_sort_column_id;
234   iface->set_sort_column_id = gtk_list_store_set_sort_column_id;
235   iface->set_sort_func = gtk_list_store_set_sort_func;
236   iface->set_default_sort_func = gtk_list_store_set_default_sort_func;
237   iface->has_default_sort_func = gtk_list_store_has_default_sort_func;
238 }
239
240 static void
241 gtk_list_store_init (GtkListStore *list_store)
242 {
243   list_store->seq = _gtk_sequence_new (NULL);
244   list_store->sort_list = NULL;
245   list_store->stamp = g_random_int ();
246   list_store->sort_column_id = -2;
247   list_store->columns_dirty = FALSE;
248   list_store->length = 0;
249 }
250
251 /**
252  * gtk_list_store_new:
253  * @n_columns: number of columns in the list store
254  * @Varargs: all #GType types for the columns, from first to last
255  *
256  * Creates a new list store as with @n_columns columns each of the types passed
257  * in.  Note that only types derived from standard GObject fundamental types 
258  * are supported. 
259  *
260  * As an example, <literal>gtk_tree_store_new (3, G_TYPE_INT, G_TYPE_STRING,
261  * GDK_TYPE_PIXBUF);</literal> will create a new #GtkListStore with three columns, of type
262  * int, string and #GdkPixbuf respectively.
263  *
264  * Return value: a new #GtkListStore
265  **/
266 GtkListStore *
267 gtk_list_store_new (gint n_columns,
268                     ...)
269 {
270   GtkListStore *retval;
271   va_list args;
272   gint i;
273
274   g_return_val_if_fail (n_columns > 0, NULL);
275
276   retval = g_object_new (GTK_TYPE_LIST_STORE, NULL);
277   gtk_list_store_set_n_columns (retval, n_columns);
278
279   va_start (args, n_columns);
280
281   for (i = 0; i < n_columns; i++)
282     {
283       GType type = va_arg (args, GType);
284       if (! _gtk_tree_data_list_check_type (type))
285         {
286           g_warning ("%s: Invalid type %s passed to gtk_list_store_new\n",
287                      G_STRLOC, g_type_name (type));
288           g_object_unref (retval);
289           return NULL;
290         }
291
292       gtk_list_store_set_column_type (retval, i, type);
293     }
294
295   va_end (args);
296
297   return retval;
298 }
299
300
301 /**
302  * gtk_list_store_newv:
303  * @n_columns: number of columns in the list store
304  * @types: an array of #GType types for the columns, from first to last
305  *
306  * Non-vararg creation function.  Used primarily by language bindings.
307  *
308  * Return value: a new #GtkListStore
309  **/
310 GtkListStore *
311 gtk_list_store_newv (gint   n_columns,
312                      GType *types)
313 {
314   GtkListStore *retval;
315   gint i;
316
317   g_return_val_if_fail (n_columns > 0, NULL);
318
319   retval = g_object_new (GTK_TYPE_LIST_STORE, NULL);
320   gtk_list_store_set_n_columns (retval, n_columns);
321
322   for (i = 0; i < n_columns; i++)
323     {
324       if (! _gtk_tree_data_list_check_type (types[i]))
325         {
326           g_warning ("%s: Invalid type %s passed to gtk_list_store_newv\n",
327                      G_STRLOC, g_type_name (types[i]));
328           g_object_unref (retval);
329           return NULL;
330         }
331
332       gtk_list_store_set_column_type (retval, i, types[i]);
333     }
334
335   return retval;
336 }
337
338 /**
339  * gtk_list_store_set_column_types:
340  * @list_store: A #GtkListStore
341  * @n_columns: Number of columns for the list store
342  * @types: An array length n of #GTypes
343  * 
344  * This function is meant primarily for #GObjects that inherit from #GtkListStore,
345  * and should only be used when constructing a new #GtkListStore.  It will not
346  * function after a row has been added, or a method on the #GtkTreeModel
347  * interface is called.
348  **/
349 void
350 gtk_list_store_set_column_types (GtkListStore *list_store,
351                                  gint          n_columns,
352                                  GType        *types)
353 {
354   gint i;
355
356   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
357   g_return_if_fail (list_store->columns_dirty == 0);
358
359   gtk_list_store_set_n_columns (list_store, n_columns);
360    for (i = 0; i < n_columns; i++)
361     {
362       if (! _gtk_tree_data_list_check_type (types[i]))
363         {
364           g_warning ("%s: Invalid type %s passed to gtk_list_store_set_column_types\n", G_STRLOC, g_type_name (types[i]));
365           continue;
366         }
367       gtk_list_store_set_column_type (list_store, i, types[i]);
368     }
369 }
370
371 static void
372 gtk_list_store_set_n_columns (GtkListStore *list_store,
373                               gint          n_columns)
374 {
375   GType *new_columns;
376
377   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
378   g_return_if_fail (n_columns > 0);
379
380   if (list_store->n_columns == n_columns)
381     return;
382
383   new_columns = g_new0 (GType, n_columns);
384   if (list_store->column_headers)
385     {
386       /* copy the old header orders over */
387       if (n_columns >= list_store->n_columns)
388         memcpy (new_columns, list_store->column_headers, list_store->n_columns * sizeof (gchar *));
389       else
390         memcpy (new_columns, list_store->column_headers, n_columns * sizeof (GType));
391
392       g_free (list_store->column_headers);
393     }
394
395   if (list_store->sort_list)
396     _gtk_tree_data_list_header_free (list_store->sort_list);
397
398   list_store->sort_list = _gtk_tree_data_list_header_new (n_columns, list_store->column_headers);
399
400   list_store->column_headers = new_columns;
401   list_store->n_columns = n_columns;
402 }
403
404 static void
405 gtk_list_store_set_column_type (GtkListStore *list_store,
406                                 gint          column,
407                                 GType         type)
408 {
409   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
410   g_return_if_fail (column >=0 && column < list_store->n_columns);
411
412   if (!_gtk_tree_data_list_check_type (type))
413     {
414       g_warning ("%s: Invalid type %s passed to gtk_list_store_set_column_type\n", G_STRLOC, g_type_name (type));
415       return;
416     }
417
418   list_store->column_headers[column] = type;
419 }
420
421 static void
422 gtk_list_store_finalize (GObject *object)
423 {
424   GtkListStore *list_store = GTK_LIST_STORE (object);
425
426   _gtk_sequence_foreach (list_store->seq,
427                         (GFunc) _gtk_tree_data_list_free, list_store->column_headers);
428
429   _gtk_sequence_free (list_store->seq);
430
431   _gtk_tree_data_list_header_free (list_store->sort_list);
432   g_free (list_store->column_headers);
433   
434   if (list_store->default_sort_destroy)
435     {
436       GtkDestroyNotify d = list_store->default_sort_destroy;
437
438       list_store->default_sort_destroy = NULL;
439       d (list_store->default_sort_data);
440       list_store->default_sort_data = NULL;
441     }
442
443   /* must chain up */
444   (* parent_class->finalize) (object);
445 }
446
447 /* Fulfill the GtkTreeModel requirements */
448 static GtkTreeModelFlags
449 gtk_list_store_get_flags (GtkTreeModel *tree_model)
450 {
451   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);
452
453   return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
454 }
455
456 static gint
457 gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
458 {
459   GtkListStore *list_store = (GtkListStore *) tree_model;
460
461   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);
462
463   list_store->columns_dirty = TRUE;
464
465   return list_store->n_columns;
466 }
467
468 static GType
469 gtk_list_store_get_column_type (GtkTreeModel *tree_model,
470                                 gint          index)
471 {
472   GtkListStore *list_store = (GtkListStore *) tree_model;
473
474   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), G_TYPE_INVALID);
475   g_return_val_if_fail (index < GTK_LIST_STORE (tree_model)->n_columns &&
476                         index >= 0, G_TYPE_INVALID);
477
478   list_store->columns_dirty = TRUE;
479
480   return list_store->column_headers[index];
481 }
482
483 static gboolean
484 gtk_list_store_get_iter (GtkTreeModel *tree_model,
485                          GtkTreeIter  *iter,
486                          GtkTreePath  *path)
487 {
488   GtkListStore *list_store = (GtkListStore *) tree_model;
489   GtkSequence *seq;
490   gint i;
491
492   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
493   g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
494
495   list_store->columns_dirty = TRUE;
496
497   seq = list_store->seq;
498   
499   i = gtk_tree_path_get_indices (path)[0];
500
501   if (i >= _gtk_sequence_get_length (seq))
502     return FALSE;
503
504   iter->stamp = list_store->stamp;
505   iter->user_data = _gtk_sequence_get_ptr_at_pos (seq, i);
506
507   return TRUE;
508 }
509
510 static GtkTreePath *
511 gtk_list_store_get_path (GtkTreeModel *tree_model,
512                          GtkTreeIter  *iter)
513 {
514   GtkTreePath *path;
515
516   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), NULL);
517   g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, NULL);
518
519   if (_gtk_sequence_ptr_is_end (iter->user_data))
520     return NULL;
521         
522   path = gtk_tree_path_new ();
523   gtk_tree_path_append_index (path, _gtk_sequence_ptr_get_position (iter->user_data));
524   
525   return path;
526 }
527
528 static void
529 gtk_list_store_get_value (GtkTreeModel *tree_model,
530                           GtkTreeIter  *iter,
531                           gint          column,
532                           GValue       *value)
533 {
534   GtkTreeDataList *list;
535   gint tmp_column = column;
536
537   g_return_if_fail (GTK_IS_LIST_STORE (tree_model));
538   g_return_if_fail (column < GTK_LIST_STORE (tree_model)->n_columns);
539   g_return_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp);
540   g_return_if_fail (VALID_ITER (iter, GTK_LIST_STORE(tree_model)));
541                     
542   list = _gtk_sequence_ptr_get_data (iter->user_data);
543
544   while (tmp_column-- > 0 && list)
545     list = list->next;
546
547   if (list == NULL)
548     g_value_init (value, GTK_LIST_STORE (tree_model)->column_headers[column]);
549   else
550     _gtk_tree_data_list_node_to_value (list,
551                                        GTK_LIST_STORE (tree_model)->column_headers[column],
552                                        value);
553 }
554
555 static gboolean
556 gtk_list_store_iter_next (GtkTreeModel  *tree_model,
557                           GtkTreeIter   *iter)
558 {
559   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
560   g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE);
561   iter->user_data = _gtk_sequence_ptr_next (iter->user_data);
562
563   return !_gtk_sequence_ptr_is_end (iter->user_data);
564 }
565
566 static gboolean
567 gtk_list_store_iter_children (GtkTreeModel *tree_model,
568                               GtkTreeIter  *iter,
569                               GtkTreeIter  *parent)
570 {
571   GtkListStore *list_store;
572   
573   /* this is a list, nodes have no children */
574   if (parent)
575     return FALSE;
576
577   list_store = GTK_LIST_STORE (tree_model);
578
579   if (_gtk_sequence_get_length (list_store->seq) == 0)
580     {
581       iter->stamp = list_store->stamp;
582       iter->user_data = _gtk_sequence_get_begin_ptr (list_store->seq);
583       return TRUE;
584     }
585   else
586     return FALSE;
587 }
588
589 static gboolean
590 gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
591                                GtkTreeIter  *iter)
592 {
593   return FALSE;
594 }
595
596 static gint
597 gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
598                                 GtkTreeIter  *iter)
599 {
600   GtkListStore *store;
601
602   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), -1);
603
604   store = GTK_LIST_STORE (tree_model);
605   
606   if (iter == NULL)
607     return _gtk_sequence_get_length (store->seq);
608
609   g_return_val_if_fail (store->stamp == iter->stamp, -1);
610   return 0;
611 }
612
613 static gboolean
614 gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
615                                GtkTreeIter  *iter,
616                                GtkTreeIter  *parent,
617                                gint          n)
618 {
619   GtkSequencePtr child;
620   GtkListStore *store;
621
622   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
623
624   store = GTK_LIST_STORE (tree_model);
625   
626   if (parent)
627     return FALSE;
628
629   child = _gtk_sequence_get_ptr_at_pos (store->seq, n);
630
631   if (_gtk_sequence_ptr_is_end (child))
632     return FALSE;
633
634   iter->stamp = store->stamp;
635   iter->user_data = child;
636   return TRUE;
637 }
638
639 static gboolean
640 gtk_list_store_iter_parent (GtkTreeModel *tree_model,
641                             GtkTreeIter  *iter,
642                             GtkTreeIter  *child)
643 {
644   return FALSE;
645 }
646
647 static gboolean
648 gtk_list_store_real_set_value (GtkListStore *list_store,
649                                GtkTreeIter  *iter,
650                                gint          column,
651                                GValue       *value,
652                                gboolean      sort)
653 {
654   GtkTreeDataList *list;
655   GtkTreeDataList *prev;
656   gint old_column = column;
657   GValue real_value = {0, };
658   gboolean converted = FALSE;
659   gboolean retval = FALSE;
660
661   g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), FALSE);
662   g_return_val_if_fail (VALID_ITER (iter, list_store), FALSE);
663   g_return_val_if_fail (column >= 0 && column < list_store->n_columns, FALSE);
664   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
665
666   if (! g_type_is_a (G_VALUE_TYPE (value), list_store->column_headers[column]))
667     {
668       if (! (g_value_type_compatible (G_VALUE_TYPE (value), list_store->column_headers[column]) &&
669              g_value_type_compatible (list_store->column_headers[column], G_VALUE_TYPE (value))))
670         {
671           g_warning ("%s: Unable to convert from %s to %s\n",
672                      G_STRLOC,
673                      g_type_name (G_VALUE_TYPE (value)),
674                      g_type_name (list_store->column_headers[column]));
675           return retval;
676         }
677       if (!g_value_transform (value, &real_value))
678         {
679           g_warning ("%s: Unable to make conversion from %s to %s\n",
680                      G_STRLOC,
681                      g_type_name (G_VALUE_TYPE (value)),
682                      g_type_name (list_store->column_headers[column]));
683           g_value_unset (&real_value);
684           return retval;
685         }
686       converted = TRUE;
687     }
688
689   prev = list = _gtk_sequence_ptr_get_data (iter->user_data);
690
691   while (list != NULL)
692     {
693       if (column == 0)
694         {
695           if (converted)
696             _gtk_tree_data_list_value_to_node (list, &real_value);
697           else
698             _gtk_tree_data_list_value_to_node (list, value);
699           retval = TRUE;
700           if (converted)
701             g_value_unset (&real_value);
702          if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
703             gtk_list_store_sort_iter_changed (list_store, iter, old_column);
704           return retval;
705         }
706
707       column--;
708       prev = list;
709       list = list->next;
710     }
711
712   if (_gtk_sequence_ptr_get_data (iter->user_data) == NULL)
713     {
714       list = _gtk_tree_data_list_alloc();
715       _gtk_sequence_set (iter->user_data, list);
716       list->next = NULL;
717     }
718   else
719     {
720       list = prev->next = _gtk_tree_data_list_alloc ();
721       list->next = NULL;
722     }
723
724   while (column != 0)
725     {
726       list->next = _gtk_tree_data_list_alloc ();
727       list = list->next;
728       list->next = NULL;
729       column --;
730     }
731
732   if (converted)
733     _gtk_tree_data_list_value_to_node (list, &real_value);
734   else
735     _gtk_tree_data_list_value_to_node (list, value);
736
737   retval = TRUE;
738   if (converted)
739     g_value_unset (&real_value);
740
741   if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
742     gtk_list_store_sort_iter_changed (list_store, iter, old_column);
743
744   return retval;
745 }
746
747
748 /**
749  * gtk_list_store_set_value:
750  * @list_store: A #GtkListStore
751  * @iter: A valid #GtkTreeIter for the row being modified
752  * @column: column number to modify
753  * @value: new value for the cell
754  *
755  * Sets the data in the cell specified by @iter and @column.
756  * The type of @value must be convertible to the type of the
757  * column.
758  *
759  **/
760 void
761 gtk_list_store_set_value (GtkListStore *list_store,
762                           GtkTreeIter  *iter,
763                           gint          column,
764                           GValue       *value)
765 {
766   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
767   g_return_if_fail (VALID_ITER (iter, list_store));
768   g_return_if_fail (column >= 0 && column < list_store->n_columns);
769   g_return_if_fail (G_IS_VALUE (value));
770
771   if (gtk_list_store_real_set_value (list_store, iter, column, value, TRUE))
772     {
773       GtkTreePath *path;
774
775       path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_store), iter);
776       gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
777       gtk_tree_path_free (path);
778     }
779 }
780
781 /**
782  * gtk_list_store_set_valist:
783  * @list_store: A #GtkListStore
784  * @iter: A valid #GtkTreeIter for the row being modified
785  * @var_args: va_list of column/value pairs
786  *
787  * See gtk_list_store_set(); this version takes a va_list for use by language
788  * bindings.
789  *
790  **/
791 void
792 gtk_list_store_set_valist (GtkListStore *list_store,
793                            GtkTreeIter  *iter,
794                            va_list       var_args)
795 {
796   gint column;
797   gboolean emit_signal = FALSE;
798   gboolean maybe_need_sort = FALSE;
799   GtkTreeIterCompareFunc func = NULL;
800
801   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
802   g_return_if_fail (VALID_ITER (iter, list_store));
803
804   column = va_arg (var_args, gint);
805
806   if (GTK_LIST_STORE_IS_SORTED (list_store))
807     {
808       if (list_store->sort_column_id != -1)
809         {
810           GtkTreeDataSortHeader *header;
811           header = _gtk_tree_data_list_get_header (list_store->sort_list,
812                                                    list_store->sort_column_id);
813           g_return_if_fail (header != NULL);
814           g_return_if_fail (header->func != NULL);
815           func = header->func;
816         }
817       else
818         {
819           func = list_store->default_sort_func;
820         }
821     }
822
823   if (func != _gtk_tree_data_list_compare_func)
824     maybe_need_sort = TRUE;
825
826   while (column != -1)
827     {
828       GValue value = { 0, };
829       gchar *error = NULL;
830
831       if (column >= list_store->n_columns)
832         {
833           g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
834           break;
835         }
836       g_value_init (&value, list_store->column_headers[column]);
837
838       G_VALUE_COLLECT (&value, var_args, 0, &error);
839       if (error)
840         {
841           g_warning ("%s: %s", G_STRLOC, error);
842           g_free (error);
843
844           /* we purposely leak the value here, it might not be
845            * in a sane state if an error condition occoured
846            */
847           break;
848         }
849
850       /* FIXME: instead of calling this n times, refactor with above */
851       emit_signal = gtk_list_store_real_set_value (list_store,
852                                                    iter,
853                                                    column,
854                                                    &value,
855                                                    FALSE) || emit_signal;
856
857       if (func == _gtk_tree_data_list_compare_func &&
858           column == list_store->sort_column_id)
859         maybe_need_sort = TRUE;
860
861       g_value_unset (&value);
862
863       column = va_arg (var_args, gint);
864     }
865
866   if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
867     gtk_list_store_sort_iter_changed (list_store, iter, list_store->sort_column_id);
868
869   if (emit_signal)
870     {
871       GtkTreePath *path;
872
873       path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_store), iter);
874       gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
875       gtk_tree_path_free (path);
876     }
877 }
878
879 /**
880  * gtk_list_store_set:
881  * @list_store: a #GtkListStore
882  * @iter: row iterator
883  * @Varargs: pairs of column number and value, terminated with -1
884  *
885  * Sets the value of one or more cells in the row referenced by @iter.
886  * The variable argument list should contain integer column numbers,
887  * each column number followed by the value to be set.
888  * The list is terminated by a -1. For example, to set column 0 with type
889  * %G_TYPE_STRING to "Foo", you would write <literal>gtk_list_store_set (store, iter,
890  * 0, "Foo", -1)</literal>.
891  **/
892 void
893 gtk_list_store_set (GtkListStore *list_store,
894                     GtkTreeIter  *iter,
895                     ...)
896 {
897   va_list var_args;
898
899   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
900   g_return_if_fail (iter != NULL);
901   g_return_if_fail (iter->stamp == list_store->stamp);
902
903   va_start (var_args, iter);
904   gtk_list_store_set_valist (list_store, iter, var_args);
905   va_end (var_args);
906 }
907
908 /**
909  * gtk_list_store_remove:
910  * @list_store: A #GtkListStore
911  * @iter: A valid #GtkTreeIter
912  *
913  * Removes the given row from the list store.  After being removed, 
914  * @iter is set to be the next valid row, or invalidated if it pointed 
915  * to the last row in @list_store.
916  *
917  * Return value: %TRUE if @iter is valid, %FALSE if not.
918  **/
919 gboolean
920 gtk_list_store_remove (GtkListStore *list_store,
921                        GtkTreeIter  *iter)
922 {
923   GtkTreePath *path;
924   GtkSequencePtr ptr, next;
925
926   g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), FALSE);
927   g_return_val_if_fail (VALID_ITER (iter, list_store), FALSE);
928
929   path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
930
931   ptr = iter->user_data;
932   next = _gtk_sequence_ptr_next (ptr);
933   
934   _gtk_tree_data_list_free (_gtk_sequence_ptr_get_data (ptr), list_store->column_headers);
935   _gtk_sequence_remove (iter->user_data);
936
937   list_store->length--;
938   
939   gtk_tree_model_row_deleted (GTK_TREE_MODEL (list_store), path);
940   gtk_tree_path_free (path);
941
942   if (_gtk_sequence_ptr_is_end (next))
943     {
944       iter->stamp = 0;
945       return FALSE;
946     }
947   else
948     {
949       iter->stamp = list_store->stamp;
950       iter->user_data = next;
951       return TRUE;
952     }
953 }
954
955 /**
956  * gtk_list_store_insert:
957  * @list_store: A #GtkListStore
958  * @iter: An unset #GtkTreeIter to set to the new row
959  * @position: position to insert the new row
960  *
961  * Creates a new row at @position.  @iter will be changed to point to this new
962  * row.  If @position is larger than the number of rows on the list, then the
963  * new row will be appended to the list.  The row will be empty before this
964  * function is called.  To fill in values, you need to call gtk_list_store_set()
965  * or gtk_list_store_set_value().
966  *
967  **/
968 void
969 gtk_list_store_insert (GtkListStore *list_store,
970                        GtkTreeIter  *iter,
971                        gint          position)
972 {
973   GtkTreePath *path;
974   GtkSequence *seq;
975   GtkSequencePtr ptr;
976   gint length;
977
978   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
979   g_return_if_fail (iter != NULL);
980   g_return_if_fail (position >= 0);
981
982   list_store->columns_dirty = TRUE;
983
984   seq = list_store->seq;
985
986   length = _gtk_sequence_get_length (seq);
987   if (position > length)
988     position = length;
989
990   ptr = _gtk_sequence_get_ptr_at_pos (seq, position);
991   ptr = _gtk_sequence_insert (ptr, NULL);
992
993   iter->stamp = list_store->stamp;
994   iter->user_data = ptr;
995
996   g_assert (VALID_ITER (iter, list_store));
997
998   list_store->length++;
999   
1000   path = gtk_tree_path_new ();
1001   gtk_tree_path_append_index (path, position);
1002   gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter);
1003   gtk_tree_path_free (path);
1004 }
1005
1006 /**
1007  * gtk_list_store_insert_before:
1008  * @list_store: A #GtkListStore
1009  * @iter: An unset #GtkTreeIter to set to the new row
1010  * @sibling: A valid #GtkTreeIter, or %NULL
1011  *
1012  * Inserts a new row before @sibling. If @sibling is %NULL, then the row will be
1013  * appended to the end of the list. @iter will be changed to point to this new 
1014  * row. The row will be empty before this function is called. To fill in values,
1015  * you need to call gtk_list_store_set() or gtk_list_store_set_value().
1016  *
1017  **/
1018 void
1019 gtk_list_store_insert_before (GtkListStore *list_store,
1020                               GtkTreeIter  *iter,
1021                               GtkTreeIter  *sibling)
1022 {
1023   GtkSequencePtr after;
1024   
1025   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1026   g_return_if_fail (iter != NULL);
1027   if (sibling)
1028     g_return_if_fail (VALID_ITER (sibling, list_store));
1029
1030   if (!sibling)
1031     after = _gtk_sequence_get_end_ptr (list_store->seq);
1032   else
1033     after = sibling->user_data;
1034
1035   gtk_list_store_insert (list_store, iter, _gtk_sequence_ptr_get_position (after));
1036 }
1037
1038 /**
1039  * gtk_list_store_insert_after:
1040  * @list_store: A #GtkListStore
1041  * @iter: An unset #GtkTreeIter to set to the new row
1042  * @sibling: A valid #GtkTreeIter, or %NULL
1043  *
1044  * Inserts a new row after @sibling. If @sibling is %NULL, then the row will be
1045  * prepended to the beginning of the list. @iter will be changed to point to
1046  * this new row. The row will be empty after this function is called. To fill
1047  * in values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1048  *
1049  **/
1050 void
1051 gtk_list_store_insert_after (GtkListStore *list_store,
1052                              GtkTreeIter  *iter,
1053                              GtkTreeIter  *sibling)
1054 {
1055   GtkSequencePtr after;
1056
1057   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1058   g_return_if_fail (iter != NULL);
1059   if (sibling)
1060     g_return_if_fail (VALID_ITER (sibling, list_store));
1061
1062   if (!sibling)
1063     after = _gtk_sequence_get_begin_ptr (list_store->seq);
1064   else
1065     after = _gtk_sequence_ptr_next (sibling->user_data);
1066
1067   gtk_list_store_insert (list_store, iter, _gtk_sequence_ptr_get_position (after));
1068 }
1069
1070 /**
1071  * gtk_list_store_prepend:
1072  * @list_store: A #GtkListStore
1073  * @iter: An unset #GtkTreeIter to set to the prepend row
1074  *
1075  * Prepends a new row to @list_store. @iter will be changed to point to this new
1076  * row. The row will be empty after this function is called. To fill in
1077  * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1078  *
1079  **/
1080 void
1081 gtk_list_store_prepend (GtkListStore *list_store,
1082                         GtkTreeIter  *iter)
1083 {
1084   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1085   g_return_if_fail (iter != NULL);
1086
1087   gtk_list_store_insert (list_store, iter, 0);
1088 }
1089
1090 /**
1091  * gtk_list_store_append:
1092  * @list_store: A #GtkListStore
1093  * @iter: An unset #GtkTreeIter to set to the appended row
1094  *
1095  * Appends a new row to @list_store.  @iter will be changed to point to this new
1096  * row.  The row will be empty after this function is called.  To fill in
1097  * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1098  *
1099  **/
1100 void
1101 gtk_list_store_append (GtkListStore *list_store,
1102                        GtkTreeIter  *iter)
1103 {
1104   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1105   g_return_if_fail (iter != NULL);
1106
1107   gtk_list_store_insert (list_store, iter, _gtk_sequence_get_length (list_store->seq));
1108 }
1109
1110 /**
1111  * gtk_list_store_clear:
1112  * @list_store: a #GtkListStore.
1113  *
1114  * Removes all rows from the list store.  
1115  *
1116  **/
1117 void
1118 gtk_list_store_clear (GtkListStore *list_store)
1119 {
1120   GtkTreeIter iter;
1121   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1122
1123   while (_gtk_sequence_get_length (list_store->seq) > 0)
1124     {
1125       iter.stamp = list_store->stamp;
1126       iter.user_data = _gtk_sequence_get_begin_ptr (list_store->seq);
1127       gtk_list_store_remove (list_store, &iter);
1128     }
1129 }
1130
1131 /**
1132  * gtk_list_store_iter_is_valid:
1133  * @list_store: A #GtkListStore.
1134  * @iter: A #GtkTreeIter.
1135  *
1136  * WARNING: This function is slow. Only use it for debugging and/or testing
1137  * purposes.
1138  *
1139  * Checks if the given iter is a valid iter for this #GtkListStore.
1140  *
1141  * Return value: %TRUE if the iter is valid, %FALSE if the iter is invalid.
1142  *
1143  * Since: 2.2
1144  **/
1145 gboolean
1146 gtk_list_store_iter_is_valid (GtkListStore *list_store,
1147                               GtkTreeIter  *iter)
1148 {
1149   g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), FALSE);
1150   g_return_val_if_fail (iter != NULL, FALSE);
1151
1152   if (!VALID_ITER (iter, list_store))
1153     return FALSE;
1154
1155   if (_gtk_sequence_ptr_get_sequence (iter->user_data) != list_store->seq)
1156     return FALSE;
1157
1158   return TRUE;
1159 }
1160
1161 static gboolean real_gtk_list_store_row_draggable (GtkTreeDragSource *drag_source,
1162                                                    GtkTreePath       *path)
1163 {
1164   return TRUE;
1165 }
1166   
1167 static gboolean
1168 gtk_list_store_drag_data_delete (GtkTreeDragSource *drag_source,
1169                                  GtkTreePath       *path)
1170 {
1171   GtkTreeIter iter;
1172   g_return_val_if_fail (GTK_IS_LIST_STORE (drag_source), FALSE);
1173
1174   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source),
1175                                &iter,
1176                                path))
1177     {
1178       gtk_list_store_remove (GTK_LIST_STORE (drag_source), &iter);
1179       return TRUE;
1180     }
1181   return FALSE;
1182 }
1183
1184 static gboolean
1185 gtk_list_store_drag_data_get (GtkTreeDragSource *drag_source,
1186                               GtkTreePath       *path,
1187                               GtkSelectionData  *selection_data)
1188 {
1189   g_return_val_if_fail (GTK_IS_LIST_STORE (drag_source), FALSE);
1190
1191   /* Note that we don't need to handle the GTK_TREE_MODEL_ROW
1192    * target, because the default handler does it for us, but
1193    * we do anyway for the convenience of someone maybe overriding the
1194    * default handler.
1195    */
1196
1197   if (gtk_tree_set_row_drag_data (selection_data,
1198                                   GTK_TREE_MODEL (drag_source),
1199                                   path))
1200     {
1201       return TRUE;
1202     }
1203   else
1204     {
1205       /* FIXME handle text targets at least. */
1206     }
1207
1208   return FALSE;
1209 }
1210
1211 static gboolean
1212 gtk_list_store_drag_data_received (GtkTreeDragDest   *drag_dest,
1213                                    GtkTreePath       *dest,
1214                                    GtkSelectionData  *selection_data)
1215 {
1216   GtkTreeModel *tree_model;
1217   GtkListStore *list_store;
1218   GtkTreeModel *src_model = NULL;
1219   GtkTreePath *src_path = NULL;
1220   gboolean retval = FALSE;
1221
1222   g_return_val_if_fail (GTK_IS_LIST_STORE (drag_dest), FALSE);
1223
1224   tree_model = GTK_TREE_MODEL (drag_dest);
1225   list_store = GTK_LIST_STORE (drag_dest);
1226
1227   if (gtk_tree_get_row_drag_data (selection_data,
1228                                   &src_model,
1229                                   &src_path) &&
1230       src_model == tree_model)
1231     {
1232       /* Copy the given row to a new position */
1233       GtkTreeIter src_iter;
1234       GtkTreeIter dest_iter;
1235       GtkTreePath *prev;
1236
1237       if (!gtk_tree_model_get_iter (src_model,
1238                                     &src_iter,
1239                                     src_path))
1240         {
1241           goto out;
1242         }
1243
1244       /* Get the path to insert _after_ (dest is the path to insert _before_) */
1245       prev = gtk_tree_path_copy (dest);
1246
1247       if (!gtk_tree_path_prev (prev))
1248         {
1249           /* dest was the first spot in the list; which means we are supposed
1250            * to prepend.
1251            */
1252           gtk_list_store_prepend (list_store, &dest_iter);
1253
1254           retval = TRUE;
1255         }
1256       else
1257         {
1258           if (gtk_tree_model_get_iter (tree_model, &dest_iter, prev))
1259             {
1260               GtkTreeIter tmp_iter = dest_iter;
1261
1262               gtk_list_store_insert_after (list_store, &dest_iter, &tmp_iter);
1263
1264               retval = TRUE;
1265             }
1266         }
1267
1268       gtk_tree_path_free (prev);
1269
1270       /* If we succeeded in creating dest_iter, copy data from src
1271        */
1272       if (retval)
1273         {
1274           GtkTreeDataList *dl = _gtk_sequence_ptr_get_data (src_iter.user_data);
1275           GtkTreeDataList *copy_head = NULL;
1276           GtkTreeDataList *copy_prev = NULL;
1277           GtkTreeDataList *copy_iter = NULL;
1278           GtkTreePath *path;
1279           gint col;
1280
1281           col = 0;
1282           while (dl)
1283             {
1284               copy_iter = _gtk_tree_data_list_node_copy (dl,
1285                                                          list_store->column_headers[col]);
1286
1287               if (copy_head == NULL)
1288                 copy_head = copy_iter;
1289
1290               if (copy_prev)
1291                 copy_prev->next = copy_iter;
1292
1293               copy_prev = copy_iter;
1294
1295               dl = dl->next;
1296               ++col;
1297             }
1298
1299           dest_iter.stamp = list_store->stamp;
1300           _gtk_sequence_set (dest_iter.user_data, copy_head);
1301
1302           path = gtk_list_store_get_path (tree_model, &dest_iter);
1303           gtk_tree_model_row_changed (tree_model, path, &dest_iter);
1304           gtk_tree_path_free (path);
1305         }
1306     }
1307   else
1308     {
1309       /* FIXME maybe add some data targets eventually, or handle text
1310        * targets in the simple case.
1311        */
1312     }
1313
1314  out:
1315
1316   if (src_path)
1317     gtk_tree_path_free (src_path);
1318
1319   return retval;
1320 }
1321
1322 static gboolean
1323 gtk_list_store_row_drop_possible (GtkTreeDragDest  *drag_dest,
1324                                   GtkTreePath      *dest_path,
1325                                   GtkSelectionData *selection_data)
1326 {
1327   gint *indices;
1328   GtkTreeModel *src_model = NULL;
1329   GtkTreePath *src_path = NULL;
1330   gboolean retval = FALSE;
1331
1332   g_return_val_if_fail (GTK_IS_LIST_STORE (drag_dest), FALSE);
1333
1334   /* don't accept drops if the list has been sorted */
1335   if (GTK_LIST_STORE_IS_SORTED (drag_dest))
1336     return FALSE;
1337
1338   if (!gtk_tree_get_row_drag_data (selection_data,
1339                                    &src_model,
1340                                    &src_path))
1341     goto out;
1342
1343   if (src_model != GTK_TREE_MODEL (drag_dest))
1344     goto out;
1345
1346   if (gtk_tree_path_get_depth (dest_path) != 1)
1347     goto out;
1348
1349   /* can drop before any existing node, or before one past any existing. */
1350
1351   indices = gtk_tree_path_get_indices (dest_path);
1352
1353   if (indices[0] <= _gtk_sequence_get_length (GTK_LIST_STORE (drag_dest)->seq))
1354     retval = TRUE;
1355
1356  out:
1357   if (src_path)
1358     gtk_tree_path_free (src_path);
1359   
1360   return retval;
1361 }
1362
1363 /* Sorting and reordering */
1364
1365 /* Reordering */
1366 static gint
1367 gtk_list_store_reorder_func (gconstpointer a,
1368                              gconstpointer b,
1369                              gpointer      user_data)
1370 {
1371   GHashTable *new_positions = user_data;
1372   gint apos = GPOINTER_TO_INT (g_hash_table_lookup (new_positions, a));
1373   gint bpos = GPOINTER_TO_INT (g_hash_table_lookup (new_positions, b));
1374
1375   if (apos < bpos)
1376     return -1;
1377   if (apos > bpos)
1378     return 1;
1379   return 0;
1380 }
1381   
1382 /**
1383  * gtk_list_store_reorder:
1384  * @store: A #GtkListStore.
1385  * @new_order: an array of integers mapping the new position of each child
1386  *      to its old position before the re-ordering,
1387  *      i.e. @new_order<literal>[newpos] = oldpos</literal>.
1388  *
1389  * Reorders @store to follow the order indicated by @new_order. Note that
1390  * this function only works with unsorted stores.
1391  *
1392  * Since: 2.2
1393  **/
1394 void
1395 gtk_list_store_reorder (GtkListStore *store,
1396                         gint         *new_order)
1397 {
1398   gint i;
1399   GtkTreePath *path;
1400   GHashTable *new_positions;
1401   GtkSequencePtr ptr;
1402
1403   g_return_if_fail (GTK_IS_LIST_STORE (store));
1404   g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1405   g_return_if_fail (new_order != NULL);
1406
1407   new_positions = g_hash_table_new (g_direct_hash, g_direct_equal);
1408
1409   ptr = _gtk_sequence_get_begin_ptr (store->seq);
1410   i = 0;
1411   while (ptr)
1412     {
1413       g_hash_table_insert (new_positions, ptr, GINT_TO_POINTER (new_order[i++]));
1414
1415       ptr = _gtk_sequence_ptr_next (ptr);
1416     }
1417   
1418   _gtk_sequence_sort (store->seq, gtk_list_store_reorder_func, new_positions);
1419
1420   g_hash_table_destroy (new_positions);
1421   
1422   /* emit signal */
1423   path = gtk_tree_path_new ();
1424   gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store),
1425                                  path, NULL, new_order);
1426   gtk_tree_path_free (path);
1427 }
1428
1429 /**
1430  * gtk_list_store_swap:
1431  * @store: A #GtkListStore.
1432  * @a: A #GtkTreeIter.
1433  * @b: Another #GtkTreeIter.
1434  *
1435  * Swaps @a and @b in @store. Note that this function only works with
1436  * unsorted stores.
1437  *
1438  * Since: 2.2
1439  **/
1440 void
1441 gtk_list_store_swap (GtkListStore *store,
1442                      GtkTreeIter  *a,
1443                      GtkTreeIter  *b)
1444 {
1445   GtkTreePath *path;
1446
1447   g_return_if_fail (GTK_IS_LIST_STORE (store));
1448   g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1449   g_return_if_fail (VALID_ITER (a, store));
1450   g_return_if_fail (VALID_ITER (b, store));
1451
1452   if (a->user_data == b->user_data)
1453     return;
1454
1455   _gtk_sequence_swap (a->user_data, b->user_data);
1456   
1457   /* emit signal */
1458   path = gtk_tree_path_new ();
1459   
1460   gtk_tree_model_row_changed (GTK_TREE_MODEL (store), path, a);
1461   gtk_tree_model_row_changed (GTK_TREE_MODEL (store), path, b);
1462   
1463   gtk_tree_path_free (path);
1464 }
1465
1466 static GHashTable *
1467 save_positions (GtkSequence *seq)
1468 {
1469   GHashTable *positions = g_hash_table_new (g_direct_hash, g_direct_equal);
1470   GtkSequencePtr ptr;
1471
1472   ptr = _gtk_sequence_get_begin_ptr (seq);
1473   while (!_gtk_sequence_ptr_is_end (ptr))
1474     {
1475       g_hash_table_insert (positions, ptr,
1476                            GINT_TO_POINTER (_gtk_sequence_ptr_get_position (ptr)));
1477       ptr = _gtk_sequence_ptr_next (ptr);
1478     }
1479
1480   return positions;
1481 }
1482
1483 static int *
1484 generate_order (GtkSequence *seq,
1485                 GHashTable *old_positions)
1486 {
1487   GtkSequencePtr ptr;
1488   int *order = g_new (int, _gtk_sequence_get_length (seq));
1489   int i;
1490
1491   i = 0;
1492   ptr = _gtk_sequence_get_begin_ptr (seq);
1493   while (!_gtk_sequence_ptr_is_end (ptr))
1494     {
1495       int old_pos = GPOINTER_TO_INT (g_hash_table_lookup (old_positions, ptr));
1496       order[old_pos] = i++;
1497       ptr = _gtk_sequence_ptr_next (ptr);
1498     }
1499
1500   g_hash_table_destroy (old_positions);
1501
1502   return order;
1503 }
1504
1505 static void
1506 gtk_list_store_move_to (GtkListStore *store,
1507                         GtkTreeIter  *iter,
1508                         gint          new_pos)
1509 {
1510   GHashTable *old_positions;
1511   GtkTreePath *path;
1512   gint *order;
1513   
1514   old_positions = save_positions (store->seq);
1515   
1516   _gtk_sequence_move (iter->user_data, _gtk_sequence_get_ptr_at_pos (store->seq, new_pos));
1517
1518   order = generate_order (store->seq, old_positions);
1519   
1520   path = gtk_tree_path_new ();
1521   gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store),
1522                                  path, NULL, order);
1523   gtk_tree_path_free (path);
1524   g_free (order);
1525 }
1526
1527 /**
1528  * gtk_list_store_move_before:
1529  * @store: A #GtkListStore.
1530  * @iter: A #GtkTreeIter.
1531  * @position: A #GtkTreeIter, or %NULL.
1532  *
1533  * Moves @iter in @store to the position before @position. Note that this
1534  * function only works with unsorted stores. If @position is %NULL, @iter
1535  * will be moved to the end of the list.
1536  *
1537  * Since: 2.2
1538  **/
1539 void
1540 gtk_list_store_move_before (GtkListStore *store,
1541                             GtkTreeIter  *iter,
1542                             GtkTreeIter  *position)
1543 {
1544   gint pos;
1545   
1546   g_return_if_fail (GTK_IS_LIST_STORE (store));
1547   g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1548   g_return_if_fail (VALID_ITER (iter, store));
1549   if (position)
1550     g_return_if_fail (VALID_ITER (position, store));
1551
1552   if (position)
1553     pos = _gtk_sequence_ptr_get_position (iter->user_data);
1554   else
1555     pos = -1;
1556   
1557   gtk_list_store_move_to (store, iter, pos);
1558 }
1559
1560 /**
1561  * gtk_list_store_move_after:
1562  * @store: A #GtkListStore.
1563  * @iter: A #GtkTreeIter.
1564  * @position: A #GtkTreeIter or %NULL.
1565  *
1566  * Moves @iter in @store to the position after @position. Note that this
1567  * function only works with unsorted stores. If @position is %NULL, @iter
1568  * will be moved to the start of the list.
1569  *
1570  * Since: 2.2
1571  **/
1572 void
1573 gtk_list_store_move_after (GtkListStore *store,
1574                            GtkTreeIter  *iter,
1575                            GtkTreeIter  *position)
1576 {
1577   gint pos;
1578   
1579   g_return_if_fail (GTK_IS_LIST_STORE (store));
1580   g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1581   g_return_if_fail (VALID_ITER (iter, store));
1582   if (position)
1583     g_return_if_fail (VALID_ITER (position, store));
1584
1585   if (position)
1586     pos = _gtk_sequence_ptr_get_position (iter->user_data);
1587   else
1588     pos = 0;
1589   
1590   gtk_list_store_move_to (store, iter, pos);
1591 }
1592     
1593 /* Sorting */
1594 static gint
1595 gtk_list_store_compare_func (gconstpointer a,
1596                              gconstpointer b,
1597                              gpointer      user_data)
1598 {
1599   GtkListStore *list_store = user_data;
1600   GtkTreeIter iter_a;
1601   GtkTreeIter iter_b;
1602   gint retval;
1603   GtkTreeIterCompareFunc func;
1604   gpointer data;
1605
1606   if (list_store->sort_column_id != -1)
1607     {
1608       GtkTreeDataSortHeader *header;
1609
1610       header = _gtk_tree_data_list_get_header (list_store->sort_list,
1611                                                list_store->sort_column_id);
1612       g_return_val_if_fail (header != NULL, 0);
1613       g_return_val_if_fail (header->func != NULL, 0);
1614
1615       func = header->func;
1616       data = header->data;
1617     }
1618   else
1619     {
1620       g_return_val_if_fail (list_store->default_sort_func != NULL, 0);
1621       func = list_store->default_sort_func;
1622       data = list_store->default_sort_data;
1623     }
1624
1625   iter_a.stamp = list_store->stamp;
1626   iter_a.user_data = (gpointer)a;
1627   iter_b.stamp = list_store->stamp;
1628   iter_b.user_data = (gpointer)b;
1629
1630   g_assert (VALID_ITER (&iter_a, list_store));
1631   g_assert (VALID_ITER (&iter_b, list_store));
1632   
1633   retval = (* func) (GTK_TREE_MODEL (list_store), &iter_a, &iter_b, data);
1634
1635   if (list_store->order == GTK_SORT_DESCENDING)
1636     {
1637       if (retval > 0)
1638         retval = -1;
1639       else if (retval < 0)
1640         retval = 1;
1641     }
1642
1643   return retval;
1644 }
1645
1646 static void
1647 gtk_list_store_sort (GtkListStore *list_store)
1648 {
1649   gint *new_order;
1650   GtkTreePath *path;
1651   GHashTable *old_positions;
1652
1653   if (_gtk_sequence_get_length (list_store->seq) <= 1)
1654     return;
1655
1656   old_positions = save_positions (list_store->seq);
1657
1658   _gtk_sequence_sort (list_store->seq, gtk_list_store_compare_func, list_store);
1659
1660   /* Let the world know about our new order */
1661   new_order = generate_order (list_store->seq, old_positions);
1662
1663   path = gtk_tree_path_new ();
1664   gtk_tree_model_rows_reordered (GTK_TREE_MODEL (list_store),
1665                                  path, NULL, new_order);
1666   gtk_tree_path_free (path);
1667   g_free (new_order);
1668 }
1669
1670 static void
1671 gtk_list_store_sort_iter_changed (GtkListStore *list_store,
1672                                   GtkTreeIter  *iter,
1673                                   gint          column)
1674
1675 {
1676   GtkTreePath *tmp_path;
1677
1678   _gtk_sequence_sort_changed (iter->user_data,
1679                               gtk_list_store_compare_func,
1680                               list_store);
1681
1682   tmp_path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_store), iter);
1683   gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), tmp_path, iter);
1684   gtk_tree_path_free (tmp_path);
1685 }
1686
1687 static gboolean
1688 gtk_list_store_get_sort_column_id (GtkTreeSortable  *sortable,
1689                                    gint             *sort_column_id,
1690                                    GtkSortType      *order)
1691 {
1692   GtkListStore *list_store = (GtkListStore *) sortable;
1693
1694   g_return_val_if_fail (GTK_IS_LIST_STORE (sortable), FALSE);
1695
1696   if (list_store->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
1697     return FALSE;
1698
1699   if (sort_column_id)
1700     * sort_column_id = list_store->sort_column_id;
1701   if (order)
1702     * order = list_store->order;
1703   return TRUE;
1704 }
1705
1706 static void
1707 gtk_list_store_set_sort_column_id (GtkTreeSortable  *sortable,
1708                                    gint              sort_column_id,
1709                                    GtkSortType       order)
1710 {
1711   GtkListStore *list_store = (GtkListStore *) sortable;
1712
1713   g_return_if_fail (GTK_IS_LIST_STORE (sortable));
1714
1715   if ((list_store->sort_column_id == sort_column_id) &&
1716       (list_store->order == order))
1717     return;
1718
1719   if (sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
1720     {
1721       GtkTreeDataSortHeader *header = NULL;
1722
1723       header = _gtk_tree_data_list_get_header (list_store->sort_list, sort_column_id);
1724
1725       /* We want to make sure that we have a function */
1726       g_return_if_fail (header != NULL);
1727       g_return_if_fail (header->func != NULL);
1728     }
1729   else
1730     {
1731       g_return_if_fail (list_store->default_sort_func != NULL);
1732     }
1733
1734
1735   list_store->sort_column_id = sort_column_id;
1736   list_store->order = order;
1737
1738   gtk_tree_sortable_sort_column_changed (sortable);
1739
1740   gtk_list_store_sort (list_store);
1741 }
1742
1743 static void
1744 gtk_list_store_set_sort_func (GtkTreeSortable        *sortable,
1745                               gint                    sort_column_id,
1746                               GtkTreeIterCompareFunc  func,
1747                               gpointer                data,
1748                               GtkDestroyNotify        destroy)
1749 {
1750   GtkListStore *list_store = (GtkListStore *) sortable;
1751   GtkTreeDataSortHeader *header = NULL;
1752   GList *list;
1753
1754   g_return_if_fail (GTK_IS_LIST_STORE (sortable));
1755   g_return_if_fail (func != NULL);
1756
1757   for (list = list_store->sort_list; list; list = list->next)
1758     {
1759       GtkTreeDataSortHeader *list_header;
1760
1761       list_header = (GtkTreeDataSortHeader*) list->data;
1762       if (list_header->sort_column_id == sort_column_id)
1763         {
1764           header = list_header;
1765           break;
1766         }
1767     }
1768
1769   if (header == NULL)
1770     {
1771       header = g_new0 (GtkTreeDataSortHeader, 1);
1772       header->sort_column_id = sort_column_id;
1773       list_store->sort_list = g_list_append (list_store->sort_list, header);
1774     }
1775
1776   if (header->destroy)
1777     {
1778       GtkDestroyNotify d = header->destroy;
1779
1780       header->destroy = NULL;
1781       d (header->data);
1782     }
1783
1784   header->func = func;
1785   header->data = data;
1786   header->destroy = destroy;
1787
1788   if (list_store->sort_column_id == sort_column_id)
1789     gtk_list_store_sort (list_store);
1790 }
1791
1792 static void
1793 gtk_list_store_set_default_sort_func (GtkTreeSortable        *sortable,
1794                                       GtkTreeIterCompareFunc  func,
1795                                       gpointer                data,
1796                                       GtkDestroyNotify        destroy)
1797 {
1798   GtkListStore *list_store = (GtkListStore *) sortable;
1799
1800   g_return_if_fail (GTK_IS_LIST_STORE (sortable));
1801
1802   if (list_store->default_sort_destroy)
1803     {
1804       GtkDestroyNotify d = list_store->default_sort_destroy;
1805
1806       list_store->default_sort_destroy = NULL;
1807       d (list_store->default_sort_data);
1808     }
1809
1810   list_store->default_sort_func = func;
1811   list_store->default_sort_data = data;
1812   list_store->default_sort_destroy = destroy;
1813
1814   if (list_store->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
1815     gtk_list_store_sort (list_store);
1816 }
1817
1818 static gboolean
1819 gtk_list_store_has_default_sort_func (GtkTreeSortable *sortable)
1820 {
1821   GtkListStore *list_store = (GtkListStore *) sortable;
1822
1823   g_return_val_if_fail (GTK_IS_LIST_STORE (sortable), FALSE);
1824
1825   return (list_store->default_sort_func != NULL);
1826 }