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