X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtktreemodelsort.c;h=9daa32fb488b8f1a7d21323e14a81d16a875cf39;hb=3e9664ce656e14a851be275e8747dfb14427a1f0;hp=b0021415e530b2b04aac171f46404b5c471e6527;hpb=ef32bad8770041697b7fe77b410c250ed3c8055a;p=~andy%2Fgtk diff --git a/gtk/gtktreemodelsort.c b/gtk/gtktreemodelsort.c index b0021415e..9daa32fb4 100644 --- a/gtk/gtktreemodelsort.c +++ b/gtk/gtktreemodelsort.c @@ -37,13 +37,124 @@ * we warned you and we're not liable for any head injuries. */ +#include "config.h" +#include + #include "gtktreemodelsort.h" #include "gtktreesortable.h" #include "gtktreestore.h" -#include "gtksignal.h" #include "gtktreedatalist.h" -#include #include "gtkintl.h" +#include "gtkprivate.h" +#include "gtktreednd.h" + + +/** + * SECTION:gtktreemodelsort + * @Short_description: A GtkTreeModel which makes an underlying tree model sortable + * @Title: GtkTreeModelSort + * @See_also: #GtkTreeModel, #GtkListStore, #GtkTreeStore, #GtkTreeSortable, #GtkTreeModelFilter + * + * The #GtkTreeModelSort is a model which implements the #GtkTreeSortable + * interface. It does not hold any data itself, but rather is created with + * a child model and proxies its data. It has identical column types to + * this child model, and the changes in the child are propagated. The + * primary purpose of this model is to provide a way to sort a different + * model without modifying it. Note that the sort function used by + * #GtkTreeModelSort is not guaranteed to be stable. + * + * The use of this is best demonstrated through an example. In the + * following sample code we create two #GtkTreeView widgets each with a + * view of the same data. As the model is wrapped here by a + * #GtkTreeModelSort, the two #GtkTreeViews can each sort their + * view of the data without affecting the other. By contrast, if we + * simply put the same model in each widget, then sorting the first would + * sort the second. + * + * + * Using a <structname>GtkTreeModelSort</structname> + * + * { + * GtkTreeView *tree_view1; + * GtkTreeView *tree_view2; + * GtkTreeModel *sort_model1; + * GtkTreeModel *sort_model2; + * GtkTreeModel *child_model; + * + * // get the child model + * child_model = get_my_model (); + * + * // Create the first tree + * sort_model1 = gtk_tree_model_sort_new_with_model (child_model); + * tree_view1 = gtk_tree_view_new_with_model (sort_model1); + * + * // Create the second tree + * sort_model2 = gtk_tree_model_sort_new_with_model (child_model); + * tree_view2 = gtk_tree_view_new_with_model (sort_model2); + * + * // Now we can sort the two models independently + * gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model1), + * COLUMN_1, GTK_SORT_ASCENDING); + * gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model2), + * COLUMN_1, GTK_SORT_DESCENDING); + * } + * + * + * + * To demonstrate how to access the underlying child model from the sort + * model, the next example will be a callback for the #GtkTreeSelection + * #GtkTreeSelection::changed signal. In this callback, we get a string + * from COLUMN_1 of the model. We then modify the string, find the same + * selected row on the child model, and change the row there. + * + * + * Accessing the child model of in a selection changed callback + * + * void + * selection_changed (GtkTreeSelection *selection, gpointer data) + * { + * GtkTreeModel *sort_model = NULL; + * GtkTreeModel *child_model; + * GtkTreeIter sort_iter; + * GtkTreeIter child_iter; + * char *some_data = NULL; + * char *modified_data; + * + * // Get the current selected row and the model. + * if (! gtk_tree_selection_get_selected (selection, + * &sort_model, + * &sort_iter)) + * return; + * + * /* Look up the current value on the selected row and get a new value + * * to change it to. + * */ + * gtk_tree_model_get (GTK_TREE_MODEL (sort_model), &sort_iter, + * COLUMN_1, &some_data, + * -1); + * + * modified_data = change_the_data (some_data); + * g_free (some_data); + * + * // Get an iterator on the child model, instead of the sort model. + * gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (sort_model), + * &child_iter, + * &sort_iter); + * + * /* Get the child model and change the value of the row. In this + * * example, the child model is a GtkListStore. It could be any other + * * type of model, though. + * */ + * child_model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model)); + * gtk_list_store_set (GTK_LIST_STORE (child_model), &child_iter, + * COLUMN_1, &modified_data, + * -1); + * g_free (modified_data); + * } + * + * + */ + typedef struct _SortElt SortElt; typedef struct _SortLevel SortLevel; @@ -63,7 +174,7 @@ struct _SortLevel { GArray *array; gint ref_count; - SortElt *parent_elt; + gint parent_elt_index; SortLevel *parent_level; }; @@ -91,21 +202,52 @@ enum { }; +struct _GtkTreeModelSortPrivate +{ + gpointer root; + gint stamp; + guint child_flags; + GtkTreeModel *child_model; + gint zero_ref_count; + + /* sort information */ + GList *sort_list; + gint sort_column_id; + GtkSortType order; + + /* default sort */ + GtkTreeIterCompareFunc default_sort_func; + gpointer default_sort_data; + GDestroyNotify default_sort_destroy; + + /* signal ids */ + gulong changed_id; + gulong inserted_id; + gulong has_child_toggled_id; + gulong deleted_id; + gulong reordered_id; +}; + #define GTK_TREE_MODEL_SORT_CACHE_CHILD_ITERS(tree_model_sort) \ - (((GtkTreeModelSort *)tree_model_sort)->child_flags>K_TREE_MODEL_ITERS_PERSIST) + (((GtkTreeModelSort *)tree_model_sort)->priv->child_flags>K_TREE_MODEL_ITERS_PERSIST) #define SORT_ELT(sort_elt) ((SortElt *)sort_elt) #define SORT_LEVEL(sort_level) ((SortLevel *)sort_level) -#define GET_CHILD_ITER(tree_model_sort,child_iter,sort_iter) gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT (tree_model_sort), child_iter, sort_iter); +#define SORT_LEVEL_PARENT_ELT(level) (&g_array_index (SORT_LEVEL ((level))->parent_level->array, SortElt, SORT_LEVEL ((level))->parent_elt_index)) +#define SORT_LEVEL_ELT_INDEX(level, elt) (SORT_ELT ((elt)) - SORT_ELT (SORT_LEVEL ((level))->array->data)) + + +#define GET_CHILD_ITER(tree_model_sort,ch_iter,so_iter) gtk_tree_model_sort_convert_iter_to_child_iter((GtkTreeModelSort*)(tree_model_sort), (ch_iter), (so_iter)); #define NO_SORT_FUNC ((GtkTreeIterCompareFunc) 0x1) +#define VALID_ITER(iter, tree_model_sort) ((iter) != NULL && (iter)->user_data != NULL && (iter)->user_data2 != NULL && (tree_model_sort)->priv->stamp == (iter)->stamp) + /* general (object/interface init, etc) */ -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_tree_sortable_init (GtkTreeSortableIface *iface); +static void gtk_tree_model_sort_drag_source_init (GtkTreeDragSourceIface*iface); static void gtk_tree_model_sort_finalize (GObject *object); static void gtk_tree_model_sort_set_property (GObject *object, guint prop_id, @@ -139,7 +281,7 @@ static void gtk_tree_model_sort_rows_reordered (GtkTreeModel *s_ gpointer data); /* TreeModel interface */ -static guint gtk_tree_model_sort_get_flags (GtkTreeModel *tree_model); +static GtkTreeModelFlags gtk_tree_model_sort_get_flags (GtkTreeModel *tree_model); 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); @@ -154,6 +296,8 @@ static void gtk_tree_model_sort_get_value (GtkTreeModel GValue *value); static gboolean gtk_tree_model_sort_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter); +static gboolean gtk_tree_model_sort_iter_previous (GtkTreeModel *tree_model, + GtkTreeIter *iter); static gboolean gtk_tree_model_sort_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent); @@ -176,6 +320,15 @@ static void gtk_tree_model_sort_real_unref_node (GtkTreeModel static void gtk_tree_model_sort_unref_node (GtkTreeModel *tree_model, GtkTreeIter *iter); +/* TreeDragSource interface */ +static gboolean gtk_tree_model_sort_row_draggable (GtkTreeDragSource *drag_source, + GtkTreePath *path); +static gboolean gtk_tree_model_sort_drag_data_get (GtkTreeDragSource *drag_source, + GtkTreePath *path, + GtkSelectionData *selection_data); +static gboolean gtk_tree_model_sort_drag_data_delete (GtkTreeDragSource *drag_source, + GtkTreePath *path); + /* TreeSortable interface */ static gboolean gtk_tree_model_sort_get_sort_column_id (GtkTreeSortable *sortable, gint *sort_column_id, @@ -187,17 +340,17 @@ static void gtk_tree_model_sort_set_sort_func (GtkTreeSortable gint sort_column_id, GtkTreeIterCompareFunc func, gpointer data, - GtkDestroyNotify destroy); + GDestroyNotify destroy); static void gtk_tree_model_sort_set_default_sort_func (GtkTreeSortable *sortable, GtkTreeIterCompareFunc func, gpointer data, - GtkDestroyNotify destroy); + GDestroyNotify destroy); static gboolean gtk_tree_model_sort_has_default_sort_func (GtkTreeSortable *sortable); /* Private functions (sort funcs, level handling and other utils) */ static void gtk_tree_model_sort_build_level (GtkTreeModelSort *tree_model_sort, SortLevel *parent_level, - SortElt *parent_elt); + gint parent_elt_index); static void gtk_tree_model_sort_free_level (GtkTreeModelSort *tree_model_sort, SortLevel *sort_level); static void gtk_tree_model_sort_increment_stamp (GtkTreeModelSort *tree_model_sort); @@ -209,7 +362,7 @@ static void gtk_tree_model_sort_sort (GtkTreeModelSort *tre static gint gtk_tree_model_sort_level_find_insert (GtkTreeModelSort *tree_model_sort, SortLevel *level, GtkTreeIter *iter, - gboolean skip_sort_elt); + gint skip_index); static gboolean gtk_tree_model_sort_insert_value (GtkTreeModelSort *tree_model_sort, SortLevel *level, GtkTreePath *s_path, @@ -222,65 +375,29 @@ static GtkTreePath *gtk_real_tree_model_sort_convert_child_path_to_path (GtkTree GtkTreePath *child_path, gboolean build_levels); -static GObjectClass *parent_class = NULL; -GType -gtk_tree_model_sort_get_type (void) -{ - static GType 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 - }; - - static const GInterfaceInfo sortable_info = - { - (GInterfaceInitFunc) gtk_tree_model_sort_tree_sortable_init, - NULL, - NULL - }; - - tree_model_sort_type = g_type_register_static (G_TYPE_OBJECT, - "GtkTreeModelSort", - &tree_model_sort_info, 0); - g_type_add_interface_static (tree_model_sort_type, - GTK_TYPE_TREE_MODEL, - &tree_model_info); - - g_type_add_interface_static (tree_model_sort_type, - GTK_TYPE_TREE_SORTABLE, - &sortable_info); - } - - return tree_model_sort_type; -} +G_DEFINE_TYPE_WITH_CODE (GtkTreeModelSort, gtk_tree_model_sort, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, + gtk_tree_model_sort_tree_model_init) + G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE, + gtk_tree_model_sort_tree_sortable_init) + G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE, + gtk_tree_model_sort_drag_source_init)) static void gtk_tree_model_sort_init (GtkTreeModelSort *tree_model_sort) { - tree_model_sort->sort_column_id = GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID; - tree_model_sort->stamp = 0; - tree_model_sort->zero_ref_count = 0; - tree_model_sort->root = NULL; - tree_model_sort->sort_list = NULL; + GtkTreeModelSortPrivate *priv; + + priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_model_sort, + GTK_TYPE_TREE_MODEL_SORT, + GtkTreeModelSortPrivate); + tree_model_sort->priv = priv; + priv->sort_column_id = GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID; + priv->stamp = 0; + priv->zero_ref_count = 0; + priv->root = NULL; + priv->sort_list = NULL; } static void @@ -289,7 +406,6 @@ gtk_tree_model_sort_class_init (GtkTreeModelSortClass *class) GObjectClass *object_class; object_class = (GObjectClass *) class; - parent_class = g_type_class_peek_parent (class); object_class->set_property = gtk_tree_model_sort_set_property; object_class->get_property = gtk_tree_model_sort_get_property; @@ -300,10 +416,12 @@ gtk_tree_model_sort_class_init (GtkTreeModelSortClass *class) g_object_class_install_property (object_class, PROP_MODEL, g_param_spec_object ("model", - _("TreeModelSort Model"), - _("The model for the TreeModelSort to sort"), + P_("TreeModelSort Model"), + P_("The model for the TreeModelSort to sort"), GTK_TYPE_TREE_MODEL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_type_class_add_private (class, sizeof (GtkTreeModelSortPrivate)); } static void @@ -316,6 +434,7 @@ gtk_tree_model_sort_tree_model_init (GtkTreeModelIface *iface) 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_previous = gtk_tree_model_sort_iter_previous; 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; @@ -335,22 +454,30 @@ gtk_tree_model_sort_tree_sortable_init (GtkTreeSortableIface *iface) iface->has_default_sort_func = gtk_tree_model_sort_has_default_sort_func; } +static void +gtk_tree_model_sort_drag_source_init (GtkTreeDragSourceIface *iface) +{ + iface->row_draggable = gtk_tree_model_sort_row_draggable; + iface->drag_data_delete = gtk_tree_model_sort_drag_data_delete; + iface->drag_data_get = gtk_tree_model_sort_drag_data_get; +} + /** * gtk_tree_model_sort_new_with_model: * @child_model: A #GtkTreeModel * - * Creates a new #GtkTreeModel, with @child_model as the child_model. + * Creates a new #GtkTreeModel, with @child_model as the child model. * - * Return value: A new #GtkTreeModel. + * Return value: (transfer full): A new #GtkTreeModel. */ GtkTreeModel * -gtk_tree_model_sort_new_with_model (GtkTreeModel *child_model) +gtk_tree_model_sort_new_with_model (GtkTreeModel *child_model) { GtkTreeModel *retval; g_return_val_if_fail (GTK_IS_TREE_MODEL (child_model), NULL); - retval = GTK_TREE_MODEL (g_object_new (gtk_tree_model_sort_get_type (), NULL)); + retval = g_object_new (gtk_tree_model_sort_get_type (), NULL); gtk_tree_model_sort_set_model (GTK_TREE_MODEL_SORT (retval), child_model); @@ -362,20 +489,29 @@ static void gtk_tree_model_sort_finalize (GObject *object) { GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) object; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; gtk_tree_model_sort_set_model (tree_model_sort, NULL); - if (tree_model_sort->root) - gtk_tree_model_sort_free_level (tree_model_sort, tree_model_sort->root); + if (priv->root) + gtk_tree_model_sort_free_level (tree_model_sort, priv->root); - if (tree_model_sort->sort_list) + if (priv->sort_list) { - _gtk_tree_data_list_header_free (tree_model_sort->sort_list); - tree_model_sort->sort_list = NULL; + _gtk_tree_data_list_header_free (priv->sort_list); + priv->sort_list = NULL; } + if (priv->default_sort_destroy) + { + priv->default_sort_destroy (priv->default_sort_data); + priv->default_sort_destroy = NULL; + priv->default_sort_data = NULL; + } + + /* must chain up */ - parent_class->finalize (object); + G_OBJECT_CLASS (gtk_tree_model_sort_parent_class)->finalize (object); } static void @@ -408,7 +544,7 @@ gtk_tree_model_sort_get_property (GObject *object, switch (prop_id) { case PROP_MODEL: - g_value_set_object (value, gtk_tree_model_sort_get_model(tree_model_sort)); + g_value_set_object (value, gtk_tree_model_sort_get_model (tree_model_sort)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -423,6 +559,7 @@ gtk_tree_model_sort_row_changed (GtkTreeModel *s_model, gpointer data) { GtkTreeModelSort *tree_model_sort = GTK_TREE_MODEL_SORT (data); + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; GtkTreePath *path = NULL; GtkTreeIter iter; GtkTreeIter tmpiter; @@ -433,7 +570,7 @@ gtk_tree_model_sort_row_changed (GtkTreeModel *s_model, gboolean free_s_path = FALSE; - gint offset, index = 0, i; + gint index = 0, old_index, i; g_return_if_fail (start_s_path != NULL || start_s_iter != NULL); @@ -454,63 +591,132 @@ gtk_tree_model_sort_row_changed (GtkTreeModel *s_model, } gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); + gtk_tree_model_sort_ref_node (GTK_TREE_MODEL (data), &iter); level = iter.user_data; elt = iter.user_data2; if (level->array->len < 2 || - (tree_model_sort->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID && - tree_model_sort->default_sort_func == NO_SORT_FUNC)) + (priv->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID && + priv->default_sort_func == NO_SORT_FUNC)) { if (free_s_path) gtk_tree_path_free (start_s_path); gtk_tree_model_row_changed (GTK_TREE_MODEL (data), path, &iter); + gtk_tree_model_sort_unref_node (GTK_TREE_MODEL (data), &iter); gtk_tree_path_free (path); return; } - + if (!GTK_TREE_MODEL_SORT_CACHE_CHILD_ITERS (tree_model_sort)) { - gtk_tree_model_get_iter (tree_model_sort->child_model, + gtk_tree_model_get_iter (priv->child_model, &tmpiter, start_s_path); } - offset = elt->offset; - - for (i = 0; i < level->array->len; i++) - if (elt->offset == g_array_index (level->array, SortElt, i).offset) - index = i; + old_index = elt - SORT_ELT (level->array->data); memcpy (&tmp, elt, sizeof (SortElt)); - g_array_remove_index (level->array, index); if (GTK_TREE_MODEL_SORT_CACHE_CHILD_ITERS (tree_model_sort)) index = gtk_tree_model_sort_level_find_insert (tree_model_sort, level, &tmp.iter, - TRUE); + old_index); else index = gtk_tree_model_sort_level_find_insert (tree_model_sort, level, &tmpiter, - TRUE); + old_index); - g_array_insert_val (level->array, index, tmp); + if (index < old_index) + { + g_memmove (level->array->data + ((index + 1)*sizeof (SortElt)), + level->array->data + ((index)*sizeof (SortElt)), + (old_index - index)* sizeof(SortElt)); + } + else if (index > old_index) + { + g_memmove (level->array->data + ((old_index)*sizeof (SortElt)), + level->array->data + ((old_index + 1)*sizeof (SortElt)), + (index - old_index)* sizeof(SortElt)); + } + memcpy (level->array->data + ((index)*sizeof (SortElt)), + &tmp, sizeof (SortElt)); for (i = 0; i < level->array->len; i++) if (g_array_index (level->array, SortElt, i).children) - g_array_index (level->array, SortElt, i).children->parent_elt = &g_array_index (level->array, SortElt, i); + g_array_index (level->array, SortElt, i).children->parent_elt_index = i; gtk_tree_path_up (path); gtk_tree_path_append_index (path, index); gtk_tree_model_sort_increment_stamp (tree_model_sort); - gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); + /* if the item moved, then emit rows_reordered */ + if (old_index != index) + { + gint *new_order; + gint j; + + GtkTreePath *tmppath; + + new_order = g_new (gint, level->array->len); + + for (j = 0; j < level->array->len; j++) + { + if (index > old_index) + { + if (j == index) + new_order[j] = old_index; + else if (j >= old_index && j < index) + new_order[j] = j + 1; + else + new_order[j] = j; + } + else if (index < old_index) + { + if (j == index) + new_order[j] = old_index; + else if (j > index && j <= old_index) + new_order[j] = j - 1; + else + new_order[j] = j; + } + /* else? shouldn't really happen */ + } + + if (level->parent_elt_index >= 0) + { + iter.stamp = priv->stamp; + iter.user_data = level->parent_level; + iter.user_data2 = SORT_LEVEL_PARENT_ELT (level); + + tmppath = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_model_sort), &iter); + + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (tree_model_sort), + tmppath, &iter, new_order); + } + else + { + /* toplevel */ + tmppath = gtk_tree_path_new (); + + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (tree_model_sort), tmppath, + NULL, new_order); + } + + gtk_tree_path_free (tmppath); + g_free (new_order); + } + + /* emit row_changed signal (at new location) */ + gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); gtk_tree_model_row_changed (GTK_TREE_MODEL (data), path, &iter); + gtk_tree_model_sort_unref_node (GTK_TREE_MODEL (data), &iter); gtk_tree_path_free (path); if (free_s_path) @@ -524,6 +730,7 @@ gtk_tree_model_sort_row_inserted (GtkTreeModel *s_model, gpointer data) { GtkTreeModelSort *tree_model_sort = GTK_TREE_MODEL_SORT (data); + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; GtkTreePath *path; GtkTreeIter iter; GtkTreeIter real_s_iter; @@ -536,7 +743,7 @@ gtk_tree_model_sort_row_inserted (GtkTreeModel *s_model, SortLevel *level; SortLevel *parent_level = NULL; - parent_level = level = SORT_LEVEL (tree_model_sort->root); + parent_level = level = SORT_LEVEL (priv->root); g_return_if_fail (s_path != NULL || s_iter != NULL); @@ -551,9 +758,9 @@ gtk_tree_model_sort_row_inserted (GtkTreeModel *s_model, else real_s_iter = *s_iter; - if (!tree_model_sort->root) + if (!priv->root) { - gtk_tree_model_sort_build_level (tree_model_sort, NULL, NULL); + gtk_tree_model_sort_build_level (tree_model_sort, NULL, -1); /* the build level already put the inserted iter in the level, so no need to handle this signal anymore */ @@ -574,9 +781,10 @@ gtk_tree_model_sort_row_inserted (GtkTreeModel *s_model, if (level->array->len < gtk_tree_path_get_indices (s_path)[i]) { - g_warning ("A node was inserted with a parent that's not in the tree.\n" + g_warning ("%s: A node was inserted with a parent that's not in the tree.\n" "This possibly means that a GtkTreeModel inserted a child node\n" - "before the parent was inserted."); + "before the parent was inserted.", + G_STRLOC); goto done; } @@ -592,20 +800,6 @@ gtk_tree_model_sort_row_inserted (GtkTreeModel *s_model, if (!elt->children) { - GtkTreePath *tmppath; - GtkTreeIter tmpiter; - - tmppath = gtk_tree_model_sort_elt_get_path (level, elt); - if (tmppath) - { - gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &tmpiter, - tmppath); - gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data), - tmppath, - &tmpiter); - gtk_tree_path_free (tmppath); - } - /* not covering this signal */ goto done; } @@ -618,6 +812,12 @@ gtk_tree_model_sort_row_inserted (GtkTreeModel *s_model, if (!parent_level) goto done; + if (level->ref_count == 0 && level != priv->root) + { + gtk_tree_model_sort_free_level (tree_model_sort, level); + goto done; + } + if (!gtk_tree_model_sort_insert_value (tree_model_sort, parent_level, s_path, @@ -667,7 +867,6 @@ gtk_tree_model_sort_row_has_child_toggled (GtkTreeModel *s_model, gtk_tree_path_free (path); } -/* FIXME: I still have doubts if this works */ static void gtk_tree_model_sort_row_deleted (GtkTreeModel *s_model, GtkTreePath *s_path, @@ -704,12 +903,20 @@ gtk_tree_model_sort_row_deleted (GtkTreeModel *s_model, while (elt->ref_count > 0) gtk_tree_model_sort_real_unref_node (GTK_TREE_MODEL (data), &iter, FALSE); - if (level->ref_count == 0 && level != tree_model_sort->root) + if (level->ref_count == 0) { - /* This will prune the level, so I can just emit the signal and not worry - * about cleaning this level up. */ + /* This will prune the level, so I can just emit the signal and + * not worry about cleaning this level up. + * Careful, root level is not cleaned up in increment stamp. + */ gtk_tree_model_sort_increment_stamp (tree_model_sort); gtk_tree_path_free (path); + if (level == tree_model_sort->priv->root) + { + gtk_tree_model_sort_free_level (tree_model_sort, + tree_model_sort->priv->root); + tree_model_sort->priv->root = NULL; + } return; } @@ -729,7 +936,7 @@ gtk_tree_model_sort_row_deleted (GtkTreeModel *s_model, if (elt->offset > offset) elt->offset--; if (elt->children) - elt->children->parent_elt = elt; + elt->children->parent_elt_index = i; } gtk_tree_path_free (path); @@ -749,15 +956,16 @@ gtk_tree_model_sort_rows_reordered (GtkTreeModel *s_model, int i, j; GtkTreePath *path; GtkTreeModelSort *tree_model_sort = GTK_TREE_MODEL_SORT (data); + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; g_return_if_fail (new_order != NULL); - if (s_path == NULL || gtk_tree_path_get_indices (s_path) == NULL) + if (s_path == NULL || gtk_tree_path_get_depth (s_path) == 0) { - if (tree_model_sort->root == NULL) + if (priv->root == NULL) return; path = gtk_tree_path_new (); - level = SORT_LEVEL (tree_model_sort->root); + level = SORT_LEVEL (priv->root); } else { @@ -798,8 +1006,8 @@ gtk_tree_model_sort_rows_reordered (GtkTreeModel *s_model, g_array_index (level->array, SortElt, i).offset = tmp_array[i]; g_free (tmp_array); - if (tree_model_sort->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID && - tree_model_sort->default_sort_func == NO_SORT_FUNC) + if (priv->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID && + priv->default_sort_func == NO_SORT_FUNC) { gtk_tree_model_sort_sort_level (tree_model_sort, level, @@ -825,10 +1033,18 @@ gtk_tree_model_sort_rows_reordered (GtkTreeModel *s_model, } /* Fulfill our model requirements */ -static guint +static GtkTreeModelFlags gtk_tree_model_sort_get_flags (GtkTreeModel *tree_model) { - g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), 0); + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; + GtkTreeModelFlags flags; + + g_return_val_if_fail (tree_model_sort->priv->child_model != NULL, 0); + + flags = gtk_tree_model_get_flags (tree_model_sort->priv->child_model); + + if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY) + return GTK_TREE_MODEL_LIST_ONLY; return 0; } @@ -838,22 +1054,21 @@ gtk_tree_model_sort_get_n_columns (GtkTreeModel *tree_model) { GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; - g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), 0); - - if (tree_model_sort->child_model == 0) + if (tree_model_sort->priv->child_model == 0) return 0; - return gtk_tree_model_get_n_columns (tree_model_sort->child_model); + return gtk_tree_model_get_n_columns (tree_model_sort->priv->child_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)->child_model != NULL, G_TYPE_INVALID); + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; + + g_return_val_if_fail (tree_model_sort->priv->child_model != NULL, G_TYPE_INVALID); - return gtk_tree_model_get_column_type (GTK_TREE_MODEL_SORT (tree_model)->child_model, index); + return gtk_tree_model_get_column_type (tree_model_sort->priv->child_model, index); } static gboolean @@ -861,20 +1076,19 @@ gtk_tree_model_sort_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path) { - GtkTreeModelSort *tree_model_sort; + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; gint *indices; SortLevel *level; gint depth, i; - g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), FALSE); - g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->child_model != NULL, FALSE); + g_return_val_if_fail (priv->child_model != NULL, FALSE); - tree_model_sort = (GtkTreeModelSort *) tree_model; indices = gtk_tree_path_get_indices (path); - if (tree_model_sort->root == NULL) - gtk_tree_model_sort_build_level (tree_model_sort, NULL, NULL); - level = SORT_LEVEL (tree_model_sort->root); + if (priv->root == NULL) + gtk_tree_model_sort_build_level (tree_model_sort, NULL, -1); + level = SORT_LEVEL (priv->root); depth = gtk_tree_path_get_depth (path); if (depth == 0) @@ -883,17 +1097,21 @@ gtk_tree_model_sort_get_iter (GtkTreeModel *tree_model, for (i = 0; i < depth - 1; i++) { if ((level == NULL) || - (level->array->len < indices[i])) + (indices[i] >= level->array->len)) return FALSE; if (g_array_index (level->array, SortElt, indices[i]).children == NULL) - gtk_tree_model_sort_build_level (tree_model_sort, level, &g_array_index (level->array, SortElt, indices[i])); + gtk_tree_model_sort_build_level (tree_model_sort, level, indices[i]); level = g_array_index (level->array, SortElt, indices[i]).children; } - if (level == NULL) - return FALSE; - iter->stamp = tree_model_sort->stamp; + if (!level || indices[i] >= level->array->len) + { + iter->stamp = 0; + return FALSE; + } + + iter->stamp = priv->stamp; iter->user_data = level; iter->user_data2 = &g_array_index (level->array, SortElt, indices[depth - 1]); @@ -904,22 +1122,25 @@ static GtkTreePath * gtk_tree_model_sort_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter) { + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; GtkTreePath *retval; SortLevel *level; - SortElt *elt; + gint elt_index; - g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), NULL); - g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->child_model != NULL, NULL); - g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == iter->stamp, NULL); + g_return_val_if_fail (priv->child_model != NULL, NULL); + g_return_val_if_fail (priv->stamp == iter->stamp, NULL); retval = gtk_tree_path_new (); - level = iter->user_data; - elt = iter->user_data2; - while (level != NULL) + + level = SORT_LEVEL (iter->user_data); + elt_index = SORT_LEVEL_ELT_INDEX (level, iter->user_data2); + + while (level) { - gtk_tree_path_prepend_index (retval, elt - (SortElt *)level->array->data); + gtk_tree_path_prepend_index (retval, elt_index); - elt = level->parent_elt; + elt_index = level->parent_elt_index; level = level->parent_level; } @@ -932,14 +1153,15 @@ gtk_tree_model_sort_get_value (GtkTreeModel *tree_model, gint column, GValue *value) { + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; GtkTreeIter child_iter; - g_return_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model)); - g_return_if_fail (GTK_TREE_MODEL_SORT (tree_model)->child_model != NULL); - g_return_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == iter->stamp); + g_return_if_fail (priv->child_model != NULL); + g_return_if_fail (VALID_ITER (iter, tree_model_sort)); - GET_CHILD_ITER (tree_model, &child_iter, iter); - gtk_tree_model_get_value (GTK_TREE_MODEL_SORT (tree_model)->child_model, + GET_CHILD_ITER (tree_model_sort, &child_iter, iter); + gtk_tree_model_get_value (priv->child_model, &child_iter, column, value); } @@ -947,12 +1169,13 @@ static gboolean gtk_tree_model_sort_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter) { + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; SortLevel *level; 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)->child_model != NULL, FALSE); - g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == iter->stamp, FALSE); + g_return_val_if_fail (priv->child_model != NULL, FALSE); + g_return_val_if_fail (priv->stamp == iter->stamp, FALSE); level = iter->user_data; elt = iter->user_data2; @@ -967,42 +1190,74 @@ gtk_tree_model_sort_iter_next (GtkTreeModel *tree_model, return TRUE; } +static gboolean +gtk_tree_model_sort_iter_previous (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; + SortLevel *level; + SortElt *elt; + + g_return_val_if_fail (priv->child_model != NULL, FALSE); + g_return_val_if_fail (priv->stamp == iter->stamp, FALSE); + + level = iter->user_data; + elt = iter->user_data2; + + if (elt == (SortElt *)level->array->data) + { + iter->stamp = 0; + return FALSE; + } + iter->user_data2 = elt - 1; + + return TRUE; +} + static gboolean gtk_tree_model_sort_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) { GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; SortLevel *level; iter->stamp = 0; - g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), FALSE); - g_return_val_if_fail (tree_model_sort->child_model != NULL, FALSE); - if (parent) g_return_val_if_fail (tree_model_sort->stamp == parent->stamp, FALSE); + g_return_val_if_fail (priv->child_model != NULL, FALSE); + if (parent) + g_return_val_if_fail (VALID_ITER (parent, tree_model_sort), FALSE); if (parent == NULL) { - if (tree_model_sort->root == NULL) - gtk_tree_model_sort_build_level (tree_model_sort, NULL, NULL); - if (tree_model_sort->root == NULL) + if (priv->root == NULL) + gtk_tree_model_sort_build_level (tree_model_sort, NULL, -1); + if (priv->root == NULL) return FALSE; - level = tree_model_sort->root; - iter->stamp = tree_model_sort->stamp; + level = priv->root; + iter->stamp = priv->stamp; iter->user_data = level; iter->user_data2 = level->array->data; } else { - if (((SortElt *)parent->user_data2)->children == NULL) - gtk_tree_model_sort_build_level (tree_model_sort, - (SortLevel *)parent->user_data, - (SortElt *)parent->user_data2); - if (((SortElt *)parent->user_data2)->children == NULL) + SortElt *elt; + + level = SORT_LEVEL (parent->user_data); + elt = SORT_ELT (parent->user_data2); + + if (elt->children == NULL) + gtk_tree_model_sort_build_level (tree_model_sort, level, + SORT_LEVEL_ELT_INDEX (level, elt)); + + if (elt->children == NULL) return FALSE; - iter->stamp = tree_model_sort->stamp; - iter->user_data = ((SortElt *)parent->user_data2)->children; - iter->user_data2 = ((SortLevel *)iter->user_data)->array->data; + + iter->stamp = priv->stamp; + iter->user_data = elt->children; + iter->user_data2 = elt->children->array->data; } return TRUE; @@ -1012,33 +1267,36 @@ static gboolean gtk_tree_model_sort_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter) { + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; GtkTreeIter child_iter; - g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), FALSE); - g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->child_model != NULL, FALSE); - g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == iter->stamp, FALSE); + g_return_val_if_fail (priv->child_model != NULL, FALSE); + g_return_val_if_fail (VALID_ITER (iter, tree_model_sort), FALSE); - GET_CHILD_ITER (tree_model, &child_iter, iter); + GET_CHILD_ITER (tree_model_sort, &child_iter, iter); - return gtk_tree_model_iter_has_child (GTK_TREE_MODEL_SORT (tree_model)->child_model, &child_iter); + return gtk_tree_model_iter_has_child (priv->child_model, &child_iter); } static gint gtk_tree_model_sort_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter) { + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; GtkTreeIter child_iter; - g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), 0); - g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->child_model != NULL, 0); - if (iter) g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == iter->stamp, 0); + g_return_val_if_fail (priv->child_model != NULL, 0); + if (iter) + g_return_val_if_fail (VALID_ITER (iter, tree_model_sort), 0); if (iter == NULL) - return gtk_tree_model_iter_n_children (GTK_TREE_MODEL_SORT (tree_model)->child_model, NULL); + return gtk_tree_model_iter_n_children (priv->child_model, NULL); - GET_CHILD_ITER (tree_model, &child_iter, iter); + GET_CHILD_ITER (tree_model_sort, &child_iter, iter); - return gtk_tree_model_iter_n_children (GTK_TREE_MODEL_SORT (tree_model)->child_model, &child_iter); + return gtk_tree_model_iter_n_children (priv->child_model, &child_iter); } static gboolean @@ -1047,12 +1305,13 @@ gtk_tree_model_sort_iter_nth_child (GtkTreeModel *tree_model, GtkTreeIter *parent, gint n) { + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; SortLevel *level; /* We have this for the iter == parent case */ GtkTreeIter children; - g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), FALSE); - if (parent) g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == parent->stamp, FALSE); + if (parent) + g_return_val_if_fail (VALID_ITER (parent, tree_model_sort), FALSE); /* Use this instead of has_child to force us to build the level, if needed */ if (gtk_tree_model_sort_iter_children (tree_model, &children, parent) == FALSE) @@ -1068,7 +1327,7 @@ gtk_tree_model_sort_iter_nth_child (GtkTreeModel *tree_model, return FALSE; } - iter->stamp = GTK_TREE_MODEL_SORT (tree_model)->stamp; + iter->stamp = tree_model_sort->priv->stamp; iter->user_data = level; iter->user_data2 = &g_array_index (level->array, SortElt, n); @@ -1079,21 +1338,22 @@ static gboolean gtk_tree_model_sort_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) -{ +{ + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; SortLevel *level; iter->stamp = 0; - g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), FALSE); - g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->child_model != NULL, FALSE); - g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == child->stamp, FALSE); + g_return_val_if_fail (priv->child_model != NULL, FALSE); + g_return_val_if_fail (VALID_ITER (child, tree_model_sort), FALSE); level = child->user_data; if (level->parent_level) { - iter->stamp = GTK_TREE_MODEL_SORT (tree_model)->stamp; + iter->stamp = priv->stamp; iter->user_data = level->parent_level; - iter->user_data2 = level->parent_elt; + iter->user_data2 = SORT_LEVEL_PARENT_ELT (level); return TRUE; } @@ -1105,42 +1365,61 @@ gtk_tree_model_sort_ref_node (GtkTreeModel *tree_model, GtkTreeIter *iter) { GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; GtkTreeIter child_iter; - SortLevel *level; + SortLevel *level, *parent_level; SortElt *elt; + gint parent_elt_index; - g_return_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model)); - g_return_if_fail (GTK_TREE_MODEL_SORT (tree_model)->child_model != NULL); - g_return_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == iter->stamp); + g_return_if_fail (priv->child_model != NULL); + g_return_if_fail (VALID_ITER (iter, tree_model_sort)); - GET_CHILD_ITER (tree_model, &child_iter, iter); + GET_CHILD_ITER (tree_model_sort, &child_iter, iter); - gtk_tree_model_ref_node (GTK_TREE_MODEL_SORT (tree_model)->child_model, &child_iter); + /* Reference the node in the child model */ + gtk_tree_model_ref_node (priv->child_model, &child_iter); + /* Increase the reference count of this element and its level */ level = iter->user_data; elt = iter->user_data2; elt->ref_count++; level->ref_count++; + + /* Increase the reference count of all parent elements */ + parent_level = level->parent_level; + parent_elt_index = level->parent_elt_index; + + while (parent_level) + { + GtkTreeIter tmp_iter; + + tmp_iter.stamp = priv->stamp; + tmp_iter.user_data = parent_level; + tmp_iter.user_data2 = &g_array_index (parent_level->array, SortElt, parent_elt_index); + + gtk_tree_model_sort_ref_node (tree_model, &tmp_iter); + + parent_elt_index = parent_level->parent_elt_index; + parent_level = parent_level->parent_level; + } + if (level->ref_count == 1) { SortLevel *parent_level = level->parent_level; - SortElt *parent_elt = level->parent_elt; + gint parent_elt_index = level->parent_elt_index; + /* We were at zero -- time to decrement the zero_ref_count val */ - do - { - if (parent_elt) - parent_elt->zero_ref_count--; - else - tree_model_sort->zero_ref_count--; + while (parent_level) + { + g_array_index (parent_level->array, SortElt, parent_elt_index).zero_ref_count--; - if (parent_level) - { - parent_elt = parent_level->parent_elt; - parent_level = parent_level->parent_level; - } + parent_elt_index = parent_level->parent_elt_index; + parent_level = parent_level->parent_level; } - while (parent_level); + + if (priv->root != level) + priv->zero_ref_count--; } } @@ -1150,18 +1429,21 @@ gtk_tree_model_sort_real_unref_node (GtkTreeModel *tree_model, gboolean propagate_unref) { GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model; - GtkTreeIter child_iter; - SortLevel *level; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; + SortLevel *level, *parent_level; SortElt *elt; + gint parent_elt_index; - g_return_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model)); - g_return_if_fail (GTK_TREE_MODEL_SORT (tree_model)->child_model != NULL); - g_return_if_fail (GTK_TREE_MODEL_SORT (tree_model)->stamp == iter->stamp); - - GET_CHILD_ITER (tree_model, &child_iter, iter); + g_return_if_fail (priv->child_model != NULL); + g_return_if_fail (VALID_ITER (iter, tree_model_sort)); if (propagate_unref) - gtk_tree_model_unref_node (GTK_TREE_MODEL_SORT (tree_model)->child_model, &child_iter); + { + GtkTreeIter child_iter; + + GET_CHILD_ITER (tree_model_sort, &child_iter, iter); + gtk_tree_model_unref_node (priv->child_model, &child_iter); + } level = iter->user_data; elt = iter->user_data2; @@ -1170,20 +1452,41 @@ gtk_tree_model_sort_real_unref_node (GtkTreeModel *tree_model, elt->ref_count--; level->ref_count--; + + /* Decrease the reference count of all parent elements */ + parent_level = level->parent_level; + parent_elt_index = level->parent_elt_index; + + while (parent_level) + { + GtkTreeIter tmp_iter; + + tmp_iter.stamp = priv->stamp; + tmp_iter.user_data = parent_level; + tmp_iter.user_data2 = &g_array_index (parent_level->array, SortElt, parent_elt_index); + + gtk_tree_model_sort_real_unref_node (tree_model, &tmp_iter, FALSE); + + parent_elt_index = parent_level->parent_elt_index; + parent_level = parent_level->parent_level; + } + if (level->ref_count == 0) { SortLevel *parent_level = level->parent_level; - SortElt *parent_elt = level->parent_elt; + gint parent_elt_index = level->parent_elt_index; /* We are at zero -- time to increment the zero_ref_count val */ while (parent_level) { - parent_elt->zero_ref_count++; + g_array_index (parent_level->array, SortElt, parent_elt_index).zero_ref_count++; - parent_elt = parent_level->parent_elt; + parent_elt_index = parent_level->parent_elt_index; parent_level = parent_level->parent_level; } - tree_model_sort->zero_ref_count++; + + if (priv->root != level) + priv->zero_ref_count++; } } @@ -1201,17 +1504,17 @@ gtk_tree_model_sort_get_sort_column_id (GtkTreeSortable *sortable, GtkSortType *order) { GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *)sortable; - - g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (sortable), FALSE); - - if (tree_model_sort->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) - return FALSE; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; if (sort_column_id) - *sort_column_id = tree_model_sort->sort_column_id; + *sort_column_id = priv->sort_column_id; if (order) - *order = tree_model_sort->order; + *order = priv->order; + if (priv->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID || + priv->sort_column_id == GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID) + return FALSE; + return TRUE; } @@ -1221,39 +1524,42 @@ gtk_tree_model_sort_set_sort_column_id (GtkTreeSortable *sortable, GtkSortType order) { GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *)sortable; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; - g_return_if_fail (GTK_IS_TREE_MODEL_SORT (sortable)); - - if (sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) + 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_model_sort->sort_list, - sort_column_id); + header = _gtk_tree_data_list_get_header (priv->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_model_sort->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 (priv->default_sort_func != NULL); - if (tree_model_sort->sort_column_id == sort_column_id) - { - if (sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) - { - if (tree_model_sort->order == order) + if (priv->sort_column_id == sort_column_id) + { + if (sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) + { + if (priv->order == order) + return; + } + else return; - } - else - return; + } } - tree_model_sort->sort_column_id = sort_column_id; - tree_model_sort->order = order; + priv->sort_column_id = sort_column_id; + priv->order = order; - gtk_tree_model_sort_sort (tree_model_sort); gtk_tree_sortable_sort_column_changed (sortable); + + gtk_tree_model_sort_sort (tree_model_sort); } static void @@ -1261,65 +1567,42 @@ gtk_tree_model_sort_set_sort_func (GtkTreeSortable *sortable, gint sort_column_id, GtkTreeIterCompareFunc func, gpointer data, - GtkDestroyNotify destroy) + GDestroyNotify destroy) { GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) sortable; - GtkTreeDataSortHeader *header = NULL; - GList *list; - - g_return_if_fail (GTK_IS_TREE_MODEL_SORT (sortable)); - g_return_if_fail (func != NULL); - - for (list = tree_model_sort->sort_list; list; list = list->next) - { - header = (GtkTreeDataSortHeader *) list->data; - - if (header->sort_column_id == sort_column_id) - break; - } + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; - if (header == NULL) - { - header = g_new0 (GtkTreeDataSortHeader, 1); - header->sort_column_id = sort_column_id; - tree_model_sort->sort_list = g_list_append (tree_model_sort->sort_list, - header); - } + priv->sort_list = _gtk_tree_data_list_set_header (priv->sort_list, + sort_column_id, + func, data, destroy); - if (header->destroy) - { - GtkDestroyNotify d = header->destroy; - - header->destroy = NULL; - d (header->data); - } - - header->func = func; - header->data = data; - header->destroy = destroy; + if (priv->sort_column_id == sort_column_id) + gtk_tree_model_sort_sort (tree_model_sort); } static void gtk_tree_model_sort_set_default_sort_func (GtkTreeSortable *sortable, GtkTreeIterCompareFunc func, gpointer data, - GtkDestroyNotify destroy) + GDestroyNotify destroy) { GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *)sortable; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; - g_return_if_fail (GTK_IS_TREE_MODEL_SORT (sortable)); - - if (tree_model_sort->default_sort_destroy) + if (priv->default_sort_destroy) { - GtkDestroyNotify d = tree_model_sort->default_sort_destroy; + GDestroyNotify d = priv->default_sort_destroy; - tree_model_sort->default_sort_destroy = NULL; - d (tree_model_sort->default_sort_data); + priv->default_sort_destroy = NULL; + d (priv->default_sort_data); } - tree_model_sort->default_sort_func = func; - tree_model_sort->default_sort_data = data; - tree_model_sort->default_sort_destroy = destroy; + priv->default_sort_func = func; + priv->default_sort_data = data; + priv->default_sort_destroy = destroy; + + if (priv->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) + gtk_tree_model_sort_sort (tree_model_sort); } static gboolean @@ -1327,9 +1610,55 @@ gtk_tree_model_sort_has_default_sort_func (GtkTreeSortable *sortable) { GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *)sortable; - g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (sortable), FALSE); + return (tree_model_sort->priv->default_sort_func != NULL); +} - return (tree_model_sort->default_sort_func != NULL); +/* DragSource interface */ +static gboolean +gtk_tree_model_sort_row_draggable (GtkTreeDragSource *drag_source, + GtkTreePath *path) +{ + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *)drag_source; + GtkTreePath *child_path; + gboolean draggable; + + child_path = gtk_tree_model_sort_convert_path_to_child_path (tree_model_sort, + path); + draggable = gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (tree_model_sort->priv->child_model), child_path); + gtk_tree_path_free (child_path); + + return draggable; +} + +static gboolean +gtk_tree_model_sort_drag_data_get (GtkTreeDragSource *drag_source, + GtkTreePath *path, + GtkSelectionData *selection_data) +{ + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *)drag_source; + GtkTreePath *child_path; + gboolean gotten; + + child_path = gtk_tree_model_sort_convert_path_to_child_path (tree_model_sort, path); + gotten = gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (tree_model_sort->priv->child_model), child_path, selection_data); + gtk_tree_path_free (child_path); + + return gotten; +} + +static gboolean +gtk_tree_model_sort_drag_data_delete (GtkTreeDragSource *drag_source, + GtkTreePath *path) +{ + GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *)drag_source; + GtkTreePath *child_path; + gboolean deleted; + + child_path = gtk_tree_model_sort_convert_path_to_child_path (tree_model_sort, path); + deleted = gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (tree_model_sort->priv->child_model), child_path); + gtk_tree_path_free (child_path); + + return deleted; } /* sorting code - private */ @@ -1340,6 +1669,7 @@ gtk_tree_model_sort_compare_func (gconstpointer a, { SortData *data = (SortData *)user_data; GtkTreeModelSort *tree_model_sort = data->tree_model_sort; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; SortTuple *sa = (SortTuple *)a; SortTuple *sb = (SortTuple *)b; @@ -1358,16 +1688,16 @@ gtk_tree_model_sort_compare_func (gconstpointer a, else { data->parent_path_indices [data->parent_path_depth-1] = sa->elt->offset; - gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_model_sort->child_model), &iter_a, data->parent_path); + gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->child_model), &iter_a, data->parent_path); data->parent_path_indices [data->parent_path_depth-1] = sb->elt->offset; - gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_model_sort->child_model), &iter_b, data->parent_path); + gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->child_model), &iter_b, data->parent_path); } - retval = (* data->sort_func) (GTK_TREE_MODEL (tree_model_sort->child_model), + retval = (* data->sort_func) (GTK_TREE_MODEL (priv->child_model), &iter_a, &iter_b, data->sort_data); - if (tree_model_sort->order == GTK_SORT_DESCENDING) + if (priv->order == GTK_SORT_DESCENDING) { if (retval > 0) retval = -1; @@ -1397,7 +1727,7 @@ gtk_tree_model_sort_offset_compare_func (gconstpointer a, else retval = 0; - if (data->tree_model_sort->order == GTK_SORT_DESCENDING) + if (data->tree_model_sort->priv->order == GTK_SORT_DESCENDING) { if (retval > 0) retval = -1; @@ -1414,7 +1744,9 @@ gtk_tree_model_sort_sort_level (GtkTreeModelSort *tree_model_sort, gboolean recurse, gboolean emit_reordered) { + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; gint i; + gint ref_offset; GArray *sort_array; GArray *new_array; gint *new_order; @@ -1424,18 +1756,24 @@ gtk_tree_model_sort_sort_level (GtkTreeModelSort *tree_model_sort, SortData data; - g_return_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model_sort)); g_return_if_fail (level != NULL); if (level->array->len < 1 && !((SortElt *)level->array->data)->children) return; + iter.stamp = priv->stamp; + iter.user_data = level; + iter.user_data2 = &g_array_index (level->array, SortElt, 0); + + gtk_tree_model_sort_ref_node (GTK_TREE_MODEL (tree_model_sort), &iter); + ref_offset = g_array_index (level->array, SortElt, 0).offset; + /* Set up data */ data.tree_model_sort = tree_model_sort; - if (level->parent_elt) + if (level->parent_elt_index >= 0) { data.parent_path = gtk_tree_model_sort_elt_get_path (level->parent_level, - level->parent_elt); + SORT_LEVEL_PARENT_ELT (level)); gtk_tree_path_append_index (data.parent_path, 0); } else @@ -1457,12 +1795,12 @@ gtk_tree_model_sort_sort_level (GtkTreeModelSort *tree_model_sort, g_array_append_val (sort_array, tuple); } - if (tree_model_sort->sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) + if (priv->sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) { GtkTreeDataSortHeader *header = NULL; - header = _gtk_tree_data_list_get_header (tree_model_sort->sort_list, - tree_model_sort->sort_column_id); + header = _gtk_tree_data_list_get_header (priv->sort_list, + priv->sort_column_id); g_return_if_fail (header != NULL); g_return_if_fail (header->func != NULL); @@ -1473,10 +1811,10 @@ gtk_tree_model_sort_sort_level (GtkTreeModelSort *tree_model_sort, else { /* absolutely SHOULD NOT happen: */ - g_return_if_fail (tree_model_sort->default_sort_func != NULL); + g_return_if_fail (priv->default_sort_func != NULL); - data.sort_func = tree_model_sort->default_sort_func; - data.sort_data = tree_model_sort->default_sort_data; + data.sort_func = priv->default_sort_func; + data.sort_data = priv->default_sort_data; } if (data.sort_func == NO_SORT_FUNC) @@ -1501,9 +1839,8 @@ gtk_tree_model_sort_sort_level (GtkTreeModelSort *tree_model_sort, new_order[i] = g_array_index (sort_array, SortTuple, i).offset; g_array_append_val (new_array, *elt); - elt = &g_array_index (new_array, SortElt, i); if (elt->children) - elt->children->parent_elt = elt; + elt->children->parent_elt_index = i; } g_array_free (level->array, TRUE); @@ -1513,11 +1850,11 @@ gtk_tree_model_sort_sort_level (GtkTreeModelSort *tree_model_sort, if (emit_reordered) { gtk_tree_model_sort_increment_stamp (tree_model_sort); - if (level->parent_elt) + if (level->parent_elt_index >= 0) { - iter.stamp = tree_model_sort->stamp; + iter.stamp = priv->stamp; iter.user_data = level->parent_level; - iter.user_data2 = level->parent_elt; + iter.user_data2 = SORT_LEVEL_PARENT_ELT (level); path = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_model_sort), &iter); @@ -1551,31 +1888,51 @@ gtk_tree_model_sort_sort_level (GtkTreeModelSort *tree_model_sort, } g_free (new_order); + + /* get the iter we referenced at the beginning of this function and + * unref it again + */ + iter.stamp = priv->stamp; + iter.user_data = level; + + for (i = 0; i < level->array->len; i++) + { + if (g_array_index (level->array, SortElt, i).offset == ref_offset) + { + iter.user_data2 = &g_array_index (level->array, SortElt, i); + break; + } + } + + gtk_tree_model_sort_unref_node (GTK_TREE_MODEL (tree_model_sort), &iter); } static void gtk_tree_model_sort_sort (GtkTreeModelSort *tree_model_sort) { - g_return_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model_sort)); + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; - if (!tree_model_sort->root) + if (priv->sort_column_id == GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID) return; - if (tree_model_sort->sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) + if (!priv->root) + return; + + if (priv->sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) { GtkTreeDataSortHeader *header = NULL; - header = _gtk_tree_data_list_get_header (tree_model_sort->sort_list, - tree_model_sort->sort_column_id); + header = _gtk_tree_data_list_get_header (priv->sort_list, + priv->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_model_sort->default_sort_func != NULL); + g_return_if_fail (priv->default_sort_func != NULL); - gtk_tree_model_sort_sort_level (tree_model_sort, tree_model_sort->root, + gtk_tree_model_sort_sort_level (tree_model_sort, priv->root, TRUE, TRUE); } @@ -1584,9 +1941,10 @@ static gint gtk_tree_model_sort_level_find_insert (GtkTreeModelSort *tree_model_sort, SortLevel *level, GtkTreeIter *iter, - gboolean skip_sort_elt) + gint skip_index) { - gint middle; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; + gint start, middle, end; gint cmp; SortElt *tmp_elt; GtkTreeIter tmp_iter; @@ -1594,14 +1952,12 @@ gtk_tree_model_sort_level_find_insert (GtkTreeModelSort *tree_model_sort, GtkTreeIterCompareFunc func; gpointer data; - GtkTreePath *path; - - if (tree_model_sort->sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) + if (priv->sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) { GtkTreeDataSortHeader *header; - header = _gtk_tree_data_list_get_header (tree_model_sort->sort_list, - tree_model_sort->sort_column_id); + header = _gtk_tree_data_list_get_header (priv->sort_list, + priv->sort_column_id); g_return_val_if_fail (header != NULL, 0); @@ -1610,38 +1966,60 @@ gtk_tree_model_sort_level_find_insert (GtkTreeModelSort *tree_model_sort, } else { - func = tree_model_sort->default_sort_func; - data = tree_model_sort->default_sort_data; + func = priv->default_sort_func; + data = priv->default_sort_data; g_return_val_if_fail (func != NO_SORT_FUNC, 0); } g_return_val_if_fail (func != NULL, 0); - - for (middle = 0; middle < level->array->len; middle++) - { - tmp_elt = &(g_array_index (level->array, SortElt, middle)); - if (!skip_sort_elt && SORT_ELT (iter->user_data2) == tmp_elt) - continue; + start = 0; + end = level->array->len; + if (skip_index < 0) + skip_index = end; + else + end--; - path = gtk_tree_model_sort_elt_get_path (level, tmp_elt); - gtk_tree_model_get_iter (tree_model_sort->child_model, - &tmp_iter, path); - gtk_tree_path_free (path); + if (start == end) + return 0; + + while (start != end) + { + middle = (start + end) / 2; - if (tree_model_sort->order == GTK_SORT_ASCENDING) - cmp = (* func) (GTK_TREE_MODEL (tree_model_sort->child_model), + if (middle < skip_index) + tmp_elt = &(g_array_index (level->array, SortElt, middle)); + else + tmp_elt = &(g_array_index (level->array, SortElt, middle + 1)); + + if (!GTK_TREE_MODEL_SORT_CACHE_CHILD_ITERS (tree_model_sort)) + { + GtkTreePath *path = gtk_tree_model_sort_elt_get_path (level, tmp_elt); + gtk_tree_model_get_iter (priv->child_model, + &tmp_iter, path); + gtk_tree_path_free (path); + } + else + tmp_iter = tmp_elt->iter; + + if (priv->order == GTK_SORT_ASCENDING) + cmp = (* func) (GTK_TREE_MODEL (priv->child_model), &tmp_iter, iter, data); else - cmp = (* func) (GTK_TREE_MODEL (tree_model_sort->child_model), + cmp = (* func) (GTK_TREE_MODEL (priv->child_model), iter, &tmp_iter, data); - if (cmp > 0) - break; + if (cmp <= 0) + start = middle + 1; + else + end = middle; } - return middle; + if (cmp <= 0) + return middle + 1; + else + return middle; } static gboolean @@ -1650,6 +2028,7 @@ gtk_tree_model_sort_insert_value (GtkTreeModelSort *tree_model_sort, GtkTreePath *s_path, GtkTreeIter *s_iter) { + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; gint offset, index, i; SortElt elt; @@ -1670,19 +2049,19 @@ gtk_tree_model_sort_insert_value (GtkTreeModelSort *tree_model_sort, if (tmp_elt->offset >= offset) tmp_elt->offset++; - if (tree_model_sort->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID && - tree_model_sort->default_sort_func == NO_SORT_FUNC) + if (priv->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID && + priv->default_sort_func == NO_SORT_FUNC) index = offset; else index = gtk_tree_model_sort_level_find_insert (tree_model_sort, level, s_iter, - FALSE); + -1); g_array_insert_vals (level->array, index, &elt, 1); tmp_elt = SORT_ELT (level->array->data); for (i = 0; i < level->array->len; i++, tmp_elt++) if (tmp_elt->children) - tmp_elt->children->parent_elt = tmp_elt; + tmp_elt->children->parent_elt_index = i; return TRUE; } @@ -1705,7 +2084,10 @@ gtk_tree_model_sort_elt_get_path (SortLevel *level, { gtk_tree_path_prepend_index (path, walker2->offset); - walker2 = walker->parent_elt; + if (!walker->parent_level) + break; + + walker2 = SORT_LEVEL_PARENT_ELT (walker); walker = walker->parent_level; } @@ -1715,84 +2097,84 @@ gtk_tree_model_sort_elt_get_path (SortLevel *level, /** * gtk_tree_model_sort_set_model: * @tree_model_sort: The #GtkTreeModelSort. - * @child_model: A #GtkTreeModel, or NULL. + * @child_model: (allow-none): A #GtkTreeModel, or %NULL. * - * Sets the model of @tree_model_sort to be @model. If @model is NULL, then the - * old model is unset. The sort function is unset as a result of this call. - * The model will be in an unsorted state until a sort function is set. + * Sets the model of @tree_model_sort to be @model. If @model is %NULL, + * then the old model is unset. The sort function is unset as a result + * of this call. The model will be in an unsorted state until a sort + * function is set. **/ static void gtk_tree_model_sort_set_model (GtkTreeModelSort *tree_model_sort, GtkTreeModel *child_model) { - g_return_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model_sort)); + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; if (child_model) - g_object_ref (G_OBJECT (child_model)); + g_object_ref (child_model); - if (tree_model_sort->child_model) + if (priv->child_model) { - g_signal_handler_disconnect (G_OBJECT (tree_model_sort->child_model), - tree_model_sort->changed_id); - g_signal_handler_disconnect (G_OBJECT (tree_model_sort->child_model), - tree_model_sort->inserted_id); - g_signal_handler_disconnect (G_OBJECT (tree_model_sort->child_model), - tree_model_sort->has_child_toggled_id); - g_signal_handler_disconnect (G_OBJECT (tree_model_sort->child_model), - tree_model_sort->deleted_id); - g_signal_handler_disconnect (G_OBJECT (tree_model_sort->child_model), - tree_model_sort->reordered_id); + g_signal_handler_disconnect (priv->child_model, + priv->changed_id); + g_signal_handler_disconnect (priv->child_model, + priv->inserted_id); + g_signal_handler_disconnect (priv->child_model, + priv->has_child_toggled_id); + g_signal_handler_disconnect (priv->child_model, + priv->deleted_id); + g_signal_handler_disconnect (priv->child_model, + priv->reordered_id); /* reset our state */ - if (tree_model_sort->root) - gtk_tree_model_sort_free_level (tree_model_sort, tree_model_sort->root); - tree_model_sort->root = NULL; - _gtk_tree_data_list_header_free (tree_model_sort->sort_list); - tree_model_sort->sort_list = NULL; - g_object_unref (G_OBJECT (tree_model_sort->child_model)); + if (priv->root) + gtk_tree_model_sort_free_level (tree_model_sort, priv->root); + priv->root = NULL; + _gtk_tree_data_list_header_free (priv->sort_list); + priv->sort_list = NULL; + g_object_unref (priv->child_model); } - tree_model_sort->child_model = child_model; + priv->child_model = child_model; if (child_model) { GType *types; gint i, n_columns; - g_object_ref (tree_model_sort->child_model); - tree_model_sort->changed_id = - g_signal_connect (child_model, "row_changed", + priv->changed_id = + g_signal_connect (child_model, "row-changed", G_CALLBACK (gtk_tree_model_sort_row_changed), tree_model_sort); - tree_model_sort->inserted_id = - g_signal_connect (child_model, "row_inserted", + priv->inserted_id = + g_signal_connect (child_model, "row-inserted", G_CALLBACK (gtk_tree_model_sort_row_inserted), tree_model_sort); - tree_model_sort->has_child_toggled_id = - g_signal_connect (child_model, "row_has_child_toggled", + priv->has_child_toggled_id = + g_signal_connect (child_model, "row-has-child-toggled", G_CALLBACK (gtk_tree_model_sort_row_has_child_toggled), tree_model_sort); - tree_model_sort->deleted_id = - g_signal_connect (child_model, "row_deleted", + priv->deleted_id = + g_signal_connect (child_model, "row-deleted", G_CALLBACK (gtk_tree_model_sort_row_deleted), tree_model_sort); - tree_model_sort->reordered_id = - g_signal_connect (child_model, "rows_reordered", + priv->reordered_id = + g_signal_connect (child_model, "rows-reordered", G_CALLBACK (gtk_tree_model_sort_rows_reordered), tree_model_sort); - tree_model_sort->child_flags = gtk_tree_model_get_flags (child_model); + priv->child_flags = gtk_tree_model_get_flags (child_model); n_columns = gtk_tree_model_get_n_columns (child_model); types = g_new (GType, n_columns); for (i = 0; i < n_columns; i++) types[i] = gtk_tree_model_get_column_type (child_model, i); - tree_model_sort->sort_list = _gtk_tree_data_list_header_new (n_columns, types); + priv->sort_list = _gtk_tree_data_list_header_new (n_columns, types); g_free (types); - tree_model_sort->default_sort_func = NO_SORT_FUNC; - tree_model_sort->stamp = g_random_int (); + priv->default_sort_func = NO_SORT_FUNC; + priv->stamp = g_random_int (); } } @@ -1802,14 +2184,14 @@ gtk_tree_model_sort_set_model (GtkTreeModelSort *tree_model_sort, * * Returns the model the #GtkTreeModelSort is sorting. * - * Return value: the "child model" being sorted + * Return value: (transfer none): the "child model" being sorted **/ GtkTreeModel * -gtk_tree_model_sort_get_model (GtkTreeModelSort *tree_model) +gtk_tree_model_sort_get_model (GtkTreeModelSort *tree_model) { g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), NULL); - return tree_model->child_model; + return tree_model->priv->child_model; } @@ -1818,21 +2200,21 @@ gtk_real_tree_model_sort_convert_child_path_to_path (GtkTreeModelSort *tree_mode GtkTreePath *child_path, gboolean build_levels) { + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; gint *child_indices; GtkTreePath *retval; SortLevel *level; gint i; - g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model_sort), NULL); - g_return_val_if_fail (tree_model_sort->child_model != NULL, NULL); + g_return_val_if_fail (priv->child_model != NULL, NULL); g_return_val_if_fail (child_path != NULL, NULL); retval = gtk_tree_path_new (); child_indices = gtk_tree_path_get_indices (child_path); - if (tree_model_sort->root == NULL && build_levels) - gtk_tree_model_sort_build_level (tree_model_sort, NULL, NULL); - level = SORT_LEVEL (tree_model_sort->root); + if (priv->root == NULL && build_levels) + gtk_tree_model_sort_build_level (tree_model_sort, NULL, -1); + level = SORT_LEVEL (priv->root); for (i = 0; i < gtk_tree_path_get_depth (child_path); i++) { @@ -1857,7 +2239,7 @@ gtk_real_tree_model_sort_convert_child_path_to_path (GtkTreeModelSort *tree_mode gtk_tree_path_append_index (retval, j); if (g_array_index (level->array, SortElt, j).children == NULL && build_levels) { - gtk_tree_model_sort_build_level (tree_model_sort, level, &g_array_index (level->array, SortElt, j)); + gtk_tree_model_sort_build_level (tree_model_sort, level, j); } level = g_array_index (level->array, SortElt, j).children; found_child = TRUE; @@ -1882,8 +2264,8 @@ gtk_real_tree_model_sort_convert_child_path_to_path (GtkTreeModelSort *tree_mode * * Converts @child_path to a path relative to @tree_model_sort. That is, * @child_path points to a path in the child model. The returned path will - * point to the same row in the sorted model. If @child_path isn't a valid path - * on the child model, then %NULL is returned. + * point to the same row in the sorted model. If @child_path isn't a valid + * path on the child model, then %NULL is returned. * * Return value: A newly allocated #GtkTreePath, or %NULL **/ @@ -1892,7 +2274,7 @@ gtk_tree_model_sort_convert_child_path_to_path (GtkTreeModelSort *tree_model_sor GtkTreePath *child_path) { g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model_sort), NULL); - g_return_val_if_fail (tree_model_sort->child_model != NULL, NULL); + g_return_val_if_fail (tree_model_sort->priv->child_model != NULL, NULL); g_return_val_if_fail (child_path != NULL, NULL); return gtk_real_tree_model_sort_convert_child_path_to_path (tree_model_sort, child_path, TRUE); @@ -1901,35 +2283,50 @@ gtk_tree_model_sort_convert_child_path_to_path (GtkTreeModelSort *tree_model_sor /** * gtk_tree_model_sort_convert_child_iter_to_iter: * @tree_model_sort: A #GtkTreeModelSort - * @sort_iter: An uninitialized #GtkTreeIter. + * @sort_iter: (out): An uninitialized #GtkTreeIter. * @child_iter: A valid #GtkTreeIter pointing to a row on the child model * * Sets @sort_iter to point to the row in @tree_model_sort that corresponds to - * the row pointed at by @child_iter. + * the row pointed at by @child_iter. If @sort_iter was not set, %FALSE + * is returned. Note: a boolean is only returned since 2.14. + * + * Return value: %TRUE, if @sort_iter was set, i.e. if @sort_iter is a + * valid iterator pointer to a visible row in the child model. **/ -void +gboolean gtk_tree_model_sort_convert_child_iter_to_iter (GtkTreeModelSort *tree_model_sort, GtkTreeIter *sort_iter, GtkTreeIter *child_iter) { + gboolean ret; GtkTreePath *child_path, *path; + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; - g_return_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model_sort)); - g_return_if_fail (tree_model_sort->child_model != NULL); - g_return_if_fail (sort_iter != NULL); - g_return_if_fail (child_iter != NULL); + g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model_sort), FALSE); + g_return_val_if_fail (priv->child_model != NULL, FALSE); + g_return_val_if_fail (sort_iter != NULL, FALSE); + g_return_val_if_fail (child_iter != NULL, FALSE); + g_return_val_if_fail (sort_iter != child_iter, FALSE); sort_iter->stamp = 0; - child_path = gtk_tree_model_get_path (tree_model_sort->child_model, child_iter); - g_return_if_fail (child_path != NULL); + child_path = gtk_tree_model_get_path (priv->child_model, child_iter); + g_return_val_if_fail (child_path != NULL, FALSE); path = gtk_tree_model_sort_convert_child_path_to_path (tree_model_sort, child_path); gtk_tree_path_free (child_path); - g_return_if_fail (path != NULL); - gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_model_sort), sort_iter, path); + if (!path) + { + g_warning ("%s: The conversion of the child path to a GtkTreeModel sort path failed", G_STRLOC); + return FALSE; + } + + ret = gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_model_sort), + sort_iter, path); gtk_tree_path_free (path); + + return ret; } /** @@ -1937,10 +2334,11 @@ gtk_tree_model_sort_convert_child_iter_to_iter (GtkTreeModelSort *tree_model_sor * @tree_model_sort: A #GtkTreeModelSort * @sorted_path: A #GtkTreePath to convert * - * Converts @sorted_path to a path on the child model of @tree_model_sort. That - * is, @sorted_path points to a location in @tree_model_sort. The returned path - * will point to the same location in the model not being sorted. If @sorted_path - * does not point to a location in the child model, %NULL is returned. + * Converts @sorted_path to a path on the child model of @tree_model_sort. + * That is, @sorted_path points to a location in @tree_model_sort. The + * returned path will point to the same location in the model not being + * sorted. If @sorted_path does not point to a location in the child model, + * %NULL is returned. * * Return value: A newly allocated #GtkTreePath, or %NULL **/ @@ -1948,20 +2346,21 @@ GtkTreePath * gtk_tree_model_sort_convert_path_to_child_path (GtkTreeModelSort *tree_model_sort, GtkTreePath *sorted_path) { + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; gint *sorted_indices; GtkTreePath *retval; SortLevel *level; gint i; g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model_sort), NULL); - g_return_val_if_fail (tree_model_sort->child_model != NULL, NULL); + g_return_val_if_fail (priv->child_model != NULL, NULL); g_return_val_if_fail (sorted_path != NULL, NULL); retval = gtk_tree_path_new (); sorted_indices = gtk_tree_path_get_indices (sorted_path); - if (tree_model_sort->root == NULL) - gtk_tree_model_sort_build_level (tree_model_sort, NULL, NULL); - level = SORT_LEVEL (tree_model_sort->root); + if (priv->root == NULL) + gtk_tree_model_sort_build_level (tree_model_sort, NULL, -1); + level = SORT_LEVEL (priv->root); for (i = 0; i < gtk_tree_path_get_depth (sorted_path); i++) { @@ -1975,7 +2374,7 @@ gtk_tree_model_sort_convert_path_to_child_path (GtkTreeModelSort *tree_model_sor } if (g_array_index (level->array, SortElt, count).children == NULL) - gtk_tree_model_sort_build_level (tree_model_sort, level, &g_array_index (level->array, SortElt, count)); + gtk_tree_model_sort_build_level (tree_model_sort, level, count); if (level == NULL) { @@ -1993,7 +2392,7 @@ gtk_tree_model_sort_convert_path_to_child_path (GtkTreeModelSort *tree_model_sor /** * gtk_tree_model_sort_convert_iter_to_child_iter: * @tree_model_sort: A #GtkTreeModelSort - * @child_iter: An uninitialized #GtkTreeIter + * @child_iter: (out): An uninitialized #GtkTreeIter * @sorted_iter: A valid #GtkTreeIter pointing to a row on @tree_model_sort. * * Sets @child_iter to point to the row pointed to by @sorted_iter. @@ -2003,11 +2402,12 @@ gtk_tree_model_sort_convert_iter_to_child_iter (GtkTreeModelSort *tree_model_sor GtkTreeIter *child_iter, GtkTreeIter *sorted_iter) { + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; g_return_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model_sort)); - g_return_if_fail (tree_model_sort->child_model != NULL); + g_return_if_fail (priv->child_model != NULL); g_return_if_fail (child_iter != NULL); - g_return_if_fail (sorted_iter != NULL); - g_return_if_fail (sorted_iter->stamp == tree_model_sort->stamp); + g_return_if_fail (VALID_ITER (sorted_iter, tree_model_sort)); + g_return_if_fail (sorted_iter != child_iter); if (GTK_TREE_MODEL_SORT_CACHE_CHILD_ITERS (tree_model_sort)) { @@ -2019,7 +2419,7 @@ gtk_tree_model_sort_convert_iter_to_child_iter (GtkTreeModelSort *tree_model_sor path = gtk_tree_model_sort_elt_get_path (sorted_iter->user_data, sorted_iter->user_data2); - gtk_tree_model_get_iter (tree_model_sort->child_model, child_iter, path); + gtk_tree_model_get_iter (priv->child_model, child_iter, path); gtk_tree_path_free (path); } } @@ -2027,34 +2427,38 @@ gtk_tree_model_sort_convert_iter_to_child_iter (GtkTreeModelSort *tree_model_sor static void gtk_tree_model_sort_build_level (GtkTreeModelSort *tree_model_sort, SortLevel *parent_level, - SortElt *parent_elt) + gint parent_elt_index) { + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; GtkTreeIter iter; + SortElt *parent_elt = NULL; SortLevel *new_level; gint length = 0; gint i; - g_assert (tree_model_sort->child_model != NULL); + g_assert (priv->child_model != NULL); if (parent_level == NULL) { - if (gtk_tree_model_get_iter_first (tree_model_sort->child_model, &iter) == FALSE) + if (gtk_tree_model_get_iter_first (priv->child_model, &iter) == FALSE) return; - length = gtk_tree_model_iter_n_children (tree_model_sort->child_model, NULL); + length = gtk_tree_model_iter_n_children (priv->child_model, NULL); } else { GtkTreeIter parent_iter; GtkTreeIter child_parent_iter; - parent_iter.stamp = tree_model_sort->stamp; + parent_elt = &g_array_index (parent_level->array, SortElt, parent_elt_index); + + parent_iter.stamp = priv->stamp; parent_iter.user_data = parent_level; parent_iter.user_data2 = parent_elt; gtk_tree_model_sort_convert_iter_to_child_iter (tree_model_sort, &child_parent_iter, &parent_iter); - if (gtk_tree_model_iter_children (tree_model_sort->child_model, + if (gtk_tree_model_iter_children (priv->child_model, &iter, &child_parent_iter) == FALSE) return; @@ -2064,7 +2468,7 @@ gtk_tree_model_sort_build_level (GtkTreeModelSort *tree_model_sort, &child_parent_iter, &parent_iter); - length = gtk_tree_model_iter_n_children (tree_model_sort->child_model, &child_parent_iter); + length = gtk_tree_model_iter_n_children (priv->child_model, &child_parent_iter); } g_return_if_fail (length > 0); @@ -2072,24 +2476,25 @@ gtk_tree_model_sort_build_level (GtkTreeModelSort *tree_model_sort, new_level = g_new (SortLevel, 1); new_level->array = g_array_sized_new (FALSE, FALSE, sizeof (SortElt), length); new_level->ref_count = 0; - new_level->parent_elt = parent_elt; new_level->parent_level = parent_level; + new_level->parent_elt_index = parent_elt_index; - if (parent_elt) + if (parent_elt_index >= 0) parent_elt->children = new_level; else - tree_model_sort->root = new_level; + priv->root = new_level; /* increase the count of zero ref_counts.*/ while (parent_level) { - parent_elt->zero_ref_count++; + g_array_index (parent_level->array, SortElt, parent_elt_index).zero_ref_count++; - parent_elt = parent_level->parent_elt; + parent_elt_index = parent_level->parent_elt_index; parent_level = parent_level->parent_level; } - if (new_level != tree_model_sort->root) - tree_model_sort->zero_ref_count++; + + if (new_level != priv->root) + priv->zero_ref_count++; for (i = 0; i < length; i++) { @@ -2102,10 +2507,33 @@ gtk_tree_model_sort_build_level (GtkTreeModelSort *tree_model_sort, if (GTK_TREE_MODEL_SORT_CACHE_CHILD_ITERS (tree_model_sort)) { sort_elt.iter = iter; - if (gtk_tree_model_iter_next (tree_model_sort->child_model, &iter) == FALSE && + if (gtk_tree_model_iter_next (priv->child_model, &iter) == FALSE && i < length - 1) { - g_warning ("There is a discrepency between the sort model and the child model."); + if (parent_level) + { + GtkTreePath *level; + gchar *str; + + level = gtk_tree_model_sort_elt_get_path (parent_level, + parent_elt); + str = gtk_tree_path_to_string (level); + gtk_tree_path_free (level); + + g_warning ("%s: There is a discrepancy between the sort model " + "and the child model. The child model is " + "advertising a wrong length for level %s:.", + G_STRLOC, str); + g_free (str); + } + else + { + g_warning ("%s: There is a discrepancy between the sort model " + "and the child model. The child model is " + "advertising a wrong length for the root level.", + G_STRLOC); + } + return; } } @@ -2121,42 +2549,39 @@ static void gtk_tree_model_sort_free_level (GtkTreeModelSort *tree_model_sort, SortLevel *sort_level) { + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; gint i; g_assert (sort_level); + for (i = 0; i < sort_level->array->len; i++) + { + if (g_array_index (sort_level->array, SortElt, i).children) + gtk_tree_model_sort_free_level (tree_model_sort, + SORT_LEVEL (g_array_index (sort_level->array, SortElt, i).children)); + } + if (sort_level->ref_count == 0) { SortLevel *parent_level = sort_level->parent_level; - SortElt *parent_elt = sort_level->parent_elt; + gint parent_elt_index = sort_level->parent_elt_index; - do - { - if (parent_elt) - parent_elt->zero_ref_count--; - else - tree_model_sort->zero_ref_count--; + while (parent_level) + { + g_array_index (parent_level->array, SortElt, parent_elt_index).zero_ref_count--; - if (parent_level) - { - parent_elt = parent_level->parent_elt; - parent_level = parent_level->parent_level; - } + parent_elt_index = parent_level->parent_elt_index; + parent_level = parent_level->parent_level; } - while (parent_level); - } - for (i = 0; i < sort_level->array->len; i++) - { - if (g_array_index (sort_level->array, SortElt, i).children) - gtk_tree_model_sort_free_level (tree_model_sort, - SORT_LEVEL(g_array_index (sort_level->array, SortElt, i).children)); + if (sort_level != priv->root) + priv->zero_ref_count--; } - if (sort_level->parent_elt) - sort_level->parent_elt->children = NULL; + if (sort_level->parent_elt_index >= 0) + SORT_LEVEL_PARENT_ELT (sort_level)->children = NULL; else - tree_model_sort->root = NULL; + priv->root = NULL; g_array_free (sort_level->array, TRUE); sort_level->array = NULL; @@ -2168,11 +2593,13 @@ gtk_tree_model_sort_free_level (GtkTreeModelSort *tree_model_sort, static void gtk_tree_model_sort_increment_stamp (GtkTreeModelSort *tree_model_sort) { + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; + do { - tree_model_sort->stamp++; + priv->stamp++; } - while (tree_model_sort->stamp == 0); + while (priv->stamp == 0); gtk_tree_model_sort_clear_cache (tree_model_sort); } @@ -2191,7 +2618,7 @@ gtk_tree_model_sort_clear_cache_helper (GtkTreeModelSort *tree_model_sort, gtk_tree_model_sort_clear_cache_helper (tree_model_sort, g_array_index (level->array, SortElt, i).children); } - if (level->ref_count == 0 && level != tree_model_sort->root) + if (level->ref_count == 0 && level != tree_model_sort->priv->root) gtk_tree_model_sort_free_level (tree_model_sort, level); } @@ -2207,23 +2634,25 @@ gtk_tree_model_sort_clear_cache_helper (GtkTreeModelSort *tree_model_sort, void gtk_tree_model_sort_reset_default_sort_func (GtkTreeModelSort *tree_model_sort) { + GtkTreeModelSortPrivate *priv = tree_model_sort->priv; + g_return_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model_sort)); - if (tree_model_sort->default_sort_destroy) + if (priv->default_sort_destroy) { - GtkDestroyNotify d = tree_model_sort->default_sort_destroy; + GDestroyNotify d = priv->default_sort_destroy; - tree_model_sort->default_sort_destroy = NULL; - d (tree_model_sort->default_sort_data); + priv->default_sort_destroy = NULL; + d (priv->default_sort_data); } - tree_model_sort->default_sort_func = NO_SORT_FUNC; - tree_model_sort->default_sort_data = NULL; - tree_model_sort->default_sort_destroy = NULL; + priv->default_sort_func = NO_SORT_FUNC; + priv->default_sort_data = NULL; + priv->default_sort_destroy = NULL; - if (tree_model_sort->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) + if (priv->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) gtk_tree_model_sort_sort (tree_model_sort); - tree_model_sort->sort_column_id = GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID; + priv->sort_column_id = GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID; } /** @@ -2242,6 +2671,56 @@ gtk_tree_model_sort_clear_cache (GtkTreeModelSort *tree_model_sort) { g_return_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model_sort)); - if (tree_model_sort->zero_ref_count) - gtk_tree_model_sort_clear_cache_helper (tree_model_sort, (SortLevel *)tree_model_sort->root); + if (tree_model_sort->priv->zero_ref_count > 0) + gtk_tree_model_sort_clear_cache_helper (tree_model_sort, (SortLevel *)tree_model_sort->priv->root); +} + +static gboolean +gtk_tree_model_sort_iter_is_valid_helper (GtkTreeIter *iter, + SortLevel *level) +{ + gint i; + + for (i = 0; i < level->array->len; i++) + { + SortElt *elt = &g_array_index (level->array, SortElt, i); + + if (iter->user_data == level && iter->user_data2 == elt) + return TRUE; + + if (elt->children) + if (gtk_tree_model_sort_iter_is_valid_helper (iter, elt->children)) + return TRUE; + } + + return FALSE; +} + +/** + * gtk_tree_model_sort_iter_is_valid: + * @tree_model_sort: A #GtkTreeModelSort. + * @iter: A #GtkTreeIter. + * + * + * This function is slow. Only use it for debugging and/or testing purposes. + * + * + * Checks if the given iter is a valid iter for this #GtkTreeModelSort. + * + * Return value: %TRUE if the iter is valid, %FALSE if the iter is invalid. + * + * Since: 2.2 + **/ +gboolean +gtk_tree_model_sort_iter_is_valid (GtkTreeModelSort *tree_model_sort, + GtkTreeIter *iter) +{ + g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model_sort), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + if (!VALID_ITER (iter, tree_model_sort)) + return FALSE; + + return gtk_tree_model_sort_iter_is_valid_helper (iter, + tree_model_sort->priv->root); }