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.
21 #include "gtktreemodel.h"
22 #include "gtkliststore.h"
23 #include "gtktreedatalist.h"
24 #include "gtksignal.h"
25 #include <gobject/gvaluecollector.h>
27 #define G_SLIST(x) ((GSList *) x)
37 static guint list_store_signals[LAST_SIGNAL] = { 0 };
39 static void gtk_list_store_init (GtkListStore *list_store);
40 static void gtk_list_store_class_init (GtkListStoreClass *class);
41 static void gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
42 static guint gtk_list_store_get_flags (GtkTreeModel *tree_model);
43 static gint gtk_list_store_get_n_columns (GtkTreeModel *tree_model);
44 static GType gtk_list_store_get_column_type (GtkTreeModel *tree_model,
46 static gboolean gtk_list_store_get_iter (GtkTreeModel *tree_model,
49 static GtkTreePath *gtk_list_store_get_path (GtkTreeModel *tree_model,
51 static void gtk_list_store_get_value (GtkTreeModel *tree_model,
55 static gboolean gtk_list_store_iter_next (GtkTreeModel *tree_model,
57 static gboolean gtk_list_store_iter_children (GtkTreeModel *tree_model,
60 static gboolean gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
62 static gint gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
64 static gboolean gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
68 static gboolean gtk_list_store_iter_parent (GtkTreeModel *tree_model,
74 gtk_list_store_get_type (void)
76 static GtkType list_store_type = 0;
80 static const GTypeInfo list_store_info =
82 sizeof (GtkListStoreClass),
84 NULL, /* base_finalize */
85 (GClassInitFunc) gtk_list_store_class_init,
86 NULL, /* class_finalize */
87 NULL, /* class_data */
88 sizeof (GtkListStore),
90 (GInstanceInitFunc) gtk_list_store_init,
93 static const GInterfaceInfo tree_model_info =
95 (GInterfaceInitFunc) gtk_list_store_tree_model_init,
100 list_store_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkListStore", &list_store_info, 0);
101 g_type_add_interface_static (list_store_type,
106 return list_store_type;
110 gtk_list_store_class_init (GtkListStoreClass *class)
112 GtkObjectClass *object_class;
114 object_class = (GtkObjectClass*) class;
116 list_store_signals[CHANGED] =
117 gtk_signal_new ("changed",
119 GTK_CLASS_TYPE (object_class),
120 GTK_SIGNAL_OFFSET (GtkListStoreClass, changed),
121 gtk_marshal_VOID__BOXED_BOXED,
125 list_store_signals[INSERTED] =
126 gtk_signal_new ("inserted",
128 GTK_CLASS_TYPE (object_class),
129 GTK_SIGNAL_OFFSET (GtkListStoreClass, inserted),
130 gtk_marshal_VOID__BOXED_BOXED,
134 list_store_signals[CHILD_TOGGLED] =
135 gtk_signal_new ("child_toggled",
137 GTK_CLASS_TYPE (object_class),
138 GTK_SIGNAL_OFFSET (GtkListStoreClass, child_toggled),
139 gtk_marshal_VOID__BOXED_BOXED,
143 list_store_signals[DELETED] =
144 gtk_signal_new ("deleted",
146 GTK_CLASS_TYPE (object_class),
147 GTK_SIGNAL_OFFSET (GtkListStoreClass, deleted),
148 gtk_marshal_VOID__BOXED,
154 gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
156 iface->get_flags = gtk_list_store_get_flags;
157 iface->get_n_columns = gtk_list_store_get_n_columns;
158 iface->get_column_type = gtk_list_store_get_column_type;
159 iface->get_iter = gtk_list_store_get_iter;
160 iface->get_path = gtk_list_store_get_path;
161 iface->get_value = gtk_list_store_get_value;
162 iface->iter_next = gtk_list_store_iter_next;
163 iface->iter_children = gtk_list_store_iter_children;
164 iface->iter_has_child = gtk_list_store_iter_has_child;
165 iface->iter_n_children = gtk_list_store_iter_n_children;
166 iface->iter_nth_child = gtk_list_store_iter_nth_child;
167 iface->iter_parent = gtk_list_store_iter_parent;
171 gtk_list_store_init (GtkListStore *list_store)
173 list_store->root = NULL;
174 list_store->stamp = g_random_int ();
178 gtk_list_store_new (void)
180 return GTK_LIST_STORE (gtk_type_new (gtk_list_store_get_type ()));
184 gtk_list_store_new_with_types (gint n_columns,
187 GtkListStore *retval;
191 g_return_val_if_fail (n_columns > 0, NULL);
193 retval = gtk_list_store_new ();
194 gtk_list_store_set_n_columns (retval, n_columns);
196 va_start (args, n_columns);
198 for (i = 0; i < n_columns; i++)
199 gtk_list_store_set_column_type (retval, i, va_arg (args, GType));
207 gtk_list_store_set_n_columns (GtkListStore *list_store,
212 g_return_if_fail (list_store != NULL);
213 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
214 g_return_if_fail (n_columns > 0);
216 if (list_store->n_columns == n_columns)
219 new_columns = g_new0 (GType, n_columns);
220 if (list_store->column_headers)
222 /* copy the old header orders over */
223 if (n_columns >= list_store->n_columns)
224 memcpy (new_columns, list_store->column_headers, list_store->n_columns * sizeof (gchar *));
226 memcpy (new_columns, list_store->column_headers, n_columns * sizeof (GType));
228 g_free (list_store->column_headers);
231 list_store->column_headers = new_columns;
232 list_store->n_columns = n_columns;
236 gtk_list_store_set_column_type (GtkListStore *list_store,
240 g_return_if_fail (list_store != NULL);
241 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
242 g_return_if_fail (column >=0 && column < list_store->n_columns);
244 list_store->column_headers[column] = type;
247 /* Fulfill the GtkTreeModel requirements */
249 gtk_list_store_get_flags (GtkTreeModel *tree_model)
251 g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);
253 return GTK_TREE_MODEL_ITERS_PERSIST;
257 gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
259 g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);
261 return GTK_LIST_STORE (tree_model)->n_columns;
265 gtk_list_store_get_column_type (GtkTreeModel *tree_model,
268 g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), G_TYPE_INVALID);
269 g_return_val_if_fail (index < GTK_LIST_STORE (tree_model)->n_columns &&
270 index >= 0, G_TYPE_INVALID);
272 return GTK_LIST_STORE (tree_model)->column_headers[index];
276 gtk_list_store_get_iter (GtkTreeModel *tree_model,
280 g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
281 g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
283 iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
284 iter->user_data = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root),
285 gtk_tree_path_get_indices (path)[0]);
287 return iter->user_data != NULL;
291 gtk_list_store_get_path (GtkTreeModel *tree_model,
298 g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), NULL);
299 g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, NULL);
301 for (list = G_SLIST (GTK_LIST_STORE (tree_model)->root); list; list = list->next)
303 if (list == G_SLIST (iter->user_data))
310 retval = gtk_tree_path_new ();
311 gtk_tree_path_append_index (retval, i);
316 gtk_list_store_get_value (GtkTreeModel *tree_model,
321 GtkTreeDataList *list;
322 gint tmp_column = column;
324 g_return_if_fail (GTK_IS_LIST_STORE (tree_model));
325 g_return_if_fail (column < GTK_LIST_STORE (tree_model)->n_columns);
326 g_return_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp);
328 list = G_SLIST (iter->user_data)->data;
330 while (tmp_column-- > 0 && list)
334 g_value_init (value, GTK_LIST_STORE (tree_model)->column_headers[column]);
336 _gtk_tree_data_list_node_to_value (list,
337 GTK_LIST_STORE (tree_model)->column_headers[column],
342 gtk_list_store_iter_next (GtkTreeModel *tree_model,
345 g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
346 g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE);
348 iter->user_data = G_SLIST (iter->user_data)->next;
350 return (iter->user_data != NULL);
354 gtk_list_store_iter_children (GtkTreeModel *tree_model,
359 iter->user_data = NULL;
365 gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
372 gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
376 return g_slist_length (G_SLIST (GTK_LIST_STORE (tree_model)->root));
382 gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
387 g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
391 g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, FALSE);
393 iter->user_data = NULL;
398 iter->user_data = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root), n);
400 iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
404 return (iter->user_data != NULL);
408 gtk_list_store_iter_parent (GtkTreeModel *tree_model,
413 iter->user_data = NULL;
418 /* Public accessors */
419 /* This is a somewhat inelegant function that does a lot of list
420 * manipulations on it's own.
423 gtk_list_store_set_cell (GtkListStore *list_store,
428 GtkTreeDataList *list;
429 GtkTreeDataList *prev;
431 g_return_if_fail (list_store != NULL);
432 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
433 g_return_if_fail (iter != NULL);
434 g_return_if_fail (column >= 0 && column < list_store->n_columns);
436 prev = list = G_SLIST (iter->user_data)->data;
442 _gtk_tree_data_list_value_to_node (list, value);
443 gtk_signal_emit_by_name (GTK_OBJECT (list_store),
454 if (G_SLIST (iter->user_data)->data == NULL)
456 G_SLIST (iter->user_data)->data = list = _gtk_tree_data_list_alloc ();
461 list = prev->next = _gtk_tree_data_list_alloc ();
467 list->next = _gtk_tree_data_list_alloc ();
472 _gtk_tree_data_list_value_to_node (list, value);
473 gtk_signal_emit_by_name (GTK_OBJECT (list_store),
479 gtk_list_store_set_valist (GtkListStore *list_store,
485 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
487 column = va_arg (var_args, gint);
491 GValue value = { 0, };
494 if (column >= list_store->n_columns)
496 g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
499 g_value_init (&value, list_store->column_headers[column]);
501 G_VALUE_COLLECT (&value, var_args, &error);
504 g_warning ("%s: %s", G_STRLOC, error);
507 /* we purposely leak the value here, it might not be
508 * in a sane state if an error condition occoured
513 gtk_list_store_set_cell (list_store,
518 g_value_unset (&value);
520 column = va_arg (var_args, gint);
525 * gtk_list_store_set:
526 * @list_store: a #GtkListStore
527 * @iter: row iterator
528 * @Varargs: pairs of column number and value, terminated with -1
530 * Sets the value of one or more cells in the row referenced by @iter.
531 * The variable argument list should contain integer column numbers,
532 * each column number followed by the value to be set. For example,
533 * The list is terminated by a -1. For example, to set column 0 with type
534 * %G_TYPE_STRING to "Foo", you would write gtk_list_store_set (store, iter,
538 gtk_list_store_set (GtkListStore *list_store,
544 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
546 va_start (var_args, iter);
547 gtk_list_store_set_valist (list_store, iter, var_args);
552 gtk_list_store_get_valist (GtkListStore *list_store,
558 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
560 column = va_arg (var_args, gint);
564 GValue value = { 0, };
567 if (column >= list_store->n_columns)
569 g_warning ("%s: Invalid column number %d accessed (remember to end your list of columns with a -1)", G_STRLOC, column);
573 gtk_list_store_get_value (GTK_TREE_MODEL (list_store), iter, column, &value);
575 G_VALUE_LCOPY (&value, var_args, &error);
578 g_warning ("%s: %s", G_STRLOC, error);
581 /* we purposely leak the value here, it might not be
582 * in a sane state if an error condition occoured
587 g_value_unset (&value);
589 column = va_arg (var_args, gint);
594 gtk_list_store_get (GtkListStore *list_store,
600 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
602 va_start (var_args, iter);
603 gtk_list_store_get_valist (list_store, iter, var_args);
608 gtk_list_store_remove (GtkListStore *list_store,
613 g_return_if_fail (list_store != NULL);
614 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
616 if (G_SLIST (iter->user_data)->data)
617 _gtk_tree_data_list_free ((GtkTreeDataList *) G_SLIST (iter->user_data)->data,
618 list_store->column_headers);
620 path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
621 list_store->root = g_slist_remove_link (G_SLIST (list_store->root),
622 G_SLIST (iter->user_data));
623 list_store->stamp ++;
624 gtk_signal_emit_by_name (GTK_OBJECT (list_store),
627 gtk_tree_path_free (path);
631 gtk_list_store_insert (GtkListStore *list_store,
638 g_return_if_fail (list_store != NULL);
639 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
640 g_return_if_fail (iter != NULL);
641 g_return_if_fail (position < 0);
645 gtk_list_store_prepend (list_store, iter);
649 iter->stamp = list_store->stamp;
650 iter->user_data = g_slist_alloc ();
652 list = g_slist_nth (G_SLIST (list_store->root), position - 1);
655 G_SLIST (iter->user_data)->next = list->next;
656 list->next = G_SLIST (iter->user_data)->next;
658 path = gtk_tree_path_new ();
659 gtk_tree_path_append_index (path, position);
660 gtk_signal_emit_by_name (GTK_OBJECT (list_store),
663 gtk_tree_path_free (path);
667 gtk_list_store_insert_before (GtkListStore *list_store,
669 GtkTreeIter *sibling)
675 g_return_if_fail (list_store != NULL);
676 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
677 g_return_if_fail (iter != NULL);
678 g_return_if_fail (G_SLIST (iter)->next == NULL);
682 gtk_list_store_append (list_store, iter);
686 iter->stamp = list_store->stamp;
687 iter->user_data = g_slist_alloc ();
689 prev = list = list_store->root;
690 while (list && list != sibling->user_data)
699 prev->next = iter->user_data;
703 G_SLIST (iter->user_data)->next = list_store->root;
704 list_store->root = iter->user_data;
707 path = gtk_tree_path_new ();
708 gtk_tree_path_append_index (path, i);
709 gtk_signal_emit_by_name (GTK_OBJECT (list_store),
712 gtk_tree_path_free (path);
716 gtk_list_store_insert_after (GtkListStore *list_store,
718 GtkTreeIter *sibling)
724 g_return_if_fail (list_store != NULL);
725 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
726 g_return_if_fail (iter == NULL);
728 g_return_if_fail (sibling->stamp == list_store->stamp);
732 gtk_list_store_prepend (list_store, iter);
736 for (list = list_store->root; list && list != sibling->user_data; list = list->next)
739 g_return_if_fail (list != NULL);
741 iter->stamp = list_store->stamp;
742 iter->user_data = g_slist_alloc ();
744 G_SLIST (iter->user_data)->next = G_SLIST (sibling->user_data)->next;
745 G_SLIST (sibling)->next = G_SLIST (iter);
747 path = gtk_tree_path_new ();
748 gtk_tree_path_append_index (path, i);
749 gtk_signal_emit_by_name (GTK_OBJECT (list_store),
752 gtk_tree_path_free (path);
756 gtk_list_store_prepend (GtkListStore *list_store,
761 g_return_if_fail (list_store != NULL);
762 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
763 g_return_if_fail (iter != NULL);
765 iter->stamp = list_store->stamp;
766 iter->user_data = g_slist_alloc ();
768 G_SLIST (iter->user_data)->next = G_SLIST (list_store->root);
769 list_store->root = iter->user_data;
771 path = gtk_tree_path_new ();
772 gtk_tree_path_append_index (path, 0);
773 gtk_signal_emit_by_name (GTK_OBJECT (list_store),
776 gtk_tree_path_free (path);
780 gtk_list_store_append (GtkListStore *list_store,
787 g_return_if_fail (list_store != NULL);
788 g_return_if_fail (GTK_IS_LIST_STORE (list_store));
789 g_return_if_fail (iter != NULL);
791 iter->stamp = list_store->stamp;
792 iter->user_data = g_slist_alloc ();
794 prev = list = list_store->root;
803 prev->next = iter->user_data;
805 list_store->root = iter->user_data;
807 path = gtk_tree_path_new ();
808 gtk_tree_path_append_index (path, i);
809 gtk_signal_emit_by_name (GTK_OBJECT (list_store),
812 gtk_tree_path_free (path);