* we warned you and we're not liable for any head injuries.
*/
+#include <config.h>
#include <string.h>
#include "gtktreemodelsort.h"
#include "gtktreestore.h"
#include "gtktreedatalist.h"
#include "gtkintl.h"
+#include "gtkprivate.h"
+#include "gtktreednd.h"
+#include "gtkalias.h"
typedef struct _SortElt SortElt;
typedef struct _SortLevel SortLevel;
#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 GET_CHILD_ITER(tree_model_sort,ch_iter,so_iter) gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT (tree_model_sort), ch_iter, so_iter);
#define NO_SORT_FUNC ((GtkTreeIterCompareFunc) 0x1)
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,
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,
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,
NULL
};
+ static const GInterfaceInfo drag_source_info =
+ {
+ (GInterfaceInitFunc) gtk_tree_model_sort_drag_source_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_SORTABLE,
&sortable_info);
+
+ g_type_add_interface_static (tree_model_sort_type,
+ GTK_TYPE_TREE_DRAG_SOURCE,
+ &drag_source_info);
}
return tree_model_sort_type;
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));
}
static void
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.
*/
gboolean free_s_path = FALSE;
- gint offset, index = 0, old_index, i;
+ gint index = 0, old_index, i;
g_return_if_fail (start_s_path != NULL || start_s_iter != NULL);
level = iter.user_data;
elt = iter.user_data2;
+ level->ref_count++;
+
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))
gtk_tree_path_free (path);
+ level->ref_count--;
+
return;
}
-
+
if (!GTK_TREE_MODEL_SORT_CACHE_CHILD_ITERS (tree_model_sort))
{
gtk_tree_model_get_iter (tree_model_sort->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)
- old_index = i;
+ old_index = elt - SORT_ELT (level->array->data);
memcpy (&tmp, elt, sizeof (SortElt));
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);
if (index < old_index)
{
g_free (new_order);
}
+ level->ref_count--;
+
/* 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);
if (!parent_level)
goto done;
+ if (level->ref_count == 0 && level != tree_model_sort->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,
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->root)
+ {
+ gtk_tree_model_sort_free_level (tree_model_sort,
+ tree_model_sort->root);
+ tree_model_sort->root = NULL;
+ }
return;
}
static GtkTreeModelFlags
gtk_tree_model_sort_get_flags (GtkTreeModel *tree_model)
{
+ GtkTreeModelFlags flags;
+
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);
+
+ flags = gtk_tree_model_get_flags (GTK_TREE_MODEL_SORT (tree_model)->child_model);
+
+ if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
+ return GTK_TREE_MODEL_LIST_ONLY;
return 0;
}
level = g_array_index (level->array, SortElt, indices[i]).children;
}
- if (level == NULL)
- return FALSE;
+ if (!level || indices[i] >= level->array->len)
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
+
iter->stamp = tree_model_sort->stamp;
iter->user_data = level;
iter->user_data2 = &g_array_index (level->array, SortElt, indices[depth - 1]);
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;
-
if (sort_column_id)
*sort_column_id = tree_model_sort->sort_column_id;
if (order)
*order = tree_model_sort->order;
+ if (tree_model_sort->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID ||
+ tree_model_sort->sort_column_id == GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
+ return FALSE;
+
return TRUE;
}
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;
+
+ g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (drag_source), FALSE);
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ 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->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;
+
+ g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (drag_source), FALSE);
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ 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->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;
+
+ g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (drag_source), FALSE);
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ 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->child_model), child_path);
+ gtk_tree_path_free (child_path);
+
+ return deleted;
+}
+
/* sorting code - private */
static gint
gtk_tree_model_sort_compare_func (gconstpointer a,
if (level->array->len < 1 && !((SortElt *)level->array->data)->children)
return;
+ level->ref_count++;
+
/* Set up data */
data.tree_model_sort = tree_model_sort;
if (level->parent_elt)
}
g_free (new_order);
+
+ level->ref_count--;
}
static void
gtk_tree_model_sort_level_find_insert (GtkTreeModelSort *tree_model_sort,
SortLevel *level,
GtkTreeIter *iter,
- gboolean skip_sort_elt)
+ gint skip_index)
{
gint start, middle, end;
- gint skip_index;
gint cmp;
SortElt *tmp_elt;
GtkTreeIter tmp_iter;
start = 0;
end = level->array->len;
- if (skip_sort_elt)
- {
- skip_index = SORT_ELT (iter->user_data2) - SORT_ELT (level->array->data);
- end--;
- }
- else
+ if (skip_index < 0)
skip_index = end;
+ else
+ end--;
if (start == end)
return 0;
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);
/**
* gtk_tree_model_sort_set_model:
* @tree_model_sort: The #GtkTreeModelSort.
- * @child_model: A #GtkTreeModel, or NULL.
+ * @child_model: A #GtkTreeModel, or %NULL.
*
- * Sets the model of @tree_model_sort to be @model. If @model is NULL, then the
- * old model is unset. 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,
*
* 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
**/
* @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
**/
if (gtk_tree_model_iter_next (tree_model_sort->child_model, &iter) == FALSE &&
i < length - 1)
{
- g_warning ("There is a discrepency between the sort model and the child model.");
+ g_warning ("There is a discrepancy between the sort model and the child model.");
return;
}
}
* @tree_model_sort: A #GtkTreeModelSort.
* @iter: A #GtkTreeIter.
*
- * WARNING: This function is slow. Only use it for debugging and/or testing
- * purposes.
+ * <warning><para>
+ * This function is slow. Only use it for debugging and/or testing purposes.
+ * </para></warning>
*
* Checks if the given iter is a valid iter for this #GtkTreeModelSort.
*
return gtk_tree_model_sort_iter_is_valid_helper (iter,
tree_model_sort->root);
}
+
+#define __GTK_TREE_MODEL_SORT_C__
+#include "gtkaliasdef.c"