2 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
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.
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.
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.
24 #include <gobject/gvaluecollector.h>
25 #include "gtktreemodel.h"
26 #include "gtkliststore.h"
27 #include "gtktreedatalist.h"
28 #include "gtktreednd.h"
30 #include "gtkbuildable.h"
31 #include "gtkbuilderprivate.h"
34 struct _GtkListStorePrivate
36 GtkTreeIterCompareFunc default_sort_func;
38 GDestroyNotify default_sort_destroy;
40 GType *column_headers;
49 guint columns_dirty : 1;
51 gpointer default_sort_data;
52 gpointer seq; /* head of the list */
55 #define GTK_LIST_STORE_IS_SORTED(list) (((GtkListStore*)(list))->priv->sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
56 #define VALID_ITER(iter, list_store) ((iter)!= NULL && (iter)->user_data != NULL && list_store->priv->stamp == (iter)->stamp && !g_sequence_iter_is_end ((iter)->user_data) && g_sequence_iter_get_sequence ((iter)->user_data) == list_store->priv->seq)
58 static void gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
59 static void gtk_list_store_drag_source_init(GtkTreeDragSourceIface *iface);
60 static void gtk_list_store_drag_dest_init (GtkTreeDragDestIface *iface);
61 static void gtk_list_store_sortable_init (GtkTreeSortableIface *iface);
62 static void gtk_list_store_buildable_init (GtkBuildableIface *iface);
63 static void gtk_list_store_finalize (GObject *object);
64 static GtkTreeModelFlags gtk_list_store_get_flags (GtkTreeModel *tree_model);
65 static gint gtk_list_store_get_n_columns (GtkTreeModel *tree_model);
66 static GType gtk_list_store_get_column_type (GtkTreeModel *tree_model,
68 static gboolean gtk_list_store_get_iter (GtkTreeModel *tree_model,
71 static GtkTreePath *gtk_list_store_get_path (GtkTreeModel *tree_model,
73 static void gtk_list_store_get_value (GtkTreeModel *tree_model,
77 static gboolean gtk_list_store_iter_next (GtkTreeModel *tree_model,
79 static gboolean gtk_list_store_iter_previous (GtkTreeModel *tree_model,
81 static gboolean gtk_list_store_iter_children (GtkTreeModel *tree_model,
84 static gboolean gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
86 static gint gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
88 static gboolean gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
92 static gboolean gtk_list_store_iter_parent (GtkTreeModel *tree_model,
97 static void gtk_list_store_set_n_columns (GtkListStore *list_store,
99 static void gtk_list_store_set_column_type (GtkListStore *list_store,
103 static void gtk_list_store_increment_stamp (GtkListStore *list_store);
107 static gboolean real_gtk_list_store_row_draggable (GtkTreeDragSource *drag_source,
109 static gboolean gtk_list_store_drag_data_delete (GtkTreeDragSource *drag_source,
111 static gboolean gtk_list_store_drag_data_get (GtkTreeDragSource *drag_source,
113 GtkSelectionData *selection_data);
114 static gboolean gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
116 GtkSelectionData *selection_data);
117 static gboolean gtk_list_store_row_drop_possible (GtkTreeDragDest *drag_dest,
118 GtkTreePath *dest_path,
119 GtkSelectionData *selection_data);
123 static void gtk_list_store_sort (GtkListStore *list_store);
124 static void gtk_list_store_sort_iter_changed (GtkListStore *list_store,
127 static gboolean gtk_list_store_get_sort_column_id (GtkTreeSortable *sortable,
128 gint *sort_column_id,
130 static void gtk_list_store_set_sort_column_id (GtkTreeSortable *sortable,
133 static void gtk_list_store_set_sort_func (GtkTreeSortable *sortable,
135 GtkTreeIterCompareFunc func,
137 GDestroyNotify destroy);
138 static void gtk_list_store_set_default_sort_func (GtkTreeSortable *sortable,
139 GtkTreeIterCompareFunc func,
141 GDestroyNotify destroy);
142 static gboolean gtk_list_store_has_default_sort_func (GtkTreeSortable *sortable);
146 static gboolean gtk_list_store_buildable_custom_tag_start (GtkBuildable *buildable,
149 const gchar *tagname,
150 GMarkupParser *parser,
152 static void gtk_list_store_buildable_custom_tag_end (GtkBuildable *buildable,
155 const gchar *tagname,
158 G_DEFINE_TYPE_WITH_CODE (GtkListStore, gtk_list_store, G_TYPE_OBJECT,
159 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
160 gtk_list_store_tree_model_init)
161 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
162 gtk_list_store_drag_source_init)
163 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST,
164 gtk_list_store_drag_dest_init)
165 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
166 gtk_list_store_sortable_init)
167 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
168 gtk_list_store_buildable_init))
172 gtk_list_store_class_init (GtkListStoreClass *class)
174 GObjectClass *object_class;
176 object_class = (GObjectClass*) class;
178 object_class->finalize = gtk_list_store_finalize;
180 g_type_class_add_private (class, sizeof (GtkListStorePrivate));
184 gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
186 iface->get_flags = gtk_list_store_get_flags;
187 iface->get_n_columns = gtk_list_store_get_n_columns;
188 iface->get_column_type = gtk_list_store_get_column_type;
189 iface->get_iter = gtk_list_store_get_iter;
190 iface->get_path = gtk_list_store_get_path;
191 iface->get_value = gtk_list_store_get_value;
192 iface->iter_next = gtk_list_store_iter_next;
193 iface->iter_previous = gtk_list_store_iter_previous;
194 iface->iter_children = gtk_list_store_iter_children;
195 iface->iter_has_child = gtk_list_store_iter_has_child;
196 iface->iter_n_children = gtk_list_store_iter_n_children;
197 iface->iter_nth_child = gtk_list_store_iter_nth_child;
198 iface->iter_parent = gtk_list_store_iter_parent;
202 gtk_list_store_drag_source_init (GtkTreeDragSourceIface *iface)
204 iface->row_draggable = real_gtk_list_store_row_draggable;
205 iface->drag_data_delete = gtk_list_store_drag_data_delete;
206 iface->drag_data_get = gtk_list_store_drag_data_get;
210 gtk_list_store_drag_dest_init (GtkTreeDragDestIface *iface)
212 iface->drag_data_received = gtk_list_store_drag_data_received;
213 iface->row_drop_possible = gtk_list_store_row_drop_possible;
217 gtk_list_store_sortable_init (GtkTreeSortableIface *iface)
219 iface->get_sort_column_id = gtk_list_store_get_sort_column_id;
220 iface->set_sort_column_id = gtk_list_store_set_sort_column_id;
221 iface->set_sort_func = gtk_list_store_set_sort_func;
222 iface->set_default_sort_func = gtk_list_store_set_default_sort_func;
223 iface->has_default_sort_func = gtk_list_store_has_default_sort_func;
227 gtk_list_store_buildable_init (GtkBuildableIface *iface)
229 iface->custom_tag_start = gtk_list_store_buildable_custom_tag_start;
230 iface->custom_tag_end = gtk_list_store_buildable_custom_tag_end;
234 gtk_list_store_init (GtkListStore *list_store)
236 GtkListStorePrivate *priv;
238 list_store->priv = G_TYPE_INSTANCE_GET_PRIVATE (list_store,
240 GtkListStorePrivate);
241 priv = list_store->priv;
243 priv->seq = g_sequence_new (NULL);
244 priv->sort_list = NULL;
245 priv->stamp = g_random_int ();
246 priv->sort_column_id = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
247 priv->columns_dirty = FALSE;
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
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
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.
264 * Return value: a new #GtkListStore
267 gtk_list_store_new (gint n_columns,
270 GtkListStore *retval;
274 g_return_val_if_fail (n_columns > 0, NULL);
276 retval = g_object_new (GTK_TYPE_LIST_STORE, NULL);
277 gtk_list_store_set_n_columns (retval, n_columns);
279 va_start (args, n_columns);
281 for (i = 0; i < n_columns; i++)
283 GType type = va_arg (args, GType);
284 if (! _gtk_tree_data_list_check_type (type))
286 g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
287 g_object_unref (retval);
291 gtk_list_store_set_column_type (retval, i, type);
301 * gtk_list_store_newv:
302 * @n_columns: number of columns in the list store
303 * @types: (array length=n_columns): an array of #GType types for the columns, from first to last
305 * Non-vararg creation function. Used primarily by language bindings.
307 * Return value: (transfer none): a new #GtkListStore
308 * Rename to: gtk_list_store_new
311 gtk_list_store_newv (gint n_columns,
314 GtkListStore *retval;
317 g_return_val_if_fail (n_columns > 0, NULL);
319 retval = g_object_new (GTK_TYPE_LIST_STORE, NULL);
320 gtk_list_store_set_n_columns (retval, n_columns);
322 for (i = 0; i < n_columns; i++)
324 if (! _gtk_tree_data_list_check_type (types[i]))
326 g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
327 g_object_unref (retval);
331 gtk_list_store_set_column_type (retval, i, types[i]);
338 * gtk_list_store_set_column_types:
339 * @list_store: A #GtkListStore
340 * @n_columns: Number of columns for the list store
341 * @types: (array length=n_columns): An array length n of #GTypes
343 * This function is meant primarily for #GObjects that inherit from #GtkListStore,
344 * and should only be used when constructing a new #GtkListStore. It will not
345 * function after a row has been added, or a method on the #GtkTreeModel
346 * interface is called.
349 gtk_list_store_set_column_types (GtkListStore *list_store,
353 GtkListStorePrivate *priv;
356 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
358 priv = list_store->priv;
360 g_return_if_fail (priv->columns_dirty == 0);
362 gtk_list_store_set_n_columns (list_store, n_columns);
363 for (i = 0; i < n_columns; i++)
365 if (! _gtk_tree_data_list_check_type (types[i]))
367 g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
370 gtk_list_store_set_column_type (list_store, i, types[i]);
375 gtk_list_store_set_n_columns (GtkListStore *list_store,
378 GtkListStorePrivate *priv = list_store->priv;
381 if (priv->n_columns == n_columns)
384 priv->column_headers = g_renew (GType, priv->column_headers, n_columns);
385 for (i = priv->n_columns; i < n_columns; i++)
386 priv->column_headers[i] = G_TYPE_INVALID;
387 priv->n_columns = n_columns;
390 _gtk_tree_data_list_header_free (priv->sort_list);
391 priv->sort_list = _gtk_tree_data_list_header_new (n_columns, priv->column_headers);
395 gtk_list_store_set_column_type (GtkListStore *list_store,
399 GtkListStorePrivate *priv = list_store->priv;
401 if (!_gtk_tree_data_list_check_type (type))
403 g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
407 priv->column_headers[column] = type;
411 gtk_list_store_finalize (GObject *object)
413 GtkListStore *list_store = GTK_LIST_STORE (object);
414 GtkListStorePrivate *priv = list_store->priv;
416 g_sequence_foreach (priv->seq,
417 (GFunc) _gtk_tree_data_list_free, priv->column_headers);
419 g_sequence_free (priv->seq);
421 _gtk_tree_data_list_header_free (priv->sort_list);
422 g_free (priv->column_headers);
424 if (priv->default_sort_destroy)
426 GDestroyNotify d = priv->default_sort_destroy;
428 priv->default_sort_destroy = NULL;
429 d (priv->default_sort_data);
430 priv->default_sort_data = NULL;
433 G_OBJECT_CLASS (gtk_list_store_parent_class)->finalize (object);
436 /* Fulfill the GtkTreeModel requirements */
437 static GtkTreeModelFlags
438 gtk_list_store_get_flags (GtkTreeModel *tree_model)
440 return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
444 gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
446 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
447 GtkListStorePrivate *priv = list_store->priv;
449 priv->columns_dirty = TRUE;
451 return priv->n_columns;
455 gtk_list_store_get_column_type (GtkTreeModel *tree_model,
458 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
459 GtkListStorePrivate *priv = list_store->priv;
461 g_return_val_if_fail (index < priv->n_columns, G_TYPE_INVALID);
463 priv->columns_dirty = TRUE;
465 return priv->column_headers[index];
469 gtk_list_store_get_iter (GtkTreeModel *tree_model,
473 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
474 GtkListStorePrivate *priv = list_store->priv;
478 priv->columns_dirty = TRUE;
482 i = gtk_tree_path_get_indices (path)[0];
484 if (i >= g_sequence_get_length (seq))
487 iter->stamp = priv->stamp;
488 iter->user_data = g_sequence_get_iter_at_pos (seq, i);
494 gtk_list_store_get_path (GtkTreeModel *tree_model,
497 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
498 GtkListStorePrivate *priv = list_store->priv;
501 g_return_val_if_fail (iter->stamp == priv->stamp, NULL);
503 if (g_sequence_iter_is_end (iter->user_data))
506 path = gtk_tree_path_new ();
507 gtk_tree_path_append_index (path, g_sequence_iter_get_position (iter->user_data));
513 gtk_list_store_get_value (GtkTreeModel *tree_model,
518 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
519 GtkListStorePrivate *priv = list_store->priv;
520 GtkTreeDataList *list;
521 gint tmp_column = column;
523 g_return_if_fail (column < priv->n_columns);
524 g_return_if_fail (VALID_ITER (iter, list_store));
526 list = g_sequence_get (iter->user_data);
528 while (tmp_column-- > 0 && list)
532 g_value_init (value, priv->column_headers[column]);
534 _gtk_tree_data_list_node_to_value (list,
535 priv->column_headers[column],
540 gtk_list_store_iter_next (GtkTreeModel *tree_model,
543 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
544 GtkListStorePrivate *priv = list_store->priv;
547 g_return_val_if_fail (priv->stamp == iter->stamp, FALSE);
548 iter->user_data = g_sequence_iter_next (iter->user_data);
550 retval = g_sequence_iter_is_end (iter->user_data);
558 gtk_list_store_iter_previous (GtkTreeModel *tree_model,
561 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
562 GtkListStorePrivate *priv = list_store->priv;
564 g_return_val_if_fail (priv->stamp == iter->stamp, FALSE);
566 if (g_sequence_iter_is_begin (iter->user_data))
572 iter->user_data = g_sequence_iter_prev (iter->user_data);
578 gtk_list_store_iter_children (GtkTreeModel *tree_model,
582 GtkListStore *list_store = (GtkListStore *) tree_model;
583 GtkListStorePrivate *priv = list_store->priv;
585 /* this is a list, nodes have no children */
592 if (g_sequence_get_length (priv->seq) > 0)
594 iter->stamp = priv->stamp;
595 iter->user_data = g_sequence_get_begin_iter (priv->seq);
606 gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
613 gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
616 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
617 GtkListStorePrivate *priv = list_store->priv;
620 return g_sequence_get_length (priv->seq);
622 g_return_val_if_fail (priv->stamp == iter->stamp, -1);
628 gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
633 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
634 GtkListStorePrivate *priv = list_store->priv;
635 GSequenceIter *child;
642 child = g_sequence_get_iter_at_pos (priv->seq, n);
644 if (g_sequence_iter_is_end (child))
647 iter->stamp = priv->stamp;
648 iter->user_data = child;
654 gtk_list_store_iter_parent (GtkTreeModel *tree_model,
663 gtk_list_store_real_set_value (GtkListStore *list_store,
669 GtkListStorePrivate *priv = list_store->priv;
670 GtkTreeDataList *list;
671 GtkTreeDataList *prev;
672 gint old_column = column;
673 GValue real_value = {0, };
674 gboolean converted = FALSE;
675 gboolean retval = FALSE;
677 if (! g_type_is_a (G_VALUE_TYPE (value), priv->column_headers[column]))
679 if (! (g_value_type_compatible (G_VALUE_TYPE (value), priv->column_headers[column]) &&
680 g_value_type_compatible (priv->column_headers[column], G_VALUE_TYPE (value))))
682 g_warning ("%s: Unable to convert from %s to %s\n",
684 g_type_name (G_VALUE_TYPE (value)),
685 g_type_name (priv->column_headers[column]));
688 if (!g_value_transform (value, &real_value))
690 g_warning ("%s: Unable to make conversion from %s to %s\n",
692 g_type_name (G_VALUE_TYPE (value)),
693 g_type_name (priv->column_headers[column]));
694 g_value_unset (&real_value);
700 prev = list = g_sequence_get (iter->user_data);
707 _gtk_tree_data_list_value_to_node (list, &real_value);
709 _gtk_tree_data_list_value_to_node (list, value);
712 g_value_unset (&real_value);
713 if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
714 gtk_list_store_sort_iter_changed (list_store, iter, old_column);
723 if (g_sequence_get (iter->user_data) == NULL)
725 list = _gtk_tree_data_list_alloc();
726 g_sequence_set (iter->user_data, list);
731 list = prev->next = _gtk_tree_data_list_alloc ();
737 list->next = _gtk_tree_data_list_alloc ();
744 _gtk_tree_data_list_value_to_node (list, &real_value);
746 _gtk_tree_data_list_value_to_node (list, value);
750 g_value_unset (&real_value);
752 if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
753 gtk_list_store_sort_iter_changed (list_store, iter, old_column);
760 * gtk_list_store_set_value:
761 * @list_store: A #GtkListStore
762 * @iter: A valid #GtkTreeIter for the row being modified
763 * @column: column number to modify
764 * @value: new value for the cell
766 * Sets the data in the cell specified by @iter and @column.
767 * The type of @value must be convertible to the type of the
772 gtk_list_store_set_value (GtkListStore *list_store,
777 GtkListStorePrivate *priv = list_store->priv;
779 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
780 g_return_if_fail (VALID_ITER (iter, list_store));
781 g_return_if_fail (G_IS_VALUE (value));
782 priv = list_store->priv;
783 g_return_if_fail (column >= 0 && column < priv->n_columns);
785 if (gtk_list_store_real_set_value (list_store, iter, column, value, TRUE))
789 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
790 gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
791 gtk_tree_path_free (path);
795 static GtkTreeIterCompareFunc
796 gtk_list_store_get_compare_func (GtkListStore *list_store)
798 GtkListStorePrivate *priv = list_store->priv;
799 GtkTreeIterCompareFunc func = NULL;
801 if (GTK_LIST_STORE_IS_SORTED (list_store))
803 if (priv->sort_column_id != -1)
805 GtkTreeDataSortHeader *header;
806 header = _gtk_tree_data_list_get_header (priv->sort_list,
807 priv->sort_column_id);
808 g_return_val_if_fail (header != NULL, NULL);
809 g_return_val_if_fail (header->func != NULL, NULL);
814 func = priv->default_sort_func;
822 gtk_list_store_set_vector_internal (GtkListStore *list_store,
824 gboolean *emit_signal,
825 gboolean *maybe_need_sort,
830 GtkListStorePrivate *priv = list_store->priv;
832 GtkTreeIterCompareFunc func = NULL;
834 func = gtk_list_store_get_compare_func (list_store);
835 if (func != _gtk_tree_data_list_compare_func)
836 *maybe_need_sort = TRUE;
838 for (i = 0; i < n_values; i++)
840 *emit_signal = gtk_list_store_real_set_value (list_store,
844 FALSE) || *emit_signal;
846 if (func == _gtk_tree_data_list_compare_func &&
847 columns[i] == priv->sort_column_id)
848 *maybe_need_sort = TRUE;
853 gtk_list_store_set_valist_internal (GtkListStore *list_store,
855 gboolean *emit_signal,
856 gboolean *maybe_need_sort,
859 GtkListStorePrivate *priv = list_store->priv;
861 GtkTreeIterCompareFunc func = NULL;
863 column = va_arg (var_args, gint);
865 func = gtk_list_store_get_compare_func (list_store);
866 if (func != _gtk_tree_data_list_compare_func)
867 *maybe_need_sort = TRUE;
871 GValue value = { 0, };
874 if (column < 0 || column >= priv->n_columns)
876 g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
880 G_VALUE_COLLECT_INIT (&value, priv->column_headers[column],
881 var_args, 0, &error);
884 g_warning ("%s: %s", G_STRLOC, error);
887 /* we purposely leak the value here, it might not be
888 * in a sane state if an error condition occoured
893 /* FIXME: instead of calling this n times, refactor with above */
894 *emit_signal = gtk_list_store_real_set_value (list_store,
898 FALSE) || *emit_signal;
900 if (func == _gtk_tree_data_list_compare_func &&
901 column == priv->sort_column_id)
902 *maybe_need_sort = TRUE;
904 g_value_unset (&value);
906 column = va_arg (var_args, gint);
911 * gtk_list_store_set_valuesv:
912 * @list_store: A #GtkListStore
913 * @iter: A valid #GtkTreeIter for the row being modified
914 * @columns: (array length=n_values): an array of column numbers
915 * @values: (array length=n_values): an array of GValues
916 * @n_values: the length of the @columns and @values arrays
918 * A variant of gtk_list_store_set_valist() which
919 * takes the columns and values as two arrays, instead of
920 * varargs. This function is mainly intended for
921 * language-bindings and in case the number of columns to
922 * change is not known until run-time.
925 * Rename to: gtk_list_store_set
928 gtk_list_store_set_valuesv (GtkListStore *list_store,
934 GtkListStorePrivate *priv;
935 gboolean emit_signal = FALSE;
936 gboolean maybe_need_sort = FALSE;
938 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
939 g_return_if_fail (VALID_ITER (iter, list_store));
941 priv = list_store->priv;
943 gtk_list_store_set_vector_internal (list_store, iter,
946 columns, values, n_values);
948 if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
949 gtk_list_store_sort_iter_changed (list_store, iter, priv->sort_column_id);
955 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
956 gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
957 gtk_tree_path_free (path);
962 * gtk_list_store_set_valist:
963 * @list_store: A #GtkListStore
964 * @iter: A valid #GtkTreeIter for the row being modified
965 * @var_args: va_list of column/value pairs
967 * See gtk_list_store_set(); this version takes a va_list for use by language
972 gtk_list_store_set_valist (GtkListStore *list_store,
976 GtkListStorePrivate *priv;
977 gboolean emit_signal = FALSE;
978 gboolean maybe_need_sort = FALSE;
980 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
981 g_return_if_fail (VALID_ITER (iter, list_store));
983 priv = list_store->priv;
985 gtk_list_store_set_valist_internal (list_store, iter,
990 if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
991 gtk_list_store_sort_iter_changed (list_store, iter, priv->sort_column_id);
997 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
998 gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
999 gtk_tree_path_free (path);
1004 * gtk_list_store_set:
1005 * @list_store: a #GtkListStore
1006 * @iter: row iterator
1007 * @Varargs: pairs of column number and value, terminated with -1
1009 * Sets the value of one or more cells in the row referenced by @iter.
1010 * The variable argument list should contain integer column numbers,
1011 * each column number followed by the value to be set.
1012 * The list is terminated by a -1. For example, to set column 0 with type
1013 * %G_TYPE_STRING to "Foo", you would write <literal>gtk_list_store_set (store, iter,
1014 * 0, "Foo", -1)</literal>.
1016 * The value will be referenced by the store if it is a %G_TYPE_OBJECT, and it
1017 * will be copied if it is a %G_TYPE_STRING or %G_TYPE_BOXED.
1020 gtk_list_store_set (GtkListStore *list_store,
1026 va_start (var_args, iter);
1027 gtk_list_store_set_valist (list_store, iter, var_args);
1032 * gtk_list_store_remove:
1033 * @list_store: A #GtkListStore
1034 * @iter: A valid #GtkTreeIter
1036 * Removes the given row from the list store. After being removed,
1037 * @iter is set to be the next valid row, or invalidated if it pointed
1038 * to the last row in @list_store.
1040 * Return value: %TRUE if @iter is valid, %FALSE if not.
1043 gtk_list_store_remove (GtkListStore *list_store,
1046 GtkListStorePrivate *priv;
1048 GSequenceIter *ptr, *next;
1050 g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), FALSE);
1051 g_return_val_if_fail (VALID_ITER (iter, list_store), FALSE);
1053 priv = list_store->priv;
1055 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
1057 ptr = iter->user_data;
1058 next = g_sequence_iter_next (ptr);
1060 _gtk_tree_data_list_free (g_sequence_get (ptr), priv->column_headers);
1061 g_sequence_remove (iter->user_data);
1065 gtk_tree_model_row_deleted (GTK_TREE_MODEL (list_store), path);
1066 gtk_tree_path_free (path);
1068 if (g_sequence_iter_is_end (next))
1075 iter->stamp = priv->stamp;
1076 iter->user_data = next;
1082 * gtk_list_store_insert:
1083 * @list_store: A #GtkListStore
1084 * @iter: (out): An unset #GtkTreeIter to set to the new row
1085 * @position: position to insert the new row
1087 * Creates a new row at @position. @iter will be changed to point to this new
1088 * row. If @position is larger than the number of rows on the list, then the
1089 * new row will be appended to the list. The row will be empty after this
1090 * function is called. To fill in values, you need to call
1091 * gtk_list_store_set() or gtk_list_store_set_value().
1095 gtk_list_store_insert (GtkListStore *list_store,
1099 GtkListStorePrivate *priv;
1105 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1106 g_return_if_fail (iter != NULL);
1107 g_return_if_fail (position >= 0);
1109 priv = list_store->priv;
1111 priv->columns_dirty = TRUE;
1115 length = g_sequence_get_length (seq);
1116 if (position > length)
1119 ptr = g_sequence_get_iter_at_pos (seq, position);
1120 ptr = g_sequence_insert_before (ptr, NULL);
1122 iter->stamp = priv->stamp;
1123 iter->user_data = ptr;
1125 g_assert (VALID_ITER (iter, list_store));
1129 path = gtk_tree_path_new ();
1130 gtk_tree_path_append_index (path, position);
1131 gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter);
1132 gtk_tree_path_free (path);
1136 * gtk_list_store_insert_before:
1137 * @list_store: A #GtkListStore
1138 * @iter: (out): An unset #GtkTreeIter to set to the new row
1139 * @sibling: (allow-none): A valid #GtkTreeIter, or %NULL
1141 * Inserts a new row before @sibling. If @sibling is %NULL, then the row will
1142 * be appended to the end of the list. @iter will be changed to point to this
1143 * new row. The row will be empty after this function is called. To fill in
1144 * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1148 gtk_list_store_insert_before (GtkListStore *list_store,
1150 GtkTreeIter *sibling)
1152 GtkListStorePrivate *priv;
1153 GSequenceIter *after;
1155 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1156 g_return_if_fail (iter != NULL);
1158 priv = list_store->priv;
1161 g_return_if_fail (VALID_ITER (sibling, list_store));
1164 after = g_sequence_get_end_iter (priv->seq);
1166 after = sibling->user_data;
1168 gtk_list_store_insert (list_store, iter, g_sequence_iter_get_position (after));
1172 * gtk_list_store_insert_after:
1173 * @list_store: A #GtkListStore
1174 * @iter: (out): An unset #GtkTreeIter to set to the new row
1175 * @sibling: (allow-none): A valid #GtkTreeIter, or %NULL
1177 * Inserts a new row after @sibling. If @sibling is %NULL, then the row will be
1178 * prepended to the beginning of the list. @iter will be changed to point to
1179 * this new row. The row will be empty after this function is called. To fill
1180 * in values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1184 gtk_list_store_insert_after (GtkListStore *list_store,
1186 GtkTreeIter *sibling)
1188 GtkListStorePrivate *priv;
1189 GSequenceIter *after;
1191 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1192 g_return_if_fail (iter != NULL);
1194 priv = list_store->priv;
1197 g_return_if_fail (VALID_ITER (sibling, list_store));
1200 after = g_sequence_get_begin_iter (priv->seq);
1202 after = g_sequence_iter_next (sibling->user_data);
1204 gtk_list_store_insert (list_store, iter, g_sequence_iter_get_position (after));
1208 * gtk_list_store_prepend:
1209 * @list_store: A #GtkListStore
1210 * @iter: (out): An unset #GtkTreeIter to set to the prepend row
1212 * Prepends a new row to @list_store. @iter will be changed to point to this new
1213 * row. The row will be empty after this function is called. To fill in
1214 * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1218 gtk_list_store_prepend (GtkListStore *list_store,
1221 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1222 g_return_if_fail (iter != NULL);
1224 gtk_list_store_insert (list_store, iter, 0);
1228 * gtk_list_store_append:
1229 * @list_store: A #GtkListStore
1230 * @iter: (out): An unset #GtkTreeIter to set to the appended row
1232 * Appends a new row to @list_store. @iter will be changed to point to this new
1233 * row. The row will be empty after this function is called. To fill in
1234 * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1238 gtk_list_store_append (GtkListStore *list_store,
1241 GtkListStorePrivate *priv;
1243 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1244 g_return_if_fail (iter != NULL);
1246 priv = list_store->priv;
1248 gtk_list_store_insert (list_store, iter, g_sequence_get_length (priv->seq));
1252 gtk_list_store_increment_stamp (GtkListStore *list_store)
1254 GtkListStorePrivate *priv = list_store->priv;
1260 while (priv->stamp == 0);
1264 * gtk_list_store_clear:
1265 * @list_store: a #GtkListStore.
1267 * Removes all rows from the list store.
1271 gtk_list_store_clear (GtkListStore *list_store)
1273 GtkListStorePrivate *priv;
1276 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1278 priv = list_store->priv;
1280 while (g_sequence_get_length (priv->seq) > 0)
1282 iter.stamp = priv->stamp;
1283 iter.user_data = g_sequence_get_begin_iter (priv->seq);
1284 gtk_list_store_remove (list_store, &iter);
1287 gtk_list_store_increment_stamp (list_store);
1291 * gtk_list_store_iter_is_valid:
1292 * @list_store: A #GtkListStore.
1293 * @iter: A #GtkTreeIter.
1295 * <warning>This function is slow. Only use it for debugging and/or testing
1296 * purposes.</warning>
1298 * Checks if the given iter is a valid iter for this #GtkListStore.
1300 * Return value: %TRUE if the iter is valid, %FALSE if the iter is invalid.
1305 gtk_list_store_iter_is_valid (GtkListStore *list_store,
1308 GtkListStorePrivate *priv;
1310 g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), FALSE);
1311 g_return_val_if_fail (iter != NULL, FALSE);
1313 priv = list_store->priv;
1315 if (!VALID_ITER (iter, list_store))
1318 if (g_sequence_iter_get_sequence (iter->user_data) != priv->seq)
1324 static gboolean real_gtk_list_store_row_draggable (GtkTreeDragSource *drag_source,
1331 gtk_list_store_drag_data_delete (GtkTreeDragSource *drag_source,
1336 if (gtk_list_store_get_iter (GTK_TREE_MODEL (drag_source),
1340 gtk_list_store_remove (GTK_LIST_STORE (drag_source), &iter);
1347 gtk_list_store_drag_data_get (GtkTreeDragSource *drag_source,
1349 GtkSelectionData *selection_data)
1351 /* Note that we don't need to handle the GTK_TREE_MODEL_ROW
1352 * target, because the default handler does it for us, but
1353 * we do anyway for the convenience of someone maybe overriding the
1357 if (gtk_tree_set_row_drag_data (selection_data,
1358 GTK_TREE_MODEL (drag_source),
1365 /* FIXME handle text targets at least. */
1372 gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
1374 GtkSelectionData *selection_data)
1376 GtkTreeModel *tree_model = GTK_TREE_MODEL (drag_dest);
1377 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
1378 GtkListStorePrivate *priv = list_store->priv;
1379 GtkTreeModel *src_model = NULL;
1380 GtkTreePath *src_path = NULL;
1381 gboolean retval = FALSE;
1383 if (gtk_tree_get_row_drag_data (selection_data,
1386 src_model == tree_model)
1388 /* Copy the given row to a new position */
1389 GtkTreeIter src_iter;
1390 GtkTreeIter dest_iter;
1393 if (!gtk_list_store_get_iter (src_model,
1400 /* Get the path to insert _after_ (dest is the path to insert _before_) */
1401 prev = gtk_tree_path_copy (dest);
1403 if (!gtk_tree_path_prev (prev))
1405 /* dest was the first spot in the list; which means we are supposed
1408 gtk_list_store_prepend (list_store, &dest_iter);
1414 if (gtk_list_store_get_iter (tree_model, &dest_iter, prev))
1416 GtkTreeIter tmp_iter = dest_iter;
1418 gtk_list_store_insert_after (list_store, &dest_iter, &tmp_iter);
1424 gtk_tree_path_free (prev);
1426 /* If we succeeded in creating dest_iter, copy data from src
1430 GtkTreeDataList *dl = g_sequence_get (src_iter.user_data);
1431 GtkTreeDataList *copy_head = NULL;
1432 GtkTreeDataList *copy_prev = NULL;
1433 GtkTreeDataList *copy_iter = NULL;
1440 copy_iter = _gtk_tree_data_list_node_copy (dl,
1441 priv->column_headers[col]);
1443 if (copy_head == NULL)
1444 copy_head = copy_iter;
1447 copy_prev->next = copy_iter;
1449 copy_prev = copy_iter;
1455 dest_iter.stamp = priv->stamp;
1456 g_sequence_set (dest_iter.user_data, copy_head);
1458 path = gtk_list_store_get_path (tree_model, &dest_iter);
1459 gtk_tree_model_row_changed (tree_model, path, &dest_iter);
1460 gtk_tree_path_free (path);
1465 /* FIXME maybe add some data targets eventually, or handle text
1466 * targets in the simple case.
1473 gtk_tree_path_free (src_path);
1479 gtk_list_store_row_drop_possible (GtkTreeDragDest *drag_dest,
1480 GtkTreePath *dest_path,
1481 GtkSelectionData *selection_data)
1484 GtkTreeModel *src_model = NULL;
1485 GtkTreePath *src_path = NULL;
1486 gboolean retval = FALSE;
1488 /* don't accept drops if the list has been sorted */
1489 if (GTK_LIST_STORE_IS_SORTED (drag_dest))
1492 if (!gtk_tree_get_row_drag_data (selection_data,
1497 if (src_model != GTK_TREE_MODEL (drag_dest))
1500 if (gtk_tree_path_get_depth (dest_path) != 1)
1503 /* can drop before any existing node, or before one past any existing. */
1505 indices = gtk_tree_path_get_indices (dest_path);
1507 if (indices[0] <= g_sequence_get_length (GTK_LIST_STORE (drag_dest)->priv->seq))
1512 gtk_tree_path_free (src_path);
1517 /* Sorting and reordering */
1521 gtk_list_store_reorder_func (GSequenceIter *a,
1525 GHashTable *new_positions = user_data;
1526 gint apos = GPOINTER_TO_INT (g_hash_table_lookup (new_positions, a));
1527 gint bpos = GPOINTER_TO_INT (g_hash_table_lookup (new_positions, b));
1537 * gtk_list_store_reorder: (skip)
1538 * @store: A #GtkListStore.
1539 * @new_order: (array): an array of integers mapping the new position of each child
1540 * to its old position before the re-ordering,
1541 * i.e. @new_order<literal>[newpos] = oldpos</literal>.
1543 * Reorders @store to follow the order indicated by @new_order. Note that
1544 * this function only works with unsorted stores.
1549 gtk_list_store_reorder (GtkListStore *store,
1552 GtkListStorePrivate *priv;
1555 GHashTable *new_positions;
1559 g_return_if_fail (GTK_IS_LIST_STORE (store));
1560 g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1561 g_return_if_fail (new_order != NULL);
1565 order = g_new (gint, g_sequence_get_length (priv->seq));
1566 for (i = 0; i < g_sequence_get_length (priv->seq); i++)
1567 order[new_order[i]] = i;
1569 new_positions = g_hash_table_new (g_direct_hash, g_direct_equal);
1571 ptr = g_sequence_get_begin_iter (priv->seq);
1573 while (!g_sequence_iter_is_end (ptr))
1575 g_hash_table_insert (new_positions, ptr, GINT_TO_POINTER (order[i++]));
1577 ptr = g_sequence_iter_next (ptr);
1581 g_sequence_sort_iter (priv->seq, gtk_list_store_reorder_func, new_positions);
1583 g_hash_table_destroy (new_positions);
1586 path = gtk_tree_path_new ();
1587 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store),
1588 path, NULL, new_order);
1589 gtk_tree_path_free (path);
1593 save_positions (GSequence *seq)
1595 GHashTable *positions = g_hash_table_new (g_direct_hash, g_direct_equal);
1598 ptr = g_sequence_get_begin_iter (seq);
1599 while (!g_sequence_iter_is_end (ptr))
1601 g_hash_table_insert (positions, ptr,
1602 GINT_TO_POINTER (g_sequence_iter_get_position (ptr)));
1603 ptr = g_sequence_iter_next (ptr);
1610 generate_order (GSequence *seq,
1611 GHashTable *old_positions)
1614 int *order = g_new (int, g_sequence_get_length (seq));
1618 ptr = g_sequence_get_begin_iter (seq);
1619 while (!g_sequence_iter_is_end (ptr))
1621 int old_pos = GPOINTER_TO_INT (g_hash_table_lookup (old_positions, ptr));
1622 order[i++] = old_pos;
1623 ptr = g_sequence_iter_next (ptr);
1626 g_hash_table_destroy (old_positions);
1632 * gtk_list_store_swap:
1633 * @store: A #GtkListStore.
1634 * @a: A #GtkTreeIter.
1635 * @b: Another #GtkTreeIter.
1637 * Swaps @a and @b in @store. Note that this function only works with
1643 gtk_list_store_swap (GtkListStore *store,
1647 GtkListStorePrivate *priv;
1648 GHashTable *old_positions;
1652 g_return_if_fail (GTK_IS_LIST_STORE (store));
1653 g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1654 g_return_if_fail (VALID_ITER (a, store));
1655 g_return_if_fail (VALID_ITER (b, store));
1659 if (a->user_data == b->user_data)
1662 old_positions = save_positions (priv->seq);
1664 g_sequence_swap (a->user_data, b->user_data);
1666 order = generate_order (priv->seq, old_positions);
1667 path = gtk_tree_path_new ();
1669 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store),
1672 gtk_tree_path_free (path);
1677 gtk_list_store_move_to (GtkListStore *store,
1681 GtkListStorePrivate *priv = store->priv;
1682 GHashTable *old_positions;
1686 old_positions = save_positions (priv->seq);
1688 g_sequence_move (iter->user_data, g_sequence_get_iter_at_pos (priv->seq, new_pos));
1690 order = generate_order (priv->seq, old_positions);
1692 path = gtk_tree_path_new ();
1693 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store),
1695 gtk_tree_path_free (path);
1700 * gtk_list_store_move_before:
1701 * @store: A #GtkListStore.
1702 * @iter: A #GtkTreeIter.
1703 * @position: (allow-none): A #GtkTreeIter, or %NULL.
1705 * Moves @iter in @store to the position before @position. Note that this
1706 * function only works with unsorted stores. If @position is %NULL, @iter
1707 * will be moved to the end of the list.
1712 gtk_list_store_move_before (GtkListStore *store,
1714 GtkTreeIter *position)
1718 g_return_if_fail (GTK_IS_LIST_STORE (store));
1719 g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1720 g_return_if_fail (VALID_ITER (iter, store));
1722 g_return_if_fail (VALID_ITER (position, store));
1725 pos = g_sequence_iter_get_position (position->user_data);
1729 gtk_list_store_move_to (store, iter, pos);
1733 * gtk_list_store_move_after:
1734 * @store: A #GtkListStore.
1735 * @iter: A #GtkTreeIter.
1736 * @position: (allow-none): A #GtkTreeIter or %NULL.
1738 * Moves @iter in @store to the position after @position. Note that this
1739 * function only works with unsorted stores. If @position is %NULL, @iter
1740 * will be moved to the start of the list.
1745 gtk_list_store_move_after (GtkListStore *store,
1747 GtkTreeIter *position)
1751 g_return_if_fail (GTK_IS_LIST_STORE (store));
1752 g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1753 g_return_if_fail (VALID_ITER (iter, store));
1755 g_return_if_fail (VALID_ITER (position, store));
1758 pos = g_sequence_iter_get_position (position->user_data) + 1;
1762 gtk_list_store_move_to (store, iter, pos);
1767 gtk_list_store_compare_func (GSequenceIter *a,
1771 GtkListStore *list_store = user_data;
1772 GtkListStorePrivate *priv = list_store->priv;
1776 GtkTreeIterCompareFunc func;
1779 if (priv->sort_column_id != -1)
1781 GtkTreeDataSortHeader *header;
1783 header = _gtk_tree_data_list_get_header (priv->sort_list,
1784 priv->sort_column_id);
1785 g_return_val_if_fail (header != NULL, 0);
1786 g_return_val_if_fail (header->func != NULL, 0);
1788 func = header->func;
1789 data = header->data;
1793 g_return_val_if_fail (priv->default_sort_func != NULL, 0);
1794 func = priv->default_sort_func;
1795 data = priv->default_sort_data;
1798 iter_a.stamp = priv->stamp;
1799 iter_a.user_data = (gpointer)a;
1800 iter_b.stamp = priv->stamp;
1801 iter_b.user_data = (gpointer)b;
1803 g_assert (VALID_ITER (&iter_a, list_store));
1804 g_assert (VALID_ITER (&iter_b, list_store));
1806 retval = (* func) (GTK_TREE_MODEL (list_store), &iter_a, &iter_b, data);
1808 if (priv->order == GTK_SORT_DESCENDING)
1812 else if (retval < 0)
1820 gtk_list_store_sort (GtkListStore *list_store)
1822 GtkListStorePrivate *priv = list_store->priv;
1825 GHashTable *old_positions;
1827 if (!GTK_LIST_STORE_IS_SORTED (list_store) ||
1828 g_sequence_get_length (priv->seq) <= 1)
1831 old_positions = save_positions (priv->seq);
1833 g_sequence_sort_iter (priv->seq, gtk_list_store_compare_func, list_store);
1835 /* Let the world know about our new order */
1836 new_order = generate_order (priv->seq, old_positions);
1838 path = gtk_tree_path_new ();
1839 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (list_store),
1840 path, NULL, new_order);
1841 gtk_tree_path_free (path);
1846 iter_is_sorted (GtkListStore *list_store,
1851 if (!g_sequence_iter_is_begin (iter->user_data))
1853 cmp = g_sequence_iter_prev (iter->user_data);
1854 if (gtk_list_store_compare_func (cmp, iter->user_data, list_store) > 0)
1858 cmp = g_sequence_iter_next (iter->user_data);
1859 if (!g_sequence_iter_is_end (cmp))
1861 if (gtk_list_store_compare_func (iter->user_data, cmp, list_store) > 0)
1869 gtk_list_store_sort_iter_changed (GtkListStore *list_store,
1874 GtkListStorePrivate *priv = list_store->priv;
1877 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
1878 gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
1879 gtk_tree_path_free (path);
1881 if (!iter_is_sorted (list_store, iter))
1883 GHashTable *old_positions;
1886 old_positions = save_positions (priv->seq);
1887 g_sequence_sort_changed_iter (iter->user_data,
1888 gtk_list_store_compare_func,
1890 order = generate_order (priv->seq, old_positions);
1891 path = gtk_tree_path_new ();
1892 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (list_store),
1894 gtk_tree_path_free (path);
1900 gtk_list_store_get_sort_column_id (GtkTreeSortable *sortable,
1901 gint *sort_column_id,
1904 GtkListStore *list_store = GTK_LIST_STORE (sortable);
1905 GtkListStorePrivate *priv = list_store->priv;
1908 * sort_column_id = priv->sort_column_id;
1910 * order = priv->order;
1912 if (priv->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID ||
1913 priv->sort_column_id == GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
1920 gtk_list_store_set_sort_column_id (GtkTreeSortable *sortable,
1921 gint sort_column_id,
1924 GtkListStore *list_store = GTK_LIST_STORE (sortable);
1925 GtkListStorePrivate *priv = list_store->priv;
1927 if ((priv->sort_column_id == sort_column_id) &&
1928 (priv->order == order))
1931 if (sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
1933 if (sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
1935 GtkTreeDataSortHeader *header = NULL;
1937 header = _gtk_tree_data_list_get_header (priv->sort_list,
1940 /* We want to make sure that we have a function */
1941 g_return_if_fail (header != NULL);
1942 g_return_if_fail (header->func != NULL);
1946 g_return_if_fail (priv->default_sort_func != NULL);
1951 priv->sort_column_id = sort_column_id;
1952 priv->order = order;
1954 gtk_tree_sortable_sort_column_changed (sortable);
1956 gtk_list_store_sort (list_store);
1960 gtk_list_store_set_sort_func (GtkTreeSortable *sortable,
1961 gint sort_column_id,
1962 GtkTreeIterCompareFunc func,
1964 GDestroyNotify destroy)
1966 GtkListStore *list_store = GTK_LIST_STORE (sortable);
1967 GtkListStorePrivate *priv = list_store->priv;
1969 priv->sort_list = _gtk_tree_data_list_set_header (priv->sort_list,
1971 func, data, destroy);
1973 if (priv->sort_column_id == sort_column_id)
1974 gtk_list_store_sort (list_store);
1978 gtk_list_store_set_default_sort_func (GtkTreeSortable *sortable,
1979 GtkTreeIterCompareFunc func,
1981 GDestroyNotify destroy)
1983 GtkListStore *list_store = GTK_LIST_STORE (sortable);
1984 GtkListStorePrivate *priv = list_store->priv;
1986 if (priv->default_sort_destroy)
1988 GDestroyNotify d = priv->default_sort_destroy;
1990 priv->default_sort_destroy = NULL;
1991 d (priv->default_sort_data);
1994 priv->default_sort_func = func;
1995 priv->default_sort_data = data;
1996 priv->default_sort_destroy = destroy;
1998 if (priv->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
1999 gtk_list_store_sort (list_store);
2003 gtk_list_store_has_default_sort_func (GtkTreeSortable *sortable)
2005 GtkListStore *list_store = GTK_LIST_STORE (sortable);
2006 GtkListStorePrivate *priv = list_store->priv;
2008 return (priv->default_sort_func != NULL);
2013 * gtk_list_store_insert_with_values:
2014 * @list_store: A #GtkListStore
2015 * @iter: (out) (allow-none): An unset #GtkTreeIter to set to the new row, or %NULL.
2016 * @position: position to insert the new row
2017 * @Varargs: pairs of column number and value, terminated with -1
2019 * Creates a new row at @position. @iter will be changed to point to this new
2020 * row. If @position is larger than the number of rows on the list, then the
2021 * new row will be appended to the list. The row will be filled with the
2022 * values given to this function.
2025 * <literal>gtk_list_store_insert_with_values(list_store, iter, position...)</literal>
2026 * has the same effect as calling
2028 * gtk_list_store_insert (list_store, iter, position);
2029 * gtk_list_store_set (list_store, iter, ...);
2031 * with the difference that the former will only emit a row_inserted signal,
2032 * while the latter will emit row_inserted, row_changed and, if the list store
2033 * is sorted, rows_reordered. Since emitting the rows_reordered signal
2034 * repeatedly can affect the performance of the program,
2035 * gtk_list_store_insert_with_values() should generally be preferred when
2036 * inserting rows in a sorted list store.
2041 gtk_list_store_insert_with_values (GtkListStore *list_store,
2046 GtkListStorePrivate *priv;
2050 GtkTreeIter tmp_iter;
2052 gboolean changed = FALSE;
2053 gboolean maybe_need_sort = FALSE;
2056 /* FIXME: refactor to reduce overlap with gtk_list_store_set() */
2057 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
2059 priv = list_store->priv;
2064 priv->columns_dirty = TRUE;
2068 length = g_sequence_get_length (seq);
2069 if (position > length)
2072 ptr = g_sequence_get_iter_at_pos (seq, position);
2073 ptr = g_sequence_insert_before (ptr, NULL);
2075 iter->stamp = priv->stamp;
2076 iter->user_data = ptr;
2078 g_assert (VALID_ITER (iter, list_store));
2082 va_start (var_args, position);
2083 gtk_list_store_set_valist_internal (list_store, iter,
2084 &changed, &maybe_need_sort,
2088 /* Don't emit rows_reordered here */
2089 if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
2090 g_sequence_sort_changed_iter (iter->user_data,
2091 gtk_list_store_compare_func,
2094 /* Just emit row_inserted */
2095 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
2096 gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter);
2097 gtk_tree_path_free (path);
2102 * gtk_list_store_insert_with_valuesv:
2103 * @list_store: A #GtkListStore
2104 * @iter: (out) (allow-none): An unset #GtkTreeIter to set to the new row, or %NULL.
2105 * @position: position to insert the new row
2106 * @columns: (array length=n_values): an array of column numbers
2107 * @values: (array length=n_values): an array of GValues
2108 * @n_values: the length of the @columns and @values arrays
2110 * A variant of gtk_list_store_insert_with_values() which
2111 * takes the columns and values as two arrays, instead of
2112 * varargs. This function is mainly intended for
2113 * language-bindings.
2118 gtk_list_store_insert_with_valuesv (GtkListStore *list_store,
2125 GtkListStorePrivate *priv;
2129 GtkTreeIter tmp_iter;
2131 gboolean changed = FALSE;
2132 gboolean maybe_need_sort = FALSE;
2134 /* FIXME refactor to reduce overlap with
2135 * gtk_list_store_insert_with_values()
2137 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
2139 priv = list_store->priv;
2144 priv->columns_dirty = TRUE;
2148 length = g_sequence_get_length (seq);
2149 if (position > length)
2152 ptr = g_sequence_get_iter_at_pos (seq, position);
2153 ptr = g_sequence_insert_before (ptr, NULL);
2155 iter->stamp = priv->stamp;
2156 iter->user_data = ptr;
2158 g_assert (VALID_ITER (iter, list_store));
2162 gtk_list_store_set_vector_internal (list_store, iter,
2163 &changed, &maybe_need_sort,
2164 columns, values, n_values);
2166 /* Don't emit rows_reordered here */
2167 if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
2168 g_sequence_sort_changed_iter (iter->user_data,
2169 gtk_list_store_compare_func,
2172 /* Just emit row_inserted */
2173 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
2174 gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter);
2175 gtk_tree_path_free (path);
2178 /* GtkBuildable custom tag implementation
2181 * <column type="..."/>
2182 * <column type="..."/>
2186 gboolean translatable;
2192 GtkBuilder *builder;
2194 GSList *column_type_names;
2195 GType *column_types;
2204 const gchar *domain;
2208 list_store_start_element (GMarkupParseContext *context,
2209 const gchar *element_name,
2210 const gchar **names,
2211 const gchar **values,
2216 SubParserData *data = (SubParserData*)user_data;
2218 if (strcmp (element_name, "col") == 0)
2221 gchar *context = NULL;
2222 gboolean translatable = FALSE;
2225 if (data->row_column >= data->n_columns)
2227 g_set_error (error, data->error_quark, 0,
2228 "Too many columns, maximum is %d\n", data->n_columns - 1);
2232 for (i = 0; names[i]; i++)
2233 if (strcmp (names[i], "id") == 0)
2236 id = atoi (values[i]);
2239 g_set_error (error, data->error_quark, 0,
2240 "the id tag %s could not be converted to an integer",
2244 if (id < 0 || id >= data->n_columns)
2246 g_set_error (error, data->error_quark, 0,
2247 "id value %d out of range", id);
2251 else if (strcmp (names[i], "translatable") == 0)
2253 if (!_gtk_builder_boolean_from_string (values[i], &translatable,
2257 else if (strcmp (names[i], "comments") == 0)
2259 /* do nothing, comments are for translators */
2261 else if (strcmp (names[i], "context") == 0)
2263 context = g_strdup (values[i]);
2268 g_set_error (error, data->error_quark, 0,
2269 "<col> needs an id attribute");
2273 info = g_slice_new0 (ColInfo);
2274 info->translatable = translatable;
2275 info->context = context;
2278 data->colids[data->row_column] = id;
2279 data->columns[data->row_column] = info;
2281 data->is_data = TRUE;
2283 else if (strcmp (element_name, "row") == 0)
2285 else if (strcmp (element_name, "column") == 0)
2286 for (i = 0; names[i]; i++)
2287 if (strcmp (names[i], "type") == 0)
2288 data->column_type_names = g_slist_prepend (data->column_type_names,
2289 g_strdup (values[i]));
2290 else if (strcmp (element_name, "columns") == 0)
2292 else if (strcmp (element_name, "data") == 0)
2295 g_set_error (error, data->error_quark, 0,
2296 "Unknown start tag: %s", element_name);
2300 list_store_end_element (GMarkupParseContext *context,
2301 const gchar *element_name,
2305 SubParserData *data = (SubParserData*)user_data;
2307 g_assert (data->builder);
2309 if (strcmp (element_name, "row") == 0)
2314 gtk_list_store_insert_with_valuesv (GTK_LIST_STORE (data->object),
2320 for (i = 0; i < data->row_column; i++)
2322 ColInfo *info = data->columns[i];
2323 g_free (info->context);
2324 g_slice_free (ColInfo, info);
2325 data->columns[i] = NULL;
2326 g_value_unset (&data->values[i]);
2328 g_free (data->values);
2329 data->values = g_new0 (GValue, data->n_columns);
2331 data->row_column = 0;
2333 else if (strcmp (element_name, "columns") == 0)
2335 GType *column_types;
2340 data->column_type_names = g_slist_reverse (data->column_type_names);
2341 column_types = g_new0 (GType, g_slist_length (data->column_type_names));
2343 for (l = data->column_type_names, i = 0; l; l = l->next, i++)
2345 type = gtk_builder_get_type_from_name (data->builder, l->data);
2346 if (type == G_TYPE_INVALID)
2348 g_warning ("Unknown type %s specified in treemodel %s",
2349 (const gchar*)l->data,
2350 gtk_buildable_get_name (GTK_BUILDABLE (data->object)));
2353 column_types[i] = type;
2358 gtk_list_store_set_column_types (GTK_LIST_STORE (data->object), i,
2361 g_free (column_types);
2363 else if (strcmp (element_name, "col") == 0)
2364 data->is_data = FALSE;
2365 else if (strcmp (element_name, "data") == 0)
2367 else if (strcmp (element_name, "column") == 0)
2370 g_set_error (error, data->error_quark, 0,
2371 "Unknown end tag: %s", element_name);
2375 list_store_text (GMarkupParseContext *context,
2381 SubParserData *data = (SubParserData*)user_data;
2383 GError *tmp_error = NULL;
2390 i = data->row_column - 1;
2391 info = data->columns[i];
2393 string = g_strndup (text, text_len);
2394 if (info->translatable && text_len)
2398 /* FIXME: This will not use the domain set in the .ui file,
2399 * since the parser is not telling the builder about the domain.
2400 * However, it will work for gtk_builder_set_translation_domain() calls.
2402 translated = _gtk_builder_parser_translate (data->domain,
2406 string = translated;
2409 if (!gtk_builder_value_from_string_type (data->builder,
2410 data->column_types[info->id],
2418 "Could not convert '%s' to type %s: %s\n",
2419 text, g_type_name (data->column_types[info->id]),
2420 tmp_error->message);
2421 g_error_free (tmp_error);
2426 static const GMarkupParser list_store_parser =
2428 list_store_start_element,
2429 list_store_end_element,
2434 gtk_list_store_buildable_custom_tag_start (GtkBuildable *buildable,
2435 GtkBuilder *builder,
2437 const gchar *tagname,
2438 GMarkupParser *parser,
2441 SubParserData *parser_data;
2446 if (strcmp (tagname, "columns") == 0)
2449 parser_data = g_slice_new0 (SubParserData);
2450 parser_data->builder = builder;
2451 parser_data->object = G_OBJECT (buildable);
2452 parser_data->column_type_names = NULL;
2454 *parser = list_store_parser;
2455 *data = parser_data;
2458 else if (strcmp (tagname, "data") == 0)
2460 gint n_columns = gtk_list_store_get_n_columns (GTK_TREE_MODEL (buildable));
2462 g_error ("Cannot append data to an empty model");
2464 parser_data = g_slice_new0 (SubParserData);
2465 parser_data->builder = builder;
2466 parser_data->object = G_OBJECT (buildable);
2467 parser_data->values = g_new0 (GValue, n_columns);
2468 parser_data->colids = g_new0 (gint, n_columns);
2469 parser_data->columns = g_new0 (ColInfo*, n_columns);
2470 parser_data->column_types = GTK_LIST_STORE (buildable)->priv->column_headers;
2471 parser_data->n_columns = n_columns;
2472 parser_data->last_row = 0;
2473 parser_data->error_quark = g_quark_from_static_string ("GtkListStore");
2474 parser_data->domain = gtk_builder_get_translation_domain (builder);
2476 *parser = list_store_parser;
2477 *data = parser_data;
2481 g_warning ("Unknown custom list store tag: %s", tagname);
2487 gtk_list_store_buildable_custom_tag_end (GtkBuildable *buildable,
2488 GtkBuilder *builder,
2490 const gchar *tagname,
2493 SubParserData *sub = (SubParserData*)data;
2495 if (strcmp (tagname, "columns") == 0)
2497 g_slist_free (sub->column_type_names);
2498 g_slice_free (SubParserData, sub);
2500 else if (strcmp (tagname, "data") == 0)
2503 for (i = 0; i < sub->n_columns; i++)
2505 ColInfo *info = sub->columns[i];
2508 g_free (info->context);
2509 g_slice_free (ColInfo, info);
2512 g_free (sub->colids);
2513 g_free (sub->columns);
2514 g_free (sub->values);
2515 g_slice_free (SubParserData, sub);
2518 g_warning ("Unknown custom list store tag: %s", tagname);