diff options
author | Jonathan Blandford <jrb@redhat.com> | 2000-11-09 16:52:17 +0000 |
---|---|---|
committer | Jonathan Blandford <jrb@src.gnome.org> | 2000-11-09 16:52:17 +0000 |
commit | c97d57ebb8ceae99ed77fc6d953470e01d74310a (patch) | |
tree | 78786db0c79bbf6692d68833d469e5d5b601a0cb /gtk | |
parent | 8898529c12e0d2d4a5dd4e3b9917a6a1272f4882 (diff) | |
download | gdk-pixbuf-c97d57ebb8ceae99ed77fc6d953470e01d74310a.tar.gz |
added more fields to allow more interesting iterators. Also, made the
Thu Nov 9 11:23:22 2000 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreemodel.h (struct _GtkTreeIter): added more fields to
allow more interesting iterators. Also, made the lifecycle of
iterators more explicit.
* gtk/gtktreemodelsort.[ch]: New model for sorting.
* gtk/gtk-boxed.defs (GtkTreeIter, GtkTreePath): Added two boxed
types.
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/Makefile.am | 2 | ||||
-rw-r--r-- | gtk/gtk-boxed.defs | 9 | ||||
-rw-r--r-- | gtk/gtk.h | 1 | ||||
-rw-r--r-- | gtk/gtkliststore.c | 15 | ||||
-rw-r--r-- | gtk/gtktreemodel.c | 144 | ||||
-rw-r--r-- | gtk/gtktreemodel.h | 26 | ||||
-rw-r--r-- | gtk/gtktreemodelsort.c | 897 | ||||
-rw-r--r-- | gtk/gtktreemodelsort.h | 94 | ||||
-rw-r--r-- | gtk/gtktreeselection.c | 13 | ||||
-rw-r--r-- | gtk/gtktreeselection.h | 1 | ||||
-rw-r--r-- | gtk/gtktreestore.c | 33 | ||||
-rw-r--r-- | gtk/gtktreeview.c | 4 | ||||
-rw-r--r-- | gtk/gtktreeviewcolumn.c | 17 | ||||
-rw-r--r-- | gtk/gtktreeviewcolumn.h | 84 | ||||
-rw-r--r-- | gtk/treestoretest.c | 20 |
15 files changed, 1280 insertions, 80 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am index f4eaa8925..e05b165c0 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -171,6 +171,7 @@ gtk_public_h_sources = @STRIP_BEGIN@ \ gtktree.h \ gtktreeitem.h \ gtktreemodel.h \ + gtktreemodelsort.h \ gtktreeselection.h \ gtktreestore.h \ gtktreeview.h \ @@ -329,6 +330,7 @@ gtk_c_sources = @STRIP_BEGIN@ \ gtktreeitem.c \ gtktreedatalist.c \ gtktreemodel.c \ + gtktreemodelsort.c \ gtktreeselection.c \ gtktreestore.c \ gtktreeview.c \ diff --git a/gtk/gtk-boxed.defs b/gtk/gtk-boxed.defs index 27a3e8733..b21c10498 100644 --- a/gtk/gtk-boxed.defs +++ b/gtk/gtk-boxed.defs @@ -1286,6 +1286,15 @@ gtk_text_iter_copy gtk_text_iter_free) +;; TreeView +(define-boxed GtkTreeIter + gtk_tree_iter_copy + gtk_tree_iter_free) + +(define-boxed GtkTreePath + gtk_tree_path_copy + gtk_tree_path_free) + ;; Alignment (define-object GtkAlignment (GtkBin)) @@ -141,6 +141,7 @@ #include <gtk/gtktree.h> #include <gtk/gtktreeitem.h> #include <gtk/gtktreemodel.h> +#include <gtk/gtktreemodelsort.h> #include <gtk/gtktreeselection.h> #include <gtk/gtktreestore.h> #include <gtk/gtktreeview.h> diff --git a/gtk/gtkliststore.c b/gtk/gtkliststore.c index 032241cf3..c50974b4e 100644 --- a/gtk/gtkliststore.c +++ b/gtk/gtkliststore.c @@ -38,6 +38,7 @@ static guint list_store_signals[LAST_SIGNAL] = { 0 }; static void gtk_list_store_init (GtkListStore *list_store); static void gtk_list_store_class_init (GtkListStoreClass *class); static void gtk_list_store_tree_model_init (GtkTreeModelIface *iface); +static guint gtk_list_store_get_flags (GtkTreeModel *tree_model); static gint gtk_list_store_get_n_columns (GtkTreeModel *tree_model); static gboolean gtk_list_store_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, @@ -152,6 +153,7 @@ gtk_list_store_class_init (GtkListStoreClass *class) static void gtk_list_store_tree_model_init (GtkTreeModelIface *iface) { + iface->get_flags = gtk_list_store_get_flags; iface->get_n_columns = gtk_list_store_get_n_columns; iface->get_iter = gtk_list_store_get_iter; iface->get_path = gtk_list_store_get_path; @@ -168,7 +170,7 @@ static void gtk_list_store_init (GtkListStore *list_store) { list_store->root = NULL; - list_store->stamp = 1; + list_store->stamp = g_random_int (); } GtkListStore * @@ -242,6 +244,14 @@ gtk_list_store_set_column_type (GtkListStore *list_store, } /* Fulfill the GtkTreeModel requirements */ +static guint +gtk_list_store_get_flags (GtkTreeModel *tree_model) +{ + g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0); + + return GTK_TREE_MODEL_ITERS_PERSIST; +} + static gint gtk_list_store_get_n_columns (GtkTreeModel *tree_model) { @@ -350,6 +360,9 @@ static gint gtk_list_store_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter) { + if (iter == NULL) + return g_slist_length (G_SLIST (GTK_LIST_STORE (tree_model)->root)); + return 0; } diff --git a/gtk/gtktreemodel.c b/gtk/gtktreemodel.c index af752dfd6..ef3f05c65 100644 --- a/gtk/gtktreemodel.c +++ b/gtk/gtktreemodel.c @@ -260,7 +260,7 @@ gtk_tree_path_free (GtkTreePath *path) * gtk_tree_path_copy: * @path: A #GtkTreePath. * - * Creates a new #GtkTreePath based upon @path. + * Creates a new #GtkTreePath as a copy of @path. * * Return value: A new #GtkTreePath. **/ @@ -381,6 +381,69 @@ gtk_tree_path_down (GtkTreePath *path) gtk_tree_path_append_index (path, 0); } + +/** + * gtk_tree_iter_copy: + * @iter: A #GtkTreeIter. + * + * Creates a dynamically allocated tree iterator as a copy of @iter. This + * function is not intended for use in applications, because you can just copy + * the structs by value (<literal>GtkTreeIter new_iter = iter;</literal>). You + * must free this iter with gtk_tree_iter_free (). + * + * Return value: a newly allocated copy of @iter. + **/ +GtkTreeIter * +gtk_tree_iter_copy (GtkTreeIter *iter) +{ + GtkTreeIter *retval; + + g_return_val_if_fail (iter != NULL, NULL); + + retval = g_new (GtkTreeIter, 1); + *retval = *iter; + + return retval; +} + +/** + * gtk_tree_iter_free: + * @iter: A dynamically allocated tree iterator. + * + * Free an iterator that has been allocated on the heap. This function is + * mainly used for language bindings. + **/ +void +gtk_tree_iter_free (GtkTreeIter *iter) +{ + g_return_if_fail (iter != NULL); + + g_free (iter); + +} + +/** + * gtk_tree_model_get_flags: + * @tree_model: A #GtkTreeModel. + * + * Returns a list of flags supported by this interface. The flags are a bitwise + * combination of #GtkTreeModelFlags. It is expected that the flags supported + * do not change for an interface. + * + * Return value: The flags supported by this interface. + **/ +guint +gtk_tree_model_get_flags (GtkTreeModel *tree_model) +{ + g_return_val_if_fail (tree_model != NULL, 0); + g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), 0); + + if (GTK_TREE_MODEL_GET_IFACE (tree_model)->get_flags) + return (GTK_TREE_MODEL_GET_IFACE (tree_model)->get_flags) (tree_model); + + return 0; +} + /** * gtk_tree_model_get_n_columns: * @tree_model: A #GtkTreeModel. @@ -400,6 +463,27 @@ gtk_tree_model_get_n_columns (GtkTreeModel *tree_model) } /** + * gtk_tree_model_get_column_type: + * @tree_model: A #GtkTreeModel. + * @index: The column index. + * + * Returns the type of the column. + * + * Return value: The type of the column. + **/ +GType +gtk_tree_model_get_column_type (GtkTreeModel *tree_model, + gint index) +{ + g_return_val_if_fail (tree_model != NULL, G_TYPE_INVALID); + g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), G_TYPE_INVALID); + g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->get_column_type != NULL, G_TYPE_INVALID); + g_return_val_if_fail (index >= 0, G_TYPE_INVALID); + + return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->get_column_type) (tree_model, index); +} + +/** * gtk_tree_model_get_iter: * @tree_model: A #GtkTreeModel. * @iter: The uninitialized #GtkTreeIter. @@ -564,9 +648,10 @@ gtk_tree_model_iter_has_child (GtkTreeModel *tree_model, /** * gtk_tree_model_iter_n_children: * @tree_model: A #GtkTreeModel. - * @iter: The #GtkTreeIter. + * @iter: The #GtkTreeIter, or NULL. * - * Returns the number of children that @iter has. + * Returns the number of children that @iter has. If @iter is NULL, then the + * number of toplevel nodes is returned. * * Return value: The number of children of @iter. **/ @@ -576,7 +661,6 @@ gtk_tree_model_iter_n_children (GtkTreeModel *tree_model, { g_return_val_if_fail (tree_model != NULL, 0); g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), 0); - g_return_val_if_fail (iter != NULL, 0); g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_n_children != NULL, 0); return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_n_children) (tree_model, iter); @@ -589,10 +673,11 @@ gtk_tree_model_iter_n_children (GtkTreeModel *tree_model, * @parent: The #GtkTreeIter to get the child from, or NULL. * @n: Then index of the desired child. * - * Sets @iter to be the child of @parent, using the given index. The first index - * is 0. If the index is too big, or @parent has no children, @iter is set to an - * invalid iterator and FALSE is returned. @parent will remain a valid node after - * this function has been called. If @parent is NULL, then the root node is assumed. + * Sets @iter to be the child of @parent, using the given index. The first + * index is 0. If the index is too big, or @parent has no children, @iter is + * set to an invalid iterator and FALSE is returned. @parent will remain a + * valid node after this function has been called. If @parent is NULL, then the + * root node is assumed. * * Return value: TRUE, if @parent has an nth child. **/ @@ -629,8 +714,51 @@ gtk_tree_model_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) { + g_return_val_if_fail (tree_model != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (child != NULL, FALSE); g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_parent != NULL, FALSE); return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_parent) (tree_model, iter, child); } +/** + * gtk_tree_model_ref_iter: + * @tree_model: A #GtkTreeModel. + * @iter: The #GtkTreeIter. + * + * Ref's the iter. This is an optional method for models to implement. To be + * more specific, models may ignore this call as it exists primarily for + * performance reasons. + **/ +void +gtk_tree_model_ref_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + g_return_if_fail (tree_model != NULL); + g_return_if_fail (GTK_IS_TREE_MODEL (tree_model)); + + if (GTK_TREE_MODEL_GET_IFACE (tree_model)->ref_iter) + (* GTK_TREE_MODEL_GET_IFACE (tree_model)->ref_iter) (tree_model, iter); +} + +/** + * gtk_tree_model_unref_iter: + * @tree_model: A #GtkTreeModel. + * @iter: The #GtkTreeIter. + * + * Unref's the iter. This is an optional method for models to implement. To be + * more specific, models may ignore this call as it exists primarily for + * performance reasons. + **/ +void +gtk_tree_model_unref_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + g_return_if_fail (tree_model != NULL); + g_return_if_fail (GTK_IS_TREE_MODEL (tree_model)); + + if (GTK_TREE_MODEL_GET_IFACE (tree_model)->unref_iter) + (* GTK_TREE_MODEL_GET_IFACE (tree_model)->unref_iter) (tree_model, iter); +} diff --git a/gtk/gtktreemodel.h b/gtk/gtktreemodel.h index fce77d607..ec5ba2b28 100644 --- a/gtk/gtktreemodel.h +++ b/gtk/gtktreemodel.h @@ -37,10 +37,18 @@ typedef struct _GtkTreePath GtkTreePath; typedef struct _GtkTreeModel GtkTreeModel; /* Dummy typedef */ typedef struct _GtkTreeModelIface GtkTreeModelIface; + +typedef enum +{ + GTK_TREE_MODEL_ITERS_PERSIST = 1 << 0 +} GtkTreeModelFlags; + struct _GtkTreeIter { gint stamp; gpointer tree_node; + gpointer tree_node2; + gpointer tree_node3; }; struct _GtkTreeModelIface @@ -65,6 +73,7 @@ struct _GtkTreeModelIface GtkTreePath *path); /* VTable - not signals */ + guint (* get_flags) (GtkTreeModel *tree_model); gint (* get_n_columns) (GtkTreeModel *tree_model); GType (* get_column_type) (GtkTreeModel *tree_model, gint index); @@ -93,10 +102,14 @@ struct _GtkTreeModelIface gboolean (* iter_parent) (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child); + void (* ref_iter) (GtkTreeModel *tree_model, + GtkTreeIter *iter); + void (* unref_iter) (GtkTreeModel *tree_model, + GtkTreeIter *iter); }; -/* Path operations */ +/* GtkTreePath operations */ GtkTreePath *gtk_tree_path_new (void); GtkTreePath *gtk_tree_path_new_from_string (gchar *path); gchar *gtk_tree_path_to_string (GtkTreePath *path); @@ -117,9 +130,13 @@ gint gtk_tree_path_up (GtkTreePath *path); void gtk_tree_path_down (GtkTreePath *path); +/* GtkTreeIter operations */ +GtkTreeIter *gtk_tree_iter_copy (GtkTreeIter *iter); +void gtk_tree_iter_free (GtkTreeIter *iter); + /* GtkTreeModel stuff */ GtkType gtk_tree_model_get_type (void) G_GNUC_CONST; - +guint gtk_tree_model_get_flags (GtkTreeModel *tree_model); /* Column information */ gint gtk_tree_model_get_n_columns (GtkTreeModel *tree_model); @@ -153,7 +170,10 @@ gboolean gtk_tree_model_iter_nth_child (GtkTreeModel *tree_model, gboolean gtk_tree_model_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child); - +void gtk_tree_model_ref_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter); +void gtk_tree_model_unref_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter); #ifdef __cplusplus } diff --git a/gtk/gtktreemodelsort.c b/gtk/gtktreemodelsort.c new file mode 100644 index 000000000..608aeb84f --- /dev/null +++ b/gtk/gtktreemodelsort.c @@ -0,0 +1,897 @@ +/* gtktreemodelsort.c + * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gtktreemodelsort.h" +#include "gtksignal.h" + +enum { + CHANGED, + INSERTED, + CHILD_TOGGLED, + DELETED, + LAST_SIGNAL +}; + +typedef struct _SortElt SortElt; +struct _SortElt +{ + GtkTreeIter iter; + SortElt *parent; + GArray *children; + gint ref; + gint offset; +}; + +static guint tree_model_sort_signals[LAST_SIGNAL] = { 0 }; + + +#define get_array(e,t) ((GArray *)((e)->parent?(e)->parent->children:GTK_TREE_MODEL_SORT(t)->root)) + +static void gtk_tree_model_sort_init (GtkTreeModelSort *tree_model_sort); +static void gtk_tree_model_sort_class_init (GtkTreeModelSortClass *tree_model_sort_class); +static void gtk_tree_model_sort_tree_model_init (GtkTreeModelIface *iface); +static void gtk_tree_model_sort_finalize (GObject *object); +static void gtk_tree_model_sort_changed (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data); +static void gtk_tree_model_sort_inserted (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data); +static void gtk_tree_model_sort_child_toggled (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data); +static void gtk_tree_model_sort_deleted (GtkTreeModel *model, + GtkTreePath *path, + gpointer data); +static gint gtk_tree_model_sort_get_n_columns (GtkTreeModel *tree_model); +static GType gtk_tree_model_sort_get_column_type (GtkTreeModel *tree_model, + gint index); +static gboolean gtk_tree_model_sort_get_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreePath *path); +static GtkTreePath *gtk_tree_model_sort_get_path (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static void gtk_tree_model_sort_get_value (GtkTreeModel *tree_model, + GtkTreeIter *iter, + gint column, + GValue *value); +static gboolean gtk_tree_model_sort_iter_next (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gboolean gtk_tree_model_sort_iter_children (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent); +static gboolean gtk_tree_model_sort_iter_has_child (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gint gtk_tree_model_sort_iter_n_children (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gboolean gtk_tree_model_sort_iter_nth_child (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n); +static gboolean gtk_tree_model_sort_iter_parent (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *child); +static void gtk_tree_model_sort_ref_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static void gtk_tree_model_sort_unref_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter); + +/* Internal functions */ +static void gtk_tree_model_sort_build_level (GtkTreeModelSort *tree_model_sort, + SortElt *place); +static void gtk_tree_model_sort_free_level (GArray *array); +gint g_value_string_compare_func (const GValue *a, + const GValue *b); +gint g_value_int_compare_func (const GValue *a, + const GValue *b); + + +GtkType +gtk_tree_model_sort_get_type (void) +{ + static GtkType tree_model_sort_type = 0; + + if (!tree_model_sort_type) + { + static const GTypeInfo tree_model_sort_info = + { + sizeof (GtkTreeModelSortClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) gtk_tree_model_sort_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GtkTreeModelSort), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_tree_model_sort_init + }; + + static const GInterfaceInfo tree_model_info = + { + (GInterfaceInitFunc) gtk_tree_model_sort_tree_model_init, + NULL, + NULL + }; + + tree_model_sort_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkTreeModelSort", &tree_model_sort_info, 0); + g_type_add_interface_static (tree_model_sort_type, + GTK_TYPE_TREE_MODEL, + &tree_model_info); + } + + return tree_model_sort_type; +} + +static void +gtk_tree_model_sort_class_init (GtkTreeModelSortClass *tree_model_sort_class) +{ + GObjectClass *object_class; + + object_class = (GObjectClass *) tree_model_sort_class; + + tree_model_sort_signals[CHANGED] = + gtk_signal_new ("changed", + GTK_RUN_FIRST, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkTreeModelSortClass, changed), + gtk_marshal_VOID__POINTER_POINTER, + GTK_TYPE_NONE, 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); + tree_model_sort_signals[INSERTED] = + gtk_signal_new ("inserted", + GTK_RUN_FIRST, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkTreeModelSortClass, inserted), + gtk_marshal_VOID__POINTER_POINTER, + GTK_TYPE_NONE, 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); + tree_model_sort_signals[CHILD_TOGGLED] = + gtk_signal_new ("child_toggled", + GTK_RUN_FIRST, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkTreeModelSortClass, child_toggled), + gtk_marshal_VOID__POINTER_POINTER, + GTK_TYPE_NONE, 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); + tree_model_sort_signals[DELETED] = + gtk_signal_new ("deleted", + GTK_RUN_FIRST, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkTreeModelSortClass, deleted), + gtk_marshal_VOID__POINTER, + GTK_TYPE_NONE, 1, + GTK_TYPE_POINTER); + + object_class->finalize = gtk_tree_model_sort_finalize; + + gtk_object_class_add_signals (GTK_OBJECT_CLASS (object_class), tree_model_sort_signals, LAST_SIGNAL); +} + +static void +gtk_tree_model_sort_tree_model_init (GtkTreeModelIface *iface) +{ + iface->get_n_columns = gtk_tree_model_sort_get_n_columns; + iface->get_column_type = gtk_tree_model_sort_get_column_type; + iface->get_iter = gtk_tree_model_sort_get_iter; + iface->get_path = gtk_tree_model_sort_get_path; + iface->get_value = gtk_tree_model_sort_get_value; + iface->iter_next = gtk_tree_model_sort_iter_next; + iface->iter_children = gtk_tree_model_sort_iter_children; + iface->iter_has_child = gtk_tree_model_sort_iter_has_child; + iface->iter_n_children = gtk_tree_model_sort_iter_n_children; + iface->iter_nth_child = gtk_tree_model_sort_iter_nth_child; + iface->iter_parent = gtk_tree_model_sort_iter_parent; + iface->ref_iter = gtk_tree_model_sort_ref_iter; + iface->unref_iter = gtk_tree_model_sort_unref_iter; +} + +static void +gtk_tree_model_sort_init (GtkTreeModelSort *tree_model_sort) +{ + tree_model_sort->stamp = g_random_int (); +} + +GtkTreeModel * +gtk_tree_model_sort_new (void) +{ + return GTK_TREE_MODEL (gtk_type_new (gtk_tree_model_sort_get_type ())); +} + +GtkTreeModel * +gtk_tree_model_sort_new_with_model (GtkTreeModel *model, + GValueCompareFunc *func, + gint sort_col) +{ + GtkTreeModel *retval; + + retval = gtk_tree_model_sort_new (); + gtk_tree_model_sort_set_model (GTK_TREE_MODEL_SORT (retval), model); + + GTK_TREE_MODEL_SORT (retval)->func = func; + GTK_TREE_MODEL_SORT (retval)->sort_col = sort_col; + return retval; +} + +/** + * gtk_tree_model_sort_set_model: + * @tree_model_sort: The #GtkTreeModelSort. + * @model: A #GtkTreeModel, or NULL. + * + * Sets the model of @tree_model_sort to be @model. If @model is NULL, then the + * old model is unset. + **/ +void +gtk_tree_model_sort_set_model (GtkTreeModelSort *tree_model_sort, + GtkTreeModel *model) +{ + g_return_if_fail (tree_model_sort != NULL); + g_return_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model_sort)); + + if (model) + g_object_ref (G_OBJECT (model)); + + if (tree_model_sort->model) + { + gtk_signal_disconnect_by_func (GTK_OBJECT (tree_model_sort->model), + gtk_tree_model_sort_changed, + tree_model_sort); + gtk_signal_disconnect_by_func (GTK_OBJECT (tree_model_sort->model), + gtk_tree_model_sort_inserted, + tree_model_sort); + gtk_signal_disconnect_by_func (GTK_OBJECT (tree_model_sort->model), + gtk_tree_model_sort_child_toggled, + tree_model_sort); + gtk_signal_disconnect_by_func (GTK_OBJECT (tree_model_sort->model), + gtk_tree_model_sort_deleted, + tree_model_sort); + + g_object_unref (G_OBJECT (tree_model_sort->model)); + } + + tree_model_sort->model = model; + + if (model) + { + gtk_signal_connect (GTK_OBJECT (model), + "changed", + gtk_tree_model_sort_changed, + tree_model_sort); + gtk_signal_connect (GTK_OBJECT (model), + "inserted", + gtk_tree_model_sort_inserted, + tree_model_sort); + gtk_signal_connect (GTK_OBJECT (model), + "child_toggled", + gtk_tree_model_sort_child_toggled, + tree_model_sort); + gtk_signal_connect (GTK_OBJECT (model), + "deleted", + gtk_tree_model_sort_deleted, + tree_model_sort); + + tree_model_sort->flags = gtk_tree_model_get_flags (model); + } +} + +/** + * gtk_tree_model_sort_convert_path: + * @tree_model_sort: The #GtkTreeModelSort. + * @path: A #GtkTreePath, relative to the @tree_model_sort 's model. + * + * Converts the @path to a new path, relative to the sorted position. In other + * words, the value found in the @tree_model_sort ->model at the @path, is + * identical to that found in the @tree_model_sort and the return value. + * + * Return value: A new path, or NULL if @path does not exist in @tree_model_sort + * ->model. + **/ +GtkTreePath * +gtk_tree_model_sort_convert_path (GtkTreeModelSort *tree_model_sort, + GtkTreePath *path) +{ + GtkTreePath *retval; + GArray *array; + gint *indices; + gint i = 0; + + if (tree_model_sort->root == NULL) + gtk_tree_model_sort_build_level (tree_model_sort, NULL); + + retval = gtk_tree_path_new (); + array = (GArray *) tree_model_sort->root; + indices = gtk_tree_path_get_indices (path); + + do + { + SortElt *elt; + gboolean found = FALSE; + gint j; + + if ((array->len < indices[i]) || (array == NULL)) + { + gtk_tree_path_free (path); + return NULL; + } + + elt = (SortElt *) array->data; + for (j = 0; j < array->len; j++, elt++) + { + if (elt->offset == indices[i]) + { + found = TRUE; + break; + } + } + if (! found) + { + gtk_tree_path_free (path); + return NULL; + } + + gtk_tree_path_prepend_index (retval, j); + if (elt->children == NULL) + gtk_tree_model_sort_build_level (tree_model_sort, elt); + i++; + } + while (i < gtk_tree_path_get_depth (path)); + + return retval; +} + +static void +gtk_tree_model_sort_finalize (GObject *object) +{ + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) object; + + if (tree_model_sort->root) + gtk_tree_model_sort_free_level (tree_model_sort->root); + + g_object_unref (G_OBJECT (tree_model_sort->model)); +} + +static void +gtk_tree_model_sort_changed (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GtkTreeModelSort *tree_model_sort = GTK_TREE_MODEL_SORT (data); + GtkTreePath *local_path; + GtkTreeIter local_iter; + + g_return_if_fail (path != NULL || iter != NULL); + + if (path == NULL) + path = gtk_tree_model_get_path (model, iter); + + local_path = gtk_tree_model_sort_convert_path (tree_model_sort, path); + gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &local_iter, local_path); + gtk_signal_emit_by_name (GTK_OBJECT (data), + "changed", + local_path, + &local_iter); + gtk_tree_path_free (local_path); +} + +#if 0 +static void +gtk_tree_model_sort_insert_value (GtkTreeModelSort *sort, + GtkTreeIter *old_iter, + GtkTreePath *path) +{ + GtkTreePath *parent_path; + GArray *array; + GtkTreeIter iter; + SortElt new_elt; + SortElt *tmp_elt; + gint high, low, middle; + GValueCompareFunc *func; + GValue tmp_value = {0, }; + GValue old_value = {0, }; + + parent_path = gtk_tree_path_copy (path); + gtk_tree_path_up (parent_path); + gtk_tree_model_get_iter (GTK_TREE_MODEL (sort), + &iter, + parent_path); + gtk_tree_path_free (parent_path); + array = ((SortElt *) iter.tree_node)->children; + + if (sort->func) + func = sort->func; + else + { + switch (gtk_tree_model_get_column_type (sort->model, sort->sort_col)) + { + case G_TYPE_STRING: + func = &g_value_string_compare_func; + break; + case G_TYPE_INT: + func = &g_value_int_compare_func; + break; + default: + g_warning ("No comparison function for row %d\n", sort->sort_col); + return; + } + } + + new_elt.iter = iter; + new_elt.ref = 0; + new_elt.parent = ((SortElt *) iter.tree_node); + new_elt.children = NULL; + + last = 0; + j = array->len/2; + while (1) + { + gint cmp; + tmp_elt = &(g_array_index (array, SortElt, j)); + gtk_tree_model_get_value (sort->model, tmp_elt, sort->sort_col, &tmp_value); + + cmp = ((func) (&tmp_value, value)); + if (retval < 0) + ; + else if (retval == 0) + g_array_insert_vals + ; + else if (retval > 0) + ; + } +} +#endif + +static void +gtk_tree_model_sort_inserted (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GtkTreeModelSort *tree_model_sort = GTK_TREE_MODEL_SORT (data); + GtkTreePath *local_path; + GtkTreeIter local_iter; + GValue value; + + g_return_if_fail (path != NULL || iter != NULL); + + if (!(tree_model_sort->flags & GTK_TREE_MODEL_ITERS_PERSIST) && + (tree_model_sort->root != NULL)) + { + gtk_tree_model_sort_free_level ((GArray *)tree_model_sort->root); + tree_model_sort->root = NULL; + } + + if (path == NULL) + path = gtk_tree_model_get_path (model, iter); + + local_path = gtk_tree_model_sort_convert_path (tree_model_sort, path); + gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &local_iter, local_path); + gtk_signal_emit_by_name (GTK_OBJECT (data), + "inserted", + local_path, + &local_iter); + gtk_tree_path_free (local_path); +} + +static void +gtk_tree_model_sort_child_toggled (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GtkTreeModelSort *tree_model_sort = GTK_TREE_MODEL_SORT (data); + GtkTreePath *local_path; + GtkTreeIter local_iter; + + g_return_if_fail (path != NULL || iter != NULL); + + if (!(tree_model_sort->flags & GTK_TREE_MODEL_ITERS_PERSIST) && + (tree_model_sort->root != NULL)) + { + gtk_tree_model_sort_free_level ((GArray *)tree_model_sort->root); + tree_model_sort->root = NULL; + } + + if (path == NULL) + path = gtk_tree_model_get_path (model, iter); + + local_path = gtk_tree_model_sort_convert_path (tree_model_sort, path); + gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &local_iter, local_path); + gtk_signal_emit_by_name (GTK_OBJECT (data), + "child_toggled", + local_path, + &local_iter); + gtk_tree_path_free (local_path); +} + +static void +gtk_tree_model_sort_deleted (GtkTreeModel *model, + GtkTreePath *path, + gpointer data) +{ + GtkTreeModelSort *tree_model_sort = GTK_TREE_MODEL_SORT (data); + GtkTreePath *local_path; + + g_return_if_fail (path != NULL); + + if (!(tree_model_sort->flags & GTK_TREE_MODEL_ITERS_PERSIST) && + (tree_model_sort->root != NULL)) + { + gtk_tree_model_sort_free_level ((GArray *)tree_model_sort->root); + tree_model_sort->root = NULL; + } + local_path = gtk_tree_model_sort_convert_path (tree_model_sort, path); + tree_model_sort->stamp++; + gtk_signal_emit_by_name (GTK_OBJECT (data), + "deleted", + local_path); + + gtk_tree_path_free (local_path); +} + +static gint +gtk_tree_model_sort_get_n_columns (GtkTreeModel *tree_model) +{ + g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), 0); + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->model != NULL, 0); + + return gtk_tree_model_get_n_columns (GTK_TREE_MODEL_SORT (tree_model)->model); +} + +static GType +gtk_tree_model_sort_get_column_type (GtkTreeModel *tree_model, + gint index) +{ + g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), G_TYPE_INVALID); + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->model != NULL, G_TYPE_INVALID); + + return gtk_tree_model_get_column_type (GTK_TREE_MODEL_SORT (tree_model)->model, index); +} + +static gboolean +gtk_tree_model_sort_get_iter_helper (GtkTreeModelSort *tree_model_sort, + GArray *array, + GtkTreeIter *iter, + gint depth, + GtkTreePath *path) +{ + SortElt *elt; + + if (array == NULL) + return FALSE; + + if (gtk_tree_path_get_indices (path)[depth] > array->len) + return FALSE; + + elt = & (g_array_index (array, SortElt, gtk_tree_path_get_indices (path)[depth])); + + if (depth == gtk_tree_path_get_depth (path) - 1) + { + iter->stamp = tree_model_sort->stamp; + iter->tree_node = elt; + return TRUE; + } + + if (elt->children != NULL) + return gtk_tree_model_sort_get_iter_helper (tree_model_sort, + elt->children, + iter, + depth + 1, + path); + + if (gtk_tree_model_iter_has_child (tree_model_sort->model, + &(elt->iter))) + + gtk_tree_model_sort_build_level (tree_model_sort, elt); + + return gtk_tree_model_sort_get_iter_helper (tree_model_sort, + elt->children, + iter, + depth + 1, + path); +} + +static gboolean +gtk_tree_model_sort_get_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreePath *path) +{ + g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), FALSE); + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->model != NULL, FALSE); + + if (GTK_TREE_MODEL_SORT (tree_model)->root == NULL) + gtk_tree_model_sort_build_level (GTK_TREE_MODEL_SORT (tree_model), NULL); + + return gtk_tree_model_sort_get_iter_helper (GTK_TREE_MODEL_SORT (tree_model), + GTK_TREE_MODEL_SORT (tree_model)->root, + iter, 0, path); +} + +static GtkTreePath * +gtk_tree_model_sort_get_path (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), NULL); + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->model != NULL, NULL); + + return gtk_tree_model_get_path (GTK_TREE_MODEL_SORT (tree_model)->model, iter); +} + +static void +gtk_tree_model_sort_get_value (GtkTreeModel *tree_model, + GtkTreeIter *iter, + gint column, + GValue *value) +{ + SortElt *elt; + + g_return_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model)); + g_return_if_fail (GTK_TREE_MODEL_SORT (tree_model)->model != NULL); + g_return_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == iter->stamp); + + elt = iter->tree_node; + + gtk_tree_model_get_value (GTK_TREE_MODEL_SORT (tree_model)->model, (GtkTreeIter *)elt, column, value); +} + +static gboolean +gtk_tree_model_sort_iter_next (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + GArray *array; + SortElt *elt; + + g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), FALSE); + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->model != NULL, FALSE); + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == iter->stamp, FALSE); + + elt = iter->tree_node; + array = get_array (elt, tree_model); + + if (elt - ((SortElt*) array->data) >= array->len - 1) + { + iter->stamp = 0; + return FALSE; + } + iter->tree_node = elt+1; + return TRUE; +} + +static gboolean +gtk_tree_model_sort_iter_children (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent) +{ + SortElt *elt; + + g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), FALSE); + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->model != NULL, FALSE); + if (parent) + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == parent->stamp, FALSE); + + if (parent) + elt = parent->tree_node; + else + elt = (SortElt *) ((GArray *)GTK_TREE_MODEL_SORT (tree_model)->root)->data; + + if (elt == NULL) + return FALSE; + + if (elt->children == NULL && + gtk_tree_model_iter_has_child (GTK_TREE_MODEL_SORT (tree_model)->model, (GtkTreeIter *)elt)) + gtk_tree_model_sort_build_level (GTK_TREE_MODEL_SORT (tree_model), elt); + + if (elt->children == NULL) + return FALSE; + + iter->stamp = GTK_TREE_MODEL_SORT (tree_model)->stamp; + iter->tree_node = elt->children->data; + + return TRUE; +} + +static gboolean +gtk_tree_model_sort_iter_has_child (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + SortElt *elt; + + g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), FALSE); + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->model != NULL, FALSE); + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == iter->stamp, FALSE); + + elt = iter->tree_node; + if (elt->children) + return TRUE; + + return gtk_tree_model_iter_has_child (GTK_TREE_MODEL_SORT (tree_model)->model, (GtkTreeIter *) elt); +} + +static gint +gtk_tree_model_sort_iter_n_children (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + SortElt *elt; + + g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), 0); + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->model != NULL, 0); + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == iter->stamp, 0); + + elt = iter->tree_node; + if (elt->children) + return elt->children->len; + + return gtk_tree_model_iter_n_children (GTK_TREE_MODEL_SORT (tree_model)->model, (GtkTreeIter *) elt); +} + + +static gboolean +gtk_tree_model_sort_iter_nth_child (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n) +{ + SortElt *elt; + + g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), FALSE); + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->model != NULL, FALSE); + if (parent) + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == parent->stamp, FALSE); + + elt = iter->tree_node; + + + if (elt->children == NULL) + { + if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL_SORT (tree_model)->model, (GtkTreeIter *)elt)) + gtk_tree_model_sort_build_level (GTK_TREE_MODEL_SORT (tree_model), elt); + else + return FALSE; + } + + if (elt->children == NULL) + return FALSE; + + if (n >= elt->children->len) + return FALSE; + + iter->stamp = GTK_TREE_MODEL_SORT (tree_model)->stamp; + iter->tree_node = &g_array_index (elt->children, SortElt, n); + + return TRUE; +} + +static gboolean +gtk_tree_model_sort_iter_parent (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *child) +{ + SortElt *elt; + + g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), FALSE); + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->model != NULL, FALSE); + g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == child->stamp, FALSE); + + elt = iter->tree_node; + if (elt->parent) + { + iter->stamp = GTK_TREE_MODEL_SORT (tree_model)->stamp; + iter->tree_node = elt->parent; + + return TRUE; + } + return FALSE; +} + +static void +gtk_tree_model_sort_ref_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ +} + +static void +gtk_tree_model_sort_unref_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + +} + +/* Internal functions */ +static void +gtk_tree_model_sort_build_level (GtkTreeModelSort *tree_model_sort, + SortElt *place) +{ + gint n, i; + GArray *children; + GtkTreeIter *parent_iter = NULL; + GtkTreeIter iter; + SortElt elt; + + if (place) + parent_iter = & (place->iter); + + + n = gtk_tree_model_iter_n_children (tree_model_sort->model, parent_iter); + + if (n == 0) + return; + + children = g_array_sized_new (FALSE, FALSE, sizeof (SortElt), n); + + if (place) + place->children = children; + else + tree_model_sort->root = children; + + gtk_tree_model_iter_children (tree_model_sort->model, + &iter, + parent_iter); + + i = 0; + do + { + elt.iter = iter; + elt.parent = place; + elt.children = NULL; + elt.ref = 0; + elt.offset = i; + + g_array_append_vals (children, &elt, 1); + i++; + } + while (gtk_tree_model_iter_next (tree_model_sort->model, &iter)); + +} + +static void +gtk_tree_model_sort_free_level (GArray *array) +{ + gint i; + + for (i = 0; i < array->len; i++) + { + SortElt *elt; + + elt = &g_array_index (array, SortElt, i); + if (elt->children) + gtk_tree_model_sort_free_level (array); + } + + g_array_free (array, TRUE); +} + +gint +g_value_string_compare_func (const GValue *a, + const GValue *b) +{ + return strcmp (g_value_get_string (a), + g_value_get_string (b)); +} + +gint +g_value_int_compare_func (const GValue *a, + const GValue *b) +{ + return g_value_get_int (a) < g_value_get_int (b); +} diff --git a/gtk/gtktreemodelsort.h b/gtk/gtktreemodelsort.h new file mode 100644 index 000000000..01366e6cb --- /dev/null +++ b/gtk/gtktreemodelsort.h @@ -0,0 +1,94 @@ +/* gtktreemodelsort.h + * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTK_TREE_MODEL_SORT_H__ +#define __GTK_TREE_MODEL_SORT_H__ + +#include <gtk/gtktreemodel.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GTK_TYPE_TREE_MODEL_SORT (gtk_tree_model_sort_get_type ()) +#define GTK_TREE_MODEL_SORT(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_TREE_MODEL_SORT, GtkTreeModelSort)) +#define GTK_TREE_MODEL_SORT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_TREE_MODEL_SORT, GtkTreeModelSortClass)) +#define GTK_IS_TREE_MODEL_SORT(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_TREE_MODEL_SORT)) +#define GTK_IS_TREE_MODEL_SORT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), GTK_TYPE_TREE_MODEL_SORT)) + +typedef struct _GtkTreeModelSort GtkTreeModelSort; +typedef struct _GtkTreeModelSortClass GtkTreeModelSortClass; + +typedef gint (* GValueCompareFunc) (const GValue *a, + const GValue *b); + +struct _GtkTreeModelSort +{ + GtkObject parent; + + /* < private > */ + gpointer root; + gint stamp; + guint flags; + GtkTreeModel *model; + gint sort_col; + GValueCompareFunc *func; +}; + +struct _GtkTreeModelSortClass +{ + GtkObjectClass parent_class; + + /* signals */ + /* Will be moved into the GtkTreeModelIface eventually */ + void (* changed) (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter); + void (* inserted) (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter); + void (* child_toggled) (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter); + void (* deleted) (GtkTreeModel *tree_model, + GtkTreePath *path); +}; + + +GtkType gtk_tree_model_sort_get_type (void); +GtkTreeModel *gtk_tree_model_sort_new (void); +GtkTreeModel *gtk_tree_model_sort_new_with_model (GtkTreeModel *model, + GValueCompareFunc *func, + gint sort_col); +void gtk_tree_model_sort_set_model (GtkTreeModelSort *tree_model_sort, + GtkTreeModel *model); +void gtk_tree_model_sort_set_sort_col (GtkTreeModelSort *tree_model_sort, + gint sort_col); +void gtk_tree_model_sort_set_compare (GtkTreeModelSort *tree_model_sort, + GValueCompareFunc *func); +void gtk_tree_model_sort_resort (GtkTreeModelSort *tree_model_sort); +GtkTreePath *gtk_tree_model_sort_convert_path (GtkTreeModelSort *tree_model_sort, + GtkTreePath *path); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TREE_MODEL_SORT_H__ */ diff --git a/gtk/gtktreeselection.c b/gtk/gtktreeselection.c index 414eae2bf..706549ee3 100644 --- a/gtk/gtktreeselection.c +++ b/gtk/gtktreeselection.c @@ -241,17 +241,20 @@ gtk_tree_selection_get_user_data (GtkTreeSelection *selection) /** * gtk_tree_selection_get_selected: * @selection: A #GtkTreeSelection. + * @model: A pointer set to the #GtkTreeModel, or NULL. * @iter: The #GtkTreeIter, or NULL. * * Sets @iter to the currently selected node if @selection is set to * #GTK_TREE_SELECTION_SINGLE. Otherwise, it uses the anchor. @iter may be - * NULL if you just want to test if @selection has any selected nodes. + * NULL if you just want to test if @selection has any selected nodes. @model + * is filled with the current model as a convenience. * * Return value: TRUE, if there is a selected node. **/ gboolean -gtk_tree_selection_get_selected (GtkTreeSelection *selection, - GtkTreeIter *iter) +gtk_tree_selection_get_selected (GtkTreeSelection *selection, + GtkTreeModel **model, + GtkTreeIter *iter) { GtkRBTree *tree; GtkRBNode *node; @@ -274,9 +277,11 @@ gtk_tree_selection_get_selected (GtkTreeSelection *selection, ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED)) /* We don't want to return the anchor if it isn't actually selected. */ - return FALSE; + if (model) + *model = selection->tree_view->priv->model; + return gtk_tree_model_get_iter (selection->tree_view->priv->model, iter, selection->tree_view->priv->anchor); diff --git a/gtk/gtktreeselection.h b/gtk/gtktreeselection.h index cafedf7dd..3f7201ec3 100644 --- a/gtk/gtktreeselection.h +++ b/gtk/gtktreeselection.h @@ -79,6 +79,7 @@ gpointer gtk_tree_selection_get_user_data (GtkTreeSelection /* Only meaningful if GTK_TREE_SELECTION_SINGLE is set */ /* Use selected_foreach for GTK_TREE_SELECTION_MULTI */ gboolean gtk_tree_selection_get_selected (GtkTreeSelection *selection, + GtkTreeModel **model, GtkTreeIter *iter); /* FIXME: Get a more convenient get_selection function???? one returning GSList?? */ diff --git a/gtk/gtktreestore.c b/gtk/gtktreestore.c index 3454202ad..44befc800 100644 --- a/gtk/gtktreestore.c +++ b/gtk/gtktreestore.c @@ -40,6 +40,7 @@ static guint tree_store_signals[LAST_SIGNAL] = { 0 }; static void gtk_tree_store_init (GtkTreeStore *tree_store); static void gtk_tree_store_class_init (GtkTreeStoreClass *tree_store_class); static void gtk_tree_store_tree_model_init (GtkTreeModelIface *iface); +static guint gtk_tree_store_get_flags (GtkTreeModel *tree_model); static gint gtk_tree_store_get_n_columns (GtkTreeModel *tree_model); static GtkTreePath *gtk_tree_store_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter); @@ -58,11 +59,11 @@ static gint gtk_tree_store_iter_n_children (GtkTreeModel *tree_mode GtkTreeIter *iter); static gboolean gtk_tree_store_iter_nth_child (GtkTreeModel *tree_model, GtkTreeIter *iter, - GtkTreeIter *child, + GtkTreeIter *parent, gint n); static gboolean gtk_tree_store_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, - GtkTreeIter *parent); + GtkTreeIter *child); GtkType @@ -150,6 +151,7 @@ gtk_tree_store_class_init (GtkTreeStoreClass *tree_store_class) static void gtk_tree_store_tree_model_init (GtkTreeModelIface *iface) { + iface->get_flags = gtk_tree_store_get_flags; iface->get_n_columns = gtk_tree_store_get_n_columns; iface->get_path = gtk_tree_store_get_path; iface->get_value = gtk_tree_store_get_value; @@ -165,7 +167,7 @@ static void gtk_tree_store_init (GtkTreeStore *tree_store) { tree_store->root = g_node_new (NULL); - tree_store->stamp = 1; + tree_store->stamp = g_random_int (); } GtkTreeStore * @@ -242,10 +244,19 @@ gtk_tree_store_set_column_type (GtkTreeStore *tree_store, * it is not visible to the tree or to the user., and the path "1" refers to the * first child of GtkTreeStore::root. */ + + +static guint +gtk_tree_store_get_flags (GtkTreeModel *tree_model) +{ + g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), 0); + + return GTK_TREE_MODEL_ITERS_PERSIST; +} + static gint gtk_tree_store_get_n_columns (GtkTreeModel *tree_model) { - g_return_val_if_fail (tree_model != NULL, 0); g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), 0); return GTK_TREE_STORE (tree_model)->n_columns; @@ -362,7 +373,10 @@ gtk_tree_store_iter_children (GtkTreeModel *tree_model, GtkTreeIter *parent) { iter->stamp = GTK_TREE_STORE (tree_model)->stamp; - iter->tree_node = G_NODE (parent->tree_node)->children; + if (parent) + iter->tree_node = G_NODE (parent->tree_node)->children; + else + iter->tree_node = G_NODE (GTK_TREE_STORE (tree_model)->root)->children; return iter->tree_node != NULL; } @@ -388,10 +402,13 @@ gtk_tree_store_iter_n_children (GtkTreeModel *tree_model, g_return_val_if_fail (tree_model != NULL, 0); g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), 0); - g_return_val_if_fail (iter != NULL, 0); - g_return_val_if_fail (iter->stamp == GTK_TREE_STORE (tree_model)->stamp, 0); + if (iter) + g_return_val_if_fail (iter->stamp == GTK_TREE_STORE (tree_model)->stamp, 0); - node = G_NODE (iter->tree_node)->children; + if (iter == NULL) + node = G_NODE (GTK_TREE_STORE (tree_model)->root)->children; + else + node = G_NODE (iter->tree_node)->children; while (node) { i++; diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c index 837948610..de3d50472 100644 --- a/gtk/gtktreeview.c +++ b/gtk/gtktreeview.c @@ -2037,6 +2037,8 @@ gtk_tree_view_inserted (GtkTreeModel *model, } } + /* ref the node */ + gtk_tree_model_ref_iter (tree_view->priv->model, iter); max_height = gtk_tree_view_insert_iter_height (tree_view, tree, iter, @@ -2245,6 +2247,8 @@ gtk_tree_view_build_tree (GtkTreeView *tree_view, tree, iter, depth); + + gtk_tree_model_ref_iter (tree_view->priv->model, iter); temp = _gtk_rbtree_insert_after (tree, temp, max_height); if (recurse) { diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c index 6c51f4355..2ecefdb5b 100644 --- a/gtk/gtktreeviewcolumn.c +++ b/gtk/gtktreeviewcolumn.c @@ -145,12 +145,12 @@ gtk_real_tree_column_clicked (GtkTreeViewColumn *tree_column) * * Return value: A newly created #GtkTreeViewColumn. **/ -GtkObject * +GtkTreeViewColumn * gtk_tree_view_column_new (void) { - GtkObject *retval; + GtkTreeViewColumn *retval; - retval = GTK_OBJECT (gtk_type_new (GTK_TYPE_TREE_COLUMN)); + retval = GTK_TREE_VIEW_COLUMN (gtk_type_new (GTK_TYPE_TREE_COLUMN)); return retval; } @@ -168,22 +168,21 @@ gtk_tree_view_column_new (void) * * Return value: A newly created #GtkTreeViewColumn. **/ -GtkObject * +GtkTreeViewColumn * gtk_tree_view_column_new_with_attributes (gchar *title, GtkCellRenderer *cell, ...) { - GtkObject *retval; + GtkTreeViewColumn *retval; va_list args; retval = gtk_tree_view_column_new (); - gtk_tree_view_column_set_title (GTK_TREE_VIEW_COLUMN (retval), title); - gtk_tree_view_column_set_cell_renderer (GTK_TREE_VIEW_COLUMN (retval), cell); + gtk_tree_view_column_set_title (retval, title); + gtk_tree_view_column_set_cell_renderer (retval, cell); va_start (args, cell); - gtk_tree_view_column_set_attributesv (GTK_TREE_VIEW_COLUMN (retval), - args); + gtk_tree_view_column_set_attributesv (retval, args); va_end (args); return retval; diff --git a/gtk/gtktreeviewcolumn.h b/gtk/gtktreeviewcolumn.h index 091ff0715..148c488ac 100644 --- a/gtk/gtktreeviewcolumn.h +++ b/gtk/gtktreeviewcolumn.h @@ -82,51 +82,53 @@ struct _GtkTreeViewColumnClass }; -GtkType gtk_tree_view_column_get_type (void); -GtkObject *gtk_tree_view_column_new (void); -GtkObject *gtk_tree_view_column_new_with_attributes (gchar *title, - GtkCellRenderer *cell, - ...); -void gtk_tree_view_column_set_cell_renderer (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell); -void gtk_tree_view_column_add_attribute (GtkTreeViewColumn *tree_column, - gchar *attribute, - gint column); -void gtk_tree_view_column_set_attributes (GtkTreeViewColumn *tree_column, - ...); -void gtk_tree_view_column_set_cell_data (GtkTreeViewColumn *tree_column, - GtkTreeModel *tree_model, - GtkTreeIter *iter); -void gtk_tree_view_column_set_visible (GtkTreeViewColumn *tree_column, - gboolean visible); -gboolean gtk_tree_view_column_get_visible (GtkTreeViewColumn *tree_column); -void gtk_tree_view_column_set_col_type (GtkTreeViewColumn *tree_column, - GtkTreeViewColumnType type); -gint gtk_tree_view_column_get_col_type (GtkTreeViewColumn *tree_column); -gint gtk_tree_view_column_get_size (GtkTreeViewColumn *tree_column); -void gtk_tree_view_column_set_size (GtkTreeViewColumn *tree_column, - gint size); -void gtk_tree_view_column_set_min_width (GtkTreeViewColumn *tree_column, - gint min_width); -gint gtk_tree_view_column_get_min_width (GtkTreeViewColumn *tree_column); -void gtk_tree_view_column_set_max_width (GtkTreeViewColumn *tree_column, - gint max_width); -gint gtk_tree_view_column_get_max_width (GtkTreeViewColumn *tree_column); +GtkType gtk_tree_view_column_get_type (void); +GtkTreeViewColumn *gtk_tree_view_column_new (void); +GtkTreeViewColumn *gtk_tree_view_column_new_with_attributes (gchar *title, + GtkCellRenderer *cell, + ...); +void gtk_tree_view_column_set_cell_renderer (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell); +void gtk_tree_view_column_add_attribute (GtkTreeViewColumn *tree_column, + gchar *attribute, + gint column); +void gtk_tree_view_column_set_attributes (GtkTreeViewColumn *tree_column, + ...); +void gtk_tree_view_column_set_cell_data (GtkTreeViewColumn *tree_column, + GtkTreeModel *tree_model, + GtkTreeIter *iter); +void gtk_tree_view_column_set_visible (GtkTreeViewColumn *tree_column, + gboolean visible); +gboolean gtk_tree_view_column_get_visible (GtkTreeViewColumn *tree_column); +void gtk_tree_view_column_set_col_type (GtkTreeViewColumn *tree_column, + GtkTreeViewColumnType type); +gint gtk_tree_view_column_get_col_type (GtkTreeViewColumn *tree_column); +gint gtk_tree_view_column_get_size (GtkTreeViewColumn *tree_column); +void gtk_tree_view_column_set_size (GtkTreeViewColumn *tree_column, + gint size); +void gtk_tree_view_column_set_min_width (GtkTreeViewColumn *tree_column, + gint min_width); +gint gtk_tree_view_column_get_min_width (GtkTreeViewColumn *tree_column); +void gtk_tree_view_column_set_max_width (GtkTreeViewColumn *tree_column, + gint max_width); +gint gtk_tree_view_column_get_max_width (GtkTreeViewColumn *tree_column); + /* Options for manipulating the column headers */ -void gtk_tree_view_column_set_title (GtkTreeViewColumn *tree_column, - gchar *title); -gchar *gtk_tree_view_column_get_title (GtkTreeViewColumn *tree_column); -void gtk_tree_view_column_set_header_active (GtkTreeViewColumn *tree_column, - gboolean active); -void gtk_tree_view_column_set_widget (GtkTreeViewColumn *tree_column, - GtkWidget *widget); -GtkWidget *gtk_tree_view_column_get_widget (GtkTreeViewColumn *tree_column); -void gtk_tree_view_column_set_justification (GtkTreeViewColumn *tree_column, - GtkJustification justification); -GtkJustification gtk_tree_view_column_get_justification (GtkTreeViewColumn *tree_column); +void gtk_tree_view_column_set_title (GtkTreeViewColumn *tree_column, + gchar *title); +gchar *gtk_tree_view_column_get_title (GtkTreeViewColumn *tree_column); +void gtk_tree_view_column_set_header_active (GtkTreeViewColumn *tree_column, + gboolean active); +void gtk_tree_view_column_set_widget (GtkTreeViewColumn *tree_column, + GtkWidget *widget); +GtkWidget *gtk_tree_view_column_get_widget (GtkTreeViewColumn *tree_column); +void gtk_tree_view_column_set_justification (GtkTreeViewColumn *tree_column, + GtkJustification justification); +GtkJustification gtk_tree_view_column_get_justification (GtkTreeViewColumn *tree_column); + #ifdef __cplusplus diff --git a/gtk/treestoretest.c b/gtk/treestoretest.c index d1c311c83..3835d9d17 100644 --- a/gtk/treestoretest.c +++ b/gtk/treestoretest.c @@ -7,8 +7,7 @@ static void selection_changed (GtkTreeSelection *selection, GtkWidget *button) { - if (gtk_tree_selection_get_selected (selection, - NULL)) + if (gtk_tree_selection_get_selected (selection, NULL, NULL)) gtk_widget_set_sensitive (button, TRUE); else gtk_widget_set_sensitive (button, FALSE); @@ -31,6 +30,7 @@ iter_remove (GtkWidget *button, GtkTreeView *tree_view) { GtkTreeIter selected; if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)), + NULL, &selected)) { gtk_tree_store_remove (model, &selected); @@ -46,6 +46,7 @@ iter_insert (GtkWidget *button, GtkTreeView *tree_view) entry = gtk_object_get_user_data (GTK_OBJECT (button)); if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)), + NULL, &selected)) { gtk_tree_store_insert (model, @@ -71,6 +72,7 @@ iter_insert_before (GtkWidget *button, GtkTreeView *tree_view) GtkTreeIter selected; if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)), + NULL, &selected)) { gtk_tree_store_insert_before (model, @@ -96,6 +98,7 @@ iter_insert_after (GtkWidget *button, GtkTreeView *tree_view) GtkTreeIter selected; if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)), + NULL, &selected)) { gtk_tree_store_insert_after (model, @@ -121,6 +124,7 @@ iter_prepend (GtkWidget *button, GtkTreeView *tree_view) GtkTreeIter selected; if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)), + NULL, &selected)) { gtk_tree_store_prepend (model, @@ -144,6 +148,7 @@ iter_append (GtkWidget *button, GtkTreeView *tree_view) GtkTreeIter selected; if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)), + NULL, &selected)) { gtk_tree_store_append (model, &iter, &selected); @@ -159,13 +164,14 @@ iter_append (GtkWidget *button, GtkTreeView *tree_view) static void make_window () { + GtkTreeModel *sort_model; GtkWidget *window; GtkWidget *vbox; GtkWidget *hbox, *entry; GtkWidget *button; GtkWidget *scrolled_window; GtkWidget *tree_view; - GtkObject *column; + GtkTreeViewColumn *column; GtkCellRenderer *cell; GtkObject *selection; @@ -175,7 +181,9 @@ make_window () gtk_container_set_border_width (GTK_CONTAINER (vbox), 8); gtk_window_set_default_size (GTK_WINDOW (window), 300, 350); scrolled_window = gtk_scrolled_window_new (NULL, NULL); - tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model)); + sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (model), + NULL, 0); + tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (sort_model)); selection = GTK_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view))); gtk_tree_selection_set_type (GTK_TREE_SELECTION (selection), GTK_TREE_SELECTION_SINGLE); @@ -237,7 +245,7 @@ make_window () /* The selected column */ cell = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("nodes", cell, "text", 0, NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (column)); + gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column); /* A few to start */ iter_prepend (NULL, GTK_TREE_VIEW (tree_view)); @@ -254,7 +262,7 @@ main (int argc, char *argv[]) gtk_init (&argc, &argv); model = gtk_tree_store_new_with_values (2, G_TYPE_STRING, G_TYPE_STRING); - + make_window (); make_window (); |