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
37 GtkTreeIterCompareFunc default_sort_func;
39 GDestroyNotify default_sort_destroy;
41 GType *column_headers;
48 guint columns_dirty : 1;
50 gpointer default_sort_data;
51 gpointer seq; /* head of the list */
54 #define GTK_LIST_STORE_IS_SORTED(list) (((GtkListStore*)(list))->priv->sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
55 #define VALID_ITER(iter, list_store) ((iter)!= NULL && (iter)->user_data != NULL && list_store->priv->stamp == (iter)->stamp && !g_sequence_iter_is_end ((iter)->user_data) && g_sequence_iter_get_sequence ((iter)->user_data) == list_store->priv->seq)
57 static void gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
58 static void gtk_list_store_drag_source_init(GtkTreeDragSourceIface *iface);
59 static void gtk_list_store_drag_dest_init (GtkTreeDragDestIface *iface);
60 static void gtk_list_store_sortable_init (GtkTreeSortableIface *iface);
61 static void gtk_list_store_buildable_init (GtkBuildableIface *iface);
62 static void gtk_list_store_finalize (GObject *object);
63 static GtkTreeModelFlags gtk_list_store_get_flags (GtkTreeModel *tree_model);
64 static gint gtk_list_store_get_n_columns (GtkTreeModel *tree_model);
65 static GType gtk_list_store_get_column_type (GtkTreeModel *tree_model,
67 static gboolean gtk_list_store_get_iter (GtkTreeModel *tree_model,
70 static GtkTreePath *gtk_list_store_get_path (GtkTreeModel *tree_model,
72 static void gtk_list_store_get_value (GtkTreeModel *tree_model,
76 static gboolean gtk_list_store_iter_next (GtkTreeModel *tree_model,
78 static gboolean gtk_list_store_iter_previous (GtkTreeModel *tree_model,
80 static gboolean gtk_list_store_iter_children (GtkTreeModel *tree_model,
83 static gboolean gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
85 static gint gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
87 static gboolean gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
91 static gboolean gtk_list_store_iter_parent (GtkTreeModel *tree_model,
96 static void gtk_list_store_set_n_columns (GtkListStore *list_store,
98 static void gtk_list_store_set_column_type (GtkListStore *list_store,
102 static void gtk_list_store_increment_stamp (GtkListStore *list_store);
106 static gboolean real_gtk_list_store_row_draggable (GtkTreeDragSource *drag_source,
108 static gboolean gtk_list_store_drag_data_delete (GtkTreeDragSource *drag_source,
110 static gboolean gtk_list_store_drag_data_get (GtkTreeDragSource *drag_source,
112 GtkSelectionData *selection_data);
113 static gboolean gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
115 GtkSelectionData *selection_data);
116 static gboolean gtk_list_store_row_drop_possible (GtkTreeDragDest *drag_dest,
117 GtkTreePath *dest_path,
118 GtkSelectionData *selection_data);
122 static void gtk_list_store_sort (GtkListStore *list_store);
123 static void gtk_list_store_sort_iter_changed (GtkListStore *list_store,
126 static gboolean gtk_list_store_get_sort_column_id (GtkTreeSortable *sortable,
127 gint *sort_column_id,
129 static void gtk_list_store_set_sort_column_id (GtkTreeSortable *sortable,
132 static void gtk_list_store_set_sort_func (GtkTreeSortable *sortable,
134 GtkTreeIterCompareFunc func,
136 GDestroyNotify destroy);
137 static void gtk_list_store_set_default_sort_func (GtkTreeSortable *sortable,
138 GtkTreeIterCompareFunc func,
140 GDestroyNotify destroy);
141 static gboolean gtk_list_store_has_default_sort_func (GtkTreeSortable *sortable);
145 static gboolean gtk_list_store_buildable_custom_tag_start (GtkBuildable *buildable,
148 const gchar *tagname,
149 GMarkupParser *parser,
151 static void gtk_list_store_buildable_custom_tag_end (GtkBuildable *buildable,
154 const gchar *tagname,
157 G_DEFINE_TYPE_WITH_CODE (GtkListStore, gtk_list_store, G_TYPE_OBJECT,
158 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
159 gtk_list_store_tree_model_init)
160 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
161 gtk_list_store_drag_source_init)
162 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST,
163 gtk_list_store_drag_dest_init)
164 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
165 gtk_list_store_sortable_init)
166 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
167 gtk_list_store_buildable_init))
171 gtk_list_store_class_init (GtkListStoreClass *class)
173 GObjectClass *object_class;
175 object_class = (GObjectClass*) class;
177 object_class->finalize = gtk_list_store_finalize;
179 g_type_class_add_private (class, sizeof (GtkListStorePrivate));
183 gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
185 iface->get_flags = gtk_list_store_get_flags;
186 iface->get_n_columns = gtk_list_store_get_n_columns;
187 iface->get_column_type = gtk_list_store_get_column_type;
188 iface->get_iter = gtk_list_store_get_iter;
189 iface->get_path = gtk_list_store_get_path;
190 iface->get_value = gtk_list_store_get_value;
191 iface->iter_next = gtk_list_store_iter_next;
192 iface->iter_previous = gtk_list_store_iter_previous;
193 iface->iter_children = gtk_list_store_iter_children;
194 iface->iter_has_child = gtk_list_store_iter_has_child;
195 iface->iter_n_children = gtk_list_store_iter_n_children;
196 iface->iter_nth_child = gtk_list_store_iter_nth_child;
197 iface->iter_parent = gtk_list_store_iter_parent;
201 gtk_list_store_drag_source_init (GtkTreeDragSourceIface *iface)
203 iface->row_draggable = real_gtk_list_store_row_draggable;
204 iface->drag_data_delete = gtk_list_store_drag_data_delete;
205 iface->drag_data_get = gtk_list_store_drag_data_get;
209 gtk_list_store_drag_dest_init (GtkTreeDragDestIface *iface)
211 iface->drag_data_received = gtk_list_store_drag_data_received;
212 iface->row_drop_possible = gtk_list_store_row_drop_possible;
216 gtk_list_store_sortable_init (GtkTreeSortableIface *iface)
218 iface->get_sort_column_id = gtk_list_store_get_sort_column_id;
219 iface->set_sort_column_id = gtk_list_store_set_sort_column_id;
220 iface->set_sort_func = gtk_list_store_set_sort_func;
221 iface->set_default_sort_func = gtk_list_store_set_default_sort_func;
222 iface->has_default_sort_func = gtk_list_store_has_default_sort_func;
226 gtk_list_store_buildable_init (GtkBuildableIface *iface)
228 iface->custom_tag_start = gtk_list_store_buildable_custom_tag_start;
229 iface->custom_tag_end = gtk_list_store_buildable_custom_tag_end;
233 gtk_list_store_init (GtkListStore *list_store)
235 GtkListStorePrivate *priv;
237 list_store->priv = G_TYPE_INSTANCE_GET_PRIVATE (list_store,
239 GtkListStorePrivate);
240 priv = list_store->priv;
242 priv->seq = g_sequence_new (NULL);
243 priv->sort_list = NULL;
244 priv->stamp = g_random_int ();
245 priv->sort_column_id = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
246 priv->columns_dirty = FALSE;
251 * gtk_list_store_new:
252 * @n_columns: number of columns in the list store
253 * @Varargs: all #GType types for the columns, from first to last
255 * Creates a new list store as with @n_columns columns each of the types passed
256 * in. Note that only types derived from standard GObject fundamental types
259 * As an example, <literal>gtk_tree_store_new (3, G_TYPE_INT, G_TYPE_STRING,
260 * GDK_TYPE_PIXBUF);</literal> will create a new #GtkListStore with three columns, of type
261 * int, string and #GdkPixbuf respectively.
263 * Return value: a new #GtkListStore
266 gtk_list_store_new (gint n_columns,
269 GtkListStore *retval;
273 g_return_val_if_fail (n_columns > 0, NULL);
275 retval = g_object_new (GTK_TYPE_LIST_STORE, NULL);
276 gtk_list_store_set_n_columns (retval, n_columns);
278 va_start (args, n_columns);
280 for (i = 0; i < n_columns; i++)
282 GType type = va_arg (args, GType);
283 if (! _gtk_tree_data_list_check_type (type))
285 g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
286 g_object_unref (retval);
290 gtk_list_store_set_column_type (retval, i, type);
300 * gtk_list_store_newv:
301 * @n_columns: number of columns in the list store
302 * @types: (array length=n_columns): an array of #GType types for the columns, from first to last
304 * Non-vararg creation function. Used primarily by language bindings.
306 * Return value: (transfer none): a new #GtkListStore
307 * Rename to: gtk_list_store_new
310 gtk_list_store_newv (gint n_columns,
313 GtkListStore *retval;
316 g_return_val_if_fail (n_columns > 0, NULL);
318 retval = g_object_new (GTK_TYPE_LIST_STORE, NULL);
319 gtk_list_store_set_n_columns (retval, n_columns);
321 for (i = 0; i < n_columns; i++)
323 if (! _gtk_tree_data_list_check_type (types[i]))
325 g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
326 g_object_unref (retval);
330 gtk_list_store_set_column_type (retval, i, types[i]);
337 * gtk_list_store_set_column_types:
338 * @list_store: A #GtkListStore
339 * @n_columns: Number of columns for the list store
340 * @types: (array length=n_columns): An array length n of #GTypes
342 * This function is meant primarily for #GObjects that inherit from #GtkListStore,
343 * and should only be used when constructing a new #GtkListStore. It will not
344 * function after a row has been added, or a method on the #GtkTreeModel
345 * interface is called.
348 gtk_list_store_set_column_types (GtkListStore *list_store,
352 GtkListStorePrivate *priv;
355 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
357 priv = list_store->priv;
359 g_return_if_fail (priv->columns_dirty == 0);
361 gtk_list_store_set_n_columns (list_store, n_columns);
362 for (i = 0; i < n_columns; i++)
364 if (! _gtk_tree_data_list_check_type (types[i]))
366 g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
369 gtk_list_store_set_column_type (list_store, i, types[i]);
374 gtk_list_store_set_n_columns (GtkListStore *list_store,
377 GtkListStorePrivate *priv = list_store->priv;
380 if (priv->n_columns == n_columns)
383 priv->column_headers = g_renew (GType, priv->column_headers, n_columns);
384 for (i = priv->n_columns; i < n_columns; i++)
385 priv->column_headers[i] = G_TYPE_INVALID;
386 priv->n_columns = n_columns;
389 _gtk_tree_data_list_header_free (priv->sort_list);
390 priv->sort_list = _gtk_tree_data_list_header_new (n_columns, priv->column_headers);
394 gtk_list_store_set_column_type (GtkListStore *list_store,
398 GtkListStorePrivate *priv = list_store->priv;
400 if (!_gtk_tree_data_list_check_type (type))
402 g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
406 priv->column_headers[column] = type;
410 gtk_list_store_finalize (GObject *object)
412 GtkListStore *list_store = GTK_LIST_STORE (object);
413 GtkListStorePrivate *priv = list_store->priv;
415 g_sequence_foreach (priv->seq,
416 (GFunc) _gtk_tree_data_list_free, priv->column_headers);
418 g_sequence_free (priv->seq);
420 _gtk_tree_data_list_header_free (priv->sort_list);
421 g_free (priv->column_headers);
423 if (priv->default_sort_destroy)
425 GDestroyNotify d = priv->default_sort_destroy;
427 priv->default_sort_destroy = NULL;
428 d (priv->default_sort_data);
429 priv->default_sort_data = NULL;
432 G_OBJECT_CLASS (gtk_list_store_parent_class)->finalize (object);
435 /* Fulfill the GtkTreeModel requirements */
436 static GtkTreeModelFlags
437 gtk_list_store_get_flags (GtkTreeModel *tree_model)
439 return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
443 gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
445 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
446 GtkListStorePrivate *priv = list_store->priv;
448 priv->columns_dirty = TRUE;
450 return priv->n_columns;
454 gtk_list_store_get_column_type (GtkTreeModel *tree_model,
457 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
458 GtkListStorePrivate *priv = list_store->priv;
460 g_return_val_if_fail (index < priv->n_columns, G_TYPE_INVALID);
462 priv->columns_dirty = TRUE;
464 return priv->column_headers[index];
468 gtk_list_store_get_iter (GtkTreeModel *tree_model,
472 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
473 GtkListStorePrivate *priv = list_store->priv;
477 priv->columns_dirty = TRUE;
481 i = gtk_tree_path_get_indices (path)[0];
483 if (i >= g_sequence_get_length (seq))
486 iter->stamp = priv->stamp;
487 iter->user_data = g_sequence_get_iter_at_pos (seq, i);
493 gtk_list_store_get_path (GtkTreeModel *tree_model,
496 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
497 GtkListStorePrivate *priv = list_store->priv;
500 g_return_val_if_fail (iter->stamp == priv->stamp, NULL);
502 if (g_sequence_iter_is_end (iter->user_data))
505 path = gtk_tree_path_new ();
506 gtk_tree_path_append_index (path, g_sequence_iter_get_position (iter->user_data));
512 gtk_list_store_get_value (GtkTreeModel *tree_model,
517 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
518 GtkListStorePrivate *priv = list_store->priv;
519 GtkTreeDataList *list;
520 gint tmp_column = column;
522 g_return_if_fail (column < priv->n_columns);
523 g_return_if_fail (VALID_ITER (iter, list_store));
525 list = g_sequence_get (iter->user_data);
527 while (tmp_column-- > 0 && list)
531 g_value_init (value, priv->column_headers[column]);
533 _gtk_tree_data_list_node_to_value (list,
534 priv->column_headers[column],
539 gtk_list_store_iter_next (GtkTreeModel *tree_model,
542 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
543 GtkListStorePrivate *priv = list_store->priv;
546 g_return_val_if_fail (priv->stamp == iter->stamp, FALSE);
547 iter->user_data = g_sequence_iter_next (iter->user_data);
549 retval = g_sequence_iter_is_end (iter->user_data);
557 gtk_list_store_iter_previous (GtkTreeModel *tree_model,
560 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
561 GtkListStorePrivate *priv = list_store->priv;
563 g_return_val_if_fail (priv->stamp == iter->stamp, FALSE);
565 if (g_sequence_iter_is_begin (iter->user_data))
571 iter->user_data = g_sequence_iter_prev (iter->user_data);
577 gtk_list_store_iter_children (GtkTreeModel *tree_model,
581 GtkListStore *list_store = (GtkListStore *) tree_model;
582 GtkListStorePrivate *priv = list_store->priv;
584 /* this is a list, nodes have no children */
591 if (g_sequence_get_length (priv->seq) > 0)
593 iter->stamp = priv->stamp;
594 iter->user_data = g_sequence_get_begin_iter (priv->seq);
605 gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
612 gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
615 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
616 GtkListStorePrivate *priv = list_store->priv;
619 return g_sequence_get_length (priv->seq);
621 g_return_val_if_fail (priv->stamp == iter->stamp, -1);
627 gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
632 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
633 GtkListStorePrivate *priv = list_store->priv;
634 GSequenceIter *child;
641 child = g_sequence_get_iter_at_pos (priv->seq, n);
643 if (g_sequence_iter_is_end (child))
646 iter->stamp = priv->stamp;
647 iter->user_data = child;
653 gtk_list_store_iter_parent (GtkTreeModel *tree_model,
662 gtk_list_store_real_set_value (GtkListStore *list_store,
668 GtkListStorePrivate *priv = list_store->priv;
669 GtkTreeDataList *list;
670 GtkTreeDataList *prev;
671 gint old_column = column;
672 GValue real_value = {0, };
673 gboolean converted = FALSE;
674 gboolean retval = FALSE;
676 if (! g_type_is_a (G_VALUE_TYPE (value), priv->column_headers[column]))
678 if (! (g_value_type_compatible (G_VALUE_TYPE (value), priv->column_headers[column]) &&
679 g_value_type_compatible (priv->column_headers[column], G_VALUE_TYPE (value))))
681 g_warning ("%s: Unable to convert from %s to %s\n",
683 g_type_name (G_VALUE_TYPE (value)),
684 g_type_name (priv->column_headers[column]));
687 if (!g_value_transform (value, &real_value))
689 g_warning ("%s: Unable to make conversion from %s to %s\n",
691 g_type_name (G_VALUE_TYPE (value)),
692 g_type_name (priv->column_headers[column]));
693 g_value_unset (&real_value);
699 prev = list = g_sequence_get (iter->user_data);
706 _gtk_tree_data_list_value_to_node (list, &real_value);
708 _gtk_tree_data_list_value_to_node (list, value);
711 g_value_unset (&real_value);
712 if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
713 gtk_list_store_sort_iter_changed (list_store, iter, old_column);
722 if (g_sequence_get (iter->user_data) == NULL)
724 list = _gtk_tree_data_list_alloc();
725 g_sequence_set (iter->user_data, list);
730 list = prev->next = _gtk_tree_data_list_alloc ();
736 list->next = _gtk_tree_data_list_alloc ();
743 _gtk_tree_data_list_value_to_node (list, &real_value);
745 _gtk_tree_data_list_value_to_node (list, value);
749 g_value_unset (&real_value);
751 if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
752 gtk_list_store_sort_iter_changed (list_store, iter, old_column);
759 * gtk_list_store_set_value:
760 * @list_store: A #GtkListStore
761 * @iter: A valid #GtkTreeIter for the row being modified
762 * @column: column number to modify
763 * @value: new value for the cell
765 * Sets the data in the cell specified by @iter and @column.
766 * The type of @value must be convertible to the type of the
771 gtk_list_store_set_value (GtkListStore *list_store,
776 GtkListStorePrivate *priv = list_store->priv;
778 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
779 g_return_if_fail (VALID_ITER (iter, list_store));
780 g_return_if_fail (G_IS_VALUE (value));
781 priv = list_store->priv;
782 g_return_if_fail (column >= 0 && column < priv->n_columns);
784 if (gtk_list_store_real_set_value (list_store, iter, column, value, TRUE))
788 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
789 gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
790 gtk_tree_path_free (path);
794 static GtkTreeIterCompareFunc
795 gtk_list_store_get_compare_func (GtkListStore *list_store)
797 GtkListStorePrivate *priv = list_store->priv;
798 GtkTreeIterCompareFunc func = NULL;
800 if (GTK_LIST_STORE_IS_SORTED (list_store))
802 if (priv->sort_column_id != -1)
804 GtkTreeDataSortHeader *header;
805 header = _gtk_tree_data_list_get_header (priv->sort_list,
806 priv->sort_column_id);
807 g_return_val_if_fail (header != NULL, NULL);
808 g_return_val_if_fail (header->func != NULL, NULL);
813 func = priv->default_sort_func;
821 gtk_list_store_set_vector_internal (GtkListStore *list_store,
823 gboolean *emit_signal,
824 gboolean *maybe_need_sort,
829 GtkListStorePrivate *priv = list_store->priv;
831 GtkTreeIterCompareFunc func = NULL;
833 func = gtk_list_store_get_compare_func (list_store);
834 if (func != _gtk_tree_data_list_compare_func)
835 *maybe_need_sort = TRUE;
837 for (i = 0; i < n_values; i++)
839 *emit_signal = gtk_list_store_real_set_value (list_store,
843 FALSE) || *emit_signal;
845 if (func == _gtk_tree_data_list_compare_func &&
846 columns[i] == priv->sort_column_id)
847 *maybe_need_sort = TRUE;
852 gtk_list_store_set_valist_internal (GtkListStore *list_store,
854 gboolean *emit_signal,
855 gboolean *maybe_need_sort,
858 GtkListStorePrivate *priv = list_store->priv;
860 GtkTreeIterCompareFunc func = NULL;
862 column = va_arg (var_args, gint);
864 func = gtk_list_store_get_compare_func (list_store);
865 if (func != _gtk_tree_data_list_compare_func)
866 *maybe_need_sort = TRUE;
870 GValue value = { 0, };
873 if (column < 0 || column >= priv->n_columns)
875 g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
879 G_VALUE_COLLECT_INIT (&value, priv->column_headers[column],
880 var_args, 0, &error);
883 g_warning ("%s: %s", G_STRLOC, error);
886 /* we purposely leak the value here, it might not be
887 * in a sane state if an error condition occoured
892 /* FIXME: instead of calling this n times, refactor with above */
893 *emit_signal = gtk_list_store_real_set_value (list_store,
897 FALSE) || *emit_signal;
899 if (func == _gtk_tree_data_list_compare_func &&
900 column == priv->sort_column_id)
901 *maybe_need_sort = TRUE;
903 g_value_unset (&value);
905 column = va_arg (var_args, gint);
910 * gtk_list_store_set_valuesv:
911 * @list_store: A #GtkListStore
912 * @iter: A valid #GtkTreeIter for the row being modified
913 * @columns: (array length=n_values): an array of column numbers
914 * @values: (array length=n_values): an array of GValues
915 * @n_values: the length of the @columns and @values arrays
917 * A variant of gtk_list_store_set_valist() which
918 * takes the columns and values as two arrays, instead of
919 * varargs. This function is mainly intended for
920 * language-bindings and in case the number of columns to
921 * change is not known until run-time.
924 * Rename to: gtk_list_store_set
927 gtk_list_store_set_valuesv (GtkListStore *list_store,
933 GtkListStorePrivate *priv;
934 gboolean emit_signal = FALSE;
935 gboolean maybe_need_sort = FALSE;
937 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
938 g_return_if_fail (VALID_ITER (iter, list_store));
940 priv = list_store->priv;
942 gtk_list_store_set_vector_internal (list_store, iter,
945 columns, values, n_values);
947 if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
948 gtk_list_store_sort_iter_changed (list_store, iter, priv->sort_column_id);
954 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
955 gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
956 gtk_tree_path_free (path);
961 * gtk_list_store_set_valist:
962 * @list_store: A #GtkListStore
963 * @iter: A valid #GtkTreeIter for the row being modified
964 * @var_args: va_list of column/value pairs
966 * See gtk_list_store_set(); this version takes a va_list for use by language
971 gtk_list_store_set_valist (GtkListStore *list_store,
975 GtkListStorePrivate *priv;
976 gboolean emit_signal = FALSE;
977 gboolean maybe_need_sort = FALSE;
979 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
980 g_return_if_fail (VALID_ITER (iter, list_store));
982 priv = list_store->priv;
984 gtk_list_store_set_valist_internal (list_store, iter,
989 if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
990 gtk_list_store_sort_iter_changed (list_store, iter, priv->sort_column_id);
996 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
997 gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
998 gtk_tree_path_free (path);
1003 * gtk_list_store_set:
1004 * @list_store: a #GtkListStore
1005 * @iter: row iterator
1006 * @Varargs: pairs of column number and value, terminated with -1
1008 * Sets the value of one or more cells in the row referenced by @iter.
1009 * The variable argument list should contain integer column numbers,
1010 * each column number followed by the value to be set.
1011 * The list is terminated by a -1. For example, to set column 0 with type
1012 * %G_TYPE_STRING to "Foo", you would write <literal>gtk_list_store_set (store, iter,
1013 * 0, "Foo", -1)</literal>.
1015 * The value will be referenced by the store if it is a %G_TYPE_OBJECT, and it
1016 * will be copied if it is a %G_TYPE_STRING or %G_TYPE_BOXED.
1019 gtk_list_store_set (GtkListStore *list_store,
1025 va_start (var_args, iter);
1026 gtk_list_store_set_valist (list_store, iter, var_args);
1031 * gtk_list_store_remove:
1032 * @list_store: A #GtkListStore
1033 * @iter: A valid #GtkTreeIter
1035 * Removes the given row from the list store. After being removed,
1036 * @iter is set to be the next valid row, or invalidated if it pointed
1037 * to the last row in @list_store.
1039 * Return value: %TRUE if @iter is valid, %FALSE if not.
1042 gtk_list_store_remove (GtkListStore *list_store,
1045 GtkListStorePrivate *priv;
1047 GSequenceIter *ptr, *next;
1049 g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), FALSE);
1050 g_return_val_if_fail (VALID_ITER (iter, list_store), FALSE);
1052 priv = list_store->priv;
1054 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
1056 ptr = iter->user_data;
1057 next = g_sequence_iter_next (ptr);
1059 _gtk_tree_data_list_free (g_sequence_get (ptr), priv->column_headers);
1060 g_sequence_remove (iter->user_data);
1064 gtk_tree_model_row_deleted (GTK_TREE_MODEL (list_store), path);
1065 gtk_tree_path_free (path);
1067 if (g_sequence_iter_is_end (next))
1074 iter->stamp = priv->stamp;
1075 iter->user_data = next;
1081 * gtk_list_store_insert:
1082 * @list_store: A #GtkListStore
1083 * @iter: (out): An unset #GtkTreeIter to set to the new row
1084 * @position: position to insert the new row
1086 * Creates a new row at @position. @iter will be changed to point to this new
1087 * row. If @position is larger than the number of rows on the list, then the
1088 * new row will be appended to the list. The row will be empty after this
1089 * function is called. To fill in values, you need to call
1090 * gtk_list_store_set() or gtk_list_store_set_value().
1094 gtk_list_store_insert (GtkListStore *list_store,
1098 GtkListStorePrivate *priv;
1104 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1105 g_return_if_fail (iter != NULL);
1106 g_return_if_fail (position >= 0);
1108 priv = list_store->priv;
1110 priv->columns_dirty = TRUE;
1114 length = g_sequence_get_length (seq);
1115 if (position > length)
1118 ptr = g_sequence_get_iter_at_pos (seq, position);
1119 ptr = g_sequence_insert_before (ptr, NULL);
1121 iter->stamp = priv->stamp;
1122 iter->user_data = ptr;
1124 g_assert (VALID_ITER (iter, list_store));
1128 path = gtk_tree_path_new ();
1129 gtk_tree_path_append_index (path, position);
1130 gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter);
1131 gtk_tree_path_free (path);
1135 * gtk_list_store_insert_before:
1136 * @list_store: A #GtkListStore
1137 * @iter: (out): An unset #GtkTreeIter to set to the new row
1138 * @sibling: (allow-none): A valid #GtkTreeIter, or %NULL
1140 * Inserts a new row before @sibling. If @sibling is %NULL, then the row will
1141 * be appended to the end of the list. @iter will be changed to point to this
1142 * new row. The row will be empty after this function is called. To fill in
1143 * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1147 gtk_list_store_insert_before (GtkListStore *list_store,
1149 GtkTreeIter *sibling)
1151 GtkListStorePrivate *priv;
1152 GSequenceIter *after;
1154 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1155 g_return_if_fail (iter != NULL);
1157 priv = list_store->priv;
1160 g_return_if_fail (VALID_ITER (sibling, list_store));
1163 after = g_sequence_get_end_iter (priv->seq);
1165 after = sibling->user_data;
1167 gtk_list_store_insert (list_store, iter, g_sequence_iter_get_position (after));
1171 * gtk_list_store_insert_after:
1172 * @list_store: A #GtkListStore
1173 * @iter: (out): An unset #GtkTreeIter to set to the new row
1174 * @sibling: (allow-none): A valid #GtkTreeIter, or %NULL
1176 * Inserts a new row after @sibling. If @sibling is %NULL, then the row will be
1177 * prepended to the beginning of the list. @iter will be changed to point to
1178 * this new row. The row will be empty after this function is called. To fill
1179 * in values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1183 gtk_list_store_insert_after (GtkListStore *list_store,
1185 GtkTreeIter *sibling)
1187 GtkListStorePrivate *priv;
1188 GSequenceIter *after;
1190 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1191 g_return_if_fail (iter != NULL);
1193 priv = list_store->priv;
1196 g_return_if_fail (VALID_ITER (sibling, list_store));
1199 after = g_sequence_get_begin_iter (priv->seq);
1201 after = g_sequence_iter_next (sibling->user_data);
1203 gtk_list_store_insert (list_store, iter, g_sequence_iter_get_position (after));
1207 * gtk_list_store_prepend:
1208 * @list_store: A #GtkListStore
1209 * @iter: (out): An unset #GtkTreeIter to set to the prepend row
1211 * Prepends a new row to @list_store. @iter will be changed to point to this new
1212 * row. The row will be empty after this function is called. To fill in
1213 * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1217 gtk_list_store_prepend (GtkListStore *list_store,
1220 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1221 g_return_if_fail (iter != NULL);
1223 gtk_list_store_insert (list_store, iter, 0);
1227 * gtk_list_store_append:
1228 * @list_store: A #GtkListStore
1229 * @iter: (out): An unset #GtkTreeIter to set to the appended row
1231 * Appends a new row to @list_store. @iter will be changed to point to this new
1232 * row. The row will be empty after this function is called. To fill in
1233 * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1237 gtk_list_store_append (GtkListStore *list_store,
1240 GtkListStorePrivate *priv;
1242 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1243 g_return_if_fail (iter != NULL);
1245 priv = list_store->priv;
1247 gtk_list_store_insert (list_store, iter, g_sequence_get_length (priv->seq));
1251 gtk_list_store_increment_stamp (GtkListStore *list_store)
1253 GtkListStorePrivate *priv = list_store->priv;
1259 while (priv->stamp == 0);
1263 * gtk_list_store_clear:
1264 * @list_store: a #GtkListStore.
1266 * Removes all rows from the list store.
1270 gtk_list_store_clear (GtkListStore *list_store)
1272 GtkListStorePrivate *priv;
1275 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1277 priv = list_store->priv;
1279 while (g_sequence_get_length (priv->seq) > 0)
1281 iter.stamp = priv->stamp;
1282 iter.user_data = g_sequence_get_begin_iter (priv->seq);
1283 gtk_list_store_remove (list_store, &iter);
1286 gtk_list_store_increment_stamp (list_store);
1290 * gtk_list_store_iter_is_valid:
1291 * @list_store: A #GtkListStore.
1292 * @iter: A #GtkTreeIter.
1294 * <warning>This function is slow. Only use it for debugging and/or testing
1295 * purposes.</warning>
1297 * Checks if the given iter is a valid iter for this #GtkListStore.
1299 * Return value: %TRUE if the iter is valid, %FALSE if the iter is invalid.
1304 gtk_list_store_iter_is_valid (GtkListStore *list_store,
1307 GtkListStorePrivate *priv;
1309 g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), FALSE);
1310 g_return_val_if_fail (iter != NULL, FALSE);
1312 priv = list_store->priv;
1314 if (!VALID_ITER (iter, list_store))
1317 if (g_sequence_iter_get_sequence (iter->user_data) != priv->seq)
1323 static gboolean real_gtk_list_store_row_draggable (GtkTreeDragSource *drag_source,
1330 gtk_list_store_drag_data_delete (GtkTreeDragSource *drag_source,
1335 if (gtk_list_store_get_iter (GTK_TREE_MODEL (drag_source),
1339 gtk_list_store_remove (GTK_LIST_STORE (drag_source), &iter);
1346 gtk_list_store_drag_data_get (GtkTreeDragSource *drag_source,
1348 GtkSelectionData *selection_data)
1350 /* Note that we don't need to handle the GTK_TREE_MODEL_ROW
1351 * target, because the default handler does it for us, but
1352 * we do anyway for the convenience of someone maybe overriding the
1356 if (gtk_tree_set_row_drag_data (selection_data,
1357 GTK_TREE_MODEL (drag_source),
1364 /* FIXME handle text targets at least. */
1371 gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
1373 GtkSelectionData *selection_data)
1375 GtkTreeModel *tree_model = GTK_TREE_MODEL (drag_dest);
1376 GtkListStore *list_store = GTK_LIST_STORE (tree_model);
1377 GtkListStorePrivate *priv = list_store->priv;
1378 GtkTreeModel *src_model = NULL;
1379 GtkTreePath *src_path = NULL;
1380 gboolean retval = FALSE;
1382 if (gtk_tree_get_row_drag_data (selection_data,
1385 src_model == tree_model)
1387 /* Copy the given row to a new position */
1388 GtkTreeIter src_iter;
1389 GtkTreeIter dest_iter;
1392 if (!gtk_list_store_get_iter (src_model,
1399 /* Get the path to insert _after_ (dest is the path to insert _before_) */
1400 prev = gtk_tree_path_copy (dest);
1402 if (!gtk_tree_path_prev (prev))
1404 /* dest was the first spot in the list; which means we are supposed
1407 gtk_list_store_prepend (list_store, &dest_iter);
1413 if (gtk_list_store_get_iter (tree_model, &dest_iter, prev))
1415 GtkTreeIter tmp_iter = dest_iter;
1417 gtk_list_store_insert_after (list_store, &dest_iter, &tmp_iter);
1423 gtk_tree_path_free (prev);
1425 /* If we succeeded in creating dest_iter, copy data from src
1429 GtkTreeDataList *dl = g_sequence_get (src_iter.user_data);
1430 GtkTreeDataList *copy_head = NULL;
1431 GtkTreeDataList *copy_prev = NULL;
1432 GtkTreeDataList *copy_iter = NULL;
1439 copy_iter = _gtk_tree_data_list_node_copy (dl,
1440 priv->column_headers[col]);
1442 if (copy_head == NULL)
1443 copy_head = copy_iter;
1446 copy_prev->next = copy_iter;
1448 copy_prev = copy_iter;
1454 dest_iter.stamp = priv->stamp;
1455 g_sequence_set (dest_iter.user_data, copy_head);
1457 path = gtk_list_store_get_path (tree_model, &dest_iter);
1458 gtk_tree_model_row_changed (tree_model, path, &dest_iter);
1459 gtk_tree_path_free (path);
1464 /* FIXME maybe add some data targets eventually, or handle text
1465 * targets in the simple case.
1472 gtk_tree_path_free (src_path);
1478 gtk_list_store_row_drop_possible (GtkTreeDragDest *drag_dest,
1479 GtkTreePath *dest_path,
1480 GtkSelectionData *selection_data)
1483 GtkTreeModel *src_model = NULL;
1484 GtkTreePath *src_path = NULL;
1485 gboolean retval = FALSE;
1487 /* don't accept drops if the list has been sorted */
1488 if (GTK_LIST_STORE_IS_SORTED (drag_dest))
1491 if (!gtk_tree_get_row_drag_data (selection_data,
1496 if (src_model != GTK_TREE_MODEL (drag_dest))
1499 if (gtk_tree_path_get_depth (dest_path) != 1)
1502 /* can drop before any existing node, or before one past any existing. */
1504 indices = gtk_tree_path_get_indices (dest_path);
1506 if (indices[0] <= g_sequence_get_length (GTK_LIST_STORE (drag_dest)->priv->seq))
1511 gtk_tree_path_free (src_path);
1516 /* Sorting and reordering */
1520 gtk_list_store_reorder_func (GSequenceIter *a,
1524 GHashTable *new_positions = user_data;
1525 gint apos = GPOINTER_TO_INT (g_hash_table_lookup (new_positions, a));
1526 gint bpos = GPOINTER_TO_INT (g_hash_table_lookup (new_positions, b));
1536 * gtk_list_store_reorder: (skip)
1537 * @store: A #GtkListStore.
1538 * @new_order: (array): an array of integers mapping the new position of each child
1539 * to its old position before the re-ordering,
1540 * i.e. @new_order<literal>[newpos] = oldpos</literal>.
1542 * Reorders @store to follow the order indicated by @new_order. Note that
1543 * this function only works with unsorted stores.
1548 gtk_list_store_reorder (GtkListStore *store,
1551 GtkListStorePrivate *priv;
1554 GHashTable *new_positions;
1558 g_return_if_fail (GTK_IS_LIST_STORE (store));
1559 g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1560 g_return_if_fail (new_order != NULL);
1564 order = g_new (gint, g_sequence_get_length (priv->seq));
1565 for (i = 0; i < g_sequence_get_length (priv->seq); i++)
1566 order[new_order[i]] = i;
1568 new_positions = g_hash_table_new (g_direct_hash, g_direct_equal);
1570 ptr = g_sequence_get_begin_iter (priv->seq);
1572 while (!g_sequence_iter_is_end (ptr))
1574 g_hash_table_insert (new_positions, ptr, GINT_TO_POINTER (order[i++]));
1576 ptr = g_sequence_iter_next (ptr);
1580 g_sequence_sort_iter (priv->seq, gtk_list_store_reorder_func, new_positions);
1582 g_hash_table_destroy (new_positions);
1585 path = gtk_tree_path_new ();
1586 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store),
1587 path, NULL, new_order);
1588 gtk_tree_path_free (path);
1592 save_positions (GSequence *seq)
1594 GHashTable *positions = g_hash_table_new (g_direct_hash, g_direct_equal);
1597 ptr = g_sequence_get_begin_iter (seq);
1598 while (!g_sequence_iter_is_end (ptr))
1600 g_hash_table_insert (positions, ptr,
1601 GINT_TO_POINTER (g_sequence_iter_get_position (ptr)));
1602 ptr = g_sequence_iter_next (ptr);
1609 generate_order (GSequence *seq,
1610 GHashTable *old_positions)
1613 int *order = g_new (int, g_sequence_get_length (seq));
1617 ptr = g_sequence_get_begin_iter (seq);
1618 while (!g_sequence_iter_is_end (ptr))
1620 int old_pos = GPOINTER_TO_INT (g_hash_table_lookup (old_positions, ptr));
1621 order[i++] = old_pos;
1622 ptr = g_sequence_iter_next (ptr);
1625 g_hash_table_destroy (old_positions);
1631 * gtk_list_store_swap:
1632 * @store: A #GtkListStore.
1633 * @a: A #GtkTreeIter.
1634 * @b: Another #GtkTreeIter.
1636 * Swaps @a and @b in @store. Note that this function only works with
1642 gtk_list_store_swap (GtkListStore *store,
1646 GtkListStorePrivate *priv;
1647 GHashTable *old_positions;
1651 g_return_if_fail (GTK_IS_LIST_STORE (store));
1652 g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1653 g_return_if_fail (VALID_ITER (a, store));
1654 g_return_if_fail (VALID_ITER (b, store));
1658 if (a->user_data == b->user_data)
1661 old_positions = save_positions (priv->seq);
1663 g_sequence_swap (a->user_data, b->user_data);
1665 order = generate_order (priv->seq, old_positions);
1666 path = gtk_tree_path_new ();
1668 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store),
1671 gtk_tree_path_free (path);
1676 gtk_list_store_move_to (GtkListStore *store,
1680 GtkListStorePrivate *priv = store->priv;
1681 GHashTable *old_positions;
1685 old_positions = save_positions (priv->seq);
1687 g_sequence_move (iter->user_data, g_sequence_get_iter_at_pos (priv->seq, new_pos));
1689 order = generate_order (priv->seq, old_positions);
1691 path = gtk_tree_path_new ();
1692 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store),
1694 gtk_tree_path_free (path);
1699 * gtk_list_store_move_before:
1700 * @store: A #GtkListStore.
1701 * @iter: A #GtkTreeIter.
1702 * @position: (allow-none): A #GtkTreeIter, or %NULL.
1704 * Moves @iter in @store to the position before @position. Note that this
1705 * function only works with unsorted stores. If @position is %NULL, @iter
1706 * will be moved to the end of the list.
1711 gtk_list_store_move_before (GtkListStore *store,
1713 GtkTreeIter *position)
1717 g_return_if_fail (GTK_IS_LIST_STORE (store));
1718 g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1719 g_return_if_fail (VALID_ITER (iter, store));
1721 g_return_if_fail (VALID_ITER (position, store));
1724 pos = g_sequence_iter_get_position (position->user_data);
1728 gtk_list_store_move_to (store, iter, pos);
1732 * gtk_list_store_move_after:
1733 * @store: A #GtkListStore.
1734 * @iter: A #GtkTreeIter.
1735 * @position: (allow-none): A #GtkTreeIter or %NULL.
1737 * Moves @iter in @store to the position after @position. Note that this
1738 * function only works with unsorted stores. If @position is %NULL, @iter
1739 * will be moved to the start of the list.
1744 gtk_list_store_move_after (GtkListStore *store,
1746 GtkTreeIter *position)
1750 g_return_if_fail (GTK_IS_LIST_STORE (store));
1751 g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store));
1752 g_return_if_fail (VALID_ITER (iter, store));
1754 g_return_if_fail (VALID_ITER (position, store));
1757 pos = g_sequence_iter_get_position (position->user_data) + 1;
1761 gtk_list_store_move_to (store, iter, pos);
1766 gtk_list_store_compare_func (GSequenceIter *a,
1770 GtkListStore *list_store = user_data;
1771 GtkListStorePrivate *priv = list_store->priv;
1775 GtkTreeIterCompareFunc func;
1778 if (priv->sort_column_id != -1)
1780 GtkTreeDataSortHeader *header;
1782 header = _gtk_tree_data_list_get_header (priv->sort_list,
1783 priv->sort_column_id);
1784 g_return_val_if_fail (header != NULL, 0);
1785 g_return_val_if_fail (header->func != NULL, 0);
1787 func = header->func;
1788 data = header->data;
1792 g_return_val_if_fail (priv->default_sort_func != NULL, 0);
1793 func = priv->default_sort_func;
1794 data = priv->default_sort_data;
1797 iter_a.stamp = priv->stamp;
1798 iter_a.user_data = (gpointer)a;
1799 iter_b.stamp = priv->stamp;
1800 iter_b.user_data = (gpointer)b;
1802 g_assert (VALID_ITER (&iter_a, list_store));
1803 g_assert (VALID_ITER (&iter_b, list_store));
1805 retval = (* func) (GTK_TREE_MODEL (list_store), &iter_a, &iter_b, data);
1807 if (priv->order == GTK_SORT_DESCENDING)
1811 else if (retval < 0)
1819 gtk_list_store_sort (GtkListStore *list_store)
1821 GtkListStorePrivate *priv = list_store->priv;
1824 GHashTable *old_positions;
1826 if (!GTK_LIST_STORE_IS_SORTED (list_store) ||
1827 g_sequence_get_length (priv->seq) <= 1)
1830 old_positions = save_positions (priv->seq);
1832 g_sequence_sort_iter (priv->seq, gtk_list_store_compare_func, list_store);
1834 /* Let the world know about our new order */
1835 new_order = generate_order (priv->seq, old_positions);
1837 path = gtk_tree_path_new ();
1838 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (list_store),
1839 path, NULL, new_order);
1840 gtk_tree_path_free (path);
1845 iter_is_sorted (GtkListStore *list_store,
1850 if (!g_sequence_iter_is_begin (iter->user_data))
1852 cmp = g_sequence_iter_prev (iter->user_data);
1853 if (gtk_list_store_compare_func (cmp, iter->user_data, list_store) > 0)
1857 cmp = g_sequence_iter_next (iter->user_data);
1858 if (!g_sequence_iter_is_end (cmp))
1860 if (gtk_list_store_compare_func (iter->user_data, cmp, list_store) > 0)
1868 gtk_list_store_sort_iter_changed (GtkListStore *list_store,
1873 GtkListStorePrivate *priv = list_store->priv;
1876 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
1877 gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
1878 gtk_tree_path_free (path);
1880 if (!iter_is_sorted (list_store, iter))
1882 GHashTable *old_positions;
1885 old_positions = save_positions (priv->seq);
1886 g_sequence_sort_changed_iter (iter->user_data,
1887 gtk_list_store_compare_func,
1889 order = generate_order (priv->seq, old_positions);
1890 path = gtk_tree_path_new ();
1891 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (list_store),
1893 gtk_tree_path_free (path);
1899 gtk_list_store_get_sort_column_id (GtkTreeSortable *sortable,
1900 gint *sort_column_id,
1903 GtkListStore *list_store = GTK_LIST_STORE (sortable);
1904 GtkListStorePrivate *priv = list_store->priv;
1907 * sort_column_id = priv->sort_column_id;
1909 * order = priv->order;
1911 if (priv->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID ||
1912 priv->sort_column_id == GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
1919 gtk_list_store_set_sort_column_id (GtkTreeSortable *sortable,
1920 gint sort_column_id,
1923 GtkListStore *list_store = GTK_LIST_STORE (sortable);
1924 GtkListStorePrivate *priv = list_store->priv;
1926 if ((priv->sort_column_id == sort_column_id) &&
1927 (priv->order == order))
1930 if (sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
1932 if (sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
1934 GtkTreeDataSortHeader *header = NULL;
1936 header = _gtk_tree_data_list_get_header (priv->sort_list,
1939 /* We want to make sure that we have a function */
1940 g_return_if_fail (header != NULL);
1941 g_return_if_fail (header->func != NULL);
1945 g_return_if_fail (priv->default_sort_func != NULL);
1950 priv->sort_column_id = sort_column_id;
1951 priv->order = order;
1953 gtk_tree_sortable_sort_column_changed (sortable);
1955 gtk_list_store_sort (list_store);
1959 gtk_list_store_set_sort_func (GtkTreeSortable *sortable,
1960 gint sort_column_id,
1961 GtkTreeIterCompareFunc func,
1963 GDestroyNotify destroy)
1965 GtkListStore *list_store = GTK_LIST_STORE (sortable);
1966 GtkListStorePrivate *priv = list_store->priv;
1968 priv->sort_list = _gtk_tree_data_list_set_header (priv->sort_list,
1970 func, data, destroy);
1972 if (priv->sort_column_id == sort_column_id)
1973 gtk_list_store_sort (list_store);
1977 gtk_list_store_set_default_sort_func (GtkTreeSortable *sortable,
1978 GtkTreeIterCompareFunc func,
1980 GDestroyNotify destroy)
1982 GtkListStore *list_store = GTK_LIST_STORE (sortable);
1983 GtkListStorePrivate *priv = list_store->priv;
1985 if (priv->default_sort_destroy)
1987 GDestroyNotify d = priv->default_sort_destroy;
1989 priv->default_sort_destroy = NULL;
1990 d (priv->default_sort_data);
1993 priv->default_sort_func = func;
1994 priv->default_sort_data = data;
1995 priv->default_sort_destroy = destroy;
1997 if (priv->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
1998 gtk_list_store_sort (list_store);
2002 gtk_list_store_has_default_sort_func (GtkTreeSortable *sortable)
2004 GtkListStore *list_store = GTK_LIST_STORE (sortable);
2005 GtkListStorePrivate *priv = list_store->priv;
2007 return (priv->default_sort_func != NULL);
2012 * gtk_list_store_insert_with_values:
2013 * @list_store: A #GtkListStore
2014 * @iter: (out) (allow-none): An unset #GtkTreeIter to set to the new row, or %NULL.
2015 * @position: position to insert the new row
2016 * @Varargs: pairs of column number and value, terminated with -1
2018 * Creates a new row at @position. @iter will be changed to point to this new
2019 * row. If @position is larger than the number of rows on the list, then the
2020 * new row will be appended to the list. The row will be filled with the
2021 * values given to this function.
2024 * <literal>gtk_list_store_insert_with_values(list_store, iter, position...)</literal>
2025 * has the same effect as calling
2027 * gtk_list_store_insert (list_store, iter, position);
2028 * gtk_list_store_set (list_store, iter, ...);
2030 * with the difference that the former will only emit a row_inserted signal,
2031 * while the latter will emit row_inserted, row_changed and, if the list store
2032 * is sorted, rows_reordered. Since emitting the rows_reordered signal
2033 * repeatedly can affect the performance of the program,
2034 * gtk_list_store_insert_with_values() should generally be preferred when
2035 * inserting rows in a sorted list store.
2040 gtk_list_store_insert_with_values (GtkListStore *list_store,
2045 GtkListStorePrivate *priv;
2049 GtkTreeIter tmp_iter;
2051 gboolean changed = FALSE;
2052 gboolean maybe_need_sort = FALSE;
2055 /* FIXME: refactor to reduce overlap with gtk_list_store_set() */
2056 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
2058 priv = list_store->priv;
2063 priv->columns_dirty = TRUE;
2067 length = g_sequence_get_length (seq);
2068 if (position > length)
2071 ptr = g_sequence_get_iter_at_pos (seq, position);
2072 ptr = g_sequence_insert_before (ptr, NULL);
2074 iter->stamp = priv->stamp;
2075 iter->user_data = ptr;
2077 g_assert (VALID_ITER (iter, list_store));
2081 va_start (var_args, position);
2082 gtk_list_store_set_valist_internal (list_store, iter,
2083 &changed, &maybe_need_sort,
2087 /* Don't emit rows_reordered here */
2088 if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
2089 g_sequence_sort_changed_iter (iter->user_data,
2090 gtk_list_store_compare_func,
2093 /* Just emit row_inserted */
2094 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
2095 gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter);
2096 gtk_tree_path_free (path);
2101 * gtk_list_store_insert_with_valuesv:
2102 * @list_store: A #GtkListStore
2103 * @iter: (out) (allow-none): An unset #GtkTreeIter to set to the new row, or %NULL.
2104 * @position: position to insert the new row
2105 * @columns: (array length=n_values): an array of column numbers
2106 * @values: (array length=n_values): an array of GValues
2107 * @n_values: the length of the @columns and @values arrays
2109 * A variant of gtk_list_store_insert_with_values() which
2110 * takes the columns and values as two arrays, instead of
2111 * varargs. This function is mainly intended for
2112 * language-bindings.
2117 gtk_list_store_insert_with_valuesv (GtkListStore *list_store,
2124 GtkListStorePrivate *priv;
2128 GtkTreeIter tmp_iter;
2130 gboolean changed = FALSE;
2131 gboolean maybe_need_sort = FALSE;
2133 /* FIXME refactor to reduce overlap with
2134 * gtk_list_store_insert_with_values()
2136 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
2138 priv = list_store->priv;
2143 priv->columns_dirty = TRUE;
2147 length = g_sequence_get_length (seq);
2148 if (position > length)
2151 ptr = g_sequence_get_iter_at_pos (seq, position);
2152 ptr = g_sequence_insert_before (ptr, NULL);
2154 iter->stamp = priv->stamp;
2155 iter->user_data = ptr;
2157 g_assert (VALID_ITER (iter, list_store));
2161 gtk_list_store_set_vector_internal (list_store, iter,
2162 &changed, &maybe_need_sort,
2163 columns, values, n_values);
2165 /* Don't emit rows_reordered here */
2166 if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
2167 g_sequence_sort_changed_iter (iter->user_data,
2168 gtk_list_store_compare_func,
2171 /* Just emit row_inserted */
2172 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
2173 gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter);
2174 gtk_tree_path_free (path);
2177 /* GtkBuildable custom tag implementation
2180 * <column type="..."/>
2181 * <column type="..."/>
2185 gboolean translatable;
2191 GtkBuilder *builder;
2193 GSList *column_type_names;
2194 GType *column_types;
2203 const gchar *domain;
2207 list_store_start_element (GMarkupParseContext *context,
2208 const gchar *element_name,
2209 const gchar **names,
2210 const gchar **values,
2215 SubParserData *data = (SubParserData*)user_data;
2217 if (strcmp (element_name, "col") == 0)
2220 gchar *context = NULL;
2221 gboolean translatable = FALSE;
2224 if (data->row_column >= data->n_columns)
2226 g_set_error (error, data->error_quark, 0,
2227 "Too many columns, maximum is %d\n", data->n_columns - 1);
2231 for (i = 0; names[i]; i++)
2232 if (strcmp (names[i], "id") == 0)
2235 id = atoi (values[i]);
2238 g_set_error (error, data->error_quark, 0,
2239 "the id tag %s could not be converted to an integer",
2243 if (id < 0 || id >= data->n_columns)
2245 g_set_error (error, data->error_quark, 0,
2246 "id value %d out of range", id);
2250 else if (strcmp (names[i], "translatable") == 0)
2252 if (!_gtk_builder_boolean_from_string (values[i], &translatable,
2256 else if (strcmp (names[i], "comments") == 0)
2258 /* do nothing, comments are for translators */
2260 else if (strcmp (names[i], "context") == 0)
2262 context = g_strdup (values[i]);
2267 g_set_error (error, data->error_quark, 0,
2268 "<col> needs an id attribute");
2272 info = g_slice_new0 (ColInfo);
2273 info->translatable = translatable;
2274 info->context = context;
2277 data->colids[data->row_column] = id;
2278 data->columns[data->row_column] = info;
2280 data->is_data = TRUE;
2282 else if (strcmp (element_name, "row") == 0)
2284 else if (strcmp (element_name, "column") == 0)
2285 for (i = 0; names[i]; i++)
2286 if (strcmp (names[i], "type") == 0)
2287 data->column_type_names = g_slist_prepend (data->column_type_names,
2288 g_strdup (values[i]));
2289 else if (strcmp (element_name, "columns") == 0)
2291 else if (strcmp (element_name, "data") == 0)
2294 g_set_error (error, data->error_quark, 0,
2295 "Unknown start tag: %s", element_name);
2299 list_store_end_element (GMarkupParseContext *context,
2300 const gchar *element_name,
2304 SubParserData *data = (SubParserData*)user_data;
2306 g_assert (data->builder);
2308 if (strcmp (element_name, "row") == 0)
2313 gtk_list_store_insert_with_valuesv (GTK_LIST_STORE (data->object),
2319 for (i = 0; i < data->row_column; i++)
2321 ColInfo *info = data->columns[i];
2322 g_free (info->context);
2323 g_slice_free (ColInfo, info);
2324 data->columns[i] = NULL;
2325 g_value_unset (&data->values[i]);
2327 g_free (data->values);
2328 data->values = g_new0 (GValue, data->n_columns);
2330 data->row_column = 0;
2332 else if (strcmp (element_name, "columns") == 0)
2334 GType *column_types;
2339 data->column_type_names = g_slist_reverse (data->column_type_names);
2340 column_types = g_new0 (GType, g_slist_length (data->column_type_names));
2342 for (l = data->column_type_names, i = 0; l; l = l->next, i++)
2344 type = gtk_builder_get_type_from_name (data->builder, l->data);
2345 if (type == G_TYPE_INVALID)
2347 g_warning ("Unknown type %s specified in treemodel %s",
2348 (const gchar*)l->data,
2349 gtk_buildable_get_name (GTK_BUILDABLE (data->object)));
2352 column_types[i] = type;
2357 gtk_list_store_set_column_types (GTK_LIST_STORE (data->object), i,
2360 g_free (column_types);
2362 else if (strcmp (element_name, "col") == 0)
2363 data->is_data = FALSE;
2364 else if (strcmp (element_name, "data") == 0)
2366 else if (strcmp (element_name, "column") == 0)
2369 g_set_error (error, data->error_quark, 0,
2370 "Unknown end tag: %s", element_name);
2374 list_store_text (GMarkupParseContext *context,
2380 SubParserData *data = (SubParserData*)user_data;
2382 GError *tmp_error = NULL;
2389 i = data->row_column - 1;
2390 info = data->columns[i];
2392 string = g_strndup (text, text_len);
2393 if (info->translatable && text_len)
2397 /* FIXME: This will not use the domain set in the .ui file,
2398 * since the parser is not telling the builder about the domain.
2399 * However, it will work for gtk_builder_set_translation_domain() calls.
2401 translated = _gtk_builder_parser_translate (data->domain,
2405 string = translated;
2408 if (!gtk_builder_value_from_string_type (data->builder,
2409 data->column_types[info->id],
2417 "Could not convert '%s' to type %s: %s\n",
2418 text, g_type_name (data->column_types[info->id]),
2419 tmp_error->message);
2420 g_error_free (tmp_error);
2425 static const GMarkupParser list_store_parser =
2427 list_store_start_element,
2428 list_store_end_element,
2433 gtk_list_store_buildable_custom_tag_start (GtkBuildable *buildable,
2434 GtkBuilder *builder,
2436 const gchar *tagname,
2437 GMarkupParser *parser,
2440 SubParserData *parser_data;
2445 if (strcmp (tagname, "columns") == 0)
2448 parser_data = g_slice_new0 (SubParserData);
2449 parser_data->builder = builder;
2450 parser_data->object = G_OBJECT (buildable);
2451 parser_data->column_type_names = NULL;
2453 *parser = list_store_parser;
2454 *data = parser_data;
2457 else if (strcmp (tagname, "data") == 0)
2459 gint n_columns = gtk_list_store_get_n_columns (GTK_TREE_MODEL (buildable));
2461 g_error ("Cannot append data to an empty model");
2463 parser_data = g_slice_new0 (SubParserData);
2464 parser_data->builder = builder;
2465 parser_data->object = G_OBJECT (buildable);
2466 parser_data->values = g_new0 (GValue, n_columns);
2467 parser_data->colids = g_new0 (gint, n_columns);
2468 parser_data->columns = g_new0 (ColInfo*, n_columns);
2469 parser_data->column_types = GTK_LIST_STORE (buildable)->priv->column_headers;
2470 parser_data->n_columns = n_columns;
2471 parser_data->last_row = 0;
2472 parser_data->error_quark = g_quark_from_static_string ("GtkListStore");
2473 parser_data->domain = gtk_builder_get_translation_domain (builder);
2475 *parser = list_store_parser;
2476 *data = parser_data;
2480 g_warning ("Unknown custom list store tag: %s", tagname);
2486 gtk_list_store_buildable_custom_tag_end (GtkBuildable *buildable,
2487 GtkBuilder *builder,
2489 const gchar *tagname,
2492 SubParserData *sub = (SubParserData*)data;
2494 if (strcmp (tagname, "columns") == 0)
2496 g_slist_free (sub->column_type_names);
2497 g_slice_free (SubParserData, sub);
2499 else if (strcmp (tagname, "data") == 0)
2502 for (i = 0; i < sub->n_columns; i++)
2504 ColInfo *info = sub->columns[i];
2507 g_free (info->context);
2508 g_slice_free (ColInfo, info);
2511 g_free (sub->colids);
2512 g_free (sub->columns);
2513 g_free (sub->values);
2514 g_slice_free (SubParserData, sub);
2517 g_warning ("Unknown custom list store tag: %s", tagname);