X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtktreestore.c;h=1569fc273e3081b79d633dbe4b83f170b83578fc;hb=4cb44fcc8fb40694f2002fcc51b56ce23b84037e;hp=7c6d8c59ecf467aca5bebff563ff7519ddcdca7b;hpb=43d4639743bb280268c4bbdd973cbac6ceab6ce4;p=~andy%2Fgtk diff --git a/gtk/gtktreestore.c b/gtk/gtktreestore.c index 7c6d8c59e..1569fc273 100644 --- a/gtk/gtktreestore.c +++ b/gtk/gtktreestore.c @@ -17,15 +17,18 @@ * Boston, MA 02111-1307, USA. */ +#include +#include +#include #include "gtktreemodel.h" #include "gtktreestore.h" #include "gtktreedatalist.h" #include "gtktreednd.h" -#include -#include +#include "gtkintl.h" +#include "gtkalias.h" #define G_NODE(node) ((GNode *)node) -#define GTK_TREE_STORE_IS_SORTED(tree) (GTK_TREE_STORE (tree)->sort_column_id != -2) +#define GTK_TREE_STORE_IS_SORTED(tree) (GTK_TREE_STORE (tree)->sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID) #define VALID_ITER(iter, tree_store) (iter!= NULL && iter->user_data != NULL && tree_store->stamp == iter->stamp) static void gtk_tree_store_init (GtkTreeStore *tree_store); @@ -35,7 +38,7 @@ static void gtk_tree_store_drag_source_init(GtkTreeDragSourceIface *ifac static void gtk_tree_store_drag_dest_init (GtkTreeDragDestIface *iface); static void gtk_tree_store_sortable_init (GtkTreeSortableIface *iface); static void gtk_tree_store_finalize (GObject *object); -static guint gtk_tree_store_get_flags (GtkTreeModel *tree_model); +static GtkTreeModelFlags gtk_tree_store_get_flags (GtkTreeModel *tree_model); static gint gtk_tree_store_get_n_columns (GtkTreeModel *tree_model); static GType gtk_tree_store_get_column_type (GtkTreeModel *tree_model, gint index); @@ -72,8 +75,12 @@ static void gtk_tree_store_set_column_type (GtkTreeStore *tree_store, gint column, GType type); +static void gtk_tree_store_increment_stamp (GtkTreeStore *tree_store); + /* DND interfaces */ +static gboolean real_gtk_tree_store_row_draggable (GtkTreeDragSource *drag_source, + GtkTreePath *path); static gboolean gtk_tree_store_drag_data_delete (GtkTreeDragSource *drag_source, GtkTreePath *path); static gboolean gtk_tree_store_drag_data_get (GtkTreeDragSource *drag_source, @@ -111,6 +118,11 @@ static gboolean gtk_tree_store_has_default_sort_func (GtkTreeSortable * static void validate_gnode (GNode *node); +static void gtk_tree_store_move (GtkTreeStore *tree_store, + GtkTreeIter *iter, + GtkTreeIter *position, + gboolean before); + static GObjectClass *parent_class = NULL; @@ -126,7 +138,7 @@ validate_tree (GtkTreeStore *tree_store) } } -GtkType +GType gtk_tree_store_get_type (void) { static GType tree_store_type = 0; @@ -174,7 +186,8 @@ gtk_tree_store_get_type (void) NULL }; - tree_store_type = g_type_register_static (G_TYPE_OBJECT, "GtkTreeStore", &tree_store_info, 0); + tree_store_type = g_type_register_static (G_TYPE_OBJECT, I_("GtkTreeStore"), + &tree_store_info, 0); g_type_add_interface_static (tree_store_type, GTK_TYPE_TREE_MODEL, @@ -225,6 +238,7 @@ gtk_tree_store_tree_model_init (GtkTreeModelIface *iface) static void gtk_tree_store_drag_source_init (GtkTreeDragSourceIface *iface) { + iface->row_draggable = real_gtk_tree_store_row_draggable; iface->drag_data_delete = gtk_tree_store_drag_data_delete; iface->drag_data_get = gtk_tree_store_drag_data_get; } @@ -269,7 +283,10 @@ gtk_tree_store_init (GtkTreeStore *tree_store) * @Varargs: all #GType types for the columns, from first to last * * Creates a new tree store as with @n_columns columns each of the types passed - * in. As an example, gtk_tree_store_new (3, G_TYPE_INT, G_TYPE_STRING, + * in. Note that only types derived from standard GObject fundamental types + * are supported. + * + * As an example, gtk_tree_store_new (3, G_TYPE_INT, G_TYPE_STRING, * GDK_TYPE_PIXBUF); will create a new #GtkTreeStore with three columns, of type * int, string and #GdkPixbuf respectively. * @@ -285,7 +302,7 @@ gtk_tree_store_new (gint n_columns, g_return_val_if_fail (n_columns > 0, NULL); - retval = GTK_TREE_STORE (g_object_new (GTK_TYPE_TREE_STORE, NULL)); + retval = g_object_new (GTK_TYPE_TREE_STORE, NULL); gtk_tree_store_set_n_columns (retval, n_columns); va_start (args, n_columns); @@ -295,8 +312,9 @@ gtk_tree_store_new (gint n_columns, GType type = va_arg (args, GType); if (! _gtk_tree_data_list_check_type (type)) { - g_warning ("%s: Invalid type %s passed to gtk_tree_store_new_with_types\n", G_STRLOC, g_type_name (type)); - g_object_unref (G_OBJECT (retval)); + g_warning ("%s: Invalid type %s passed to gtk_tree_store_new_with_types\n", + G_STRLOC, g_type_name (type)); + g_object_unref (retval); return NULL; } gtk_tree_store_set_column_type (retval, i, type); @@ -323,15 +341,16 @@ gtk_tree_store_newv (gint n_columns, g_return_val_if_fail (n_columns > 0, NULL); - retval = GTK_TREE_STORE (g_object_new (GTK_TYPE_TREE_STORE, NULL)); + retval = g_object_new (GTK_TYPE_TREE_STORE, NULL); gtk_tree_store_set_n_columns (retval, n_columns); for (i = 0; i < n_columns; i++) { if (! _gtk_tree_data_list_check_type (types[i])) { - g_warning ("%s: Invalid type %s passed to gtk_tree_store_new_with_types\n", G_STRLOC, g_type_name (types[i])); - g_object_unref (G_OBJECT (retval)); + g_warning ("%s: Invalid type %s passed to gtk_tree_store_new_with_types\n", + G_STRLOC, g_type_name (types[i])); + g_object_unref (retval); return NULL; } gtk_tree_store_set_column_type (retval, i, types[i]); @@ -345,12 +364,12 @@ gtk_tree_store_newv (gint n_columns, * gtk_tree_store_set_column_types: * @tree_store: A #GtkTreeStore * @n_columns: Number of columns for the tree store - * @types: An array length n of @GTypes + * @types: An array of #GType types, one for each column * - * This function is meant primarily for GObjects that inherit from GtkTreeStore, - * and should only be used when constructing a new @GtkTreeStore. It will not - * function after a row has been added, or a method on the @GtkTreeModel - * interface is called. + * This function is meant primarily for #GObjects that inherit from + * #GtkTreeStore, and should only be used when constructing a new + * #GtkTreeStore. It will not function after a row has been added, + * or a method on the #GtkTreeModel interface is called. **/ void gtk_tree_store_set_column_types (GtkTreeStore *tree_store, @@ -433,10 +452,14 @@ gtk_tree_store_set_column_type (GtkTreeStore *tree_store, tree_store->column_headers[column] = type; } -static void +static gboolean node_free (GNode *node, gpointer data) { - _gtk_tree_data_list_free (node->data, (GType*)data); + if (node->data) + _gtk_tree_data_list_free (node->data, (GType*)data); + node->data = NULL; + + return FALSE; } static void @@ -444,17 +467,22 @@ gtk_tree_store_finalize (GObject *object) { GtkTreeStore *tree_store = GTK_TREE_STORE (object); - g_node_children_foreach (tree_store->root, G_TRAVERSE_LEAFS, node_free, tree_store->column_headers); + g_node_traverse (tree_store->root, G_POST_ORDER, G_TRAVERSE_ALL, -1, + node_free, tree_store->column_headers); + g_node_destroy (tree_store->root); _gtk_tree_data_list_header_free (tree_store->sort_list); g_free (tree_store->column_headers); if (tree_store->default_sort_destroy) { - (* tree_store->default_sort_destroy) (tree_store->default_sort_data); + GtkDestroyNotify d = tree_store->default_sort_destroy; + tree_store->default_sort_destroy = NULL; + d (tree_store->default_sort_data); tree_store->default_sort_data = NULL; } + /* must chain up */ (* parent_class->finalize) (object); } @@ -465,7 +493,7 @@ gtk_tree_store_finalize (GObject *object) */ -static guint +static GtkTreeModelFlags gtk_tree_store_get_flags (GtkTreeModel *tree_model) { g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), 0); @@ -612,6 +640,7 @@ gtk_tree_store_get_value (GtkTreeModel *tree_model, g_return_if_fail (GTK_IS_TREE_STORE (tree_model)); g_return_if_fail (iter != NULL); + g_return_if_fail (iter->stamp == GTK_TREE_STORE (tree_model)->stamp); g_return_if_fail (column < GTK_TREE_STORE (tree_model)->n_columns); list = G_NODE (iter->user_data)->data; @@ -636,7 +665,9 @@ static gboolean gtk_tree_store_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter) { + g_return_val_if_fail (iter != NULL, FALSE); g_return_val_if_fail (iter->user_data != NULL, FALSE); + g_return_val_if_fail (iter->stamp == GTK_TREE_STORE (tree_model)->stamp, FALSE); if (G_NODE (iter->user_data)->next) { @@ -655,6 +686,7 @@ gtk_tree_store_iter_children (GtkTreeModel *tree_model, GNode *children; g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE); + g_return_val_if_fail (parent == NULL || parent->stamp == GTK_TREE_STORE (tree_model)->stamp, FALSE); if (parent) children = G_NODE (parent->user_data)->children; @@ -690,7 +722,7 @@ gtk_tree_store_iter_n_children (GtkTreeModel *tree_model, gint i = 0; g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), 0); - g_return_val_if_fail (iter == NULL || iter->user_data != NULL, FALSE); + g_return_val_if_fail (iter == NULL || iter->user_data != NULL, 0); if (iter == NULL) node = G_NODE (GTK_TREE_STORE (tree_model)->root)->children; @@ -743,7 +775,9 @@ gtk_tree_store_iter_parent (GtkTreeModel *tree_model, GNode *parent; g_return_val_if_fail (iter != NULL, FALSE); - g_return_val_if_fail (iter->user_data != NULL, FALSE); + g_return_val_if_fail (child != NULL, FALSE); + g_return_val_if_fail (child->user_data != NULL, FALSE); + g_return_val_if_fail (child->stamp == GTK_TREE_STORE (tree_model)->stamp, FALSE); parent = G_NODE (child->user_data)->parent; @@ -765,16 +799,21 @@ static gboolean gtk_tree_store_real_set_value (GtkTreeStore *tree_store, GtkTreeIter *iter, gint column, - GValue *value) + GValue *value, + gboolean sort) { GtkTreeDataList *list; GtkTreeDataList *prev; - GtkTreePath *path = NULL; + gint old_column = column; GValue real_value = {0, }; gboolean converted = FALSE; - gint orig_column = column; gboolean retval = FALSE; + g_return_val_if_fail (GTK_IS_TREE_STORE (tree_store), FALSE); + g_return_val_if_fail (VALID_ITER (iter, tree_store), FALSE); + g_return_val_if_fail (column >= 0 && column < tree_store->n_columns, FALSE); + g_return_val_if_fail (G_IS_VALUE (value), FALSE); + if (! g_type_is_a (G_VALUE_TYPE (value), tree_store->column_headers[column])) { if (! (g_value_type_compatible (G_VALUE_TYPE (value), tree_store->column_headers[column]) && @@ -800,8 +839,6 @@ gtk_tree_store_real_set_value (GtkTreeStore *tree_store, prev = list = G_NODE (iter->user_data)->data; - path = gtk_tree_store_get_path (GTK_TREE_MODEL (tree_store), iter); - while (list != NULL) { if (column == 0) @@ -811,9 +848,10 @@ gtk_tree_store_real_set_value (GtkTreeStore *tree_store, else _gtk_tree_data_list_value_to_node (list, value); retval = TRUE; - gtk_tree_path_free (path); if (converted) g_value_unset (&real_value); + if (sort && GTK_TREE_STORE_IS_SORTED (tree_store)) + gtk_tree_store_sort_iter_changed (tree_store, iter, old_column); return retval; } @@ -840,17 +878,18 @@ gtk_tree_store_real_set_value (GtkTreeStore *tree_store, list->next = NULL; column --; } + if (converted) _gtk_tree_data_list_value_to_node (list, &real_value); else _gtk_tree_data_list_value_to_node (list, value); - - gtk_tree_path_free (path); + + retval = TRUE; if (converted) g_value_unset (&real_value); - if (GTK_TREE_STORE_IS_SORTED (tree_store)) - gtk_tree_store_sort_iter_changed (tree_store, iter, orig_column); + if (sort && GTK_TREE_STORE_IS_SORTED (tree_store)) + gtk_tree_store_sort_iter_changed (tree_store, iter, old_column); return retval; } @@ -878,7 +917,7 @@ gtk_tree_store_set_value (GtkTreeStore *tree_store, g_return_if_fail (column >= 0 && column < tree_store->n_columns); g_return_if_fail (G_IS_VALUE (value)); - if (gtk_tree_store_real_set_value (tree_store, iter, column, value)) + if (gtk_tree_store_real_set_value (tree_store, iter, column, value, TRUE)) { GtkTreePath *path; @@ -892,9 +931,9 @@ gtk_tree_store_set_value (GtkTreeStore *tree_store, * gtk_tree_store_set_valist: * @tree_store: A #GtkTreeStore * @iter: A valid #GtkTreeIter for the row being modified - * @var_args: va_list of column/value pairs + * @var_args: va_list of column/value pairs * - * See gtk_tree_store_set(); this version takes a va_list for + * See gtk_tree_store_set(); this version takes a va_list for * use by language bindings. * **/ @@ -905,12 +944,34 @@ gtk_tree_store_set_valist (GtkTreeStore *tree_store, { gint column; gboolean emit_signal = FALSE; + gboolean maybe_need_sort = FALSE; + GtkTreeIterCompareFunc func = NULL; g_return_if_fail (GTK_IS_TREE_STORE (tree_store)); g_return_if_fail (VALID_ITER (iter, tree_store)); column = va_arg (var_args, gint); + if (GTK_TREE_STORE_IS_SORTED (tree_store)) + { + if (tree_store->sort_column_id != -1) + { + GtkTreeDataSortHeader *header; + header = _gtk_tree_data_list_get_header (tree_store->sort_list, + tree_store->sort_column_id); + g_return_if_fail (header != NULL); + g_return_if_fail (header->func != NULL); + func = header->func; + } + else + { + func = tree_store->default_sort_func; + } + } + + if (func != _gtk_tree_data_list_compare_func) + maybe_need_sort = TRUE; + while (column != -1) { GValue value = { 0, }; @@ -938,12 +999,21 @@ gtk_tree_store_set_valist (GtkTreeStore *tree_store, emit_signal = gtk_tree_store_real_set_value (tree_store, iter, column, - &value) || emit_signal; + &value, + FALSE) || emit_signal; + + if (func == _gtk_tree_data_list_compare_func && + column == tree_store->sort_column_id) + maybe_need_sort = TRUE; g_value_unset (&value); column = va_arg (var_args, gint); } + + if (maybe_need_sort && GTK_TREE_STORE_IS_SORTED (tree_store)) + gtk_tree_store_sort_iter_changed (tree_store, iter, tree_store->sort_column_id); + if (emit_signal) { GtkTreePath *path; @@ -964,8 +1034,8 @@ gtk_tree_store_set_valist (GtkTreeStore *tree_store, * The variable argument list should contain integer column numbers, * each column number followed by the value to be set. * The list is terminated by a -1. For example, to set column 0 with type - * %G_TYPE_STRING to "Foo", you would write gtk_tree_store_set (store, iter, - * 0, "Foo", -1). + * %G_TYPE_STRING to "Foo", you would write + * gtk_tree_store_set (store, iter, 0, "Foo", -1). **/ void gtk_tree_store_set (GtkTreeStore *tree_store, @@ -990,8 +1060,10 @@ gtk_tree_store_set (GtkTreeStore *tree_store, * Removes @iter from @tree_store. After being removed, @iter is set to the * next valid row at that level, or invalidated if it previously pointed to the * last one. + * + * Return value: %TRUE if @iter is still valid, %FALSE if not. **/ -void +gboolean gtk_tree_store_remove (GtkTreeStore *tree_store, GtkTreeIter *iter) { @@ -1000,8 +1072,8 @@ gtk_tree_store_remove (GtkTreeStore *tree_store, GNode *parent; GNode *next_node; - g_return_if_fail (GTK_IS_TREE_STORE (tree_store)); - g_return_if_fail (VALID_ITER (iter, tree_store)); + g_return_val_if_fail (GTK_IS_TREE_STORE (tree_store), FALSE); + g_return_val_if_fail (VALID_ITER (iter, tree_store), FALSE); parent = G_NODE (iter->user_data)->parent; @@ -1009,8 +1081,8 @@ gtk_tree_store_remove (GtkTreeStore *tree_store, next_node = G_NODE (iter->user_data)->next; if (G_NODE (iter->user_data)->data) - _gtk_tree_data_list_free ((GtkTreeDataList *) G_NODE (iter->user_data)->data, - tree_store->column_headers); + g_node_traverse (G_NODE (iter->user_data), G_POST_ORDER, G_TRAVERSE_ALL, + -1, node_free, tree_store->column_headers); path = gtk_tree_store_get_path (GTK_TREE_MODEL (tree_store), iter); g_node_destroy (G_NODE (iter->user_data)); @@ -1036,17 +1108,20 @@ gtk_tree_store_remove (GtkTreeStore *tree_store, { iter->stamp = tree_store->stamp; iter->user_data = next_node; + return TRUE; } else { iter->stamp = 0; iter->user_data = NULL; } + + return FALSE; } /** * gtk_tree_store_insert: - * @tree_store: A #GtkListStore + * @tree_store: A #GtkTreeStore * @iter: An unset #GtkTreeIter to set to the new row * @parent: A valid #GtkTreeIter, or %NULL * @position: position to insert the new row @@ -1055,9 +1130,9 @@ gtk_tree_store_remove (GtkTreeStore *tree_store, * made a child of @parent. Otherwise, the row will be created at the toplevel. * If @position is larger than the number of rows at that level, then the new * row will be inserted to the end of the list. @iter will be changed to point - * to this new row. The row will be empty before this function is called. To - * fill in values, you need to call gtk_list_store_set() or - * gtk_list_store_set_value(). + * to this new row. The row will be empty after this function is called. To + * fill in values, you need to call gtk_tree_store_set() or + * gtk_tree_store_set_value(). * **/ void @@ -1068,8 +1143,10 @@ gtk_tree_store_insert (GtkTreeStore *tree_store, { GtkTreePath *path; GNode *parent_node; + GNode *new_node; g_return_if_fail (GTK_IS_TREE_STORE (tree_store)); + g_return_if_fail (iter != NULL); if (parent) g_return_if_fail (VALID_ITER (parent, tree_store)); @@ -1080,13 +1157,24 @@ gtk_tree_store_insert (GtkTreeStore *tree_store, tree_store->columns_dirty = TRUE; + new_node = g_node_new (NULL); + iter->stamp = tree_store->stamp; - iter->user_data = g_node_new (NULL); - g_node_insert (parent_node, position, G_NODE (iter->user_data)); + iter->user_data = new_node; + g_node_insert (parent_node, position, new_node); path = gtk_tree_store_get_path (GTK_TREE_MODEL (tree_store), iter); gtk_tree_model_row_inserted (GTK_TREE_MODEL (tree_store), path, iter); + if (parent_node != tree_store->root) + { + if (new_node->prev == NULL && new_node->next == NULL) + { + gtk_tree_path_up (path); + gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (tree_store), path, parent); + } + } + gtk_tree_path_free (path); validate_tree ((GtkTreeStore*)tree_store); @@ -1100,10 +1188,10 @@ gtk_tree_store_insert (GtkTreeStore *tree_store, * @sibling: A valid #GtkTreeIter, or %NULL * * Inserts a new row before @sibling. If @sibling is %NULL, then the row will - * be appended to the beginning of the @parent 's children. If @parent and - * @sibling are %NULL, then the row will be appended to the toplevel. If both - * @sibling and @parent are set, then @parent must be the parent of @sibling. - * When @sibling is set, @parent is optional. + * be appended to @parent 's children. If @parent and @sibling are %NULL, then + * the row will be appended to the toplevel. If both @sibling and @parent are + * set, then @parent must be the parent of @sibling. When @sibling is set, + * @parent is optional. * * @iter will be changed to point to this new row. The row will be empty after * this function is called. To fill in values, you need to call @@ -1127,10 +1215,6 @@ gtk_tree_store_insert_before (GtkTreeStore *tree_store, if (sibling != NULL) g_return_if_fail (VALID_ITER (sibling, tree_store)); - tree_store->columns_dirty = TRUE; - - new_node = g_node_new (NULL); - if (parent == NULL && sibling == NULL) parent_node = tree_store->root; else if (parent == NULL) @@ -1143,6 +1227,10 @@ gtk_tree_store_insert_before (GtkTreeStore *tree_store, parent_node = G_NODE (parent->user_data); } + tree_store->columns_dirty = TRUE; + + new_node = g_node_new (NULL); + g_node_insert_before (parent_node, sibling ? G_NODE (sibling->user_data) : NULL, new_node); @@ -1153,6 +1241,20 @@ gtk_tree_store_insert_before (GtkTreeStore *tree_store, path = gtk_tree_store_get_path (GTK_TREE_MODEL (tree_store), iter); gtk_tree_model_row_inserted (GTK_TREE_MODEL (tree_store), path, iter); + if (parent_node != tree_store->root) + { + if (new_node->prev == NULL && new_node->next == NULL) + { + GtkTreeIter parent_iter; + + parent_iter.stamp = tree_store->stamp; + parent_iter.user_data = parent_node; + + gtk_tree_path_up (path); + gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (tree_store), path, &parent_iter); + } + } + gtk_tree_path_free (path); validate_tree ((GtkTreeStore*)tree_store); @@ -1166,10 +1268,10 @@ gtk_tree_store_insert_before (GtkTreeStore *tree_store, * @sibling: A valid #GtkTreeIter, or %NULL * * Inserts a new row after @sibling. If @sibling is %NULL, then the row will be - * prepended to the beginning of the @parent 's children. If @parent and - * @sibling are %NULL, then the row will be prepended to the toplevel. If both - * @sibling and @parent are set, then @parent must be the parent of @sibling. - * When @sibling is set, @parent is optional. + * prepended to @parent 's children. If @parent and @sibling are %NULL, then + * the row will be prepended to the toplevel. If both @sibling and @parent are + * set, then @parent must be the parent of @sibling. When @sibling is set, + * @parent is optional. * * @iter will be changed to point to this new row. The row will be empty after * this function is called. To fill in values, you need to call @@ -1193,10 +1295,6 @@ gtk_tree_store_insert_after (GtkTreeStore *tree_store, if (sibling != NULL) g_return_if_fail (VALID_ITER (sibling, tree_store)); - tree_store->columns_dirty = TRUE; - - new_node = g_node_new (NULL); - if (parent == NULL && sibling == NULL) parent_node = tree_store->root; else if (parent == NULL) @@ -1210,6 +1308,9 @@ gtk_tree_store_insert_after (GtkTreeStore *tree_store, parent_node = G_NODE (parent->user_data); } + tree_store->columns_dirty = TRUE; + + new_node = g_node_new (NULL); g_node_insert_after (parent_node, sibling ? G_NODE (sibling->user_data) : NULL, @@ -1221,6 +1322,20 @@ gtk_tree_store_insert_after (GtkTreeStore *tree_store, path = gtk_tree_store_get_path (GTK_TREE_MODEL (tree_store), iter); gtk_tree_model_row_inserted (GTK_TREE_MODEL (tree_store), path, iter); + if (parent_node != tree_store->root) + { + if (new_node->prev == NULL && new_node->next == NULL) + { + GtkTreeIter parent_iter; + + parent_iter.stamp = tree_store->stamp; + parent_iter.user_data = parent_node; + + gtk_tree_path_up (path); + gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (tree_store), path, &parent_iter); + } + } + gtk_tree_path_free (path); validate_tree ((GtkTreeStore*)tree_store); @@ -1264,7 +1379,7 @@ gtk_tree_store_prepend (GtkTreeStore *tree_store, iter->stamp = tree_store->stamp; iter->user_data = g_node_new (NULL); - g_node_prepend (parent_node, iter->user_data); + g_node_prepend (parent_node, G_NODE (iter->user_data)); path = gtk_tree_store_get_path (GTK_TREE_MODEL (tree_store), iter); gtk_tree_model_row_inserted (GTK_TREE_MODEL (tree_store), path, iter); @@ -1388,30 +1503,132 @@ gtk_tree_store_iter_depth (GtkTreeStore *tree_store, return g_node_depth (G_NODE (iter->user_data)) - 2; } +/* simple ripoff from g_node_traverse_post_order */ +static gboolean +gtk_tree_store_clear_traverse (GNode *node, + GtkTreeStore *store) +{ + GtkTreeIter iter; + + if (node->children) + { + GNode *child; + + child = node->children; + while (child) + { + register GNode *current; + + current = child; + child = current->next; + if (gtk_tree_store_clear_traverse (current, store)) + return TRUE; + } + + if (node->parent) + { + iter.stamp = store->stamp; + iter.user_data = node; + + gtk_tree_store_remove (store, &iter); + } + } + else if (node->parent) + { + iter.stamp = store->stamp; + iter.user_data = node; + + gtk_tree_store_remove (store, &iter); + } + + return FALSE; +} + +static void +gtk_tree_store_increment_stamp (GtkTreeStore *tree_store) +{ + do + { + tree_store->stamp++; + } + while (tree_store->stamp == 0); +} + /** * gtk_tree_store_clear: - * @tree_store: @ #GtkTreeStore + * @tree_store: a #GtkTreeStore * * Removes all rows from @tree_store **/ void gtk_tree_store_clear (GtkTreeStore *tree_store) { - GtkTreeIter iter; - g_return_if_fail (GTK_IS_TREE_STORE (tree_store)); - while (G_NODE (tree_store->root)->children) + gtk_tree_store_clear_traverse (tree_store->root, tree_store); + gtk_tree_store_increment_stamp (tree_store); +} + +static gboolean +gtk_tree_store_iter_is_valid_helper (GtkTreeIter *iter, + GNode *first) +{ + GNode *node; + + node = first; + + do { - iter.stamp = tree_store->stamp; - iter.user_data = G_NODE (tree_store->root)->children; - gtk_tree_store_remove (tree_store, &iter); + if (node == iter->user_data) + return TRUE; + + if (node->children) + if (gtk_tree_store_iter_is_valid_helper (iter, node->children)) + return TRUE; + + node = node->next; } + while (node); + + return FALSE; +} + +/** + * gtk_tree_store_iter_is_valid: + * @tree_store: A #GtkTreeStore. + * @iter: A #GtkTreeIter. + * + * WARNING: This function is slow. Only use it for debugging and/or testing + * purposes. + * + * Checks if the given iter is a valid iter for this #GtkTreeStore. + * + * Return value: %TRUE if the iter is valid, %FALSE if the iter is invalid. + * + * Since: 2.2 + **/ +gboolean +gtk_tree_store_iter_is_valid (GtkTreeStore *tree_store, + GtkTreeIter *iter) +{ + g_return_val_if_fail (GTK_IS_TREE_STORE (tree_store), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + if (!VALID_ITER (iter, tree_store)) + return FALSE; + + return gtk_tree_store_iter_is_valid_helper (iter, tree_store->root); } /* DND */ +static gboolean real_gtk_tree_store_row_draggable (GtkTreeDragSource *drag_source, + GtkTreePath *path) +{ + return TRUE; +} + static gboolean gtk_tree_store_drag_data_delete (GtkTreeDragSource *drag_source, GtkTreePath *path) @@ -1582,7 +1799,8 @@ gtk_tree_store_drag_data_received (GtkTreeDragDest *drag_dest, /* Get the parent, NULL if parent is the root */ dest_parent_p = NULL; parent = gtk_tree_path_copy (dest); - if (gtk_tree_path_up (parent)) + if (gtk_tree_path_up (parent) && + gtk_tree_path_get_depth (parent) > 0) { gtk_tree_model_get_iter (tree_model, &dest_parent, @@ -1592,7 +1810,7 @@ gtk_tree_store_drag_data_received (GtkTreeDragDest *drag_dest, gtk_tree_path_free (parent); parent = NULL; - gtk_tree_store_prepend (GTK_TREE_STORE (tree_model), + gtk_tree_store_prepend (tree_store, &dest_iter, dest_parent_p); @@ -1600,17 +1818,14 @@ gtk_tree_store_drag_data_received (GtkTreeDragDest *drag_dest, } else { - if (gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_model), - &dest_iter, - prev)) + if (gtk_tree_model_get_iter (tree_model, &dest_iter, prev)) { GtkTreeIter tmp_iter = dest_iter; - gtk_tree_store_insert_after (GTK_TREE_STORE (tree_model), - &dest_iter, - NULL, + + gtk_tree_store_insert_after (tree_store, &dest_iter, NULL, &tmp_iter); - retval = TRUE; + retval = TRUE; } } @@ -1653,6 +1868,12 @@ gtk_tree_store_row_drop_possible (GtkTreeDragDest *drag_dest, GtkTreePath *tmp = NULL; gboolean retval = FALSE; + g_return_val_if_fail (GTK_IS_TREE_STORE (drag_dest), FALSE); + + /* don't accept drops if the tree has been sorted */ + if (GTK_TREE_STORE_IS_SORTED (drag_dest)) + return FALSE; + if (!gtk_tree_get_row_drag_data (selection_data, &src_model, &src_path)) @@ -1695,13 +1916,622 @@ gtk_tree_store_row_drop_possible (GtkTreeDragDest *drag_dest, return retval; } -/* Sorting */ +/* Sorting and reordering */ typedef struct _SortTuple { gint offset; GNode *node; } SortTuple; +/* Reordering */ +static gint +gtk_tree_store_reorder_func (gconstpointer a, + gconstpointer b, + gpointer user_data) +{ + SortTuple *a_reorder; + SortTuple *b_reorder; + + a_reorder = (SortTuple *)a; + b_reorder = (SortTuple *)b; + + if (a_reorder->offset < b_reorder->offset) + return -1; + if (a_reorder->offset > b_reorder->offset) + return 1; + + return 0; +} + +/** + * gtk_tree_store_reorder: + * @tree_store: A #GtkTreeStore. + * @parent: A #GtkTreeIter. + * @new_order: an array of integers mapping the new position of each child + * to its old position before the re-ordering, + * i.e. @new_order[newpos] = oldpos. + * + * Reorders the children of @parent in @tree_store to follow the order + * indicated by @new_order. Note that this function only works with + * unsorted stores. + * + * Since: 2.2 + **/ +void +gtk_tree_store_reorder (GtkTreeStore *tree_store, + GtkTreeIter *parent, + gint *new_order) +{ + gint i, length = 0; + GNode *level, *node; + GtkTreePath *path; + SortTuple *sort_array; + + g_return_if_fail (GTK_IS_TREE_STORE (tree_store)); + g_return_if_fail (!GTK_TREE_STORE_IS_SORTED (tree_store)); + g_return_if_fail (parent == NULL || VALID_ITER (parent, tree_store)); + g_return_if_fail (new_order != NULL); + + if (!parent) + level = G_NODE (tree_store->root)->children; + else + level = G_NODE (parent->user_data)->children; + + /* count nodes */ + node = level; + while (node) + { + length++; + node = node->next; + } + + /* set up sortarray */ + sort_array = g_new (SortTuple, length); + + node = level; + for (i = 0; i < length; i++) + { + sort_array[new_order[i]].offset = i; + sort_array[i].node = node; + + node = node->next; + } + + g_qsort_with_data (sort_array, + length, + sizeof (SortTuple), + gtk_tree_store_reorder_func, + NULL); + + /* fix up level */ + for (i = 0; i < length - 1; i++) + { + sort_array[i].node->next = sort_array[i+1].node; + sort_array[i+1].node->prev = sort_array[i].node; + } + + sort_array[length-1].node->next = NULL; + sort_array[0].node->prev = NULL; + if (parent) + G_NODE (parent->user_data)->children = sort_array[0].node; + else + G_NODE (tree_store->root)->children = sort_array[0].node; + + /* emit signal */ + if (parent) + path = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_store), parent); + else + path = gtk_tree_path_new (); + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (tree_store), path, + parent, new_order); + gtk_tree_path_free (path); + g_free (sort_array); +} + +/** + * gtk_tree_store_swap: + * @tree_store: A #GtkTreeStore. + * @a: A #GtkTreeIter. + * @b: Another #GtkTreeIter. + * + * Swaps @a and @b in the same level of @tree_store. Note that this function + * only works with unsorted stores. + * + * Since: 2.2 + **/ +void +gtk_tree_store_swap (GtkTreeStore *tree_store, + GtkTreeIter *a, + GtkTreeIter *b) +{ + GNode *tmp, *node_a, *node_b, *parent_node; + GNode *a_prev, *a_next, *b_prev, *b_next; + gint i, a_count, b_count, length, *order; + GtkTreePath *path_a, *path_b; + GtkTreeIter parent; + + g_return_if_fail (GTK_IS_TREE_STORE (tree_store)); + g_return_if_fail (VALID_ITER (a, tree_store)); + g_return_if_fail (VALID_ITER (b, tree_store)); + + node_a = G_NODE (a->user_data); + node_b = G_NODE (b->user_data); + + /* basic sanity checking */ + if (node_a == node_b) + return; + + path_a = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_store), a); + path_b = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_store), b); + + g_return_if_fail (path_a && path_b); + + gtk_tree_path_up (path_a); + gtk_tree_path_up (path_b); + + if (gtk_tree_path_get_depth (path_a) == 0 + || gtk_tree_path_get_depth (path_b) == 0) + { + if (gtk_tree_path_get_depth (path_a) != gtk_tree_path_get_depth (path_b)) + { + gtk_tree_path_free (path_a); + gtk_tree_path_free (path_b); + + g_warning ("Given children are not in the same level\n"); + return; + } + parent_node = G_NODE (tree_store->root); + } + else + { + if (gtk_tree_path_compare (path_a, path_b)) + { + gtk_tree_path_free (path_a); + gtk_tree_path_free (path_b); + + g_warning ("Given children don't have a common parent\n"); + return; + } + gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_store), &parent, + path_a); + parent_node = G_NODE (parent.user_data); + } + gtk_tree_path_free (path_b); + + /* old links which we have to keep around */ + a_prev = node_a->prev; + a_next = node_a->next; + + b_prev = node_b->prev; + b_next = node_b->next; + + /* fix up links if the nodes are next to eachother */ + if (a_prev == node_b) + a_prev = node_a; + if (a_next == node_b) + a_next = node_a; + + if (b_prev == node_a) + b_prev = node_b; + if (b_next == node_a) + b_next = node_b; + + /* counting nodes */ + tmp = parent_node->children; + i = a_count = b_count = 0; + while (tmp) + { + if (tmp == node_a) + a_count = i; + if (tmp == node_b) + b_count = i; + + tmp = tmp->next; + i++; + } + length = i; + + /* hacking the tree */ + if (!a_prev) + parent_node->children = node_b; + else + a_prev->next = node_b; + + if (a_next) + a_next->prev = node_b; + + if (!b_prev) + parent_node->children = node_a; + else + b_prev->next = node_a; + + if (b_next) + b_next->prev = node_a; + + node_a->prev = b_prev; + node_a->next = b_next; + + node_b->prev = a_prev; + node_b->next = a_next; + + /* emit signal */ + order = g_new (gint, length); + for (i = 0; i < length; i++) + if (i == a_count) + order[i] = b_count; + else if (i == b_count) + order[i] = a_count; + else + order[i] = i; + + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (tree_store), path_a, + parent_node == tree_store->root + ? NULL : &parent, order); + gtk_tree_path_free (path_a); + g_free (order); +} + +/* WARNING: this function is *incredibly* fragile. Please smashtest after + * making changes here. + * -Kris + */ +static void +gtk_tree_store_move (GtkTreeStore *tree_store, + GtkTreeIter *iter, + GtkTreeIter *position, + gboolean before) +{ + GNode *parent, *node, *a, *b, *tmp, *tmp_a, *tmp_b; + gint old_pos, new_pos, length, i, *order; + GtkTreePath *path = NULL, *tmppath, *pos_path = NULL; + GtkTreeIter parent_iter, dst_a, dst_b; + gint depth = 0; + gboolean handle_b = TRUE; + + g_return_if_fail (GTK_IS_TREE_STORE (tree_store)); + g_return_if_fail (!GTK_TREE_STORE_IS_SORTED (tree_store)); + g_return_if_fail (VALID_ITER (iter, tree_store)); + if (position) + g_return_if_fail (VALID_ITER (position, tree_store)); + + a = b = NULL; + + /* sanity checks */ + if (position) + { + path = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_store), iter); + pos_path = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_store), + position); + + /* if before: + * moving the iter before path or "path + 1" doesn't make sense + * else + * moving the iter before path or "path - 1" doesn't make sense + */ + if (!gtk_tree_path_compare (path, pos_path)) + goto free_paths_and_out; + + if (before) + gtk_tree_path_next (path); + else + gtk_tree_path_prev (path); + + if (!gtk_tree_path_compare (path, pos_path)) + goto free_paths_and_out; + + if (before) + gtk_tree_path_prev (path); + else + gtk_tree_path_next (path); + + if (gtk_tree_path_get_depth (path) != gtk_tree_path_get_depth (pos_path)) + { + g_warning ("Given children are not in the same level\n"); + + goto free_paths_and_out; + } + + tmppath = gtk_tree_path_copy (pos_path); + gtk_tree_path_up (path); + gtk_tree_path_up (tmppath); + + if (gtk_tree_path_get_depth (path) > 0 && + gtk_tree_path_compare (path, tmppath)) + { + g_warning ("Given children are not in the same level\n"); + + gtk_tree_path_free (tmppath); + goto free_paths_and_out; + } + + gtk_tree_path_free (tmppath); + } + + if (!path) + { + path = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_store), iter); + gtk_tree_path_up (path); + } + + depth = gtk_tree_path_get_depth (path); + + if (depth) + { + gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_store), &parent_iter, path); + + parent = G_NODE (parent_iter.user_data); + } + else + parent = G_NODE (tree_store->root); + + /* yes, I know that this can be done shorter, but I'm doing it this way + * so the code is also maintainable + */ + + if (before && position) + { + b = G_NODE (position->user_data); + + if (gtk_tree_path_get_indices (pos_path)[gtk_tree_path_get_depth (pos_path) - 1] > 0) + { + gtk_tree_path_prev (pos_path); + if (gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_store), &dst_a, pos_path)) + a = G_NODE (dst_a.user_data); + else + a = NULL; + gtk_tree_path_next (pos_path); + } + + /* if b is NULL, a is NULL too -- we are at the beginning of the list + * yes and we leak memory here ... + */ + g_return_if_fail (b); + } + else if (before && !position) + { + /* move before without position is appending */ + a = NULL; + b = NULL; + } + else /* !before */ + { + if (position) + a = G_NODE (position->user_data); + else + a = NULL; + + if (position) + { + gtk_tree_path_next (pos_path); + if (gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_store), &dst_b, pos_path)) + b = G_NODE (dst_b.user_data); + else + b = NULL; + gtk_tree_path_prev (pos_path); + } + else + { + /* move after without position is prepending */ + if (depth) + gtk_tree_model_iter_children (GTK_TREE_MODEL (tree_store), &dst_b, + &parent_iter); + else + gtk_tree_model_iter_children (GTK_TREE_MODEL (tree_store), &dst_b, + NULL); + + b = G_NODE (dst_b.user_data); + } + + /* if a is NULL, b is NULL too -- we are at the end of the list + * yes and we leak memory here ... + */ + if (position) + g_return_if_fail (a); + } + + /* counting nodes */ + tmp = parent->children; + + length = old_pos = 0; + while (tmp) + { + if (tmp == iter->user_data) + old_pos = length; + + tmp = tmp->next; + length++; + } + + /* remove node from list */ + node = G_NODE (iter->user_data); + tmp_a = node->prev; + tmp_b = node->next; + + if (tmp_a) + tmp_a->next = tmp_b; + else + parent->children = tmp_b; + + if (tmp_b) + tmp_b->prev = tmp_a; + + /* and reinsert the node */ + if (a) + { + tmp = a->next; + + a->next = node; + node->next = tmp; + node->prev = a; + } + else if (!a && !before) + { + tmp = parent->children; + + node->prev = NULL; + parent->children = node; + + node->next = tmp; + if (tmp) + tmp->prev = node; + + handle_b = FALSE; + } + else if (!a && before) + { + if (!position) + { + node->parent = NULL; + node->next = node->prev = NULL; + + /* before with sibling = NULL appends */ + g_node_insert_before (parent, NULL, node); + } + else + { + node->parent = NULL; + node->next = node->prev = NULL; + + /* after with sibling = NULL prepends */ + g_node_insert_after (parent, NULL, node); + } + + handle_b = FALSE; + } + + if (handle_b) + { + if (b) + { + tmp = b->prev; + + b->prev = node; + node->prev = tmp; + node->next = b; + } + else if (!(!a && before)) /* !a && before is completely handled above */ + node->next = NULL; + } + + /* emit signal */ + if (position) + new_pos = gtk_tree_path_get_indices (pos_path)[gtk_tree_path_get_depth (pos_path)-1]; + else if (before) + { + if (depth) + new_pos = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree_store), + &parent_iter) - 1; + else + new_pos = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree_store), + NULL) - 1; + } + else + new_pos = 0; + + if (new_pos > old_pos) + { + if (before && position) + new_pos--; + } + else + { + if (!before && position) + new_pos++; + } + + order = g_new (gint, length); + if (new_pos > old_pos) + { + for (i = 0; i < length; i++) + if (i < old_pos) + order[i] = i; + else if (i >= old_pos && i < new_pos) + order[i] = i + 1; + else if (i == new_pos) + order[i] = old_pos; + else + order[i] = i; + } + else + { + for (i = 0; i < length; i++) + if (i == new_pos) + order[i] = old_pos; + else if (i > new_pos && i <= old_pos) + order[i] = i - 1; + else + order[i] = i; + } + + if (depth) + { + tmppath = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_store), &parent_iter); + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (tree_store), + tmppath, &parent_iter, order); + } + else + { + tmppath = gtk_tree_path_new (); + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (tree_store), + tmppath, NULL, order); + } + + gtk_tree_path_free (tmppath); + gtk_tree_path_free (path); + if (position) + gtk_tree_path_free (pos_path); + g_free (order); + + return; + +free_paths_and_out: + gtk_tree_path_free (path); + gtk_tree_path_free (pos_path); +} + +/** + * gtk_tree_store_move_before: + * @tree_store: A #GtkTreeStore. + * @iter: A #GtkTreeIter. + * @position: A #GtkTreeIter or %NULL. + * + * Moves @iter in @tree_store to the position before @position. @iter and + * @position should be in the same level. Note that this function only + * works with unsorted stores. If @position is %NULL, @iter will be + * moved to the end of the level. + * + * Since: 2.2 + **/ +void +gtk_tree_store_move_before (GtkTreeStore *tree_store, + GtkTreeIter *iter, + GtkTreeIter *position) +{ + gtk_tree_store_move (tree_store, iter, position, TRUE); +} + +/** + * gtk_tree_store_move_after: + * @tree_store: A #GtkTreeStore. + * @iter: A #GtkTreeIter. + * @position: A #GtkTreeIter. + * + * Moves @iter in @tree_store to the position after @position. @iter and + * @position should be in the same level. Note that this function only + * works with unsorted stores. If @position is %NULL, @iter will be moved + * to the start of the level. + * + * Since: 2.2 + **/ +void +gtk_tree_store_move_after (GtkTreeStore *tree_store, + GtkTreeIter *iter, + GtkTreeIter *position) +{ + gtk_tree_store_move (tree_store, iter, position, FALSE); +} + +/* Sorting */ static gint gtk_tree_store_compare_func (gconstpointer a, gconstpointer b, @@ -1772,9 +2602,12 @@ gtk_tree_store_sort_helper (GtkTreeStore *tree_store, node = parent->children; if (node == NULL || node->next == NULL) - return; + { + if (recurse && node && node->children) + gtk_tree_store_sort_helper (tree_store, node, TRUE); - g_assert (GTK_TREE_STORE_IS_SORTED (tree_store)); + return; + } list_length = 0; for (tmp_node = node; tmp_node; tmp_node = tmp_node->next) @@ -1793,6 +2626,7 @@ gtk_tree_store_sort_helper (GtkTreeStore *tree_store, i++; } + /* Sort the array */ g_array_sort_with_data (sort_array, gtk_tree_store_compare_func, tree_store); for (i = 0; i < list_length - 1; i++) @@ -1833,11 +2667,15 @@ gtk_tree_store_sort_helper (GtkTreeStore *tree_store, static void gtk_tree_store_sort (GtkTreeStore *tree_store) { + if (!GTK_TREE_STORE_IS_SORTED (tree_store)) + return; + if (tree_store->sort_column_id != -1) { GtkTreeDataSortHeader *header = NULL; - header = _gtk_tree_data_list_get_header (tree_store->sort_list, tree_store->sort_column_id); + header = _gtk_tree_data_list_get_header (tree_store->sort_list, + tree_store->sort_column_id); /* We want to make sure that we have a function */ g_return_if_fail (header != NULL); @@ -1892,7 +2730,7 @@ gtk_tree_store_sort_iter_changed (GtkTreeStore *tree_store, } /* If it's the built in function, we don't sort. */ - if (func == gtk_tree_data_list_compare_func && + if (func == _gtk_tree_data_list_compare_func && tree_store->sort_column_id != column) return; @@ -1924,7 +2762,6 @@ gtk_tree_store_sort_iter_changed (GtkTreeStore *tree_store, cmp_b = (* func) (GTK_TREE_MODEL (tree_store), iter, &tmp_iter, data); } - if (tree_store->order == GTK_SORT_DESCENDING) { if (cmp_a < 0) @@ -1953,6 +2790,7 @@ gtk_tree_store_sort_iter_changed (GtkTreeStore *tree_store, prev->next = next; else node->parent->children = next; + if (next) next->prev = prev; @@ -1983,6 +2821,7 @@ gtk_tree_store_sort_iter_changed (GtkTreeStore *tree_store, if ((!node->next) && (cmp_a > 0)) { + new_location++; node->next = G_NODE (iter->user_data); node->next->prev = node; } @@ -1996,6 +2835,7 @@ gtk_tree_store_sort_iter_changed (GtkTreeStore *tree_store, else { G_NODE (iter->user_data)->next = G_NODE (iter->user_data)->parent->children; + G_NODE (iter->user_data)->next->prev = G_NODE (iter->user_data); G_NODE (iter->user_data)->parent->children = G_NODE (iter->user_data); } @@ -2048,15 +2888,16 @@ gtk_tree_store_get_sort_column_id (GtkTreeSortable *sortable, g_return_val_if_fail (GTK_IS_TREE_STORE (sortable), FALSE); - if (tree_store->sort_column_id == -1) - return FALSE; - if (sort_column_id) * sort_column_id = tree_store->sort_column_id; if (order) * order = tree_store->order; - return TRUE; + if (tree_store->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID || + tree_store->sort_column_id == GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID) + return FALSE; + + return TRUE; } static void @@ -2073,27 +2914,31 @@ gtk_tree_store_set_sort_column_id (GtkTreeSortable *sortable, (tree_store->order == order)) return; - if (sort_column_id != -1) + if (sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID) { - GtkTreeDataSortHeader *header = NULL; + if (sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) + { + GtkTreeDataSortHeader *header = NULL; - header = _gtk_tree_data_list_get_header (tree_store->sort_list, sort_column_id); + header = _gtk_tree_data_list_get_header (tree_store->sort_list, + sort_column_id); - /* We want to make sure that we have a function */ - g_return_if_fail (header != NULL); - g_return_if_fail (header->func != NULL); - } - else - { - g_return_if_fail (tree_store->default_sort_func != NULL); + /* We want to make sure that we have a function */ + g_return_if_fail (header != NULL); + g_return_if_fail (header->func != NULL); + } + else + { + g_return_if_fail (tree_store->default_sort_func != NULL); + } } tree_store->sort_column_id = sort_column_id; tree_store->order = order; - gtk_tree_store_sort (tree_store); - gtk_tree_sortable_sort_column_changed (sortable); + + gtk_tree_store_sort (tree_store); } static void @@ -2104,33 +2949,16 @@ gtk_tree_store_set_sort_func (GtkTreeSortable *sortable, GtkDestroyNotify destroy) { GtkTreeStore *tree_store = (GtkTreeStore *) sortable; - GtkTreeDataSortHeader *header = NULL; - GList *list; g_return_if_fail (GTK_IS_TREE_STORE (sortable)); g_return_if_fail (func != NULL); - for (list = tree_store->sort_list; list; list = list->next) - { - header = (GtkTreeDataSortHeader*) list->data; - if (header->sort_column_id == sort_column_id) - break; - } - - if (header == NULL) - { - header = g_new0 (GtkTreeDataSortHeader, 1); - header->sort_column_id = sort_column_id; - tree_store->sort_list = g_list_append (tree_store->sort_list, header); - } - - if (header->destroy) - (* header->destroy) (header->data); - - header->func = func; - header->data = data; - header->destroy = destroy; + tree_store->sort_list = _gtk_tree_data_list_set_header (tree_store->sort_list, + sort_column_id, + func, data, destroy); + if (tree_store->sort_column_id == sort_column_id) + gtk_tree_store_sort (tree_store); } static void @@ -2144,11 +2972,19 @@ gtk_tree_store_set_default_sort_func (GtkTreeSortable *sortable, g_return_if_fail (GTK_IS_TREE_STORE (sortable)); if (tree_store->default_sort_destroy) - (* tree_store->default_sort_destroy) (tree_store->default_sort_data); + { + GtkDestroyNotify d = tree_store->default_sort_destroy; + + tree_store->default_sort_destroy = NULL; + d (tree_store->default_sort_data); + } tree_store->default_sort_func = func; tree_store->default_sort_data = data; tree_store->default_sort_destroy = destroy; + + if (tree_store->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) + gtk_tree_store_sort (tree_store); } static gboolean @@ -2177,5 +3013,5 @@ validate_gnode (GNode* node) } } - - +#define __GTK_TREE_STORE_C__ +#include "gtkaliasdef.c"