From 20dd70b526a557dccd623f9a1c0b05720317e9f7 Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Mon, 7 Apr 2003 19:41:46 +0000 Subject: Move and autoupdate these from egg. 2003-04-07 Marco Pesenti Gritti * lib/widgets/Makefile.am: * lib/widgets/eggtreemodelfilter.c: * lib/widgets/eggtreemodelfilter.h: * lib/widgets/eggtreemultidnd.c: * lib/widgets/eggtreemultidnd.h: * lib/egg/Makefile.am: * lib/egg/eggtreemodelfilter.c: * lib/egg/eggtreemodelfilter.h: * lib/egg/eggtreemultidnd.c: * lib/egg/eggtreemultidnd.h: * lib/egg/update-from-egg.sh: Move and autoupdate these from egg. * lib/ephy-dnd.c: * lib/ephy-dnd.h: * src/ephy-favicon-action.c: Remove an unnecessary param in ephydnd API. * lib/widgets/ephy-tree-model-sort.c: Use the real multidnd api. 2 --- lib/egg/Makefile.am | 10 +- lib/egg/eggtreemodelfilter.c | 2636 ++++++++++++++++++++++++++++++++++++ lib/egg/eggtreemodelfilter.h | 125 ++ lib/egg/eggtreemultidnd.c | 412 ++++++ lib/egg/eggtreemultidnd.h | 76 ++ lib/egg/update-from-egg.sh | 3 + lib/ephy-dnd.c | 1 - lib/ephy-dnd.h | 1 - lib/widgets/Makefile.am | 4 - lib/widgets/eggtreemodelfilter.c | 2560 ---------------------------------- lib/widgets/eggtreemodelfilter.h | 123 -- lib/widgets/eggtreemultidnd.c | 425 ------ lib/widgets/eggtreemultidnd.h | 78 -- lib/widgets/ephy-tree-model-sort.c | 6 +- 14 files changed, 3261 insertions(+), 3199 deletions(-) create mode 100644 lib/egg/eggtreemodelfilter.c create mode 100644 lib/egg/eggtreemodelfilter.h create mode 100644 lib/egg/eggtreemultidnd.c create mode 100644 lib/egg/eggtreemultidnd.h delete mode 100644 lib/widgets/eggtreemodelfilter.c delete mode 100644 lib/widgets/eggtreemodelfilter.h delete mode 100644 lib/widgets/eggtreemultidnd.c delete mode 100644 lib/widgets/eggtreemultidnd.h (limited to 'lib') diff --git a/lib/egg/Makefile.am b/lib/egg/Makefile.am index da634d881..06070380f 100644 --- a/lib/egg/Makefile.am +++ b/lib/egg/Makefile.am @@ -10,6 +10,8 @@ EGGSOURCES = \ egg-action.c \ egg-action-group.c \ egg-toggle-action.c \ + eggtreemodelfilter.c \ + eggtreemultidnd.c \ egg-radio-action.c \ egg-menu-merge.c \ egg-accel-dialog.c \ @@ -19,14 +21,16 @@ EGGSOURCES = \ eggseparatortoolitem.c \ eggtoolbar.c \ eggtoolbutton.c \ - eggmarshalers.c \ egg-editable-toolbar.c \ egg-toolbars-group.c libegg_la_SOURCES = \ - $(EGGSOURCES) + $(EGGSOURCES) \ + eggmarshalers.c EGGHEADERS = \ + eggtreemodelfilter.h \ + eggtreemultidnd.h \ egg-menu.h \ egg-action.h \ egg-action-group.h \ @@ -40,12 +44,12 @@ EGGHEADERS = \ eggseparatortoolitem.h \ eggtoolbar.h \ eggtoolbutton.h \ - eggmarshalers.h \ egg-editable-toolbar.h \ egg-toolbars-group.h noinst_HEADERS = \ $(EGGHEADERS) \ + eggmarshalers.h \ eggintl.h eggmarshalers.h: diff --git a/lib/egg/eggtreemodelfilter.c b/lib/egg/eggtreemodelfilter.c new file mode 100644 index 000000000..9bff9cd1a --- /dev/null +++ b/lib/egg/eggtreemodelfilter.c @@ -0,0 +1,2636 @@ +/* eggtreemodelfilter.c + * Copyright (C) 2000,2001 Red Hat, Inc., Jonathan Blandford + * Copyright (C) 2001,2002 Kristian Rietveld + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "eggtreemodelfilter.h" +#include +#include + +/* FIXME: remove this when we move it to GTK+ */ +#include "eggintl.h" + +/* ITER FORMAT: + * + * iter->stamp = filter->stamp + * iter->user_data = FilterLevel + * iter->user_data2 = FilterElt + */ + +/* all paths, iters, etc prefixed with c_ are paths, iters, etc relative to the + * child model. + */ + +typedef struct _FilterElt FilterElt; +typedef struct _FilterLevel FilterLevel; + +struct _FilterElt +{ + GtkTreeIter iter; + FilterLevel *children; + gint offset; + gint ref_count; + gint zero_ref_count; + gboolean visible; +}; + +struct _FilterLevel +{ + GArray *array; + gint ref_count; + + FilterElt *parent_elt; + FilterLevel *parent_level; +}; + +/* properties */ +enum +{ + PROP_0, + PROP_CHILD_MODEL, + PROP_VIRTUAL_ROOT +}; + +#define EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS(filter) \ + (((EggTreeModelFilter *)filter)->child_flags & GTK_TREE_MODEL_ITERS_PERSIST) + +#define FILTER_ELT(filter_elt) ((FilterElt *)filter_elt) +#define FILTER_LEVEL(filter_level) ((FilterLevel *)filter_level) + +/* general code (object/interface init, properties, etc) */ +static void egg_tree_model_filter_init (EggTreeModelFilter *filter); +static void egg_tree_model_filter_class_init (EggTreeModelFilterClass *filter_class); +static void egg_tree_model_filter_tree_model_init (GtkTreeModelIface *iface); +static void egg_tree_model_filter_finalize (GObject *object); +static void egg_tree_model_filter_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void egg_tree_model_filter_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +/* signal handlers */ +static void egg_tree_model_filter_row_changed (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gpointer data); +static void egg_tree_model_filter_row_inserted (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gpointer data); +static void egg_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gpointer data); +static void egg_tree_model_filter_row_deleted (GtkTreeModel *c_model, + GtkTreePath *c_path, + gpointer data); +static void egg_tree_model_filter_rows_reordered (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gint *new_order, + gpointer data); + +/* GtkTreeModel interface */ +static guint egg_tree_model_filter_get_flags (GtkTreeModel *model); +static gint egg_tree_model_filter_get_n_columns (GtkTreeModel *model); +static GType egg_tree_model_filter_get_column_type (GtkTreeModel *model, + gint index); +static gboolean egg_tree_model_filter_get_iter (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreePath *path); +static GtkTreePath *egg_tree_model_filter_get_path (GtkTreeModel *model, + GtkTreeIter *iter); +static void egg_tree_model_filter_get_value (GtkTreeModel *model, + GtkTreeIter *iter, + gint column, + GValue *value); +static gboolean egg_tree_model_filter_iter_next (GtkTreeModel *model, + GtkTreeIter *iter); +static gboolean egg_tree_model_filter_iter_children (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *parent); +static gboolean egg_tree_model_filter_iter_has_child (GtkTreeModel *model, + GtkTreeIter *iter); +static gint egg_tree_model_filter_iter_n_children (GtkTreeModel *model, + GtkTreeIter *iter); +static gboolean egg_tree_model_filter_iter_nth_child (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n); +static gboolean egg_tree_model_filter_iter_parent (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *child); +static void egg_tree_model_filter_ref_node (GtkTreeModel *model, + GtkTreeIter *iter); +static void egg_tree_model_filter_unref_node (GtkTreeModel *model, + GtkTreeIter *iter); + + + +/* private functions */ +static void egg_tree_model_filter_build_level (EggTreeModelFilter *filter, + FilterLevel *parent_level, + FilterElt *parent_elt); +static void egg_tree_model_filter_free_level (EggTreeModelFilter *filter, + FilterLevel *filter_level); + +static GtkTreePath *egg_tree_model_filter_elt_get_path (FilterLevel *level, + FilterElt *elt, + GtkTreePath *root); + +static GtkTreePath *egg_tree_model_filter_add_root (GtkTreePath *src, + GtkTreePath *root); +static GtkTreePath *egg_tree_model_filter_remove_root (GtkTreePath *src, + GtkTreePath *root); + +static void egg_tree_model_filter_increment_stamp (EggTreeModelFilter *filter); + +static gboolean egg_tree_model_filter_visible (EggTreeModelFilter *filter, + GtkTreeIter *child_iter); +static void egg_tree_model_filter_clear_cache_helper (EggTreeModelFilter *filter, + FilterLevel *level); + +static void egg_tree_model_filter_real_unref_node (GtkTreeModel *model, + GtkTreeIter *iter, + gboolean propagate_unref); + +static void egg_tree_model_filter_set_model (EggTreeModelFilter *filter, + GtkTreeModel *child_model); +static void egg_tree_model_filter_set_root (EggTreeModelFilter *filter, + GtkTreePath *root); + +static GtkTreePath *egg_real_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter, + GtkTreePath *child_path, + gboolean build_levels, + gboolean fetch_childs); + +static gboolean egg_tree_model_filter_fetch_child (EggTreeModelFilter *filter, + FilterLevel *level, + gint offset); +static void egg_tree_model_filter_remove_node (EggTreeModelFilter *filter, + GtkTreeIter *iter, + gboolean emit_signal); +static void egg_tree_model_filter_update_childs (EggTreeModelFilter *filter, + FilterLevel *level, + FilterElt *elt); + + +static GObjectClass *parent_class = NULL; + +GType +egg_tree_model_filter_get_type (void) +{ + static GType tree_model_filter_type = 0; + + if (!tree_model_filter_type) + { + static const GTypeInfo tree_model_filter_info = + { + sizeof (EggTreeModelFilterClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) egg_tree_model_filter_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EggTreeModelFilter), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_tree_model_filter_init + }; + + static const GInterfaceInfo tree_model_info = + { + (GInterfaceInitFunc) egg_tree_model_filter_tree_model_init, + NULL, + NULL + }; + + tree_model_filter_type = g_type_register_static (G_TYPE_OBJECT, + "EggTreeModelFilter", + &tree_model_filter_info, 0); + + g_type_add_interface_static (tree_model_filter_type, + GTK_TYPE_TREE_MODEL, + &tree_model_info); + } + + return tree_model_filter_type; +} + +static void +egg_tree_model_filter_init (EggTreeModelFilter *filter) +{ + filter->visible_column = -1; + filter->zero_ref_count = 0; + filter->visible_method_set = FALSE; + filter->modify_func_set = FALSE; +} + +static void +egg_tree_model_filter_class_init (EggTreeModelFilterClass *filter_class) +{ + GObjectClass *object_class; + + object_class = (GObjectClass *) filter_class; + parent_class = g_type_class_peek_parent (filter_class); + + object_class->set_property = egg_tree_model_filter_set_property; + object_class->get_property = egg_tree_model_filter_get_property; + + object_class->finalize = egg_tree_model_filter_finalize; + + /* Properties -- FIXME: write a better description ... */ + g_object_class_install_property (object_class, + PROP_CHILD_MODEL, + g_param_spec_object ("child_model", + _("The child model"), + _("The model for the filtermodel to filter"), + GTK_TYPE_TREE_MODEL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, + PROP_VIRTUAL_ROOT, + g_param_spec_boxed ("virtual_root", + _("The virtual root"), + _("The virtual root (relative to the child model) for this filtermodel"), + GTK_TYPE_TREE_PATH, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +egg_tree_model_filter_tree_model_init (GtkTreeModelIface *iface) +{ + iface->get_flags = egg_tree_model_filter_get_flags; + iface->get_n_columns = egg_tree_model_filter_get_n_columns; + iface->get_column_type = egg_tree_model_filter_get_column_type; + iface->get_iter = egg_tree_model_filter_get_iter; + iface->get_path = egg_tree_model_filter_get_path; + iface->get_value = egg_tree_model_filter_get_value; + iface->iter_next = egg_tree_model_filter_iter_next; + iface->iter_children = egg_tree_model_filter_iter_children; + iface->iter_has_child = egg_tree_model_filter_iter_has_child; + iface->iter_n_children = egg_tree_model_filter_iter_n_children; + iface->iter_nth_child = egg_tree_model_filter_iter_nth_child; + iface->iter_parent = egg_tree_model_filter_iter_parent; + iface->ref_node = egg_tree_model_filter_ref_node; + iface->unref_node = egg_tree_model_filter_unref_node; +} + + +static void +egg_tree_model_filter_finalize (GObject *object) +{ + EggTreeModelFilter *filter = (EggTreeModelFilter *) object; + + egg_tree_model_filter_set_model (filter, NULL); + + if (filter->virtual_root) + gtk_tree_path_free (filter->virtual_root); + + if (filter->root) + egg_tree_model_filter_free_level (filter, filter->root); + + if (filter->modify_types) + g_free (filter->modify_types); + + /* must chain up */ + parent_class->finalize (object); +} + +static void +egg_tree_model_filter_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (object); + + switch (prop_id) + { + case PROP_CHILD_MODEL: + egg_tree_model_filter_set_model (filter, g_value_get_object (value)); + break; + case PROP_VIRTUAL_ROOT: + egg_tree_model_filter_set_root (filter, g_value_get_boxed (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +egg_tree_model_filter_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (object); + + switch (prop_id) + { + case PROP_CHILD_MODEL: + g_value_set_object (value, filter->child_model); + break; + case PROP_VIRTUAL_ROOT: + g_value_set_boxed (value, filter->virtual_root); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/* helpers */ + +static void +egg_tree_model_filter_build_level (EggTreeModelFilter *filter, + FilterLevel *parent_level, + FilterElt *parent_elt) +{ + GtkTreeIter iter; + GtkTreeIter root; + FilterLevel *new_level; + gint length = 0; + gint i; + + g_assert (filter->child_model != NULL); + + if (!parent_level) + { + if (filter->virtual_root) + { + if (gtk_tree_model_get_iter (filter->child_model, &root, filter->virtual_root) == FALSE) + return; + length = gtk_tree_model_iter_n_children (filter->child_model, &root); + + if (gtk_tree_model_iter_children (filter->child_model, &iter, &root) == FALSE) + return; + } + else + { + if (!gtk_tree_model_get_iter_first (filter->child_model, &iter)) + return; + length = gtk_tree_model_iter_n_children (filter->child_model, NULL); + } + } + else + { + GtkTreeIter parent_iter; + GtkTreeIter child_parent_iter; + + parent_iter.stamp = filter->stamp; + parent_iter.user_data = parent_level; + parent_iter.user_data2 = parent_elt; + + egg_tree_model_filter_convert_iter_to_child_iter (filter, + &child_parent_iter, + &parent_iter); + if (gtk_tree_model_iter_children (filter->child_model, &iter, &child_parent_iter) == FALSE) + return; + + /* stamp may have changed */ + egg_tree_model_filter_convert_iter_to_child_iter (filter, + &child_parent_iter, + &parent_iter); + length = gtk_tree_model_iter_n_children (filter->child_model, &child_parent_iter); + } + + g_return_if_fail (length > 0); + + new_level = g_new (FilterLevel, 1); + new_level->array = g_array_sized_new (FALSE, FALSE, + sizeof (FilterElt), + length); + new_level->ref_count = 0; + new_level->parent_elt = parent_elt; + new_level->parent_level = parent_level; + + if (parent_elt) + parent_elt->children = new_level; + else + filter->root = new_level; + + /* increase the count of zero ref_counts */ + while (parent_level) + { + parent_elt->zero_ref_count++; + + parent_elt = parent_level->parent_elt; + parent_level = parent_level->parent_level; + } + filter->zero_ref_count++; + + i = 0; + + if (!new_level->parent_level) + filter->root_level_visible = 0; + + do + { + if (egg_tree_model_filter_visible (filter, &iter)) + { + FilterElt filter_elt; + + filter_elt.offset = i; + filter_elt.zero_ref_count = 0; + filter_elt.ref_count = 0; + filter_elt.children = NULL; + filter_elt.visible = TRUE; + + if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter)) + filter_elt.iter = iter; + + g_array_append_val (new_level->array, filter_elt); + + if (!new_level->parent_level) + filter->root_level_visible++; + } + i++; + } + while (gtk_tree_model_iter_next (filter->child_model, &iter)); +} + +static void +egg_tree_model_filter_free_level (EggTreeModelFilter *filter, + FilterLevel *filter_level) +{ + gint i; + + g_assert (filter_level); + + if (filter_level->ref_count == 0) + { + FilterLevel *parent_level = filter_level->parent_level; + FilterElt *parent_elt = filter_level->parent_elt; + + do + { + if (parent_elt) + parent_elt->zero_ref_count--; + + if (parent_level) + { + parent_elt = parent_level->parent_elt; + parent_level = parent_level->parent_level; + } + } + while (parent_level); + filter->zero_ref_count--; + } + + for (i = 0; i < filter_level->array->len; i++) + { + if (g_array_index (filter_level->array, FilterElt, i).children) + egg_tree_model_filter_free_level (filter, + FILTER_LEVEL (g_array_index (filter_level->array, FilterElt, i).children)); + } + + if (!filter_level->parent_level) + filter->root_level_visible = 0; + + if (filter_level->parent_elt) + filter_level->parent_elt->children = NULL; + else + filter->root = NULL; + + g_array_free (filter_level->array, TRUE); + filter_level->array = NULL; + + g_free (filter_level); + filter_level = NULL; +} + +static GtkTreePath * +egg_tree_model_filter_elt_get_path (FilterLevel *level, + FilterElt *elt, + GtkTreePath *root) +{ + FilterLevel *walker = level; + FilterElt *walker2 = elt; + GtkTreePath *path; + GtkTreePath *real_path; + + g_return_val_if_fail (level != NULL, NULL); + g_return_val_if_fail (elt != NULL, NULL); + + path = gtk_tree_path_new (); + + while (walker) + { + gtk_tree_path_prepend_index (path, walker2->offset); + + walker2 = walker->parent_elt; + walker = walker->parent_level; + } + + if (root) + { + real_path = gtk_tree_path_copy (root); + + egg_tree_model_filter_add_root (real_path, path); + gtk_tree_path_free (path); + return real_path; + } + + return path; +} + +static GtkTreePath * +egg_tree_model_filter_add_root (GtkTreePath *src, + GtkTreePath *root) +{ + GtkTreePath *retval; + gint i; + + retval = gtk_tree_path_copy (root); + + for (i = 0; i < gtk_tree_path_get_depth (src); i++) + gtk_tree_path_append_index (retval, gtk_tree_path_get_indices (src)[i]); + + return retval; +} + +static GtkTreePath * +egg_tree_model_filter_remove_root (GtkTreePath *src, + GtkTreePath *root) +{ + GtkTreePath *retval; + gint i; + gint depth; + gint *indices; + + if (gtk_tree_path_get_depth (src) <= gtk_tree_path_get_depth (root)) + return NULL; + + depth = gtk_tree_path_get_depth (src); + indices = gtk_tree_path_get_indices (src); + + for (i = 0; i < gtk_tree_path_get_depth (root); i++) + if (indices[i] != gtk_tree_path_get_indices (root)[i]) + return NULL; + + retval = gtk_tree_path_new (); + + for (; i < depth; i++) + gtk_tree_path_append_index (retval, indices[i]); + + return retval; +} + +static void +egg_tree_model_filter_increment_stamp (EggTreeModelFilter *filter) +{ + do + { + filter->stamp++; + } + while (filter->stamp == 0); + + egg_tree_model_filter_clear_cache (filter); +} + +static gboolean +egg_tree_model_filter_visible (EggTreeModelFilter *filter, + GtkTreeIter *child_iter) +{ + if (filter->visible_func) + { + return (filter->visible_func (filter->child_model, + child_iter, + filter->visible_data)); + } + else if (filter->visible_column >= 0) + { + GValue val = {0, }; + + gtk_tree_model_get_value (filter->child_model, child_iter, + filter->visible_column, &val); + + if (g_value_get_boolean (&val)) + { + g_value_unset (&val); + return TRUE; + } + + g_value_unset (&val); + return FALSE; + } + + /* no filter thing set, so always visible */ + return TRUE; +} + +static void +egg_tree_model_filter_clear_cache_helper (EggTreeModelFilter *filter, + FilterLevel *level) +{ + gint i; + + g_assert (level); + + for (i = 0; i < level->array->len; i++) + { + if (g_array_index (level->array, FilterElt, i).zero_ref_count > 0) + egg_tree_model_filter_clear_cache_helper (filter, g_array_index (level->array, FilterElt, i).children); + } + + if (level->ref_count == 0 && level != filter->root) + { + egg_tree_model_filter_free_level (filter, level); + return; + } +} + +static gboolean +egg_tree_model_filter_fetch_child (EggTreeModelFilter *filter, + FilterLevel *level, + gint offset) +{ + gint i = 0; + gint len; + GtkTreePath *c_path = NULL; + GtkTreeIter c_iter; + GtkTreePath *c_parent_path = NULL; + GtkTreeIter c_parent_iter; + FilterElt elt; + + /* check if child exists and is visible */ + if (level->parent_elt) + { + c_parent_path = + egg_tree_model_filter_elt_get_path (level->parent_level, + level->parent_elt, + filter->virtual_root); + if (!c_parent_path) + return FALSE; + } + else + { + if (filter->virtual_root) + c_parent_path = gtk_tree_path_copy (filter->virtual_root); + else + c_parent_path = NULL; + } + + if (c_parent_path) + { + gtk_tree_model_get_iter (filter->child_model, + &c_parent_iter, + c_parent_path); + len = gtk_tree_model_iter_n_children (filter->child_model, + &c_parent_iter); + + c_path = gtk_tree_path_copy (c_parent_path); + gtk_tree_path_free (c_parent_path); + } + else + { + len = gtk_tree_model_iter_n_children (filter->child_model, NULL); + c_path = gtk_tree_path_new (); + } + + gtk_tree_path_append_index (c_path, offset); + gtk_tree_model_get_iter (filter->child_model, &c_iter, c_path); + gtk_tree_path_free (c_path); + + if (offset >= len || !egg_tree_model_filter_visible (filter, &c_iter)) + return FALSE; + + /* add child */ + elt.offset = offset; + elt.zero_ref_count = 0; + elt.ref_count = 0; + elt.children = NULL; + /* visibility should be FALSE as we don't emit row_inserted */ + elt.visible = FALSE; + + if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter)) + elt.iter = c_iter; + + /* find index */ + for (i = 0; i < level->array->len; i++) + if (g_array_index (level->array, FilterElt, i).offset > offset) + break; + + g_array_insert_val (level->array, i, elt); + + for (i = 0; i < level->array->len; i++) + { + FilterElt *e = &(g_array_index (level->array, FilterElt, i)); + if (e->children) + e->children->parent_elt = e; + } + + return TRUE; +} + +static void +egg_tree_model_filter_remove_node (EggTreeModelFilter *filter, + GtkTreeIter *iter, + gboolean emit_signal) +{ + FilterElt *elt, *parent; + FilterLevel *level, *parent_level; + gint offset, i, length, level_refcount; + + /* FIXME: this function is very ugly. I need to rethink and + * rewrite it someday. + */ + + level = FILTER_LEVEL (iter->user_data); + elt = FILTER_ELT (iter->user_data2); + + parent = level->parent_elt; + parent_level = level->parent_level; + length = level->array->len; + offset = elt->offset; + + /* ref counting */ + while (elt->ref_count > 0) + egg_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter), + iter, FALSE); + + level_refcount = level->ref_count; + + /* do the ref counting first! this touches the stamp */ + if (emit_signal) + { + GtkTreePath *path; + + path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter); + egg_tree_model_filter_increment_stamp (filter); + gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter), path); + gtk_tree_path_free (path); + } + + if ((length == 1 || level_refcount == 0) && + emit_signal && iter->user_data != filter->root) + { + /* above code destroyed the level */ + goto emit_has_child_toggled; + } + + if (length == 1) + { + /* kill the level */ + egg_tree_model_filter_free_level (filter, level); + + if (!filter->root) + /* we killed the root */ + return; + } + else + { + /* remove the node */ + for (i = 0; i < level->array->len; i++) + if (elt->offset == g_array_index (level->array, FilterElt, i).offset) + break; + + g_array_remove_index (level->array, i); + + for (i = 0; i < level->array->len; i++) + { + /* NOTE: here we do *not* decrease offsets, because the node was + * not removed from the child model + */ + elt = &g_array_index (level->array, FilterElt, i); + if (elt->children) + elt->children->parent_elt = elt; + } + } + +emit_has_child_toggled: + /* children are being handled first, so we can check it this way + * + * yes this if-statement is ugly + */ + if ((parent && parent->children && parent->children->array->len <= 1) || + (length == 1 && emit_signal && iter->user_data != filter->root)) + { + /* latest child has been removed, level has been destroyed */ + GtkTreeIter piter; + GtkTreePath *ppath; + + piter.stamp = filter->stamp; + piter.user_data = parent_level; + piter.user_data2 = parent; + + ppath = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &piter); + + gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter), + ppath, &piter); + gtk_tree_path_free (ppath); + } +} + +static void +egg_tree_model_filter_update_childs (EggTreeModelFilter *filter, + FilterLevel *level, + FilterElt *elt) +{ + GtkTreeIter c_iter; + GtkTreeIter iter; + + if (!elt->visible) + return; + + iter.stamp = filter->stamp; + iter.user_data = level; + iter.user_data2 = elt; + + egg_tree_model_filter_convert_iter_to_child_iter (filter, &c_iter, &iter); + + if (gtk_tree_model_iter_has_child (filter->child_model, &c_iter)) + { + GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), + &iter); + gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter), + path, + &iter); + if (path) + gtk_tree_path_free (path); + } +} + +/* TreeModel signals */ +static void +egg_tree_model_filter_row_changed (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gpointer data) +{ + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); + GtkTreeIter iter; + GtkTreeIter real_c_iter; + GtkTreePath *path; + + FilterElt *elt; + FilterLevel *level; + gint offset; + + gboolean new; + gboolean free_c_path = FALSE; + + g_return_if_fail (c_path != NULL || c_iter != NULL); + + if (!c_path) + { + c_path = gtk_tree_model_get_path (c_model, c_iter); + free_c_path = TRUE; + } + + if (c_iter) + real_c_iter = *c_iter; + else + gtk_tree_model_get_iter (c_model, &real_c_iter, c_path); + + if (!filter->root) + { + gint i; + FilterLevel *root; + + /* build root level */ + egg_tree_model_filter_build_level (filter, NULL, NULL); + + root = FILTER_LEVEL (filter->root); + + /* FIXME: + * we set the visibilities to FALSE here, so we ever emit + * a row_inserted. maybe it's even better to emit row_inserted + * here, not sure. + */ + if (root) + { + for (i = 0; i < root->array->len; i++) + g_array_index (root->array, FilterElt, i).visible = FALSE; + filter->root_level_visible = 0; + } + } + + path = egg_real_tree_model_filter_convert_child_path_to_path (filter, + c_path, + FALSE, + TRUE); + if (!path) + goto done; + + gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path); + + level = FILTER_LEVEL (iter.user_data); + elt = FILTER_ELT (iter.user_data2); + offset = elt->offset; + new = egg_tree_model_filter_visible (filter, c_iter); + + if (elt->visible == TRUE && new == FALSE) + { + egg_tree_model_filter_remove_node (filter, &iter, TRUE); + + if (!level->parent_level) + filter->root_level_visible--; + } + else if (elt->visible == FALSE && new == TRUE) + { + GtkTreeIter childs; + + elt->visible = TRUE; + + egg_tree_model_filter_increment_stamp (filter); + + if (!level->parent_level) + filter->root_level_visible++; + + /* update stamp */ + gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path); + gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter), path, &iter); + + if (gtk_tree_model_iter_children (c_model, &childs, c_iter)) + egg_tree_model_filter_update_childs (filter, level, elt); + } + else if (elt->visible == FALSE && new == FALSE) + { + egg_tree_model_filter_remove_node (filter, &iter, FALSE); + } + else + { + GtkTreeIter childs; + + gtk_tree_model_row_changed (GTK_TREE_MODEL (filter), path, &iter); + + if (gtk_tree_model_iter_children (c_model, &childs, c_iter) && + elt->visible) + egg_tree_model_filter_update_childs (filter, level, elt); + } + + gtk_tree_path_free (path); + +done: + if (free_c_path) + gtk_tree_path_free (c_path); +} + +static void +egg_tree_model_filter_row_inserted (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gpointer data) +{ + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); + GtkTreePath *path; + GtkTreePath *real_path; + GtkTreeIter iter; + + GtkTreeIter real_c_iter; + + FilterElt *elt; + FilterLevel *level; + FilterLevel *parent_level; + + gint i = 0, offset, index = -1; + + gboolean free_c_path = FALSE; + + g_return_if_fail (c_path != NULL || c_iter != NULL); + + if (!c_path) + { + c_path = gtk_tree_model_get_path (c_model, c_iter); + free_c_path = TRUE; + } + + if (c_iter) + real_c_iter = *c_iter; + else + gtk_tree_model_get_iter (c_model, &real_c_iter, c_path); + + /* the row has already been inserted. so we need to fixup the + * virtual root here first + */ + if (filter->virtual_root) + { + if (gtk_tree_path_get_depth (filter->virtual_root) >= + gtk_tree_path_get_depth (c_path)) + { + gint level; + gint *v_indices, *c_indices; + + level = gtk_tree_path_get_depth (c_path) - 1; + v_indices = gtk_tree_path_get_indices (filter->virtual_root); + c_indices = gtk_tree_path_get_indices (c_path); + + if (v_indices[level] >= c_indices[level]) + (v_indices[level])++; + } + } + + if (!filter->root) + { + egg_tree_model_filter_build_level (filter, NULL, NULL); + /* that already put the inserted iter in the level */ + + goto done_and_emit; + } + + parent_level = level = FILTER_LEVEL (filter->root); + + /* subtract virtual root if necessary */ + if (filter->virtual_root) + { + real_path = egg_tree_model_filter_remove_root (c_path, + filter->virtual_root); + /* not our kiddo */ + if (!real_path) + goto done; + } + else + real_path = gtk_tree_path_copy (c_path); + + if (gtk_tree_path_get_depth (real_path) - 1 >= 1) + { + /* find the parent level */ + while (i < gtk_tree_path_get_depth (real_path) - 1) + { + gint j; + + if (!level) + /* we don't cover this signal */ + goto done; + + elt = NULL; + for (j = 0; j < level->array->len; j++) + if (g_array_index (level->array, FilterElt, j).offset == + gtk_tree_path_get_indices (real_path)[i]) + { + elt = &g_array_index (level->array, FilterElt, j); + break; + } + + if (!elt) + /* parent is probably being filtered out */ + goto done; + + if (!elt->children) + { + GtkTreePath *tmppath; + GtkTreeIter tmpiter; + + tmpiter.stamp = filter->stamp; + tmpiter.user_data = level; + tmpiter.user_data2 = elt; + + tmppath = gtk_tree_model_get_path (GTK_TREE_MODEL (data), + &tmpiter); + + if (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; + } + + level = elt->children; + parent_level = level; + i++; + } + } + + if (!parent_level) + goto done; + + /* let's try to insert the value */ + offset = gtk_tree_path_get_indices (real_path)[gtk_tree_path_get_depth (real_path) - 1]; + + /* update the offsets, yes if we didn't insert the node above, there will + * be a gap here. This will be filled with the node (via fetch_child) when + * it becomes visible + */ + for (i = 0; i < level->array->len; i++) + { + FilterElt *e = &g_array_index (level->array, FilterElt, i); + if ((e->offset >= offset)) + e->offset++; + } + + /* only insert when visible */ + if (egg_tree_model_filter_visible (filter, &real_c_iter)) + { + FilterElt felt; + + if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter)) + felt.iter = real_c_iter; + + felt.offset = offset; + felt.zero_ref_count = 0; + felt.ref_count = 0; + felt.visible = TRUE; + felt.children = NULL; + + for (i = 0; i < level->array->len; i++) + if (g_array_index (level->array, FilterElt, i).offset > offset) + break; + + g_array_insert_val (level->array, i, felt); + index = i; + + if (!level->parent_level) + filter->root_level_visible++; + } + + /* another iteration to update the references of childs to parents. */ + for (i = 0; i < level->array->len; i++) + { + FilterElt *e = &g_array_index (level->array, FilterElt, i); + if (e->children) + e->children->parent_elt = e; + } + + /* don't emit the signal if we aren't visible */ + if (!egg_tree_model_filter_visible (filter, &real_c_iter)) + goto done; + +done_and_emit: + /* NOTE: pass c_path here and NOT real_path. This function does + * root subtraction itself + */ + path = egg_real_tree_model_filter_convert_child_path_to_path (filter, + c_path, + FALSE, TRUE); + + if (!path) + return; + + egg_tree_model_filter_increment_stamp (filter); + + gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); + gtk_tree_model_row_inserted (GTK_TREE_MODEL (data), path, &iter); + +done: + if (free_c_path) + gtk_tree_path_free (c_path); +} + +static void +egg_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gpointer data) +{ + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); + GtkTreePath *path; + GtkTreeIter iter; + + g_return_if_fail (c_path != NULL && c_iter != NULL); + + /* FIXME: does this code work? */ + + if (!egg_tree_model_filter_visible (filter, c_iter)) + return; + + path = egg_real_tree_model_filter_convert_child_path_to_path (filter, + c_path, + FALSE, + TRUE); + if (!path) + return; + + gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); + gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data), path, &iter); + + gtk_tree_path_free (path); +} + +static void +egg_tree_model_filter_row_deleted (GtkTreeModel *c_model, + GtkTreePath *c_path, + gpointer data) +{ + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); + GtkTreePath *path; + GtkTreeIter iter; + FilterElt *elt; + FilterLevel *level; + gint offset; + gboolean emit_signal = TRUE; + gint i; + + g_return_if_fail (c_path != NULL); + + /* special case the deletion of an ancestor of the virtual root */ + if (filter->virtual_root && + (gtk_tree_path_is_ancestor (c_path, filter->virtual_root) || + !gtk_tree_path_compare (c_path, filter->virtual_root))) + { + gint i; + GtkTreePath *path; + FilterLevel *level = FILTER_LEVEL (filter->root); + + if (!level) + return; + + /* remove everything in the filter model + * + * For now, we just iterate over the root level and emit a + * row_deleted for each FilterElt. Not sure if this is correct. + */ + + egg_tree_model_filter_increment_stamp (filter); + path = gtk_tree_path_new (); + gtk_tree_path_append_index (path, 0); + + for (i = 0; i < level->array->len; i++) + gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path); + + gtk_tree_path_free (path); + egg_tree_model_filter_free_level (filter, filter->root); + + return; + } + + /* fixup virtual root */ + if (filter->virtual_root) + { + if (gtk_tree_path_get_depth (filter->virtual_root) >= + gtk_tree_path_get_depth (c_path)) + { + gint level; + gint *v_indices, *c_indices; + + level = gtk_tree_path_get_depth (c_path) - 1; + v_indices = gtk_tree_path_get_indices (filter->virtual_root); + c_indices = gtk_tree_path_get_indices (c_path); + + if (v_indices[level] > c_indices[level]) + (v_indices[level])--; + } + } + + path = egg_real_tree_model_filter_convert_child_path_to_path (filter, + c_path, + FALSE, + FALSE); + if (!path) + { + path = egg_real_tree_model_filter_convert_child_path_to_path (filter, + c_path, + FALSE, + TRUE); + + if (!path) + { + /* fixup the offsets */ + GtkTreePath *real_path; + + if (!filter->root) + return; + + level = FILTER_LEVEL (filter->root); + + /* subtract vroot if necessary */ + if (filter->virtual_root) + { + real_path = egg_tree_model_filter_remove_root (c_path, + filter->virtual_root); + /* we don't handle this */ + if (!real_path) + return; + } + else + real_path = gtk_tree_path_copy (c_path); + + i = 0; + if (gtk_tree_path_get_depth (real_path) - 1 >= 1) + { + while (i < gtk_tree_path_get_depth (real_path) - 1) + { + gint j; + + if (!level) + { + /* we don't cover this */ + gtk_tree_path_free (real_path); + return; + } + + elt = NULL; + for (j = 0; j < level->array->len; j++) + if (g_array_index (level->array, FilterElt, j).offset == + gtk_tree_path_get_indices (real_path)[i]) + { + elt = &g_array_index (level->array, FilterElt, j); + break; + } + + if (!elt || !elt->children) + { + /* parent is filtered out, so no level */ + gtk_tree_path_free (real_path); + return; + } + + level = elt->children; + i++; + } + } + + offset = gtk_tree_path_get_indices (real_path)[gtk_tree_path_get_depth (real_path) - 1]; + gtk_tree_path_free (real_path); + + if (!level) + return; + + /* we need: + * - the offset of the removed item + * - the level + */ + for (i = 0; i < level->array->len; i++) + { + elt = &g_array_index (level->array, FilterElt, i); + if (elt->offset > offset) + elt->offset--; + if (elt->children) + elt->children->parent_elt = elt; + } + + return; + } + + emit_signal = FALSE; + } + + gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); + + level = FILTER_LEVEL (iter.user_data); + elt = FILTER_ELT (iter.user_data2); + offset = elt->offset; + + if (!level->parent_level && elt->visible) + filter->root_level_visible--; + + if (emit_signal) + { + if (level->ref_count == 0 && level != filter->root) + { + egg_tree_model_filter_increment_stamp (filter); + gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path); + + gtk_tree_path_free (path); + return; + } + + egg_tree_model_filter_increment_stamp (filter); + gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path); + iter.stamp = filter->stamp; + + while (elt->ref_count > 0) + egg_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter, + FALSE); + } + + if (level->array->len == 1) + { + /* kill level */ + egg_tree_model_filter_free_level (filter, level); + } + else + { + /* remove the row */ + for (i = 0; i < level->array->len; i++) + if (elt->offset == g_array_index (level->array, FilterElt, i).offset) + break; + + offset = g_array_index (level->array, FilterElt, i).offset; + g_array_remove_index (level->array, i); + + for (i = 0; i < level->array->len; i++) + { + elt = &g_array_index (level->array, FilterElt, i); + if (elt->offset > offset) + elt->offset--; + if (elt->children) + elt->children->parent_elt = elt; + } + } + + gtk_tree_path_free (path); +} + +static void +egg_tree_model_filter_rows_reordered (GtkTreeModel *c_model, + GtkTreePath *c_path, + GtkTreeIter *c_iter, + gint *new_order, + gpointer data) +{ + FilterElt *elt; + FilterLevel *level; + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); + + GtkTreePath *path; + GtkTreeIter iter; + + gint *tmp_array; + gint i, j, elt_count; + gint length; + + GArray *new_array; + + g_return_if_fail (new_order != NULL); + + if (c_path == NULL || gtk_tree_path_get_indices (c_path) == NULL) + { + if (!filter->root) + return; + + length = gtk_tree_model_iter_n_children (c_model, NULL); + + if (filter->virtual_root) + { + gint new_pos = -1; + + /* reorder root level of path */ + for (i = 0; i < length; i++) + if (new_order[i] == gtk_tree_path_get_indices (filter->virtual_root)[0]) + new_pos = i; + + if (new_pos < 0) + return; + + gtk_tree_path_get_indices (filter->virtual_root)[0] = new_pos; + return; + } + + path = gtk_tree_path_new (); + level = FILTER_LEVEL (filter->root); + } + else + { + GtkTreeIter child_iter; + + /* virtual root anchor reordering */ + if (filter->virtual_root && + gtk_tree_path_get_depth (c_path) < + gtk_tree_path_get_depth (filter->virtual_root)) + { + gint new_pos = -1; + gint length; + gint level; + GtkTreeIter real_c_iter; + + level = gtk_tree_path_get_depth (c_path); + + if (c_iter) + real_c_iter = *c_iter; + else + gtk_tree_model_get_iter (c_model, &real_c_iter, c_path); + + length = gtk_tree_model_iter_n_children (c_model, &real_c_iter); + + for (i = 0; i < length; i++) + if (new_order[i] == gtk_tree_path_get_indices (filter->virtual_root)[level]) + new_pos = i; + + if (new_pos < 0) + return; + + gtk_tree_path_get_indices (filter->virtual_root)[level] = new_pos; + return; + } + + path = egg_real_tree_model_filter_convert_child_path_to_path (filter, + c_path, + FALSE, + FALSE); + if (!path && filter->virtual_root && + gtk_tree_path_compare (c_path, filter->virtual_root)) + return; + + if (!path && !filter->virtual_root) + return; + + if (!path) + { + /* root level mode */ + if (!c_iter) + gtk_tree_model_get_iter (c_model, c_iter, c_path); + length = gtk_tree_model_iter_n_children (c_model, c_iter); + path = gtk_tree_path_new (); + level = FILTER_LEVEL (filter->root); + } + else + { + gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); + + level = FILTER_LEVEL (iter.user_data); + elt = FILTER_ELT (iter.user_data2); + + if (!elt->children) + { + gtk_tree_path_free (path); + return; + } + + level = elt->children; + + egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (filter), &child_iter, &iter); + length = gtk_tree_model_iter_n_children (c_model, &child_iter); + } + } + + if (level->array->len < 1) + return; + + /* NOTE: we do not bail out here if level->array->len < 2 like + * GtkTreeModelSort does. This because we do some special tricky + * reordering. + */ + + /* construct a new array */ + new_array = g_array_sized_new (FALSE, FALSE, sizeof (FilterElt), + level->array->len); + tmp_array = g_new (gint, level->array->len); + + for (i = 0, elt_count = 0; i < length; i++) + { + FilterElt *e = NULL; + gint old_offset = -1; + + for (j = 0; j < level->array->len; j++) + if (g_array_index (level->array, FilterElt, j).offset == new_order[i]) + { + e = &g_array_index (level->array, FilterElt, j); + old_offset = j; + break; + } + + if (!e) + continue; + + tmp_array[elt_count] = old_offset; + g_array_append_val (new_array, *e); + g_array_index (new_array, FilterElt, elt_count).offset = i; + elt_count++; + } + + g_array_free (level->array, TRUE); + level->array = new_array; + + /* fix up stuff */ + for (i = 0; i < level->array->len; i++) + { + FilterElt *e = &g_array_index (level->array, FilterElt, i); + if (e->children) + e->children->parent_elt = e; + } + + /* emit rows_reordered */ + if (!gtk_tree_path_get_indices (path)) + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, NULL, + tmp_array); + else + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, &iter, + tmp_array); + + /* done */ + g_free (tmp_array); + gtk_tree_path_free (path); +} + +/* TreeModelIface implementation */ +static guint +egg_tree_model_filter_get_flags (GtkTreeModel *model) +{ + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0); + + return 0; +} + +static gint +egg_tree_model_filter_get_n_columns (GtkTreeModel *model) +{ + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0); + g_return_val_if_fail (filter->child_model != NULL, 0); + + if (filter->child_model == NULL) + return 0; + + /* so we can't modify the modify func after this ... */ + filter->modify_func_set = TRUE; + + if (filter->modify_n_columns > 0) + return filter->modify_n_columns; + + return gtk_tree_model_get_n_columns (filter->child_model); +} + +static GType +egg_tree_model_filter_get_column_type (GtkTreeModel *model, + gint index) +{ + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), G_TYPE_INVALID); + g_return_val_if_fail (filter->child_model != NULL, G_TYPE_INVALID); + + /* so we can't modify the modify func after this ... */ + filter->modify_func_set = TRUE; + + if (filter->modify_types) + { + g_return_val_if_fail (index < filter->modify_n_columns, G_TYPE_INVALID); + + return filter->modify_types[index]; + } + + return gtk_tree_model_get_column_type (filter->child_model, index); +} + +static gboolean +egg_tree_model_filter_get_iter (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreePath *path) +{ + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + gint *indices; + FilterLevel *level; + gint depth, i; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); + g_return_val_if_fail (filter->child_model != NULL, FALSE); + + indices = gtk_tree_path_get_indices (path); + + if (filter->root == NULL) + egg_tree_model_filter_build_level (filter, NULL, NULL); + level = FILTER_LEVEL (filter->root); + + depth = gtk_tree_path_get_depth (path); + if (!depth) + { + iter->stamp = 0; + return FALSE; + } + + for (i = 0; i < depth - 1; i++) + { + if (!level || indices[i] >= level->array->len) + { + return FALSE; + } + + if (!g_array_index (level->array, FilterElt, indices[i]).children) + egg_tree_model_filter_build_level (filter, level, + &g_array_index (level->array, + FilterElt, + indices[i])); + level = g_array_index (level->array, FilterElt, indices[i]).children; + } + + if (!level || indices[i] >= level->array->len) + { + iter->stamp = 0; + return FALSE; + } + + iter->stamp = filter->stamp; + iter->user_data = level; + iter->user_data2 = &g_array_index (level->array, FilterElt, + indices[depth - 1]); + + return TRUE; +} + +static GtkTreePath * +egg_tree_model_filter_get_path (GtkTreeModel *model, + GtkTreeIter *iter) +{ + GtkTreePath *retval; + FilterLevel *level; + FilterElt *elt; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), NULL); + g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL, NULL); + g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp, NULL); + + retval = gtk_tree_path_new (); + level = iter->user_data; + elt = iter->user_data2; + + while (level) + { + gtk_tree_path_prepend_index (retval, + elt - FILTER_ELT (level->array->data)); + elt = level->parent_elt; + level = level->parent_level; + } + + return retval; +} + +static void +egg_tree_model_filter_get_value (GtkTreeModel *model, + GtkTreeIter *iter, + gint column, + GValue *value) +{ + GtkTreeIter child_iter; + EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (model); + + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model)); + g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL); + g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp); + + if (filter->modify_func) + { + g_return_if_fail (column < filter->modify_n_columns); + + g_value_init (value, filter->modify_types[column]); + filter->modify_func (model, + iter, + value, + column, + filter->modify_data); + + return; + } + + egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); + gtk_tree_model_get_value (EGG_TREE_MODEL_FILTER (model)->child_model, + &child_iter, column, value); +} + +static gboolean +egg_tree_model_filter_iter_next (GtkTreeModel *model, + GtkTreeIter *iter) +{ + FilterLevel *level; + FilterElt *elt; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); + g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL, FALSE); + g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp, FALSE); + + level = iter->user_data; + elt = iter->user_data2; + + if (elt - FILTER_ELT (level->array->data) >= level->array->len - 1) + { + iter->stamp = 0; + return FALSE; + } + + iter->user_data2 = elt + 1; + + return TRUE; +} + +static gboolean +egg_tree_model_filter_iter_children (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *parent) +{ + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + FilterLevel *level; + + iter->stamp = 0; + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); + g_return_val_if_fail (filter->child_model != NULL, FALSE); + if (parent) + g_return_val_if_fail (filter->stamp == parent->stamp, FALSE); + + if (!parent) + { + if (!filter->root) + egg_tree_model_filter_build_level (filter, NULL, NULL); + if (!filter->root) + return FALSE; + + level = filter->root; + iter->stamp = filter->stamp; + iter->user_data = level; + iter->user_data2 = level->array->data; + } + else + { + if (FILTER_ELT (parent->user_data2)->children == NULL) + egg_tree_model_filter_build_level (filter, + FILTER_LEVEL (parent->user_data), + FILTER_ELT (parent->user_data2)); + if (FILTER_ELT (parent->user_data2)->children == NULL) + return FALSE; + + /* empty array? */ + if (FILTER_ELT (parent->user_data2)->children->array->len <= 0) + return FALSE; + + iter->stamp = filter->stamp; + iter->user_data = FILTER_ELT (parent->user_data2)->children; + iter->user_data2 = FILTER_LEVEL (iter->user_data)->array->data; + } + + return TRUE; +} + +static gboolean +egg_tree_model_filter_iter_has_child (GtkTreeModel *model, + GtkTreeIter *iter) +{ + GtkTreeIter child_iter; + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + FilterElt *elt; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); + g_return_val_if_fail (filter->child_model != NULL, FALSE); + g_return_val_if_fail (filter->stamp == iter->stamp, FALSE); + + filter = EGG_TREE_MODEL_FILTER (model); + + egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); + elt = FILTER_ELT (iter->user_data2); + + /* we need to build the level to check if not all children are filtered + * out + */ + if (!elt->children + && gtk_tree_model_iter_has_child (filter->child_model, &child_iter)) + egg_tree_model_filter_build_level (filter, FILTER_LEVEL (iter->user_data), + elt); + + /* FIXME: we should prolly count the visible nodes here, just like in + * _iter_n_children. + */ + if (elt->children && elt->children->array->len > 0) + return TRUE; + + return FALSE; +} + +static gint +egg_tree_model_filter_iter_n_children (GtkTreeModel *model, + GtkTreeIter *iter) +{ + GtkTreeIter child_iter; + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + FilterElt *elt; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0); + g_return_val_if_fail (filter->child_model != NULL, 0); + if (iter) + g_return_val_if_fail (filter->stamp == iter->stamp, 0); + + if (!iter) + { + if (!filter->root) + egg_tree_model_filter_build_level (filter, NULL, NULL); + + /* count visible nodes */ + return filter->root_level_visible; + } + + elt = FILTER_ELT (iter->user_data2); + egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); + + if (!elt->children && + gtk_tree_model_iter_has_child (filter->child_model, &child_iter)) + egg_tree_model_filter_build_level (filter, + FILTER_LEVEL (iter->user_data), + elt); + + if (elt->children && elt->children->array->len) + { + int i = 0; + int count = 0; + GArray *a = elt->children->array; + + /* count visible nodes */ + for (i = 0; i < a->len; i++) + if (g_array_index (a, FilterElt, i).visible) + count++; + + return count; + } + + return 0; +} + +static gboolean +egg_tree_model_filter_iter_nth_child (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n) +{ + FilterLevel *level; + GtkTreeIter children; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); + if (parent) + g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == parent->stamp, FALSE); + + /* use this instead of has_Child to force us to build the level, if needed */ + if (egg_tree_model_filter_iter_children (model, &children, parent) == FALSE) + { + iter->stamp = 0; + return FALSE; + } + + level = children.user_data; + if (n >= level->array->len) + { + iter->stamp = 0; + return FALSE; + } + + iter->stamp = EGG_TREE_MODEL_FILTER (model)->stamp; + iter->user_data = level; + iter->user_data2 = &g_array_index (level->array, FilterElt, n); + + return TRUE; +} + +static gboolean +egg_tree_model_filter_iter_parent (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *child) +{ + FilterLevel *level; + + iter->stamp = 0; + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); + g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL, FALSE); + g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == child->stamp, FALSE); + + level = child->user_data; + + if (level->parent_level) + { + iter->stamp = EGG_TREE_MODEL_FILTER (model)->stamp; + iter->user_data = level->parent_level; + iter->user_data2 = level->parent_elt; + + return TRUE; + } + + return FALSE; +} + +static void +egg_tree_model_filter_ref_node (GtkTreeModel *model, + GtkTreeIter *iter) +{ + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + GtkTreeIter child_iter; + FilterLevel *level; + FilterElt *elt; + + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model)); + g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL); + g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp); + + egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); + + gtk_tree_model_ref_node (filter->child_model, &child_iter); + + level = iter->user_data; + elt = iter->user_data2; + + elt->ref_count++; + level->ref_count++; + if (level->ref_count == 1) + { + FilterLevel *parent_level = level->parent_level; + FilterElt *parent_elt = level->parent_elt; + + /* we were at zero -- time to decrease the zero_ref_count val */ + do + { + if (parent_elt) + parent_elt->zero_ref_count--; + + if (parent_level) + { + parent_elt = parent_level->parent_elt; + parent_level = parent_level->parent_level; + } + } + while (parent_level); + filter->zero_ref_count--; + } +} + +static void +egg_tree_model_filter_unref_node (GtkTreeModel *model, + GtkTreeIter *iter) +{ + egg_tree_model_filter_real_unref_node (model, iter, TRUE); +} + +static void +egg_tree_model_filter_real_unref_node (GtkTreeModel *model, + GtkTreeIter *iter, + gboolean propagate_unref) +{ + EggTreeModelFilter *filter = (EggTreeModelFilter *)model; + FilterLevel *level; + FilterElt *elt; + + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model)); + g_return_if_fail (filter->child_model != NULL); + g_return_if_fail (filter->stamp == iter->stamp); + + if (propagate_unref) + { + GtkTreeIter child_iter; + egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); + gtk_tree_model_unref_node (filter->child_model, &child_iter); + } + + level = iter->user_data; + elt = iter->user_data2; + + g_return_if_fail (elt->ref_count > 0); + + elt->ref_count--; + level->ref_count--; + if (level->ref_count == 0) + { + FilterLevel *parent_level = level->parent_level; + FilterElt *parent_elt = level->parent_elt; + + /* we are at zero -- time to increase the zero_ref_count val */ + while (parent_level) + { + parent_elt->zero_ref_count++; + + parent_elt = parent_level->parent_elt; + parent_level = parent_level->parent_level; + } + filter->zero_ref_count++; + } +} + +/* bits and pieces */ +static void +egg_tree_model_filter_set_model (EggTreeModelFilter *filter, + GtkTreeModel *child_model) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + + if (filter->child_model) + { + g_signal_handler_disconnect (G_OBJECT (filter->child_model), + filter->changed_id); + g_signal_handler_disconnect (G_OBJECT (filter->child_model), + filter->inserted_id); + g_signal_handler_disconnect (G_OBJECT (filter->child_model), + filter->has_child_toggled_id); + g_signal_handler_disconnect (G_OBJECT (filter->child_model), + filter->deleted_id); + g_signal_handler_disconnect (G_OBJECT (filter->child_model), + filter->reordered_id); + + /* reset our state */ + if (filter->root) + egg_tree_model_filter_free_level (filter, filter->root); + + filter->root = NULL; + g_object_unref (G_OBJECT (filter->child_model)); + filter->visible_column = -1; + /* FIXME: destroy more crack here? the funcs? */ + } + + filter->child_model = child_model; + + if (child_model) + { + g_object_ref (G_OBJECT (filter->child_model)); + filter->changed_id = + g_signal_connect (child_model, "row_changed", + G_CALLBACK (egg_tree_model_filter_row_changed), + filter); + filter->inserted_id = + g_signal_connect (child_model, "row_inserted", + G_CALLBACK (egg_tree_model_filter_row_inserted), + filter); + filter->has_child_toggled_id = + g_signal_connect (child_model, "row_has_child_toggled", + G_CALLBACK (egg_tree_model_filter_row_has_child_toggled), + filter); + filter->deleted_id = + g_signal_connect (child_model, "row_deleted", + G_CALLBACK (egg_tree_model_filter_row_deleted), + filter); + filter->reordered_id = + g_signal_connect (child_model, "rows_reordered", + G_CALLBACK (egg_tree_model_filter_rows_reordered), + filter); + + filter->child_flags = gtk_tree_model_get_flags (child_model); + filter->stamp = g_random_int (); + } +} + +static void +egg_tree_model_filter_set_root (EggTreeModelFilter *filter, + GtkTreePath *root) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + + if (!root) + filter->virtual_root = NULL; + else + filter->virtual_root = gtk_tree_path_copy (root); +} + +/* public API */ + +/** + * egg_tree_model_filter_new: + * @child_model: A #GtkTreeModel. + * @root: A #GtkTreePath or %NULL. + * + * Creates a new #GtkTreeModel, with @child_model as the child_model + * and @root as the virtual root. + * + * Return value: A new #GtkTreeModel. + */ +GtkTreeModel * +egg_tree_model_filter_new (GtkTreeModel *child_model, + GtkTreePath *root) +{ + GtkTreeModel *retval; + + g_return_val_if_fail (GTK_IS_TREE_MODEL (child_model), NULL); + + retval = GTK_TREE_MODEL (g_object_new (egg_tree_model_filter_get_type (), NULL)); + + egg_tree_model_filter_set_model (EGG_TREE_MODEL_FILTER (retval), + child_model); + egg_tree_model_filter_set_root (EGG_TREE_MODEL_FILTER (retval), root); + + return retval; +} + +/** + * egg_tree_model_filter_get_model: + * @filter: A #EggTreeModelFilter. + * + * Returns a pointer to the child model of @filter. + * + * Return value: A pointer to a #GtkTreeModel. + */ +GtkTreeModel * +egg_tree_model_filter_get_model (EggTreeModelFilter *filter) +{ + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter), NULL); + + return filter->child_model; +} + +/** + * egg_tree_model_filter_set_visible_func: + * @filter: A #EggTreeModelFilter. + * @func: A #EggTreeModelFilterVisibleFunc, the visible function. + * @data: User data to pass to the visible function, or %NULL. + * @destroy: Destroy notifier of @data, or %NULL. + * + * Sets the visible function used when filtering the @filter to be @func. The + * function should return %TRUE if the given row should be visible and + * %FALSE otherwise. + */ +void +egg_tree_model_filter_set_visible_func (EggTreeModelFilter *filter, + EggTreeModelFilterVisibleFunc func, + gpointer data, + GtkDestroyNotify destroy) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + g_return_if_fail (func != NULL); + g_return_if_fail (filter->visible_method_set == FALSE); + + if (filter->visible_func) + { + GtkDestroyNotify d = filter->visible_destroy; + + filter->visible_destroy = NULL; + d (filter->visible_data); + } + + filter->visible_func = func; + filter->visible_data = data; + filter->visible_destroy = destroy; + + filter->visible_method_set = TRUE; +} + +/** + * egg_tree_model_filter_set_modify_func: + * @filter: A #EggTreeModelFilter. + * @n_columns: The number of columns in the filter model. + * @types: The #GTypes of the columns. + * @func: A #EggTreeModelFilterModifyFunc, or %NULL. + * @data: User data to pass to the modify function, or %NULL. + * @destroy: Destroy notifier of @data, or %NULL. + * + * Sets the @filter to have @n_columns columns with @types. If @func + * is not %NULL, it will set @func to be the modify function of @filter. + */ +void +egg_tree_model_filter_set_modify_func (EggTreeModelFilter *filter, + gint n_columns, + GType *types, + EggTreeModelFilterModifyFunc func, + gpointer data, + GtkDestroyNotify destroy) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + g_return_if_fail (func != NULL); + g_return_if_fail (filter->modify_func_set == FALSE); + + if (filter->modify_destroy) + { + GtkDestroyNotify d = filter->modify_destroy; + + filter->modify_destroy = NULL; + d (filter->modify_data); + } + + filter->modify_n_columns = n_columns; + filter->modify_types = g_new0 (GType, n_columns); + memcpy (filter->modify_types, types, sizeof (GType) * n_columns); + filter->modify_func = func; + filter->modify_data = data; + filter->modify_destroy = destroy; + + filter->modify_func_set = TRUE; +} + +/** + * egg_tree_model_filter_set_visible_column: + * @filter: A #EggTreeModelFilter. + * @column: A #gint which is the column containing the visible information. + * + * Sets @column of the child_model to be the column where @filter should + * look for visibility information. @columns should be a column of type + * %G_TYPE_BOOLEAN, where %TRUE means that a row is visible, and %FALSE + * if not. + */ +void +egg_tree_model_filter_set_visible_column (EggTreeModelFilter *filter, + gint column) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + g_return_if_fail (column >= 0); + g_return_if_fail (filter->visible_method_set == FALSE); + + filter->visible_column = column; + + filter->visible_method_set = TRUE; +} + +/* conversion */ + +/** + * egg_tree_model_filter_convert_child_iter_to_iter: + * @filter: A #EggTreeModelFilter. + * @filter_iter: An uninitialized #GtkTreeIter. + * @child_iter: A valid #GtkTreeIter pointing to a row on the child model. + * + * Sets @filter_iter to point to the row in @filter that corresponds to the + * row pointed at by @child_iter. + */ +void +egg_tree_model_filter_convert_child_iter_to_iter (EggTreeModelFilter *filter, + GtkTreeIter *filter_iter, + GtkTreeIter *child_iter) +{ + GtkTreePath *child_path, *path; + + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + g_return_if_fail (filter->child_model != NULL); + g_return_if_fail (filter_iter != NULL); + g_return_if_fail (child_iter != NULL); + + filter_iter->stamp = 0; + + child_path = gtk_tree_model_get_path (filter->child_model, child_iter); + g_return_if_fail (child_path != NULL); + + path = egg_tree_model_filter_convert_child_path_to_path (filter, + child_path); + gtk_tree_path_free (child_path); + g_return_if_fail (path != NULL); + + gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), filter_iter, path); + gtk_tree_path_free (path); +} + +/** + * egg_tree_model_filter_convert_iter_to_child_iter: + * @filter: A #EggTreeModelFilter. + * @child_iter: An uninitialized #GtkTreeIter. + * @filter_iter: A valid #GtkTreeIter pointing to a row on @filter. + * + * Sets @child_iter to point to the row pointed to by @filter_iter. + */ +void +egg_tree_model_filter_convert_iter_to_child_iter (EggTreeModelFilter *filter, + GtkTreeIter *child_iter, + GtkTreeIter *filter_iter) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + g_return_if_fail (filter->child_model != NULL); + g_return_if_fail (child_iter != NULL); + g_return_if_fail (filter_iter != NULL); + g_return_if_fail (filter_iter->stamp == filter->stamp); + + if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter)) + { + *child_iter = FILTER_ELT (filter_iter->user_data2)->iter; + } + else + { + GtkTreePath *path; + + path = egg_tree_model_filter_elt_get_path (filter_iter->user_data, + filter_iter->user_data2, + NULL); + gtk_tree_model_get_iter (filter->child_model, child_iter, path); + gtk_tree_path_free (path); + } +} + +static GtkTreePath * +egg_real_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter, + GtkTreePath *child_path, + gboolean build_levels, + gboolean fetch_childs) +{ + gint *child_indices; + GtkTreePath *retval; + GtkTreePath *real_path; + FilterLevel *level; + gint i; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter), NULL); + g_return_val_if_fail (filter->child_model != NULL, NULL); + g_return_val_if_fail (child_path != NULL, NULL); + + if (!filter->virtual_root) + real_path = gtk_tree_path_copy (child_path); + else + real_path = egg_tree_model_filter_remove_root (child_path, + filter->virtual_root); + + if (!real_path) + return NULL; + + retval = gtk_tree_path_new (); + child_indices = gtk_tree_path_get_indices (real_path); + + if (filter->root == NULL && build_levels) + egg_tree_model_filter_build_level (filter, NULL, NULL); + level = FILTER_LEVEL (filter->root); + + for (i = 0; i < gtk_tree_path_get_depth (real_path); i++) + { + gint j; + gboolean found_child = FALSE; + + if (!level) + { + gtk_tree_path_free (real_path); + gtk_tree_path_free (retval); + return NULL; + } + + for (j = 0; j < level->array->len; j++) + { + if ((g_array_index (level->array, FilterElt, j)).offset == child_indices[i]) + { + gtk_tree_path_append_index (retval, j); + if (g_array_index (level->array, FilterElt, j).children == NULL && build_levels) + egg_tree_model_filter_build_level (filter, + level, + &g_array_index (level->array, FilterElt, j)); + level = g_array_index (level->array, FilterElt, j).children; + found_child = TRUE; + break; + } + } + + if (!found_child && fetch_childs) + { + /* didn't find the child, let's try to bring it back */ + if (!egg_tree_model_filter_fetch_child (filter, level, child_indices[i])) + { + /* not there */ + gtk_tree_path_free (real_path); + gtk_tree_path_free (retval); + return NULL; + } + + /* yay, let's search for the child again */ + for (j = 0; j < level->array->len; j++) + { + if ((g_array_index (level->array, FilterElt, j)).offset == child_indices[i]) + { + gtk_tree_path_append_index (retval, j); + if (g_array_index (level->array, FilterElt, j).children == NULL && build_levels) + egg_tree_model_filter_build_level (filter, + level, + &g_array_index (level->array, FilterElt, j)); + level = g_array_index (level->array, FilterElt, j).children; + found_child = TRUE; + break; + } + } + + if (!found_child) + { + /* our happy fun fetch attempt failed ?!?!?! no child! */ + gtk_tree_path_free (real_path); + gtk_tree_path_free (retval); + return NULL; + } + } + else if (!found_child && !fetch_childs) + { + /* no path */ + gtk_tree_path_free (real_path); + gtk_tree_path_free (retval); + return NULL; + } + } + + gtk_tree_path_free (real_path); + return retval; +} + +/** + * egg_tree_model_filter_convert_child_path_to_path: + * @filter: A #EggTreeModelFilter. + * @child_path: A #GtkTreePath to convert. + * + * Converts @child_path to a path relative to @filter. That is, @child_path + * points to a path in the child model. The rerturned path will point to the + * same row in the filtered 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. + */ +GtkTreePath * +egg_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter, + GtkTreePath *child_path) +{ + /* this function does the sanity checks */ + return egg_real_tree_model_filter_convert_child_path_to_path (filter, + child_path, + TRUE, + TRUE); +} + +/** + * egg_tree_model_filter_convert_path_to_child_path: + * @filter: A #EggTreeModelFilter. + * @filter_path: A #GtkTreePath to convert. + * + * Converts @filter_path to a path on the child model of @filter. That is, + * @filter_path points to a location in @filter. The returned path will + * point to the same location in the model not being filtered. If @filter_path + * does not point to a location in the child model, %NULL is returned. + * + * Return value: A newly allocated #GtkTreePath, or %NULL. + */ +GtkTreePath * +egg_tree_model_filter_convert_path_to_child_path (EggTreeModelFilter *filter, + GtkTreePath *filter_path) +{ + gint *filter_indices; + GtkTreePath *retval; + FilterLevel *level; + gint i; + + g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter), NULL); + g_return_val_if_fail (filter->child_model != NULL, NULL); + g_return_val_if_fail (filter_path != NULL, NULL); + + /* convert path */ + retval = gtk_tree_path_new (); + filter_indices = gtk_tree_path_get_indices (filter_path); + if (!filter->root) + egg_tree_model_filter_build_level (filter, NULL, NULL); + level = FILTER_LEVEL (filter->root); + + for (i = 0; i < gtk_tree_path_get_depth (filter_path); i++) + { + gint count = filter_indices[i]; + + if (!level || level->array->len <= filter_indices[i]) + { + gtk_tree_path_free (retval); + return NULL; + } + + if (g_array_index (level->array, FilterElt, count).children == NULL) + egg_tree_model_filter_build_level (filter, level, &g_array_index (level->array, FilterElt, count)); + + if (!level || level->array->len <= filter_indices[i]) + { + gtk_tree_path_free (retval); + return NULL; + } + + gtk_tree_path_append_index (retval, g_array_index (level->array, FilterElt, count).offset); + level = g_array_index (level->array, FilterElt, count).children; + } + + /* apply vroot */ + + if (filter->virtual_root) + { + GtkTreePath *real_retval; + + real_retval = egg_tree_model_filter_add_root (retval, + filter->virtual_root); + gtk_tree_path_free (retval); + + return real_retval; + } + + return retval; +} + +static gboolean +egg_tree_model_filter_refilter_helper (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + gtk_tree_model_row_changed (model, path, iter); + + return FALSE; +} + +/** + * egg_tree_model_filter_refilter: + * @filter: A #EggTreeModelFilter. + * + * Emits ::row_changed for each row in the child model, which causes + * the filter to re-evaluate whether a row is visible or not. + */ +void +egg_tree_model_filter_refilter (EggTreeModelFilter *filter) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + + if (!filter->root) + return; + + /* S L O W */ + gtk_tree_model_foreach (filter->child_model, + egg_tree_model_filter_refilter_helper, + filter); +} + +/** + * egg_tree_model_filter_clear_cache: + * @filter: A #EggTreeModelFilter. + * + * This function should almost never be called. It clears the @filter + * of any cached iterators that haven't been reffed with + * gtk_tree_model_ref_node(). This might be useful if the child model + * being filtered is static (and doesn't change often) and there has been + * a lot of unreffed access to nodes. As a side effect of this function, + * all unreffed itters will be invalid. + */ +void +egg_tree_model_filter_clear_cache (EggTreeModelFilter *filter) +{ + g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); + + if (filter->zero_ref_count) + egg_tree_model_filter_clear_cache_helper (filter, + FILTER_LEVEL (filter->root)); +} diff --git a/lib/egg/eggtreemodelfilter.h b/lib/egg/eggtreemodelfilter.h new file mode 100644 index 000000000..b30fc2e1a --- /dev/null +++ b/lib/egg/eggtreemodelfilter.h @@ -0,0 +1,125 @@ +/* eggtreemodelfilter.h + * Copyright (C) 2000,2001 Red Hat, Inc., Jonathan Blandford + * Copyright (C) 2001,2002 Kristian Rietveld + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_TREE_MODEL_FILTER_H__ +#define __EGG_TREE_MODEL_FILTER_H__ + +#include + +G_BEGIN_DECLS + +#define EGG_TYPE_TREE_MODEL_FILTER (egg_tree_model_filter_get_type ()) +#define EGG_TREE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TREE_MODEL_FILTER, EggTreeModelFilter)) +#define EGG_TREE_MODEL_FILTER_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), EGG_TYPE_TREE_MODEL_FILTER, EggTreeModelFilterClass)) +#define EGG_IS_TREE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TREE_MODEL_FILTER)) +#define EGG_IS_TREE_MODEL_FILTER_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), EGG_TYPE_TREE_MODEL_FILTER)) +#define EGG_TREE_MODEL_FILTER_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TREE_MODEL_FILTER, EggTreeModelFilterClass)) + +typedef gboolean (* EggTreeModelFilterVisibleFunc) (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data); +typedef void (* EggTreeModelFilterModifyFunc) (GtkTreeModel *model, + GtkTreeIter *iter, + GValue *value, + gint column, + gpointer data); + +typedef struct _EggTreeModelFilter EggTreeModelFilter; +typedef struct _EggTreeModelFilterClass EggTreeModelFilterClass; + +struct _EggTreeModelFilter +{ + GObject parent; + + /*< private >*/ + gpointer root; + gint stamp; + guint child_flags; + GtkTreeModel *child_model; + gint zero_ref_count; + + guint root_level_visible; + + GtkTreePath *virtual_root; + + EggTreeModelFilterVisibleFunc visible_func; + gpointer visible_data; + GtkDestroyNotify visible_destroy; + + gint modify_n_columns; + GType *modify_types; + EggTreeModelFilterModifyFunc modify_func; + gpointer modify_data; + gpointer modify_destroy; + + gint visible_column; + + gboolean visible_method_set; + gboolean modify_func_set; + + /* signal ids */ + guint changed_id; + guint inserted_id; + guint has_child_toggled_id; + guint deleted_id; + guint reordered_id; +}; + +struct _EggTreeModelFilterClass +{ + GObjectClass parent_class; +}; + +GType egg_tree_model_filter_get_type (void); +GtkTreeModel *egg_tree_model_filter_new (GtkTreeModel *child_model, + GtkTreePath *root); +void egg_tree_model_filter_set_visible_func (EggTreeModelFilter *filter, + EggTreeModelFilterVisibleFunc func, + gpointer data, + GtkDestroyNotify destroy); +void egg_tree_model_filter_set_modify_func (EggTreeModelFilter *filter, + gint n_columns, + GType *types, + EggTreeModelFilterModifyFunc func, + gpointer data, + GtkDestroyNotify destroy); +void egg_tree_model_filter_set_visible_column (EggTreeModelFilter *filter, + gint column); + +GtkTreeModel *egg_tree_model_filter_get_model (EggTreeModelFilter *filter); + +/* conversion */ +void egg_tree_model_filter_convert_child_iter_to_iter (EggTreeModelFilter *filter, + GtkTreeIter *filter_iter, + GtkTreeIter *child_iter); +void egg_tree_model_filter_convert_iter_to_child_iter (EggTreeModelFilter *filter, + GtkTreeIter *child_iter, + GtkTreeIter *filter_iter); +GtkTreePath *egg_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter, + GtkTreePath *child_path); +GtkTreePath *egg_tree_model_filter_convert_path_to_child_path (EggTreeModelFilter *path, + GtkTreePath *filter_path); + +void egg_tree_model_filter_refilter (EggTreeModelFilter *filter); +void egg_tree_model_filter_clear_cache (EggTreeModelFilter *filter); + +G_END_DECLS + +#endif /* __EGG_TREE_MODEL_FILTER_H__ */ diff --git a/lib/egg/eggtreemultidnd.c b/lib/egg/eggtreemultidnd.c new file mode 100644 index 000000000..ae7a4d5aa --- /dev/null +++ b/lib/egg/eggtreemultidnd.c @@ -0,0 +1,412 @@ +/* eggtreemultidnd.c + * Copyright (C) 2001 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include "eggtreemultidnd.h" + +#define EGG_TREE_MULTI_DND_STRING "EggTreeMultiDndString" + +typedef struct +{ + guint pressed_button; + gint x; + gint y; + guint motion_notify_handler; + guint button_release_handler; + guint drag_data_get_handler; + GSList *event_list; +} EggTreeMultiDndData; + +/* CUT-N-PASTE from gtktreeview.c */ +typedef struct _TreeViewDragInfo TreeViewDragInfo; +struct _TreeViewDragInfo +{ + GdkModifierType start_button_mask; + GtkTargetList *source_target_list; + GdkDragAction source_actions; + + GtkTargetList *dest_target_list; + + guint source_set : 1; + guint dest_set : 1; +}; + + +GType +egg_tree_multi_drag_source_get_type (void) +{ + static GType our_type = 0; + + if (!our_type) + { + static const GTypeInfo our_info = + { + sizeof (EggTreeMultiDragSourceIface), /* class_size */ + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL + }; + + our_type = g_type_register_static (G_TYPE_INTERFACE, "EggTreeMultiDragSource", &our_info, 0); + } + + return our_type; +} + + +/** + * egg_tree_multi_drag_source_row_draggable: + * @drag_source: a #EggTreeMultiDragSource + * @path: row on which user is initiating a drag + * + * Asks the #EggTreeMultiDragSource whether a particular row can be used as + * the source of a DND operation. If the source doesn't implement + * this interface, the row is assumed draggable. + * + * Return value: %TRUE if the row can be dragged + **/ +gboolean +egg_tree_multi_drag_source_row_draggable (EggTreeMultiDragSource *drag_source, + GList *path_list) +{ + EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); + + g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); + g_return_val_if_fail (iface->row_draggable != NULL, FALSE); + g_return_val_if_fail (path_list != NULL, FALSE); + + if (iface->row_draggable) + return (* iface->row_draggable) (drag_source, path_list); + else + return TRUE; +} + + +/** + * egg_tree_multi_drag_source_drag_data_delete: + * @drag_source: a #EggTreeMultiDragSource + * @path: row that was being dragged + * + * Asks the #EggTreeMultiDragSource to delete the row at @path, because + * it was moved somewhere else via drag-and-drop. Returns %FALSE + * if the deletion fails because @path no longer exists, or for + * some model-specific reason. Should robustly handle a @path no + * longer found in the model! + * + * Return value: %TRUE if the row was successfully deleted + **/ +gboolean +egg_tree_multi_drag_source_drag_data_delete (EggTreeMultiDragSource *drag_source, + GList *path_list) +{ + EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); + + g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); + g_return_val_if_fail (iface->drag_data_delete != NULL, FALSE); + g_return_val_if_fail (path_list != NULL, FALSE); + + return (* iface->drag_data_delete) (drag_source, path_list); +} + +/** + * egg_tree_multi_drag_source_drag_data_get: + * @drag_source: a #EggTreeMultiDragSource + * @path: row that was dragged + * @selection_data: a #EggSelectionData to fill with data from the dragged row + * + * Asks the #EggTreeMultiDragSource to fill in @selection_data with a + * representation of the row at @path. @selection_data->target gives + * the required type of the data. Should robustly handle a @path no + * longer found in the model! + * + * Return value: %TRUE if data of the required type was provided + **/ +gboolean +egg_tree_multi_drag_source_drag_data_get (EggTreeMultiDragSource *drag_source, + GList *path_list, + GtkSelectionData *selection_data) +{ + EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); + + g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); + g_return_val_if_fail (iface->drag_data_get != NULL, FALSE); + g_return_val_if_fail (path_list != NULL, FALSE); + g_return_val_if_fail (selection_data != NULL, FALSE); + + return (* iface->drag_data_get) (drag_source, path_list, selection_data); +} + +static void +stop_drag_check (GtkWidget *widget) +{ + EggTreeMultiDndData *priv_data; + GSList *l; + + priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); + + for (l = priv_data->event_list; l != NULL; l = l->next) + gdk_event_free (l->data); + + g_slist_free (priv_data->event_list); + priv_data->event_list = NULL; + g_signal_handler_disconnect (widget, priv_data->motion_notify_handler); + g_signal_handler_disconnect (widget, priv_data->button_release_handler); +} + +static gboolean +egg_tree_multi_drag_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + EggTreeMultiDndData *priv_data; + GSList *l; + + priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); + + for (l = priv_data->event_list; l != NULL; l = l->next) + gtk_propagate_event (widget, l->data); + + stop_drag_check (widget); + + return FALSE; +} + +static void +selection_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GList **list_ptr; + + list_ptr = (GList **) data; + + *list_ptr = g_list_prepend (*list_ptr, gtk_tree_row_reference_new (model, path)); +} + +static void +path_list_free (GList *path_list) +{ + g_list_foreach (path_list, (GFunc) gtk_tree_row_reference_free, NULL); + g_list_free (path_list); +} + +static void +set_context_data (GdkDragContext *context, + GList *path_list) +{ + g_object_set_data_full (G_OBJECT (context), + "egg-tree-view-multi-source-row", + path_list, + (GDestroyNotify) path_list_free); +} + +static GList * +get_context_data (GdkDragContext *context) +{ + return g_object_get_data (G_OBJECT (context), + "egg-tree-view-multi-source-row"); +} + +/* CUT-N-PASTE from gtktreeview.c */ +static TreeViewDragInfo* +get_info (GtkTreeView *tree_view) +{ + return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info"); +} + + +static void +egg_tree_multi_drag_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + GtkTreeView *tree_view; + GtkTreeModel *model; + TreeViewDragInfo *di; + GList *path_list; + + tree_view = GTK_TREE_VIEW (widget); + + model = gtk_tree_view_get_model (tree_view); + + if (model == NULL) + return; + + di = get_info (GTK_TREE_VIEW (widget)); + + if (di == NULL) + return; + + path_list = get_context_data (context); + + if (path_list == NULL) + return; + + /* We can implement the GTK_TREE_MODEL_ROW target generically for + * any model; for DragSource models there are some other targets + * we also support. + */ + + if (EGG_IS_TREE_MULTI_DRAG_SOURCE (model)) + { + egg_tree_multi_drag_source_drag_data_get (EGG_TREE_MULTI_DRAG_SOURCE (model), + path_list, + selection_data); + } +} + +static gboolean +egg_tree_multi_drag_motion_event (GtkWidget *widget, + GdkEventMotion *event, + gpointer data) +{ + EggTreeMultiDndData *priv_data; + + priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); + + if (gtk_drag_check_threshold (widget, + priv_data->x, + priv_data->y, + event->x, + event->y)) + { + GList *path_list = NULL; + GtkTreeSelection *selection; + GtkTreeModel *model; + GdkDragContext *context; + TreeViewDragInfo *di; + + di = get_info (GTK_TREE_VIEW (widget)); + + if (di == NULL) + return FALSE; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + stop_drag_check (widget); + gtk_tree_selection_selected_foreach (selection, selection_foreach, &path_list); + path_list = g_list_reverse (path_list); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); + if (egg_tree_multi_drag_source_row_draggable (EGG_TREE_MULTI_DRAG_SOURCE (model), path_list)) + { + + context = gtk_drag_begin (widget, + di->source_target_list, + di->source_actions, + priv_data->pressed_button, + (GdkEvent*)event); + set_context_data (context, path_list); + gtk_drag_set_icon_default (context); + + } + else + { + path_list_free (path_list); + } + } + + return TRUE; +} + +static gboolean +egg_tree_multi_drag_button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + GtkTreeView *tree_view; + GtkTreePath *path = NULL; + GtkTreeViewColumn *column = NULL; + gint cell_x, cell_y; + GtkTreeSelection *selection; + EggTreeMultiDndData *priv_data; + + tree_view = GTK_TREE_VIEW (widget); + priv_data = g_object_get_data (G_OBJECT (tree_view), EGG_TREE_MULTI_DND_STRING); + if (priv_data == NULL) + { + priv_data = g_new0 (EggTreeMultiDndData, 1); + g_object_set_data (G_OBJECT (tree_view), EGG_TREE_MULTI_DND_STRING, priv_data); + } + + if (g_slist_find (priv_data->event_list, event)) + return FALSE; + + if (priv_data->event_list) + { + /* save the event to be propagated in order */ + priv_data->event_list = g_slist_append (priv_data->event_list, gdk_event_copy ((GdkEvent*)event)); + return TRUE; + } + + if (event->type == GDK_2BUTTON_PRESS) + return FALSE; + + gtk_tree_view_get_path_at_pos (tree_view, + event->x, event->y, + &path, &column, + &cell_x, &cell_y); + + selection = gtk_tree_view_get_selection (tree_view); + + if (path && gtk_tree_selection_path_is_selected (selection, path)) + { + priv_data->pressed_button = event->button; + priv_data->x = event->x; + priv_data->y = event->y; + priv_data->event_list = g_slist_append (priv_data->event_list, gdk_event_copy ((GdkEvent*)event)); + priv_data->motion_notify_handler = + g_signal_connect (G_OBJECT (tree_view), "motion_notify_event", G_CALLBACK (egg_tree_multi_drag_motion_event), NULL); + priv_data->button_release_handler = + g_signal_connect (G_OBJECT (tree_view), "button_release_event", G_CALLBACK (egg_tree_multi_drag_button_release_event), NULL); + + if (priv_data->drag_data_get_handler == 0) + { + priv_data->drag_data_get_handler = + g_signal_connect (G_OBJECT (tree_view), "drag_data_get", G_CALLBACK (egg_tree_multi_drag_drag_data_get), NULL); + } + + return TRUE; + } + + if (path) + { + gtk_tree_path_free (path); + } + + return FALSE; +} + +void +egg_tree_multi_drag_add_drag_support (GtkTreeView *tree_view) +{ + g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); + g_signal_connect (G_OBJECT (tree_view), "button_press_event", G_CALLBACK (egg_tree_multi_drag_button_press_event), NULL); +} + diff --git a/lib/egg/eggtreemultidnd.h b/lib/egg/eggtreemultidnd.h new file mode 100644 index 000000000..810d48ea7 --- /dev/null +++ b/lib/egg/eggtreemultidnd.h @@ -0,0 +1,76 @@ +/* eggtreednd.h + * Copyright (C) 2001 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_TREE_MULTI_DND_H__ +#define __EGG_TREE_MULTI_DND_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define EGG_TYPE_TREE_MULTI_DRAG_SOURCE (egg_tree_multi_drag_source_get_type ()) +#define EGG_TREE_MULTI_DRAG_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE, EggTreeMultiDragSource)) +#define EGG_IS_TREE_MULTI_DRAG_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE)) +#define EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE, EggTreeMultiDragSourceIface)) + +typedef struct _EggTreeMultiDragSource EggTreeMultiDragSource; /* Dummy typedef */ +typedef struct _EggTreeMultiDragSourceIface EggTreeMultiDragSourceIface; + +struct _EggTreeMultiDragSourceIface +{ + GTypeInterface g_iface; + + /* VTable - not signals */ + gboolean (* row_draggable) (EggTreeMultiDragSource *drag_source, + GList *path_list); + + gboolean (* drag_data_get) (EggTreeMultiDragSource *drag_source, + GList *path_list, + GtkSelectionData *selection_data); + + gboolean (* drag_data_delete) (EggTreeMultiDragSource *drag_source, + GList *path_list); +}; + +GType egg_tree_multi_drag_source_get_type (void) G_GNUC_CONST; + +/* Returns whether the given row can be dragged */ +gboolean egg_tree_multi_drag_source_row_draggable (EggTreeMultiDragSource *drag_source, + GList *path_list); + +/* Deletes the given row, or returns FALSE if it can't */ +gboolean egg_tree_multi_drag_source_drag_data_delete (EggTreeMultiDragSource *drag_source, + GList *path_list); + + +/* Fills in selection_data with type selection_data->target based on the row + * denoted by path, returns TRUE if it does anything + */ +gboolean egg_tree_multi_drag_source_drag_data_get (EggTreeMultiDragSource *drag_source, + GList *path_list, + GtkSelectionData *selection_data); +void egg_tree_multi_drag_add_drag_support (GtkTreeView *tree_view); + + + +G_END_DECLS + +#endif /* __EGG_TREE_MULTI_DND_H__ */ diff --git a/lib/egg/update-from-egg.sh b/lib/egg/update-from-egg.sh index b2e74bb7a..40de7352d 100755 --- a/lib/egg/update-from-egg.sh +++ b/lib/egg/update-from-egg.sh @@ -30,6 +30,9 @@ for FILE in $EGGFILES; do if test -e $EGGDIR/util/$FILE ; then SRCFILE=$EGGDIR/util/$FILE fi + if test -e $EGGDIR/treeviewutils/$FILE ; then + SRCFILE=$EGGDIR/treeviewutils/$FILE + fi fi if cmp -s $SRCFILE $FILE; then echo "File $FILE is unchanged" diff --git a/lib/ephy-dnd.c b/lib/ephy-dnd.c index ef39f37f0..1543d9818 100644 --- a/lib/ephy-dnd.c +++ b/lib/ephy-dnd.c @@ -67,7 +67,6 @@ gboolean ephy_dnd_drag_data_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, - guint info, guint32 time, gpointer container_context, EphyDragEachSelectedItemIterator each_selected_item_iterator) diff --git a/lib/ephy-dnd.h b/lib/ephy-dnd.h index afeb4704d..b8c415b0b 100644 --- a/lib/ephy-dnd.h +++ b/lib/ephy-dnd.h @@ -43,7 +43,6 @@ typedef void (* EphyDragEachSelectedItemIterator) (EphyDragEachSelectedItemDat gboolean ephy_dnd_drag_data_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, - guint info, guint32 time, gpointer container_context, EphyDragEachSelectedItemIterator each_selected_item_iterator); diff --git a/lib/widgets/Makefile.am b/lib/widgets/Makefile.am index 23aad4b01..809041a49 100644 --- a/lib/widgets/Makefile.am +++ b/lib/widgets/Makefile.am @@ -13,10 +13,6 @@ INCLUDES = \ noinst_LTLIBRARIES = libephywidgets.la libephywidgets_la_SOURCES = \ - eggtreemodelfilter.c \ - eggtreemodelfilter.h \ - eggtreemultidnd.c \ - eggtreemultidnd.h \ ephy-arrow-toolbutton.c \ ephy-arrow-toolbutton.h \ ephy-autocompletion-window.c \ diff --git a/lib/widgets/eggtreemodelfilter.c b/lib/widgets/eggtreemodelfilter.c deleted file mode 100644 index b3b31a46d..000000000 --- a/lib/widgets/eggtreemodelfilter.c +++ /dev/null @@ -1,2560 +0,0 @@ -/* eggtreemodelfilter.c - * Copyright (C) 2000,2001 Red Hat, Inc., Jonathan Blandford - * Copyright (C) 2001,2002 Kristian Rietveld - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "eggtreemodelfilter.h" -#include -#include - -/****** NOTE NOTE NOTE WARNING WARNING ****** - * - * This is *unstable* code. Don't use it in any project. This warning - * will be removed when this treemodel works. - */ - -/*#define VERBOSE 1*/ - -/* removed this when you add support for i18n */ -#define _ - -/* ITER FORMAT: - * - * iter->stamp = filter->stamp - * iter->user_data = FilterLevel - * iter->user_data2 = FilterElt - */ - -/* all paths, iters, etc prefixed with c_ are paths, iters, etc relative to the - * child model. - */ - -typedef struct _FilterElt FilterElt; -typedef struct _FilterLevel FilterLevel; - -struct _FilterElt -{ - GtkTreeIter iter; - FilterLevel *children; - gint offset; - gint ref_count; - gint zero_ref_count; - gboolean visible; -}; - -struct _FilterLevel -{ - GArray *array; - gint ref_count; - - FilterElt *parent_elt; - FilterLevel *parent_level; -}; - -/* properties */ -enum -{ - PROP_0, - PROP_CHILD_MODEL, - PROP_VIRTUAL_ROOT -}; - -#define EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS(filter) \ - (((EggTreeModelFilter *)filter)->child_flags & GTK_TREE_MODEL_ITERS_PERSIST) - -#define FILTER_ELT(filter_elt) ((FilterElt *)filter_elt) -#define FILTER_LEVEL(filter_level) ((FilterLevel *)filter_level) - -/* general code (object/interface init, properties, etc) */ -static void egg_tree_model_filter_init (EggTreeModelFilter *filter); -static void egg_tree_model_filter_class_init (EggTreeModelFilterClass *filter_class); -static void egg_tree_model_filter_tree_model_init (GtkTreeModelIface *iface); -static void egg_tree_model_filter_finalize (GObject *object); -static void egg_tree_model_filter_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void egg_tree_model_filter_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); - -/* signal handlers */ -static void egg_tree_model_filter_row_changed (GtkTreeModel *c_model, - GtkTreePath *c_path, - GtkTreeIter *c_iter, - gpointer data); -static void egg_tree_model_filter_row_inserted (GtkTreeModel *c_model, - GtkTreePath *c_path, - GtkTreeIter *c_iter, - gpointer data); -static void egg_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model, - GtkTreePath *c_path, - GtkTreeIter *c_iter, - gpointer data); -static void egg_tree_model_filter_row_deleted (GtkTreeModel *c_model, - GtkTreePath *c_path, - gpointer data); -static void egg_tree_model_filter_rows_reordered (GtkTreeModel *c_model, - GtkTreePath *c_path, - GtkTreeIter *c_iter, - gint *new_order, - gpointer data); - -/* GtkTreeModel interface */ -static guint egg_tree_model_filter_get_flags (GtkTreeModel *model); -static gint egg_tree_model_filter_get_n_columns (GtkTreeModel *model); -static GType egg_tree_model_filter_get_column_type (GtkTreeModel *model, - gint index); -static gboolean egg_tree_model_filter_get_iter (GtkTreeModel *model, - GtkTreeIter *iter, - GtkTreePath *path); -static GtkTreePath *egg_tree_model_filter_get_path (GtkTreeModel *model, - GtkTreeIter *iter); -static void egg_tree_model_filter_get_value (GtkTreeModel *model, - GtkTreeIter *iter, - gint column, - GValue *value); -static gboolean egg_tree_model_filter_iter_next (GtkTreeModel *model, - GtkTreeIter *iter); -static gboolean egg_tree_model_filter_iter_children (GtkTreeModel *model, - GtkTreeIter *iter, - GtkTreeIter *parent); -static gboolean egg_tree_model_filter_iter_has_child (GtkTreeModel *model, - GtkTreeIter *iter); -static gint egg_tree_model_filter_iter_n_children (GtkTreeModel *model, - GtkTreeIter *iter); -static gboolean egg_tree_model_filter_iter_nth_child (GtkTreeModel *model, - GtkTreeIter *iter, - GtkTreeIter *parent, - gint n); -static gboolean egg_tree_model_filter_iter_parent (GtkTreeModel *model, - GtkTreeIter *iter, - GtkTreeIter *child); -static void egg_tree_model_filter_ref_node (GtkTreeModel *model, - GtkTreeIter *iter); -static void egg_tree_model_filter_unref_node (GtkTreeModel *model, - GtkTreeIter *iter); - - - -/* private functions */ -static void egg_tree_model_filter_build_level (EggTreeModelFilter *filter, - FilterLevel *parent_level, - FilterElt *parent_elt); -static void egg_tree_model_filter_free_level (EggTreeModelFilter *filter, - FilterLevel *filter_level); - -static GtkTreePath *egg_tree_model_filter_elt_get_path (FilterLevel *level, - FilterElt *elt, - GtkTreePath *root); - -static GtkTreePath *egg_tree_model_filter_add_root (GtkTreePath *src, - GtkTreePath *root); -static GtkTreePath *egg_tree_model_filter_remove_root (GtkTreePath *src, - GtkTreePath *root); - -static void egg_tree_model_filter_increment_stamp (EggTreeModelFilter *filter); - -static gboolean egg_tree_model_filter_visible (EggTreeModelFilter *filter, - GtkTreeIter *child_iter); -static void egg_tree_model_filter_clear_cache_helper (EggTreeModelFilter *filter, - FilterLevel *level); - -static void egg_tree_model_filter_real_unref_node (GtkTreeModel *model, - GtkTreeIter *iter, - gboolean propagate_unref); - -static void egg_tree_model_filter_set_model (EggTreeModelFilter *filter, - GtkTreeModel *child_model); -static void egg_tree_model_filter_set_root (EggTreeModelFilter *filter, - GtkTreePath *root); - -static GtkTreePath *egg_real_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter, - GtkTreePath *child_path, - gboolean build_levels, - gboolean fetch_childs); - -static gboolean egg_tree_model_filter_fetch_child (EggTreeModelFilter *filter, - FilterLevel *level, - gint offset); -static void egg_tree_model_filter_remove_node (EggTreeModelFilter *filter, - GtkTreeIter *iter, - gboolean emit_signal); -static void egg_tree_model_filter_update_childs (EggTreeModelFilter *filter, - FilterLevel *level, - FilterElt *elt); - - -static GObjectClass *parent_class = NULL; - -GType -egg_tree_model_filter_get_type (void) -{ - static GType tree_model_filter_type = 0; - - if (!tree_model_filter_type) - { - static const GTypeInfo tree_model_filter_info = - { - sizeof (EggTreeModelFilterClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) egg_tree_model_filter_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (EggTreeModelFilter), - 0, /* n_preallocs */ - (GInstanceInitFunc) egg_tree_model_filter_init - }; - - static const GInterfaceInfo tree_model_info = - { - (GInterfaceInitFunc) egg_tree_model_filter_tree_model_init, - NULL, - NULL - }; - - tree_model_filter_type = g_type_register_static (G_TYPE_OBJECT, - "EggTreeModelFilter", - &tree_model_filter_info, 0); - - g_type_add_interface_static (tree_model_filter_type, - GTK_TYPE_TREE_MODEL, - &tree_model_info); - } - - return tree_model_filter_type; -} - -static void -egg_tree_model_filter_init (EggTreeModelFilter *filter) -{ - filter->visible_column = -1; - filter->zero_ref_count = 0; - filter->visible_method_set = FALSE; - filter->modify_func_set = FALSE; -} - -static void -egg_tree_model_filter_class_init (EggTreeModelFilterClass *filter_class) -{ - GObjectClass *object_class; - - object_class = (GObjectClass *) filter_class; - parent_class = g_type_class_peek_parent (filter_class); - - object_class->set_property = egg_tree_model_filter_set_property; - object_class->get_property = egg_tree_model_filter_get_property; - - object_class->finalize = egg_tree_model_filter_finalize; - - /* Properties -- FIXME: write a better description ... */ - g_object_class_install_property (object_class, - PROP_CHILD_MODEL, - g_param_spec_object ("child_model", - "The child model", - "The model for the TreeModelFilter to filter", - GTK_TYPE_TREE_MODEL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (object_class, - PROP_VIRTUAL_ROOT, - g_param_spec_boxed ("virtual_root", - "The virtual root", - "The virtual root (relative to the child model) for this filtermodel", - GTK_TYPE_TREE_PATH, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -} - -static void -egg_tree_model_filter_tree_model_init (GtkTreeModelIface *iface) -{ - iface->get_flags = egg_tree_model_filter_get_flags; - iface->get_n_columns = egg_tree_model_filter_get_n_columns; - iface->get_column_type = egg_tree_model_filter_get_column_type; - iface->get_iter = egg_tree_model_filter_get_iter; - iface->get_path = egg_tree_model_filter_get_path; - iface->get_value = egg_tree_model_filter_get_value; - iface->iter_next = egg_tree_model_filter_iter_next; - iface->iter_children = egg_tree_model_filter_iter_children; - iface->iter_has_child = egg_tree_model_filter_iter_has_child; - iface->iter_n_children = egg_tree_model_filter_iter_n_children; - iface->iter_nth_child = egg_tree_model_filter_iter_nth_child; - iface->iter_parent = egg_tree_model_filter_iter_parent; - iface->ref_node = egg_tree_model_filter_ref_node; - iface->unref_node = egg_tree_model_filter_unref_node; -} - - -static void -egg_tree_model_filter_finalize (GObject *object) -{ - EggTreeModelFilter *filter = (EggTreeModelFilter *) object; - - egg_tree_model_filter_set_model (filter, NULL); - - if (filter->virtual_root) - gtk_tree_path_free (filter->virtual_root); - - if (filter->root) - egg_tree_model_filter_free_level (filter, filter->root); - - if (filter->modify_types) - g_free (filter->modify_types); - - /* must chain up */ - parent_class->finalize (object); -} - -static void -egg_tree_model_filter_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (object); - - switch (prop_id) - { - case PROP_CHILD_MODEL: - egg_tree_model_filter_set_model (filter, g_value_get_object (value)); - break; - case PROP_VIRTUAL_ROOT: - egg_tree_model_filter_set_root (filter, g_value_get_boxed (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -egg_tree_model_filter_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (object); - - switch (prop_id) - { - case PROP_CHILD_MODEL: - g_value_set_object (value, filter->child_model); - break; - case PROP_VIRTUAL_ROOT: - g_value_set_boxed (value, filter->virtual_root); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* helpers */ - -static void -egg_tree_model_filter_build_level (EggTreeModelFilter *filter, - FilterLevel *parent_level, - FilterElt *parent_elt) -{ - GtkTreeIter iter; - GtkTreeIter root; - FilterLevel *new_level; - gint length = 0; - gint i; - - g_assert (filter->child_model != NULL); - - if (!parent_level) - { - if (filter->virtual_root) - { - if (gtk_tree_model_get_iter (filter->child_model, &root, filter->virtual_root) == FALSE) - return; - length = gtk_tree_model_iter_n_children (filter->child_model, &root); - -#ifdef VERBOSE - g_print ("-- vroot %d children\n", length); -#endif - - if (gtk_tree_model_iter_children (filter->child_model, &iter, &root) == FALSE) - return; - } - else - { - if (!gtk_tree_model_get_iter_first (filter->child_model, &iter)) - return; - length = gtk_tree_model_iter_n_children (filter->child_model, NULL); - } - } - else - { - GtkTreeIter parent_iter; - GtkTreeIter child_parent_iter; - - parent_iter.stamp = filter->stamp; - parent_iter.user_data = parent_level; - parent_iter.user_data2 = parent_elt; - - egg_tree_model_filter_convert_iter_to_child_iter (filter, - &child_parent_iter, - &parent_iter); - if (gtk_tree_model_iter_children (filter->child_model, &iter, &child_parent_iter) == FALSE) - return; - - /* stamp may have changed */ - egg_tree_model_filter_convert_iter_to_child_iter (filter, - &child_parent_iter, - &parent_iter); - length = gtk_tree_model_iter_n_children (filter->child_model, &child_parent_iter); - } - - g_return_if_fail (length > 0); - -#ifdef VERBOSE - g_print ("-- building new level with %d childs\n", length); -#endif - - new_level = g_new (FilterLevel, 1); - new_level->array = g_array_sized_new (FALSE, FALSE, - sizeof (FilterElt), - length); - new_level->ref_count = 0; - new_level->parent_elt = parent_elt; - new_level->parent_level = parent_level; - - if (parent_elt) - parent_elt->children = new_level; - else - filter->root = new_level; - - /* increase the count of zero ref_counts */ - while (parent_level) - { - parent_elt->zero_ref_count++; - - parent_elt = parent_level->parent_elt; - parent_level = parent_level->parent_level; - } - filter->zero_ref_count++; - -#ifdef VERBOSE - g_print ("_build_level: zero ref count on filter is now %d\n", - filter->zero_ref_count); -#endif - - i = 0; - do - { - if (egg_tree_model_filter_visible (filter, &iter)) - { - FilterElt filter_elt; - - filter_elt.offset = i; - filter_elt.zero_ref_count = 0; - filter_elt.ref_count = 0; - filter_elt.children = NULL; - filter_elt.visible = TRUE; - - if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter)) - filter_elt.iter = iter; - - g_array_append_val (new_level->array, filter_elt); - } - i++; - } - while (gtk_tree_model_iter_next (filter->child_model, &iter)); -} - -static void -egg_tree_model_filter_free_level (EggTreeModelFilter *filter, - FilterLevel *filter_level) -{ - gint i; - - g_assert (filter_level); - - if (filter_level->ref_count == 0) - { - FilterLevel *parent_level = filter_level->parent_level; - FilterElt *parent_elt = filter_level->parent_elt; - - do - { - if (parent_elt) - parent_elt->zero_ref_count--; - - if (parent_level) - { - parent_elt = parent_level->parent_elt; - parent_level = parent_level->parent_level; - } - } - while (parent_level); - filter->zero_ref_count--; - } - -#ifdef VERBOSE - g_print ("freeing level\n"); - g_print ("zero ref count is %d\n", filter->zero_ref_count); -#endif - - for (i = 0; i < filter_level->array->len; i++) - { - if (g_array_index (filter_level->array, FilterElt, i).children) - egg_tree_model_filter_free_level (filter, - FILTER_LEVEL (g_array_index (filter_level->array, FilterElt, i).children)); - } - - if (filter_level->parent_elt) - filter_level->parent_elt->children = NULL; - else - filter->root = NULL; - - g_array_free (filter_level->array, TRUE); - filter_level->array = NULL; - - g_free (filter_level); - filter_level = NULL; -} - -static GtkTreePath * -egg_tree_model_filter_elt_get_path (FilterLevel *level, - FilterElt *elt, - GtkTreePath *root) -{ - FilterLevel *walker = level; - FilterElt *walker2 = elt; - GtkTreePath *path; - GtkTreePath *real_path; - - g_return_val_if_fail (level != NULL, NULL); - g_return_val_if_fail (elt != NULL, NULL); - - path = gtk_tree_path_new (); - - while (walker) - { - gtk_tree_path_prepend_index (path, walker2->offset); - - walker2 = walker->parent_elt; - walker = walker->parent_level; - } - - if (root) - { - real_path = gtk_tree_path_copy (root); - - egg_tree_model_filter_add_root (real_path, path); - gtk_tree_path_free (path); - return real_path; - } - - return path; -} - -static GtkTreePath * -egg_tree_model_filter_add_root (GtkTreePath *src, - GtkTreePath *root) -{ - GtkTreePath *retval; - gint i; - - retval = gtk_tree_path_copy (root); - - for (i = 0; i < gtk_tree_path_get_depth (src); i++) - gtk_tree_path_append_index (retval, gtk_tree_path_get_indices (src)[i]); - - return retval; -} - -static GtkTreePath * -egg_tree_model_filter_remove_root (GtkTreePath *src, - GtkTreePath *root) -{ - GtkTreePath *retval; - gint i; - gint depth; - gint *indices; - - if (gtk_tree_path_get_depth (src) <= gtk_tree_path_get_depth (root)) - return NULL; - - depth = gtk_tree_path_get_depth (src); - indices = gtk_tree_path_get_indices (src); - - for (i = 0; i < gtk_tree_path_get_depth (root); i++) - if (indices[i] != gtk_tree_path_get_indices (root)[i]) - return NULL; - - retval = gtk_tree_path_new (); - - for (; i < depth; i++) - gtk_tree_path_append_index (retval, indices[i]); - - return retval; -} - -static void -egg_tree_model_filter_increment_stamp (EggTreeModelFilter *filter) -{ - do - { - filter->stamp++; - } - while (filter->stamp == 0); - - egg_tree_model_filter_clear_cache (filter); -} - -static gboolean -egg_tree_model_filter_visible (EggTreeModelFilter *filter, - GtkTreeIter *child_iter) -{ - if (filter->visible_func) - { - return (filter->visible_func (filter->child_model, - child_iter, - filter->visible_data)); - } - else if (filter->visible_column >= 0) - { - GValue val = {0, }; - - gtk_tree_model_get_value (filter->child_model, child_iter, - filter->visible_column, &val); - - if (g_value_get_boolean (&val)) - { - g_value_unset (&val); - return TRUE; - } - - g_value_unset (&val); - return FALSE; - } - - /* no filter thing set, so always visible */ - return TRUE; -} - -static void -egg_tree_model_filter_clear_cache_helper (EggTreeModelFilter *filter, - FilterLevel *level) -{ - gint i; - - g_assert (level); - - for (i = 0; i < level->array->len; i++) - { - if (g_array_index (level->array, FilterElt, i).zero_ref_count > 0) - egg_tree_model_filter_clear_cache_helper (filter, g_array_index (level->array, FilterElt, i).children); - } - - if (level->ref_count == 0 && level != filter->root) - { - egg_tree_model_filter_free_level (filter, level); - return; - } -} - -static gboolean -egg_tree_model_filter_fetch_child (EggTreeModelFilter *filter, - FilterLevel *level, - gint offset) -{ - gint i = 0; - gint len; - GtkTreePath *c_path = NULL; - GtkTreeIter c_iter; - GtkTreePath *c_parent_path = NULL; - GtkTreeIter c_parent_iter; - FilterElt elt; - -#ifdef VERBOSE - g_print ("_fetch_child: for offset %d\n", offset); -#endif - - /* check if child exists and is visible */ - if (level->parent_elt) - { - c_parent_path = - egg_tree_model_filter_elt_get_path (level->parent_level, - level->parent_elt, - filter->virtual_root); - if (!c_parent_path) - return FALSE; - } - else - { - if (filter->virtual_root) - c_parent_path = gtk_tree_path_copy (filter->virtual_root); - else - c_parent_path = NULL; - } - - if (c_parent_path) - { - gtk_tree_model_get_iter (filter->child_model, - &c_parent_iter, - c_parent_path); - len = gtk_tree_model_iter_n_children (filter->child_model, - &c_parent_iter); - - c_path = gtk_tree_path_copy (c_parent_path); - gtk_tree_path_free (c_parent_path); - } - else - { - len = gtk_tree_model_iter_n_children (filter->child_model, NULL); - c_path = gtk_tree_path_new (); - } - - gtk_tree_path_append_index (c_path, offset); - gtk_tree_model_get_iter (filter->child_model, &c_iter, c_path); - gtk_tree_path_free (c_path); - - if (offset >= len || !egg_tree_model_filter_visible (filter, &c_iter)) - return FALSE; - - /* add child */ - elt.offset = offset; - elt.zero_ref_count = 0; - elt.ref_count = 0; - elt.children = NULL; - /* visibility should be FALSE as we don't emit row_inserted */ - elt.visible = FALSE; - - if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter)) - elt.iter = c_iter; - - /* find index */ - for (i = 0; i < level->array->len; i++) - if (g_array_index (level->array, FilterElt, i).offset > offset) - break; - - g_array_insert_val (level->array, i, elt); - - for (i = 0; i < level->array->len; i++) - { - FilterElt *e = &(g_array_index (level->array, FilterElt, i)); - if (e->children) - e->children->parent_elt = e; - } - - return TRUE; -} - -static void -egg_tree_model_filter_remove_node (EggTreeModelFilter *filter, - GtkTreeIter *iter, - gboolean emit_signal) -{ - FilterElt *elt, *parent; - FilterLevel *level, *parent_level; - gint offset, i, length, level_refcount; - - /* FIXME: this function is very ugly. I need to rethink and - * rewrite it someday. - */ - - level = FILTER_LEVEL (iter->user_data); - elt = FILTER_ELT (iter->user_data2); - - parent = level->parent_elt; - parent_level = level->parent_level; - length = level->array->len; - offset = elt->offset; - -#ifdef VERBOSE - g_print ("|___ removing node\n"); -#endif - - /* ref counting */ - while (elt->ref_count > 0) - egg_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter), - iter, FALSE); - - level_refcount = level->ref_count; - - /* do the ref counting first! this touches the stamp */ - if (emit_signal) - { - GtkTreePath *path; - - path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter); - egg_tree_model_filter_increment_stamp (filter); - gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter), path); - gtk_tree_path_free (path); - } - - if ((length == 1 || level_refcount == 0) && - emit_signal && iter->user_data != filter->root) - { - /* above code destroyed the level */ - goto emit_has_child_toggled; - } - - if (length == 1) - { - /* kill the level */ -#ifdef VERBOSE - g_print ("killing level ...\n"); -#endif - egg_tree_model_filter_free_level (filter, level); - - if (!filter->root) - /* we killed the root */ - return; - } - else - { -#ifdef VERBOSE - g_print ("removing the node...\n"); -#endif - - /* remove the node */ - for (i = 0; i < level->array->len; i++) - if (elt->offset == g_array_index (level->array, FilterElt, i).offset) - break; - - g_array_remove_index (level->array, i); - - for (i = 0; i < level->array->len; i++) - { - /* NOTE: here we do *not* decrease offsets, because the node was - * not removed from the child model - */ - elt = &g_array_index (level->array, FilterElt, i); - if (elt->children) - elt->children->parent_elt = elt; - } - } - -emit_has_child_toggled: - /* children are being handled first, so we can check it this way - * - * yes this if-statement is ugly - */ - if ((parent && parent->children && parent->children->array->len <= 1) || - (length == 1 && emit_signal && iter->user_data != filter->root)) - { - /* latest child has been removed, level has been destroyed */ - GtkTreeIter piter; - GtkTreePath *ppath; - - piter.stamp = filter->stamp; - piter.user_data = parent_level; - piter.user_data2 = parent; - - ppath = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &piter); - -#ifdef VERBOSE - g_print ("emitting has_child_toggled (by _filter_remove)\n"); -#endif - - gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter), - ppath, &piter); - gtk_tree_path_free (ppath); - } -} - -static void -egg_tree_model_filter_update_childs (EggTreeModelFilter *filter, - FilterLevel *level, - FilterElt *elt) -{ - GtkTreeIter c_iter; - GtkTreeIter iter; - -#ifdef VERBOSE - g_print ("~~ a node came back, search childs\n"); -#endif - - if (!elt->visible) - { -#ifdef VERBOSE - g_print (" + given elt not visible -- bailing out\n"); -#endif - return; - } - - iter.stamp = filter->stamp; - iter.user_data = level; - iter.user_data2 = elt; - - egg_tree_model_filter_convert_iter_to_child_iter (filter, &c_iter, &iter); - - if (gtk_tree_model_iter_has_child (filter->child_model, &c_iter)) - { - GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), - &iter); - gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter), - path, - &iter); - if (path) - gtk_tree_path_free (path); - } -} - -/* TreeModel signals */ -static void -egg_tree_model_filter_row_changed (GtkTreeModel *c_model, - GtkTreePath *c_path, - GtkTreeIter *c_iter, - gpointer data) -{ - EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); - GtkTreeIter iter; - GtkTreeIter real_c_iter; - GtkTreePath *path; - - FilterElt *elt; - FilterLevel *level; - gint offset; - - gboolean new; - gboolean free_c_path = FALSE; - - g_return_if_fail (c_path != NULL || c_iter != NULL); - - if (!c_path) - { - c_path = gtk_tree_model_get_path (c_model, c_iter); - free_c_path = TRUE; - } - - if (c_iter) - real_c_iter = *c_iter; - else - gtk_tree_model_get_iter (c_model, &real_c_iter, c_path); - - if (!filter->root) - { - gint i; - FilterLevel *root; - - /* build root level */ - egg_tree_model_filter_build_level (filter, NULL, NULL); - - root = FILTER_LEVEL (filter->root); - - /* FIXME: - * we set the visibilities to FALSE here, so we ever emit - * a row_inserted. maybe it's even better to emit row_inserted - * here, not sure. - */ - if (root) - for (i = 0; i < root->array->len; i++) - g_array_index (root->array, FilterElt, i).visible = FALSE; - } - - path = egg_real_tree_model_filter_convert_child_path_to_path (filter, - c_path, - FALSE, - TRUE); - if (!path) - goto done; - - gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path); - - level = FILTER_LEVEL (iter.user_data); - elt = FILTER_ELT (iter.user_data2); - offset = elt->offset; - new = egg_tree_model_filter_visible (filter, c_iter); - - if (elt->visible == TRUE && new == FALSE) - { -#ifdef VERBOSE - g_print ("visible to false -> delete row\n"); -#endif - egg_tree_model_filter_remove_node (filter, &iter, TRUE); - } - else if (elt->visible == FALSE && new == TRUE) - { - GtkTreeIter childs; - -#ifdef VERBOSE - g_print ("visible to true -> insert row\n"); -#endif - - elt->visible = TRUE; - - egg_tree_model_filter_increment_stamp (filter); - /* update stamp */ - gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path); - gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter), path, &iter); - - if (gtk_tree_model_iter_children (c_model, &childs, c_iter)) - egg_tree_model_filter_update_childs (filter, level, elt); - } - else if (elt->visible == FALSE && new == FALSE) - { -#ifdef VERBOSE - g_print ("remove node in silence\n"); -#endif - egg_tree_model_filter_remove_node (filter, &iter, FALSE); - } - else - { - GtkTreeIter childs; - -#ifdef VERBOSE - g_print ("no change in visibility -- pass row_changed\n"); -#endif - - gtk_tree_model_row_changed (GTK_TREE_MODEL (filter), path, &iter); - - if (gtk_tree_model_iter_children (c_model, &childs, c_iter) && - elt->visible) - egg_tree_model_filter_update_childs (filter, level, elt); - } - - gtk_tree_path_free (path); - -done: - if (free_c_path) - gtk_tree_path_free (c_path); -} - -static void -egg_tree_model_filter_row_inserted (GtkTreeModel *c_model, - GtkTreePath *c_path, - GtkTreeIter *c_iter, - gpointer data) -{ - EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); - GtkTreePath *path; - GtkTreePath *real_path; - GtkTreeIter iter; - - GtkTreeIter real_c_iter; - - FilterElt *elt; - FilterLevel *level; - FilterLevel *parent_level; - - gint i = 0, offset, index = -1; - - gboolean free_c_path = FALSE; - - g_return_if_fail (c_path != NULL || c_iter != NULL); - - if (!c_path) - { - c_path = gtk_tree_model_get_path (c_model, c_iter); - free_c_path = TRUE; - } - - if (c_iter) - real_c_iter = *c_iter; - else - gtk_tree_model_get_iter (c_model, &real_c_iter, c_path); - - /* the row has already been inserted. so we need to fixup the - * virtual root here first - */ - if (filter->virtual_root) - { - if (gtk_tree_path_get_depth (filter->virtual_root) >= - gtk_tree_path_get_depth (c_path)) - { - gint level; - gint *v_indices, *c_indices; - - level = gtk_tree_path_get_depth (c_path) - 1; - v_indices = gtk_tree_path_get_indices (filter->virtual_root); - c_indices = gtk_tree_path_get_indices (c_path); - - if (v_indices[level] >= c_indices[level]) - (v_indices[level])++; - } - } - - if (!filter->root) - { - egg_tree_model_filter_build_level (filter, NULL, NULL); - /* that already put the inserted iter in the level */ - - goto done_and_emit; - } - - parent_level = level = FILTER_LEVEL (filter->root); - - /* subtract virtual root if necessary */ - if (filter->virtual_root) - { - real_path = egg_tree_model_filter_remove_root (c_path, - filter->virtual_root); - /* not our kiddo */ - if (!real_path) - goto done; - } - else - real_path = gtk_tree_path_copy (c_path); - - if (gtk_tree_path_get_depth (real_path) - 1 >= 1) - { - /* find the parent level */ - while (i < gtk_tree_path_get_depth (real_path) - 1) - { - gint j; - - if (!level) - /* we don't cover this signal */ - goto done; - - elt = NULL; - for (j = 0; j < level->array->len; j++) - if (g_array_index (level->array, FilterElt, j).offset == - gtk_tree_path_get_indices (real_path)[i]) - { - elt = &g_array_index (level->array, FilterElt, j); - break; - } - - if (!elt) - /* parent is probably being filtered out */ - goto done; - - if (!elt->children) - { - GtkTreePath *tmppath; - GtkTreeIter tmpiter; - - tmpiter.stamp = filter->stamp; - tmpiter.user_data = level; - tmpiter.user_data2 = elt; - - tmppath = gtk_tree_model_get_path (GTK_TREE_MODEL (data), - &tmpiter); - - if (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; - } - - level = elt->children; - parent_level = level; - i++; - } - } - - if (!parent_level) - goto done; - - /* let's try to insert the value */ - offset = gtk_tree_path_get_indices (real_path)[gtk_tree_path_get_depth (real_path) - 1]; - - /* only insert when visible */ - if (egg_tree_model_filter_visible (filter, &real_c_iter)) - { - FilterElt felt; - - if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter)) - felt.iter = real_c_iter; - felt.offset = offset; - felt.zero_ref_count = 0; - felt.ref_count = 0; - felt.visible = TRUE; - felt.children = NULL; - - for (i = 0; i < level->array->len; i++) - if (g_array_index (level->array, FilterElt, i).offset > offset) - break; - - g_array_insert_val (level->array, i, felt); - index = i; - } - - /* update the offsets, yes if we didn't insert the node above, there will - * be a gap here. This will be filled with the node (via fetch_child) when - * it becomes visible - */ - for (i = 0; i < level->array->len; i++) - { - FilterElt *e = &g_array_index (level->array, FilterElt, i); - if ((e->offset >= offset) && i != index) - e->offset++; - if (e->children) - e->children->parent_elt = e; - } - - /* don't emit the signal if we aren't visible */ - if (!egg_tree_model_filter_visible (filter, &real_c_iter)) - goto done; - -done_and_emit: - /* NOTE: pass c_path here and NOT real_path. This function does - * root subtraction itself - */ - path = egg_real_tree_model_filter_convert_child_path_to_path (filter, - c_path, - FALSE, TRUE); - - if (!path) - return; - - egg_tree_model_filter_increment_stamp (filter); - - gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); - gtk_tree_model_row_inserted (GTK_TREE_MODEL (data), path, &iter); - -#ifdef VERBOSE - g_print ("inserted row with offset %d\n", index); -#endif - -done: - if (free_c_path) - gtk_tree_path_free (c_path); -} - -static void -egg_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model, - GtkTreePath *c_path, - GtkTreeIter *c_iter, - gpointer data) -{ - EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); - GtkTreePath *path; - GtkTreeIter iter; - - g_return_if_fail (c_path != NULL && c_iter != NULL); - - /* FIXME: does this code work? */ - - if (!egg_tree_model_filter_visible (filter, c_iter)) - return; - - path = egg_real_tree_model_filter_convert_child_path_to_path (filter, - c_path, - FALSE, - TRUE); - if (!path) - return; - - gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); - gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data), path, &iter); - - gtk_tree_path_free (path); -} - -static void -egg_tree_model_filter_row_deleted (GtkTreeModel *c_model, - GtkTreePath *c_path, - gpointer data) -{ - EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); - GtkTreePath *path; - GtkTreeIter iter; - FilterElt *elt; - FilterLevel *level; - gint offset; - gboolean emit_signal = TRUE; - gint i; - - g_return_if_fail (c_path != NULL); - - /* special case the deletion of an ancestor of the virtual root */ - if (filter->virtual_root && - (gtk_tree_path_is_ancestor (c_path, filter->virtual_root) || - !gtk_tree_path_compare (c_path, filter->virtual_root))) - { - gint i; - GtkTreePath *path; - FilterLevel *level = FILTER_LEVEL (filter->root); - - if (!level) - return; - - /* remove everything in the filter model - * - * For now, we just iterate over the root level and emit a - * row_deleted for each FilterElt. Not sure if this is correct. - */ - - egg_tree_model_filter_increment_stamp (filter); - path = gtk_tree_path_new (); - gtk_tree_path_append_index (path, 0); - - for (i = 0; i < level->array->len; i++) - gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path); - - gtk_tree_path_free (path); - egg_tree_model_filter_free_level (filter, filter->root); - - return; - } - - /* fixup virtual root */ - if (filter->virtual_root) - { - if (gtk_tree_path_get_depth (filter->virtual_root) >= - gtk_tree_path_get_depth (c_path)) - { - gint level; - gint *v_indices, *c_indices; - - level = gtk_tree_path_get_depth (c_path) - 1; - v_indices = gtk_tree_path_get_indices (filter->virtual_root); - c_indices = gtk_tree_path_get_indices (c_path); - - if (v_indices[level] > c_indices[level]) - (v_indices[level])--; - } - } - - path = egg_real_tree_model_filter_convert_child_path_to_path (filter, - c_path, - FALSE, - FALSE); - if (!path) - { - path = egg_real_tree_model_filter_convert_child_path_to_path (filter, - c_path, - FALSE, - TRUE); - - if (!path) - { - /* fixup the offsets */ - GtkTreePath *real_path; - - if (!filter->root) - return; - - level = FILTER_LEVEL (filter->root); - - /* subtract vroot if necessary */ - if (filter->virtual_root) - { - real_path = egg_tree_model_filter_remove_root (c_path, - filter->virtual_root); - /* we don't handle this */ - if (!real_path) - return; - } - else - real_path = gtk_tree_path_copy (c_path); - - i = 0; - if (gtk_tree_path_get_depth (real_path) - 1 >= 1) - { - while (i < gtk_tree_path_get_depth (real_path) - 1) - { - gint j; - - if (!level) - { - /* we don't cover this */ - gtk_tree_path_free (real_path); - return; - } - - elt = NULL; - for (j = 0; j < level->array->len; j++) - if (g_array_index (level->array, FilterElt, j).offset == - gtk_tree_path_get_indices (real_path)[i]) - { - elt = &g_array_index (level->array, FilterElt, j); - break; - } - - if (!elt || !elt->children) - { - /* parent is filtered out, so no level */ - gtk_tree_path_free (real_path); - return; - } - - level = elt->children; - i++; - } - } - - offset = gtk_tree_path_get_indices (real_path)[gtk_tree_path_get_depth (real_path) - 1]; - gtk_tree_path_free (real_path); - - if (!level) - return; - - /* we need: - * - the offset of the removed item - * - the level - */ - for (i = 0; i < level->array->len; i++) - { - elt = &g_array_index (level->array, FilterElt, i); - if (elt->offset > offset) - elt->offset--; - if (elt->children) - elt->children->parent_elt = elt; - } - - return; - } - - emit_signal = FALSE; - } - - gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); - - level = FILTER_LEVEL (iter.user_data); - elt = FILTER_ELT (iter.user_data2); - offset = elt->offset; - - if (emit_signal) - { - if (level->ref_count == 0 && level != filter->root) - { - egg_tree_model_filter_increment_stamp (filter); - gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path); - - gtk_tree_path_free (path); - return; - } - - egg_tree_model_filter_increment_stamp (filter); - gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path); - iter.stamp = filter->stamp; - - while (elt->ref_count > 0) - egg_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter, - FALSE); - } - - if (level->array->len == 1) - { - /* kill level */ - egg_tree_model_filter_free_level (filter, level); - } - else - { - /* remove the row */ - for (i = 0; i < level->array->len; i++) - if (elt->offset == g_array_index (level->array, FilterElt, i).offset) - break; - - offset = g_array_index (level->array, FilterElt, i).offset; - g_array_remove_index (level->array, i); - - for (i = 0; i < level->array->len; i++) - { - elt = &g_array_index (level->array, FilterElt, i); - if (elt->offset > offset) - elt->offset--; - if (elt->children) - elt->children->parent_elt = elt; - } - } - - gtk_tree_path_free (path); -} - -static void -egg_tree_model_filter_rows_reordered (GtkTreeModel *c_model, - GtkTreePath *c_path, - GtkTreeIter *c_iter, - gint *new_order, - gpointer data) -{ - FilterElt *elt; - FilterLevel *level; - EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data); - - GtkTreePath *path; - GtkTreeIter iter; - - gint *tmp_array; - gint i, j, elt_count; - gint length; - - GArray *new_array; - - g_return_if_fail (new_order != NULL); - -#ifdef VERBOSE - g_print ("filter: reordering\n"); -#endif - - if (c_path == NULL || gtk_tree_path_get_indices (c_path) == NULL) - { - if (!filter->root) - return; - - length = gtk_tree_model_iter_n_children (c_model, NULL); - - if (filter->virtual_root) - { - gint new_pos = -1; - - /* reorder root level of path */ - for (i = 0; i < length; i++) - if (new_order[i] == gtk_tree_path_get_indices (filter->virtual_root)[0]) - new_pos = i; - - if (new_pos < 0) - return; - - gtk_tree_path_get_indices (filter->virtual_root)[0] = new_pos; - return; - } - - path = gtk_tree_path_new (); - level = FILTER_LEVEL (filter->root); - } - else - { - GtkTreeIter child_iter; - - /* virtual root anchor reordering */ - if (filter->virtual_root && - gtk_tree_path_get_depth (c_path) < - gtk_tree_path_get_depth (filter->virtual_root)) - { - gint new_pos = -1; - gint length; - gint level; - GtkTreeIter real_c_iter; - - level = gtk_tree_path_get_depth (c_path); - - if (c_iter) - real_c_iter = *c_iter; - else - gtk_tree_model_get_iter (c_model, &real_c_iter, c_path); - - length = gtk_tree_model_iter_n_children (c_model, &real_c_iter); - - for (i = 0; i < length; i++) - if (new_order[i] == gtk_tree_path_get_indices (filter->virtual_root)[level]) - new_pos = i; - - if (new_pos < 0) - return; - - gtk_tree_path_get_indices (filter->virtual_root)[level] = new_pos; - return; - } - - path = egg_real_tree_model_filter_convert_child_path_to_path (filter, - c_path, - FALSE, - FALSE); - if (!path && filter->virtual_root && - gtk_tree_path_compare (c_path, filter->virtual_root)) - return; - - if (!path && !filter->virtual_root) - return; - - if (!path) - { - /* root level mode */ - if (!c_iter) - gtk_tree_model_get_iter (c_model, c_iter, c_path); - length = gtk_tree_model_iter_n_children (c_model, c_iter); - path = gtk_tree_path_new (); - level = FILTER_LEVEL (filter->root); - } - else - { - gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path); - - level = FILTER_LEVEL (iter.user_data); - elt = FILTER_ELT (iter.user_data2); - - if (!elt->children) - { - gtk_tree_path_free (path); - return; - } - - level = elt->children; - - egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (filter), &child_iter, &iter); - length = gtk_tree_model_iter_n_children (c_model, &child_iter); - } - } - - if (level->array->len < 1) - return; - - /* NOTE: we do not bail out here if level->array->len < 2 like - * GtkTreeModelSort does. This because we do some special tricky - * reordering. - */ - - /* construct a new array */ - new_array = g_array_sized_new (FALSE, FALSE, sizeof (FilterElt), - level->array->len); - tmp_array = g_new (gint, level->array->len); - - for (i = 0, elt_count = 0; i < length; i++) - { - FilterElt *e = NULL; - gint old_offset = -1; - - for (j = 0; j < level->array->len; j++) - if (g_array_index (level->array, FilterElt, j).offset == new_order[i]) - { - e = &g_array_index (level->array, FilterElt, j); - old_offset = j; - break; - } - - if (!e) - continue; - - tmp_array[elt_count] = old_offset; - g_array_append_val (new_array, *e); - g_array_index (new_array, FilterElt, elt_count).offset = i; - elt_count++; - } - - g_array_free (level->array, TRUE); - level->array = new_array; - - /* fix up stuff */ - for (i = 0; i < level->array->len; i++) - { - FilterElt *e = &g_array_index (level->array, FilterElt, i); - if (e->children) - e->children->parent_elt = e; - } - - /* emit rows_reordered */ - if (!gtk_tree_path_get_indices (path)) - gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, NULL, - tmp_array); - else - gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, &iter, - tmp_array); - - /* done */ - g_free (tmp_array); - gtk_tree_path_free (path); -} - -/* TreeModelIface implementation */ -static guint -egg_tree_model_filter_get_flags (GtkTreeModel *model) -{ - g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0); - - return 0; -} - -static gint -egg_tree_model_filter_get_n_columns (GtkTreeModel *model) -{ - EggTreeModelFilter *filter = (EggTreeModelFilter *)model; - - g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0); - g_return_val_if_fail (filter->child_model != NULL, 0); - - if (filter->child_model == NULL) - return 0; - - /* so we can't modify the modify func after this ... */ - filter->modify_func_set = TRUE; - - if (filter->modify_n_columns > 0) - return filter->modify_n_columns; - - return gtk_tree_model_get_n_columns (filter->child_model); -} - -static GType -egg_tree_model_filter_get_column_type (GtkTreeModel *model, - gint index) -{ - EggTreeModelFilter *filter = (EggTreeModelFilter *)model; - - g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), G_TYPE_INVALID); - g_return_val_if_fail (filter->child_model != NULL, G_TYPE_INVALID); - - /* so we can't modify the modify func after this ... */ - filter->modify_func_set = TRUE; - - if (filter->modify_types) - { - g_return_val_if_fail (index < filter->modify_n_columns, G_TYPE_INVALID); - - return filter->modify_types[index]; - } - - return gtk_tree_model_get_column_type (filter->child_model, index); -} - -static gboolean -egg_tree_model_filter_get_iter (GtkTreeModel *model, - GtkTreeIter *iter, - GtkTreePath *path) -{ - EggTreeModelFilter *filter = (EggTreeModelFilter *)model; - gint *indices; - FilterLevel *level; - gint depth, i; - - g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); - g_return_val_if_fail (filter->child_model != NULL, FALSE); - - indices = gtk_tree_path_get_indices (path); - - if (filter->root == NULL) - egg_tree_model_filter_build_level (filter, NULL, NULL); - level = FILTER_LEVEL (filter->root); - - depth = gtk_tree_path_get_depth (path); - if (!depth) - { - iter->stamp = 0; - return FALSE; - } - - for (i = 0; i < depth - 1; i++) - { - if (!level || indices[i] >= level->array->len) - { - return FALSE; - } - - if (!g_array_index (level->array, FilterElt, indices[i]).children) - egg_tree_model_filter_build_level (filter, level, - &g_array_index (level->array, - FilterElt, - indices[i])); - level = g_array_index (level->array, FilterElt, indices[i]).children; - } - - if (!level || indices[i] >= level->array->len) - { - iter->stamp = 0; - return FALSE; - } - - iter->stamp = filter->stamp; - iter->user_data = level; - iter->user_data2 = &g_array_index (level->array, FilterElt, - indices[depth - 1]); - - return TRUE; -} - -static GtkTreePath * -egg_tree_model_filter_get_path (GtkTreeModel *model, - GtkTreeIter *iter) -{ - GtkTreePath *retval; - FilterLevel *level; - FilterElt *elt; - - g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), NULL); - g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL, NULL); - g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp, NULL); - - retval = gtk_tree_path_new (); - level = iter->user_data; - elt = iter->user_data2; - - while (level) - { - gtk_tree_path_prepend_index (retval, - elt - FILTER_ELT (level->array->data)); - elt = level->parent_elt; - level = level->parent_level; - } - - return retval; -} - -static void -egg_tree_model_filter_get_value (GtkTreeModel *model, - GtkTreeIter *iter, - gint column, - GValue *value) -{ - GtkTreeIter child_iter; - EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (model); - - g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model)); - g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL); - g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp); - - if (filter->modify_func) - { - g_return_if_fail (column < filter->modify_n_columns); - - g_value_init (value, filter->modify_types[column]); - filter->modify_func (model, - iter, - value, - column, - filter->modify_data); - - return; - } - - egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); - gtk_tree_model_get_value (EGG_TREE_MODEL_FILTER (model)->child_model, - &child_iter, column, value); -} - -static gboolean -egg_tree_model_filter_iter_next (GtkTreeModel *model, - GtkTreeIter *iter) -{ - FilterLevel *level; - FilterElt *elt; - - g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); - g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL, FALSE); - g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp, FALSE); - - level = iter->user_data; - elt = iter->user_data2; - - if (elt - FILTER_ELT (level->array->data) >= level->array->len - 1) - { - iter->stamp = 0; - return FALSE; - } - - iter->user_data2 = elt + 1; - - return TRUE; -} - -static gboolean -egg_tree_model_filter_iter_children (GtkTreeModel *model, - GtkTreeIter *iter, - GtkTreeIter *parent) -{ - EggTreeModelFilter *filter = (EggTreeModelFilter *)model; - FilterLevel *level; - - iter->stamp = 0; - g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); - g_return_val_if_fail (filter->child_model != NULL, FALSE); - if (parent) - g_return_val_if_fail (filter->stamp == parent->stamp, FALSE); - - if (!parent) - { - if (!filter->root) - egg_tree_model_filter_build_level (filter, NULL, NULL); - if (!filter->root) - return FALSE; - - level = filter->root; - iter->stamp = filter->stamp; - iter->user_data = level; - iter->user_data2 = level->array->data; - } - else - { - if (FILTER_ELT (parent->user_data2)->children == NULL) - egg_tree_model_filter_build_level (filter, - FILTER_LEVEL (parent->user_data), - FILTER_ELT (parent->user_data2)); - if (FILTER_ELT (parent->user_data2)->children == NULL) - return FALSE; - - iter->stamp = filter->stamp; - iter->user_data = FILTER_ELT (parent->user_data2)->children; - iter->user_data2 = FILTER_LEVEL (iter->user_data)->array->data; - } - - return TRUE; -} - -static gboolean -egg_tree_model_filter_iter_has_child (GtkTreeModel *model, - GtkTreeIter *iter) -{ - GtkTreeIter child_iter; - EggTreeModelFilter *filter = (EggTreeModelFilter *)model; - FilterElt *elt; - - g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); - g_return_val_if_fail (filter->child_model != NULL, FALSE); - g_return_val_if_fail (filter->stamp == iter->stamp, FALSE); - - filter = EGG_TREE_MODEL_FILTER (model); - - egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); - elt = FILTER_ELT (iter->user_data2); - - /* we need to build the level to check if not all children are filtered - * out - */ - if (!elt->children - && gtk_tree_model_iter_has_child (filter->child_model, &child_iter)) - egg_tree_model_filter_build_level (filter, FILTER_LEVEL (iter->user_data), - elt); - - if (elt->children && elt->children->array->len > 0) - return TRUE; - - return FALSE; -} - -static gint -egg_tree_model_filter_iter_n_children (GtkTreeModel *model, - GtkTreeIter *iter) -{ - GtkTreeIter child_iter; - EggTreeModelFilter *filter = (EggTreeModelFilter *)model; - FilterElt *elt; - - g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0); - g_return_val_if_fail (filter->child_model != NULL, 0); - if (iter) - g_return_val_if_fail (filter->stamp == iter->stamp, 0); - - if (!iter) - { - int i = 0; - int count = 0; - GArray *a; - - if (!filter->root) - egg_tree_model_filter_build_level (filter, NULL, NULL); - - a = FILTER_LEVEL (filter->root)->array; - - /* count visible nodes */ - - for (i = 0; i < a->len; i++) - if (g_array_index (a, FilterElt, i).visible) - count++; - - return count; - } - - elt = FILTER_ELT (iter->user_data2); - egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); - - if (!elt->children && - gtk_tree_model_iter_has_child (filter->child_model, &child_iter)) - egg_tree_model_filter_build_level (filter, - FILTER_LEVEL (iter->user_data), - elt); - - if (elt->children && elt->children->array->len) - { - int i = 0; - int count = 0; - GArray *a = elt->children->array; - - /* count visible nodes */ - - for (i = 0; i < a->len; i++) - if (g_array_index (a, FilterElt, i).visible) - count++; - - return count; - } - - return 0; -} - -static gboolean -egg_tree_model_filter_iter_nth_child (GtkTreeModel *model, - GtkTreeIter *iter, - GtkTreeIter *parent, - gint n) -{ - FilterLevel *level; - GtkTreeIter children; - - g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); - if (parent) - g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == parent->stamp, FALSE); - - /* use this instead of has_Child to force us to build the level, if needed */ - if (egg_tree_model_filter_iter_children (model, &children, parent) == FALSE) - { - iter->stamp = 0; - return FALSE; - } - - level = children.user_data; - if (n >= level->array->len) - { - iter->stamp = 0; - return FALSE; - } - - iter->stamp = EGG_TREE_MODEL_FILTER (model)->stamp; - iter->user_data = level; - iter->user_data2 = &g_array_index (level->array, FilterElt, n); - - return TRUE; -} - -static gboolean -egg_tree_model_filter_iter_parent (GtkTreeModel *model, - GtkTreeIter *iter, - GtkTreeIter *child) -{ - FilterLevel *level; - - iter->stamp = 0; - g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE); - g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL, FALSE); - g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == child->stamp, FALSE); - - level = child->user_data; - - if (level->parent_level) - { - iter->stamp = EGG_TREE_MODEL_FILTER (model)->stamp; - iter->user_data = level->parent_level; - iter->user_data2 = level->parent_elt; - - return TRUE; - } - - return FALSE; -} - -static void -egg_tree_model_filter_ref_node (GtkTreeModel *model, - GtkTreeIter *iter) -{ - EggTreeModelFilter *filter = (EggTreeModelFilter *)model; - GtkTreeIter child_iter; - FilterLevel *level; - FilterElt *elt; - - g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model)); - g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL); - g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp); - - egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); - - gtk_tree_model_ref_node (filter->child_model, &child_iter); - - level = iter->user_data; - elt = iter->user_data2; - - elt->ref_count++; - level->ref_count++; - if (level->ref_count == 1) - { - FilterLevel *parent_level = level->parent_level; - FilterElt *parent_elt = level->parent_elt; - - /* we were at zero -- time to decrease the zero_ref_count val */ - do - { - if (parent_elt) - parent_elt->zero_ref_count--; - - if (parent_level) - { - parent_elt = parent_level->parent_elt; - parent_level = parent_level->parent_level; - } - } - while (parent_level); - filter->zero_ref_count--; - } - -#ifdef VERBOSE - g_print ("reffed %p\n", iter->user_data2); - g_print ("zero ref count is now %d\n", filter->zero_ref_count); - if (filter->zero_ref_count < 0) - g_warning ("zero_ref_count < 0."); -#endif -} - -static void -egg_tree_model_filter_unref_node (GtkTreeModel *model, - GtkTreeIter *iter) -{ - egg_tree_model_filter_real_unref_node (model, iter, TRUE); -} - -static void -egg_tree_model_filter_real_unref_node (GtkTreeModel *model, - GtkTreeIter *iter, - gboolean propagate_unref) -{ - EggTreeModelFilter *filter = (EggTreeModelFilter *)model; - FilterLevel *level; - FilterElt *elt; - - g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model)); - g_return_if_fail (filter->child_model != NULL); - g_return_if_fail (filter->stamp == iter->stamp); - - if (propagate_unref) - { - GtkTreeIter child_iter; - egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter); - gtk_tree_model_unref_node (filter->child_model, &child_iter); - } - - level = iter->user_data; - elt = iter->user_data2; - - g_return_if_fail (elt->ref_count > 0); - - elt->ref_count--; - level->ref_count--; - if (level->ref_count == 0) - { - FilterLevel *parent_level = level->parent_level; - FilterElt *parent_elt = level->parent_elt; - - /* we are at zero -- time to increase the zero_ref_count val */ - while (parent_level) - { - parent_elt->zero_ref_count++; - - parent_elt = parent_level->parent_elt; - parent_level = parent_level->parent_level; - } - filter->zero_ref_count++; - } - -#ifdef VERBOSE - g_print ("unreffed %p\n", iter->user_data2); - g_print ("zero ref count is now %d\n", filter->zero_ref_count); -#endif -} - -/* bits and pieces */ -static void -egg_tree_model_filter_set_model (EggTreeModelFilter *filter, - GtkTreeModel *child_model) -{ - g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); - - if (filter->child_model) - { - g_signal_handler_disconnect (G_OBJECT (filter->child_model), - filter->changed_id); - g_signal_handler_disconnect (G_OBJECT (filter->child_model), - filter->inserted_id); - g_signal_handler_disconnect (G_OBJECT (filter->child_model), - filter->has_child_toggled_id); - g_signal_handler_disconnect (G_OBJECT (filter->child_model), - filter->deleted_id); - g_signal_handler_disconnect (G_OBJECT (filter->child_model), - filter->reordered_id); - - /* reset our state */ - if (filter->root) - egg_tree_model_filter_free_level (filter, filter->root); - - filter->root = NULL; - g_object_unref (G_OBJECT (filter->child_model)); - filter->visible_column = -1; - /* FIXME: destroy more crack here? the funcs? */ - } - - filter->child_model = child_model; - - if (child_model) - { - g_object_ref (G_OBJECT (filter->child_model)); - filter->changed_id = - g_signal_connect (child_model, "row_changed", - G_CALLBACK (egg_tree_model_filter_row_changed), - filter); - filter->inserted_id = - g_signal_connect (child_model, "row_inserted", - G_CALLBACK (egg_tree_model_filter_row_inserted), - filter); - filter->has_child_toggled_id = - g_signal_connect (child_model, "row_has_child_toggled", - G_CALLBACK (egg_tree_model_filter_row_has_child_toggled), - filter); - filter->deleted_id = - g_signal_connect (child_model, "row_deleted", - G_CALLBACK (egg_tree_model_filter_row_deleted), - filter); - filter->reordered_id = - g_signal_connect (child_model, "rows_reordered", - G_CALLBACK (egg_tree_model_filter_rows_reordered), - filter); - - filter->child_flags = gtk_tree_model_get_flags (child_model); - filter->stamp = g_random_int (); - } -} - -static void -egg_tree_model_filter_set_root (EggTreeModelFilter *filter, - GtkTreePath *root) -{ - g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); - - if (!root) - filter->virtual_root = NULL; - else - filter->virtual_root = gtk_tree_path_copy (root); -} - -/* public API */ - -GtkTreeModel * -egg_tree_model_filter_new (GtkTreeModel *child_model, - GtkTreePath *root) -{ - GtkTreeModel *retval; - - g_return_val_if_fail (GTK_IS_TREE_MODEL (child_model), NULL); - - retval = GTK_TREE_MODEL (g_object_new (egg_tree_model_filter_get_type (), NULL)); - - egg_tree_model_filter_set_model (EGG_TREE_MODEL_FILTER (retval), - child_model); - egg_tree_model_filter_set_root (EGG_TREE_MODEL_FILTER (retval), root); - - return retval; -} - -GtkTreeModel * -egg_tree_model_filter_get_model (EggTreeModelFilter *filter) -{ - g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter), NULL); - - return filter->child_model; -} - -void -egg_tree_model_filter_set_visible_func (EggTreeModelFilter *filter, - EggTreeModelFilterVisibleFunc func, - gpointer data, - GtkDestroyNotify destroy) -{ - g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); - g_return_if_fail (func != NULL); - g_return_if_fail (filter->visible_method_set == FALSE); - - if (filter->visible_func) - { - GtkDestroyNotify d = filter->visible_destroy; - - filter->visible_destroy = NULL; - d (filter->visible_data); - } - - filter->visible_func = func; - filter->visible_data = data; - filter->visible_destroy = destroy; - - filter->visible_method_set = TRUE; -} - -void -egg_tree_model_filter_set_modify_func (EggTreeModelFilter *filter, - gint n_columns, - GType *types, - EggTreeModelFilterModifyFunc func, - gpointer data, - GtkDestroyNotify destroy) -{ - g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); - g_return_if_fail (func != NULL); - g_return_if_fail (filter->modify_func_set == FALSE); - - if (filter->modify_destroy) - { - GtkDestroyNotify d = filter->modify_destroy; - - filter->modify_destroy = NULL; - d (filter->modify_data); - } - - filter->modify_n_columns = n_columns; - filter->modify_types = g_new0 (GType, n_columns); - memcpy (filter->modify_types, types, sizeof (GType) * n_columns); - filter->modify_func = func; - filter->modify_data = data; - filter->modify_destroy = destroy; - - filter->modify_func_set = TRUE; -} - -void -egg_tree_model_filter_set_visible_column (EggTreeModelFilter *filter, - gint column) -{ - g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); - g_return_if_fail (column >= 0); - g_return_if_fail (filter->visible_method_set == FALSE); - - filter->visible_column = column; - - filter->visible_method_set = TRUE; -} - -/* conversion */ -void -egg_tree_model_filter_convert_child_iter_to_iter (EggTreeModelFilter *filter, - GtkTreeIter *filter_iter, - GtkTreeIter *child_iter) -{ - GtkTreePath *child_path, *path; - - g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); - g_return_if_fail (filter->child_model != NULL); - g_return_if_fail (filter_iter != NULL); - g_return_if_fail (child_iter != NULL); - - filter_iter->stamp = 0; - - child_path = gtk_tree_model_get_path (filter->child_model, child_iter); - g_return_if_fail (child_path != NULL); - - path = egg_tree_model_filter_convert_child_path_to_path (filter, - child_path); - gtk_tree_path_free (child_path); - g_return_if_fail (path != NULL); - - gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), filter_iter, path); - gtk_tree_path_free (path); -} - -void -egg_tree_model_filter_convert_iter_to_child_iter (EggTreeModelFilter *filter, - GtkTreeIter *child_iter, - GtkTreeIter *filter_iter) -{ - g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); - g_return_if_fail (filter->child_model != NULL); - g_return_if_fail (child_iter != NULL); - g_return_if_fail (filter_iter != NULL); - g_return_if_fail (filter_iter->stamp == filter->stamp); - - if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter)) - { - *child_iter = FILTER_ELT (filter_iter->user_data2)->iter; - } - else - { - GtkTreePath *path; - - path = egg_tree_model_filter_elt_get_path (filter_iter->user_data, - filter_iter->user_data2, - NULL); - gtk_tree_model_get_iter (filter->child_model, child_iter, path); - gtk_tree_path_free (path); - } -} - -static GtkTreePath * -egg_real_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter, - GtkTreePath *child_path, - gboolean build_levels, - gboolean fetch_childs) -{ - gint *child_indices; - GtkTreePath *retval; - GtkTreePath *real_path; - FilterLevel *level; - gint i; - - g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter), NULL); - g_return_val_if_fail (filter->child_model != NULL, NULL); - g_return_val_if_fail (child_path != NULL, NULL); - - if (!filter->virtual_root) - real_path = gtk_tree_path_copy (child_path); - else - real_path = egg_tree_model_filter_remove_root (child_path, - filter->virtual_root); - - if (!real_path) - return NULL; - - retval = gtk_tree_path_new (); - child_indices = gtk_tree_path_get_indices (real_path); - - if (filter->root == NULL && build_levels) - egg_tree_model_filter_build_level (filter, NULL, NULL); - level = FILTER_LEVEL (filter->root); - - for (i = 0; i < gtk_tree_path_get_depth (real_path); i++) - { - gint j; - gboolean found_child = FALSE; - - if (!level) - { - gtk_tree_path_free (real_path); - gtk_tree_path_free (retval); - return NULL; - } - - for (j = 0; j < level->array->len; j++) - { - if ((g_array_index (level->array, FilterElt, j)).offset == child_indices[i]) - { - gtk_tree_path_append_index (retval, j); - if (g_array_index (level->array, FilterElt, j).children == NULL && build_levels) - egg_tree_model_filter_build_level (filter, - level, - &g_array_index (level->array, FilterElt, j)); - level = g_array_index (level->array, FilterElt, j).children; - found_child = TRUE; - break; - } - } - - if (!found_child && fetch_childs) - { - /* didn't find the child, let's try to bring it back */ - if (!egg_tree_model_filter_fetch_child (filter, level, child_indices[i])) - { - /* not there */ - gtk_tree_path_free (real_path); - gtk_tree_path_free (retval); - return NULL; - } - - /* yay, let's search for the child again */ - for (j = 0; j < level->array->len; j++) - { - if ((g_array_index (level->array, FilterElt, j)).offset == child_indices[i]) - { - gtk_tree_path_append_index (retval, j); - if (g_array_index (level->array, FilterElt, j).children == NULL && build_levels) - egg_tree_model_filter_build_level (filter, - level, - &g_array_index (level->array, FilterElt, j)); - level = g_array_index (level->array, FilterElt, j).children; - found_child = TRUE; - break; - } - } - - if (!found_child) - { - /* our happy fun fetch attempt failed ?!?!?! no child! */ - gtk_tree_path_free (real_path); - gtk_tree_path_free (retval); - return NULL; - } - } - else if (!found_child && !fetch_childs) - { - /* no path */ - gtk_tree_path_free (real_path); - gtk_tree_path_free (retval); - return NULL; - } - } - - gtk_tree_path_free (real_path); - return retval; -} - -GtkTreePath * -egg_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter, - GtkTreePath *child_path) -{ - /* this function does the sanity checks */ - return egg_real_tree_model_filter_convert_child_path_to_path (filter, - child_path, - TRUE, - TRUE); -} - -GtkTreePath * -egg_tree_model_filter_convert_path_to_child_path (EggTreeModelFilter *filter, - GtkTreePath *filter_path) -{ - gint *filter_indices; - GtkTreePath *retval; - FilterLevel *level; - gint i; - - g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter), NULL); - g_return_val_if_fail (filter->child_model != NULL, NULL); - g_return_val_if_fail (filter_path != NULL, NULL); - - /* convert path */ - retval = gtk_tree_path_new (); - filter_indices = gtk_tree_path_get_indices (filter_path); - if (!filter->root) - egg_tree_model_filter_build_level (filter, NULL, NULL); - level = FILTER_LEVEL (filter->root); - - for (i = 0; i < gtk_tree_path_get_depth (filter_path); i++) - { - gint count = filter_indices[i]; - - if (!level || level->array->len <= filter_indices[i]) - { - gtk_tree_path_free (retval); - return NULL; - } - - if (g_array_index (level->array, FilterElt, count).children == NULL) - egg_tree_model_filter_build_level (filter, level, &g_array_index (level->array, FilterElt, count)); - - if (!level || level->array->len <= filter_indices[i]) - { - gtk_tree_path_free (retval); - return NULL; - } - - gtk_tree_path_append_index (retval, g_array_index (level->array, FilterElt, count).offset); - level = g_array_index (level->array, FilterElt, count).children; - } - - /* apply vroot */ - - if (filter->virtual_root) - { - GtkTreePath *real_retval; - - real_retval = egg_tree_model_filter_add_root (retval, - filter->virtual_root); - gtk_tree_path_free (retval); - - return real_retval; - } - - return retval; -} - -void -egg_tree_model_filter_clear_cache (EggTreeModelFilter *filter) -{ - g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter)); - - if (filter->zero_ref_count) - egg_tree_model_filter_clear_cache_helper (filter, - FILTER_LEVEL (filter->root)); -} diff --git a/lib/widgets/eggtreemodelfilter.h b/lib/widgets/eggtreemodelfilter.h deleted file mode 100644 index ada78c1be..000000000 --- a/lib/widgets/eggtreemodelfilter.h +++ /dev/null @@ -1,123 +0,0 @@ -/* eggtreemodelfilter.h - * Copyright (C) 2000,2001 Red Hat, Inc., Jonathan Blandford - * Copyright (C) 2001,2002 Kristian Rietveld - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __EGG_TREE_MODEL_FILTER_H__ -#define __EGG_TREE_MODEL_FILTER_H__ - -#include - -G_BEGIN_DECLS - -#define EGG_TYPE_TREE_MODEL_FILTER (egg_tree_model_filter_get_type ()) -#define EGG_TREE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TREE_MODEL_FILTER, EggTreeModelFilter)) -#define EGG_TREE_MODEL_FILTER_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), EGG_TYPE_TREE_MODEL_FILTER, EggTreeModelFilterClass)) -#define EGG_IS_TREE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TREE_MODEL_FILTER)) -#define EGG_IS_TREE_MODEL_FILTER_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), EGG_TYPE_TREE_MODEL_FILTER)) -#define EGG_TREE_MODEL_FILTER_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TREE_MODEL_FILTER, EggTreeModelFilterClass)) - -typedef gboolean (* EggTreeModelFilterVisibleFunc) (GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data); -typedef void (* EggTreeModelFilterModifyFunc) (GtkTreeModel *model, - GtkTreeIter *iter, - GValue *value, - gint column, - gpointer data); - -typedef struct _EggTreeModelFilter EggTreeModelFilter; -typedef struct _EggTreeModelFilterClass EggTreeModelFilterClass; - -struct _EggTreeModelFilter -{ - GObject parent; - - /*< private >*/ - gpointer root; - gint stamp; - guint child_flags; - GtkTreeModel *child_model; - gint zero_ref_count; - - GtkTreePath *virtual_root; - - EggTreeModelFilterVisibleFunc visible_func; - gpointer visible_data; - GtkDestroyNotify visible_destroy; - - gint modify_n_columns; - GType *modify_types; - EggTreeModelFilterModifyFunc modify_func; - gpointer modify_data; - gpointer modify_destroy; - - gint visible_column; - - gboolean visible_method_set; - gboolean modify_func_set; - - /* signal ids */ - guint changed_id; - guint inserted_id; - guint has_child_toggled_id; - guint deleted_id; - guint reordered_id; -}; - -struct _EggTreeModelFilterClass -{ - GObjectClass parent_class; -}; - -GType egg_tree_model_filter_get_type (void); -GtkTreeModel * egg_tree_model_filter_new (GtkTreeModel *child_model, - GtkTreePath *root); -void egg_tree_model_filter_set_visible_func (EggTreeModelFilter *filter, - EggTreeModelFilterVisibleFunc func, - gpointer data, - GtkDestroyNotify destroy); -void egg_tree_model_filter_set_modify_func (EggTreeModelFilter *filter, - gint n_columns, - GType *types, - EggTreeModelFilterModifyFunc func, - gpointer data, - GtkDestroyNotify destroy); -void egg_tree_model_filter_set_visible_column (EggTreeModelFilter *filter, - gint column); - -GtkTreeModel *egg_tree_model_filter_get_model (EggTreeModelFilter *filter); - -/* conversion */ -void egg_tree_model_filter_convert_child_iter_to_iter (EggTreeModelFilter *filter, - GtkTreeIter *filter_iter, - GtkTreeIter *child_iter); -void egg_tree_model_filter_convert_iter_to_child_iter (EggTreeModelFilter *filter, - GtkTreeIter *child_iter, - GtkTreeIter *filter_iter); -GtkTreePath *egg_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter, - GtkTreePath *child_path); -GtkTreePath *egg_tree_model_filter_convert_path_to_child_path (EggTreeModelFilter *path, - GtkTreePath *filter_path); - - -void egg_tree_model_filter_clear_cache (EggTreeModelFilter *filter); - -G_END_DECLS - -#endif /* __EGG_TREE_MODEL_FILTER_H__ */ diff --git a/lib/widgets/eggtreemultidnd.c b/lib/widgets/eggtreemultidnd.c deleted file mode 100644 index 5215a7bfc..000000000 --- a/lib/widgets/eggtreemultidnd.c +++ /dev/null @@ -1,425 +0,0 @@ -/* eggtreemultidnd.c - * Copyright (C) 2001 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include "eggtreemultidnd.h" - -#define EGG_TREE_MULTI_DND_STRING "EggTreeMultiDndString" - -typedef struct -{ - guint pressed_button; - gint x; - gint y; - guint motion_notify_handler; - guint button_release_handler; - guint drag_data_get_handler; - GSList *event_list; -} EggTreeMultiDndData; - -/* CUT-N-PASTE from gtktreeview.c */ -typedef struct _TreeViewDragInfo TreeViewDragInfo; -struct _TreeViewDragInfo -{ - GdkModifierType start_button_mask; - GtkTargetList *source_target_list; - GdkDragAction source_actions; - - GtkTargetList *dest_target_list; - - guint source_set : 1; - guint dest_set : 1; -}; - - -GType -egg_tree_multi_drag_source_get_type (void) -{ - static GType our_type = 0; - - if (!our_type) - { - static const GTypeInfo our_info = - { - sizeof (EggTreeMultiDragSourceIface), /* class_size */ - NULL, /* base_init */ - NULL, /* base_finalize */ - NULL, - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL - }; - - our_type = g_type_register_static (G_TYPE_INTERFACE, "EggTreeMultiDragSource", &our_info, 0); - } - - return our_type; -} - - -/** - * egg_tree_multi_drag_source_row_draggable: - * @drag_source: a #EggTreeMultiDragSource - * @path: row on which user is initiating a drag - * - * Asks the #EggTreeMultiDragSource whether a particular row can be used as - * the source of a DND operation. If the source doesn't implement - * this interface, the row is assumed draggable. - * - * Return value: %TRUE if the row can be dragged - **/ -gboolean -egg_tree_multi_drag_source_row_draggable (EggTreeMultiDragSource *drag_source, - GList *path_list) -{ - EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); - - g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); - g_return_val_if_fail (iface->row_draggable != NULL, FALSE); - g_return_val_if_fail (path_list != NULL, FALSE); - - if (iface->row_draggable) - return (* iface->row_draggable) (drag_source, path_list); - else - return TRUE; -} - - -/** - * egg_tree_multi_drag_source_drag_data_delete: - * @drag_source: a #EggTreeMultiDragSource - * @path: row that was being dragged - * - * Asks the #EggTreeMultiDragSource to delete the row at @path, because - * it was moved somewhere else via drag-and-drop. Returns %FALSE - * if the deletion fails because @path no longer exists, or for - * some model-specific reason. Should robustly handle a @path no - * longer found in the model! - * - * Return value: %TRUE if the row was successfully deleted - **/ -gboolean -egg_tree_multi_drag_source_drag_data_delete (EggTreeMultiDragSource *drag_source, - GList *path_list) -{ - EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); - - g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); - g_return_val_if_fail (iface->drag_data_delete != NULL, FALSE); - g_return_val_if_fail (path_list != NULL, FALSE); - - return (* iface->drag_data_delete) (drag_source, path_list); -} - -/** - * egg_tree_multi_drag_source_drag_data_get: - * @drag_source: a #EggTreeMultiDragSource - * @path: row that was dragged - * @selection_data: a #EggSelectionData to fill with data from the dragged row - * - * Asks the #EggTreeMultiDragSource to fill in @selection_data with a - * representation of the row at @path. @selection_data->target gives - * the required type of the data. Should robustly handle a @path no - * longer found in the model! - * - * Return value: %TRUE if data of the required type was provided - **/ -gboolean -egg_tree_multi_drag_source_drag_data_get (EggTreeMultiDragSource *drag_source, - GList *path_list, - guint info, - GtkSelectionData *selection_data) -{ - EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); - - g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); - g_return_val_if_fail (iface->drag_data_get != NULL, FALSE); - g_return_val_if_fail (path_list != NULL, FALSE); - g_return_val_if_fail (selection_data != NULL, FALSE); - - return (* iface->drag_data_get) (drag_source, path_list, info, selection_data); -} - -static void -stop_drag_check (GtkWidget *widget) -{ - EggTreeMultiDndData *priv_data; - GSList *l; - - priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); - - for (l = priv_data->event_list; l != NULL; l = l->next) - gdk_event_free (l->data); - - g_slist_free (priv_data->event_list); - priv_data->event_list = NULL; - g_signal_handler_disconnect (widget, priv_data->motion_notify_handler); - g_signal_handler_disconnect (widget, priv_data->button_release_handler); -} - -static gboolean -egg_tree_multi_drag_button_release_event (GtkWidget *widget, - GdkEventButton *event, - gpointer data) -{ - EggTreeMultiDndData *priv_data; - GSList *l; - - priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); - - for (l = priv_data->event_list; l != NULL; l = l->next) - gtk_propagate_event (widget, l->data); - - stop_drag_check (widget); - - return FALSE; -} - -static void -selection_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer data) -{ - GList **list_ptr; - - list_ptr = (GList **) data; - - *list_ptr = g_list_prepend (*list_ptr, gtk_tree_row_reference_new (model, path)); -} - -static void -path_list_free (GList *path_list) -{ - g_list_foreach (path_list, (GFunc) gtk_tree_row_reference_free, NULL); - g_list_free (path_list); -} - -static void -set_context_data (GdkDragContext *context, - GList *path_list) -{ - g_object_set_data_full (G_OBJECT (context), - "egg-tree-view-multi-source-row", - path_list, - (GDestroyNotify) path_list_free); -} - -static GList * -get_context_data (GdkDragContext *context) -{ - return g_object_get_data (G_OBJECT (context), - "egg-tree-view-multi-source-row"); -} - -/* CUT-N-PASTE from gtktreeview.c */ -static TreeViewDragInfo* -get_info (GtkTreeView *tree_view) -{ - return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info"); -} - - -static void -egg_tree_multi_drag_drag_data_get (GtkWidget *widget, - GdkDragContext *context, - GtkSelectionData *selection_data, - guint info, - guint time) -{ - GtkTreeView *tree_view; - GtkTreeModel *model; - TreeViewDragInfo *di; - GList *path_list; - - tree_view = GTK_TREE_VIEW (widget); - - model = gtk_tree_view_get_model (tree_view); - - if (model == NULL) - return; - - di = get_info (GTK_TREE_VIEW (widget)); - - if (di == NULL) - return; - - path_list = get_context_data (context); - - if (path_list == NULL) - return; - - /* We can implement the GTK_TREE_MODEL_ROW target generically for - * any model; for DragSource models there are some other targets - * we also support. - */ - - if (EGG_IS_TREE_MULTI_DRAG_SOURCE (model)) - { - egg_tree_multi_drag_source_drag_data_get (EGG_TREE_MULTI_DRAG_SOURCE (model), - path_list, - info, - selection_data); - } -} - -static gboolean -egg_tree_multi_drag_motion_event (GtkWidget *widget, - GdkEventMotion *event, - gpointer data) -{ - EggTreeMultiDndData *priv_data; - - priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); - - if (gtk_drag_check_threshold (widget, - priv_data->x, - priv_data->y, - event->x, - event->y)) - { - GList *path_list = NULL; - GtkTreeSelection *selection; - GtkTreeModel *model; - GdkDragContext *context; - TreeViewDragInfo *di; - - di = get_info (GTK_TREE_VIEW (widget)); - - if (di == NULL) - return FALSE; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); - stop_drag_check (widget); - gtk_tree_selection_selected_foreach (selection, selection_foreach, &path_list); - path_list = g_list_reverse (path_list); - model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); - - if (egg_tree_multi_drag_source_row_draggable (EGG_TREE_MULTI_DRAG_SOURCE (model), path_list)) - { - context = gtk_drag_begin (widget, - di->source_target_list, - di->source_actions, - priv_data->pressed_button, - (GdkEvent*)event); - set_context_data (context, path_list); - - if (g_list_length (path_list) > 1) - { - gtk_drag_set_icon_stock (context, GTK_STOCK_DND_MULTIPLE, -2, -2); - } - else - { - gtk_drag_set_icon_stock (context, GTK_STOCK_DND, -2, -2); - } - } - else - { - path_list_free (path_list); - } - } - - return TRUE; -} - -static gboolean -egg_tree_multi_drag_button_press_event (GtkWidget *widget, - GdkEventButton *event, - gpointer data) -{ - GtkTreeView *tree_view; - GtkTreePath *path = NULL; - GtkTreeViewColumn *column = NULL; - gint cell_x, cell_y; - GtkTreeSelection *selection; - EggTreeMultiDndData *priv_data; - - if (event->button == 3) - return FALSE; - - tree_view = GTK_TREE_VIEW (widget); - priv_data = g_object_get_data (G_OBJECT (tree_view), EGG_TREE_MULTI_DND_STRING); - if (priv_data == NULL) - { - priv_data = g_new0 (EggTreeMultiDndData, 1); - g_object_set_data (G_OBJECT (tree_view), EGG_TREE_MULTI_DND_STRING, priv_data); - } - - if (g_slist_find (priv_data->event_list, event)) - return FALSE; - - if (priv_data->event_list) - { - /* save the event to be propagated in order */ - priv_data->event_list = g_slist_append (priv_data->event_list, gdk_event_copy ((GdkEvent*)event)); - return TRUE; - } - - if (event->type == GDK_2BUTTON_PRESS) - return FALSE; - - gtk_tree_view_get_path_at_pos (tree_view, - event->x, event->y, - &path, &column, - &cell_x, &cell_y); - - selection = gtk_tree_view_get_selection (tree_view); - - if (path && gtk_tree_selection_path_is_selected (selection, path)) - { - priv_data->pressed_button = event->button; - priv_data->x = event->x; - priv_data->y = event->y; - priv_data->event_list = g_slist_append (priv_data->event_list, gdk_event_copy ((GdkEvent*)event)); - priv_data->motion_notify_handler = - g_signal_connect (G_OBJECT (tree_view), "motion_notify_event", G_CALLBACK (egg_tree_multi_drag_motion_event), NULL); - priv_data->button_release_handler = - g_signal_connect (G_OBJECT (tree_view), "button_release_event", G_CALLBACK (egg_tree_multi_drag_button_release_event), NULL); - - if (priv_data->drag_data_get_handler == 0) - { - priv_data->drag_data_get_handler = - g_signal_connect (G_OBJECT (tree_view), "drag_data_get", G_CALLBACK (egg_tree_multi_drag_drag_data_get), NULL); - } - - return TRUE; - } - - if (path) - { - gtk_tree_path_free (path); - } - - return FALSE; -} - -void -egg_tree_multi_drag_add_drag_support (GtkTreeView *tree_view) -{ - g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); - g_signal_connect (G_OBJECT (tree_view), "button_press_event", G_CALLBACK (egg_tree_multi_drag_button_press_event), NULL); -} - diff --git a/lib/widgets/eggtreemultidnd.h b/lib/widgets/eggtreemultidnd.h deleted file mode 100644 index 460e60239..000000000 --- a/lib/widgets/eggtreemultidnd.h +++ /dev/null @@ -1,78 +0,0 @@ -/* eggtreednd.h - * Copyright (C) 2001 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __EGG_TREE_MULTI_DND_H__ -#define __EGG_TREE_MULTI_DND_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -#define EGG_TYPE_TREE_MULTI_DRAG_SOURCE (egg_tree_multi_drag_source_get_type ()) -#define EGG_TREE_MULTI_DRAG_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE, EggTreeMultiDragSource)) -#define EGG_IS_TREE_MULTI_DRAG_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE)) -#define EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE, EggTreeMultiDragSourceIface)) - -typedef struct _EggTreeMultiDragSource EggTreeMultiDragSource; /* Dummy typedef */ -typedef struct _EggTreeMultiDragSourceIface EggTreeMultiDragSourceIface; - -struct _EggTreeMultiDragSourceIface -{ - GTypeInterface g_iface; - - /* VTable - not signals */ - gboolean (* row_draggable) (EggTreeMultiDragSource *drag_source, - GList *path_list); - - gboolean (* drag_data_get) (EggTreeMultiDragSource *drag_source, - GList *path_list, - guint info, - GtkSelectionData *selection_data); - - gboolean (* drag_data_delete) (EggTreeMultiDragSource *drag_source, - GList *path_list); -}; - -GType egg_tree_multi_drag_source_get_type (void) G_GNUC_CONST; - -/* Returns whether the given row can be dragged */ -gboolean egg_tree_multi_drag_source_row_draggable (EggTreeMultiDragSource *drag_source, - GList *path_list); - -/* Deletes the given row, or returns FALSE if it can't */ -gboolean egg_tree_multi_drag_source_drag_data_delete (EggTreeMultiDragSource *drag_source, - GList *path_list); - - -/* Fills in selection_data with type selection_data->target based on the row - * denoted by path, returns TRUE if it does anything - */ -gboolean egg_tree_multi_drag_source_drag_data_get (EggTreeMultiDragSource *drag_source, - GList *path_list, - guint info, - GtkSelectionData *selection_data); -void egg_tree_multi_drag_add_drag_support (GtkTreeView *tree_view); - - - -G_END_DECLS - -#endif /* __EGG_TREE_MULTI_DND_H__ */ diff --git a/lib/widgets/ephy-tree-model-sort.c b/lib/widgets/ephy-tree-model-sort.c index bc32131f3..1d03effb8 100644 --- a/lib/widgets/ephy-tree-model-sort.c +++ b/lib/widgets/ephy-tree-model-sort.c @@ -37,7 +37,6 @@ static gboolean ephy_tree_model_sort_multi_row_draggable (EggTreeMultiDragSource GList *path_list); static gboolean ephy_tree_model_sort_multi_drag_data_get (EggTreeMultiDragSource *drag_source, GList *path_list, - guint info, GtkSelectionData *selection_data); static gboolean ephy_tree_model_sort_multi_drag_data_delete (EggTreeMultiDragSource *drag_source, GList *path_list); @@ -269,7 +268,6 @@ each_node_get_data_binder (EphyDragEachSelectedItemDataGet iteratee, static gboolean ephy_tree_model_sort_multi_drag_data_get (EggTreeMultiDragSource *drag_source, GList *path_list, - guint info, GtkSelectionData *selection_data) { GdkAtom target; @@ -285,7 +283,7 @@ ephy_tree_model_sort_multi_drag_data_get (EggTreeMultiDragSource *drag_source, icontext[1] = drag_source; ephy_dnd_drag_data_get (NULL, NULL, selection_data, - info, 0, &icontext, each_node_get_data_binder); + 0, &icontext, each_node_get_data_binder); } else @@ -296,7 +294,7 @@ ephy_tree_model_sort_multi_drag_data_get (EggTreeMultiDragSource *drag_source, icontext[1] = drag_source; ephy_dnd_drag_data_get (NULL, NULL, selection_data, - info, 0, &icontext, each_url_get_data_binder); + 0, &icontext, each_url_get_data_binder); } return TRUE; -- cgit v1.2.3