#include "gtktreemodelfilter.h"
#include "gtkintl.h"
#include "gtktreednd.h"
-#include "gtkalias.h"
#include "gtkprivate.h"
+#include "gtkalias.h"
#include <string.h>
/* ITER FORMAT:
* child model.
*/
+/* A few notes:
+ * There are three model/views involved, so there are two mappings:
+ * * this model -> child model: mapped via offset in FilterElt.
+ * * this model -> parent model (or view): mapped via the array index
+ * of FilterElt.
+ *
+ * Note that there are two kinds of paths relative to the filter model
+ * (those generated from the array indices): paths taking non-visible
+ * nodes into account, and paths which don't. Paths which take
+ * non-visible nodes into account should only be used internally and
+ * NEVER be passed along with a signal emission.
+ *
+ * The filter model has a reference on every node that is not in the root
+ * level and has a parent with ref_count > 1. Exception is a virtual root
+ * level; all nodes in the virtual root level are referenced too.
+ */
+
typedef struct _FilterElt FilterElt;
typedef struct _FilterLevel FilterLevel;
{
GArray *array;
gint ref_count;
+ gint visible_nodes;
FilterElt *parent_elt;
FilterLevel *parent_level;
GtkTreeModel *child_model;
gint zero_ref_count;
- guint root_level_visible;
-
GtkTreePath *virtual_root;
GtkTreeModelFilterVisibleFunc visible_func;
GType *modify_types;
GtkTreeModelFilterModifyFunc modify_func;
gpointer modify_data;
- gpointer modify_destroy;
+ GtkDestroyNotify modify_destroy;
gint visible_column;
gboolean visible_method_set;
gboolean modify_func_set;
+ gboolean in_row_deleted;
+ gboolean virtual_root_deleted;
+
/* signal ids */
guint changed_id;
guint inserted_id;
#define FILTER_LEVEL(filter_level) ((FilterLevel *)filter_level)
/* general code (object/interface init, properties, etc) */
-static void gtk_tree_model_filter_init (GtkTreeModelFilter *filter);
-static void gtk_tree_model_filter_class_init (GtkTreeModelFilterClass *filter_class);
static void gtk_tree_model_filter_tree_model_init (GtkTreeModelIface *iface);
static void gtk_tree_model_filter_drag_source_init (GtkTreeDragSourceIface *iface);
static void gtk_tree_model_filter_finalize (GObject *object);
static gint gtk_tree_model_filter_get_n_columns (GtkTreeModel *model);
static GType gtk_tree_model_filter_get_column_type (GtkTreeModel *model,
gint index);
+static gboolean gtk_tree_model_filter_get_iter_full (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreePath *path);
static gboolean gtk_tree_model_filter_get_iter (GtkTreeModel *model,
GtkTreeIter *iter,
GtkTreePath *path);
/* private functions */
static void gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
FilterLevel *parent_level,
- FilterElt *parent_elt);
+ FilterElt *parent_elt,
+ gboolean emit_inserted);
+
static void gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
FilterLevel *filter_level);
static void gtk_tree_model_filter_set_model (GtkTreeModelFilter *filter,
GtkTreeModel *child_model);
+static void gtk_tree_model_filter_ref_path (GtkTreeModelFilter *filter,
+ GtkTreePath *path);
+static void gtk_tree_model_filter_unref_path (GtkTreeModelFilter *filter,
+ GtkTreePath *path);
static void gtk_tree_model_filter_set_root (GtkTreeModelFilter *filter,
GtkTreePath *root);
gboolean build_levels,
gboolean fetch_children);
+static FilterElt *gtk_tree_model_filter_get_nth (GtkTreeModelFilter *filter,
+ FilterLevel *level,
+ int n);
+static FilterElt *gtk_tree_model_filter_get_nth_visible (GtkTreeModelFilter *filter,
+ FilterLevel *level,
+ int n);
+
static FilterElt *gtk_tree_model_filter_fetch_child (GtkTreeModelFilter *filter,
FilterLevel *level,
gint offset,
gint *index);
static void gtk_tree_model_filter_remove_node (GtkTreeModelFilter *filter,
- GtkTreeIter *iter,
- gboolean emit_signal);
+ GtkTreeIter *iter);
static void gtk_tree_model_filter_update_children (GtkTreeModelFilter *filter,
FilterLevel *level,
FilterElt *elt);
gint *index);
-static GObjectClass *parent_class = NULL;
-
-GType
-gtk_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 (GtkTreeModelFilterClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) gtk_tree_model_filter_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GtkTreeModelFilter),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gtk_tree_model_filter_init
- };
-
- static const GInterfaceInfo tree_model_info =
- {
- (GInterfaceInitFunc) gtk_tree_model_filter_tree_model_init,
- NULL,
- NULL
- };
-
- static const GInterfaceInfo drag_source_info =
- {
- (GInterfaceInitFunc) gtk_tree_model_filter_drag_source_init,
- NULL,
- NULL
- };
-
- tree_model_filter_type = g_type_register_static (G_TYPE_OBJECT,
- g_intern_static_string ("GtkTreeModelFilter"),
- &tree_model_filter_info, 0);
-
- g_type_add_interface_static (tree_model_filter_type,
- GTK_TYPE_TREE_MODEL,
- &tree_model_info);
-
- g_type_add_interface_static (tree_model_filter_type,
- GTK_TYPE_TREE_DRAG_SOURCE,
- &drag_source_info);
- }
-
- return tree_model_filter_type;
-}
+G_DEFINE_TYPE_WITH_CODE (GtkTreeModelFilter, gtk_tree_model_filter, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
+ gtk_tree_model_filter_tree_model_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
+ gtk_tree_model_filter_drag_source_init))
static void
gtk_tree_model_filter_init (GtkTreeModelFilter *filter)
filter->priv->zero_ref_count = 0;
filter->priv->visible_method_set = FALSE;
filter->priv->modify_func_set = FALSE;
+ filter->priv->in_row_deleted = FALSE;
+ filter->priv->virtual_root_deleted = FALSE;
}
static void
GObjectClass *object_class;
object_class = (GObjectClass *) filter_class;
- parent_class = g_type_class_peek_parent (filter_class);
object_class->set_property = gtk_tree_model_filter_set_property;
object_class->get_property = gtk_tree_model_filter_get_property;
{
GtkTreeModelFilter *filter = (GtkTreeModelFilter *) object;
+ if (filter->priv->virtual_root && !filter->priv->virtual_root_deleted)
+ {
+ gtk_tree_model_filter_unref_path (filter, filter->priv->virtual_root);
+ filter->priv->virtual_root_deleted = TRUE;
+ }
+
gtk_tree_model_filter_set_model (filter, NULL);
if (filter->priv->virtual_root)
if (filter->priv->root)
gtk_tree_model_filter_free_level (filter, filter->priv->root);
- if (filter->priv->modify_types)
- g_free (filter->priv->modify_types);
+ g_free (filter->priv->modify_types);
+
+ if (filter->priv->modify_destroy)
+ filter->priv->modify_destroy (filter->priv->modify_data);
+
+ if (filter->priv->visible_destroy)
+ filter->priv->visible_destroy (filter->priv->visible_data);
/* must chain up */
- parent_class->finalize (object);
+ G_OBJECT_CLASS (gtk_tree_model_filter_parent_class)->finalize (object);
}
static void
static void
gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
FilterLevel *parent_level,
- FilterElt *parent_elt)
+ FilterElt *parent_elt,
+ gboolean emit_inserted)
{
GtkTreeIter iter;
+ GtkTreeIter first_node;
GtkTreeIter root;
FilterLevel *new_level;
gint length = 0;
g_assert (filter->priv->child_model != NULL);
+ if (filter->priv->in_row_deleted)
+ return;
+
if (!parent_level)
{
if (filter->priv->virtual_root)
sizeof (FilterElt),
length);
new_level->ref_count = 0;
+ new_level->visible_nodes = 0;
new_level->parent_elt = parent_elt;
new_level->parent_level = parent_level;
parent_elt = parent_level->parent_elt;
parent_level = parent_level->parent_level;
}
- filter->priv->zero_ref_count++;
+ if (new_level != filter->priv->root)
+ filter->priv->zero_ref_count++;
i = 0;
- if (!new_level->parent_level)
- filter->priv->root_level_visible = 0;
+ first_node = iter;
do
{
filter_elt.iter = iter;
g_array_append_val (new_level->array, filter_elt);
+ new_level->visible_nodes++;
+
+ if (new_level->parent_level || filter->priv->virtual_root)
+ {
+ GtkTreeIter f_iter;
+
+ f_iter.stamp = filter->priv->stamp;
+ f_iter.user_data = new_level;
+ f_iter.user_data2 = &(g_array_index (new_level->array, FilterElt, new_level->array->len - 1));
+
+ gtk_tree_model_filter_ref_node (GTK_TREE_MODEL (filter), &f_iter);
- if (!new_level->parent_level)
- filter->priv->root_level_visible++;
+ if (emit_inserted)
+ {
+ GtkTreePath *f_path;
+
+ f_path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter),
+ &f_iter);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter),
+ f_path, &f_iter);
+ gtk_tree_path_free (f_path);
+ }
+ }
}
i++;
}
while (gtk_tree_model_iter_next (filter->priv->child_model, &iter));
+
+ if (new_level->array->len == 0
+ && (new_level != filter->priv->root || filter->priv->virtual_root))
+ {
+ /* If none of the nodes are visible, we will just pull in the
+ * first node of the level and keep a reference on it. We need this
+ * to make sure that we get all signals for this level.
+ */
+ FilterElt filter_elt;
+ GtkTreeIter f_iter;
+
+ filter_elt.offset = 0;
+ filter_elt.zero_ref_count = 0;
+ filter_elt.ref_count = 0;
+ filter_elt.children = NULL;
+ filter_elt.visible = FALSE;
+
+ if (GTK_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
+ filter_elt.iter = first_node;
+
+ g_array_append_val (new_level->array, filter_elt);
+
+ f_iter.stamp = filter->priv->stamp;
+ f_iter.user_data = new_level;
+ f_iter.user_data2 = &(g_array_index (new_level->array, FilterElt, new_level->array->len - 1));
+
+ gtk_tree_model_filter_ref_node (GTK_TREE_MODEL (filter), &f_iter);
+ }
+ else if (new_level->array->len == 0)
+ gtk_tree_model_filter_free_level (filter, new_level);
}
static void
g_assert (filter_level);
+ for (i = 0; i < filter_level->array->len; i++)
+ {
+ if (g_array_index (filter_level->array, FilterElt, i).children)
+ gtk_tree_model_filter_free_level (filter,
+ FILTER_LEVEL (g_array_index (filter_level->array, FilterElt, i).children));
+
+ if (filter_level->parent_level || filter->priv->virtual_root)
+ {
+ GtkTreeIter f_iter;
+
+ f_iter.stamp = filter->priv->stamp;
+ f_iter.user_data = filter_level;
+ f_iter.user_data2 = &(g_array_index (filter_level->array, FilterElt, i));
+
+ gtk_tree_model_filter_unref_node (GTK_TREE_MODEL (filter), &f_iter);
+ }
+ }
+
if (filter_level->ref_count == 0)
{
FilterLevel *parent_level = filter_level->parent_level;
FilterElt *parent_elt = filter_level->parent_elt;
- do
+ while (parent_level)
{
- if (parent_elt)
- parent_elt->zero_ref_count--;
+ parent_elt->zero_ref_count--;
- if (parent_level)
- {
- parent_elt = parent_level->parent_elt;
- parent_level = parent_level->parent_level;
- }
+ parent_elt = parent_level->parent_elt;
+ parent_level = parent_level->parent_level;
}
- while (parent_level);
- filter->priv->zero_ref_count--;
- }
- for (i = 0; i < filter_level->array->len; i++)
- {
- if (g_array_index (filter_level->array, FilterElt, i).children)
- gtk_tree_model_filter_free_level (filter,
- FILTER_LEVEL (g_array_index (filter_level->array, FilterElt, i).children));
+ if (filter_level != filter->priv->root)
+ filter->priv->zero_ref_count--;
}
- if (!filter_level->parent_level)
- filter->priv->root_level_visible = 0;
-
if (filter_level->parent_elt)
filter_level->parent_elt->children = NULL;
else
filter_level = NULL;
}
+/* Creates paths suitable for accessing the child model. */
static GtkTreePath *
gtk_tree_model_filter_elt_get_path (FilterLevel *level,
FilterElt *elt,
return FALSE;
}
- /* no filter thing set, so always visible */
+ /* no visible function set, so always visible */
return TRUE;
}
}
}
+static FilterElt *
+gtk_tree_model_filter_get_nth (GtkTreeModelFilter *filter,
+ FilterLevel *level,
+ int n)
+{
+ if (level->array->len <= n)
+ return NULL;
+
+ return &g_array_index (level->array, FilterElt, n);
+}
+
+static FilterElt *
+gtk_tree_model_filter_get_nth_visible (GtkTreeModelFilter *filter,
+ FilterLevel *level,
+ int n)
+{
+ int i = 0;
+ FilterElt *elt;
+
+ if (level->visible_nodes <= n)
+ return NULL;
+
+ elt = FILTER_ELT (level->array->data);
+ while (!elt->visible)
+ elt++;
+
+ while (i < n)
+ {
+ if (elt->visible)
+ i++;
+ elt++;
+ }
+
+ while (!elt->visible)
+ elt++;
+
+ return elt;
+}
+
static FilterElt *
gtk_tree_model_filter_fetch_child (GtkTreeModelFilter *filter,
FilterLevel *level,
g_array_insert_val (level->array, i, elt);
*index = i;
- if (i > 0)
- i--;
-
- for ( ; i < level->array->len; i++)
+ 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;
}
+ c_iter.stamp = filter->priv->stamp;
+ c_iter.user_data = level;
+ c_iter.user_data2 = &g_array_index (level->array, FilterElt, *index);
+
+ if (level->parent_level || filter->priv->virtual_root)
+ gtk_tree_model_filter_ref_node (GTK_TREE_MODEL (filter), &c_iter);
+
return &g_array_index (level->array, FilterElt, *index);
}
static void
gtk_tree_model_filter_remove_node (GtkTreeModelFilter *filter,
- GtkTreeIter *iter,
- gboolean emit_signal)
+ GtkTreeIter *iter)
{
FilterElt *elt, *parent;
FilterLevel *level, *parent_level;
- gint offset, i, length, level_refcount;
+ gint i, length;
- /* FIXME: this function is very ugly. I need to rethink and
- * rewrite it someday.
- */
+ gboolean emit_child_toggled = FALSE;
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)
- gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
- iter, FALSE);
+ /* we distinguish a couple of cases:
+ * - root level, length > 1: emit row-deleted and remove.
+ * - root level, length == 1: emit row-deleted and keep in cache.
+ * - level, length == 1: parent->ref_count > 1: emit row-deleted and keep.
+ * - level, length > 1: emit row-deleted and remove.
+ * - else, remove level.
+ *
+ * if level != root level and visible nodes == 0, emit row-has-child-toggled.
+ */
- level_refcount = level->ref_count;
+ if (level != filter->priv->root && level->visible_nodes == 0)
+ emit_child_toggled = TRUE;
- /* do the ref counting first! this touches the stamp */
- if (emit_signal)
+ if (length > 1)
{
GtkTreePath *path;
+ FilterElt *tmp;
+
+ /* we emit row-deleted, and remove the node from the cache.
+ */
path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter);
+ elt->visible = FALSE;
gtk_tree_model_filter_increment_stamp (filter);
+ iter->stamp = filter->priv->stamp;
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->priv->root)
- {
- /* above code destroyed the level */
- goto emit_has_child_toggled;
- }
-
- if (length == 1)
- {
- /* kill the level */
- gtk_tree_model_filter_free_level (filter, level);
+ while (elt->ref_count > 1)
+ gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
+ iter, FALSE);
- if (!filter->priv->root)
- /* we killed the root */
- return;
- }
- else
- {
- FilterElt *tmp;
+ if (parent_level || filter->priv->virtual_root)
+ gtk_tree_model_filter_unref_node (GTK_TREE_MODEL (filter), iter);
+ else if (elt->ref_count > 0)
+ gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
+ iter, FALSE);
/* remove the node */
tmp = bsearch_elt_with_offset (level->array, elt->offset, &i);
}
}
}
+ else if ((length == 1 && parent && parent->ref_count > 1)
+ || (length == 1 && level == filter->priv->root))
+ {
+ GtkTreePath *path;
+
+ /* we emit row-deleted, but keep the node in the cache and
+ * referenced.
+ */
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter);
+ elt->visible = FALSE;
+ gtk_tree_model_filter_increment_stamp (filter);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter), path);
+ gtk_tree_path_free (path);
+ }
+ else
+ {
+ GtkTreePath *path;
-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->priv->root))
+ /* blow level away */
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter);
+ elt->visible = FALSE;
+ gtk_tree_model_filter_increment_stamp (filter);
+ iter->stamp = filter->priv->stamp;
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter), path);
+ gtk_tree_path_free (path);
+
+ while (elt->ref_count > 1)
+ gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
+ iter, FALSE);
+
+ gtk_tree_model_filter_free_level (filter, level);
+ }
+
+ if (emit_child_toggled)
{
- /* latest child has been removed, level has been destroyed */
GtkTreeIter piter;
GtkTreePath *ppath;
if (path)
{
- gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path);
+ gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (filter),
+ &iter, path);
current_state = FILTER_ELT (iter.user_data2)->visible;
}
else
if (current_state == TRUE && requested_state == FALSE)
{
/* get rid of this node */
- gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path);
-
level = FILTER_LEVEL (iter.user_data);
+ level->visible_nodes--;
- if (!level->parent_level)
- filter->priv->root_level_visible--;
-
- gtk_tree_model_filter_remove_node (filter, &iter, TRUE);
+ gtk_tree_model_filter_remove_node (filter, &iter);
goto done;
}
if (current_state == TRUE && requested_state == TRUE)
{
- /* progate the signal */
- gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path);
+ /* propagate the signal; also get a path taking only visible
+ * nodes into account.
+ */
+ gtk_tree_path_free (path);
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter);
gtk_tree_model_row_changed (GTK_TREE_MODEL (filter), path, &iter);
level = FILTER_LEVEL (iter.user_data);
gint i;
FilterLevel *root;
- gtk_tree_model_filter_build_level (filter, NULL, NULL);
+ gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
root = FILTER_LEVEL (filter->priv->root);
{
for (i = 0; i < root->array->len; i++)
g_array_index (root->array, FilterElt, i).visible = FALSE;
- filter->priv->root_level_visible = 0;
+ root->visible_nodes = 0;
}
}
/* parent is probably being filtered out */
goto done;
- gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path);
+ gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (filter), &iter, path);
level = FILTER_LEVEL (iter.user_data);
elt = FILTER_ELT (iter.user_data2);
- elt->visible = TRUE;
+ /* elt->visible can be TRUE at this point if it was pulled in above */
+ if (!elt->visible)
+ {
+ elt->visible = TRUE;
+ level->visible_nodes++;
+ }
- if (!level->parent_level)
- filter->priv->root_level_visible++;
+ if ((level->parent_elt && level->parent_elt->visible) || !level->parent_elt)
+ {
+ /* visibility changed -- reget path */
+ gtk_tree_path_free (path);
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter);
- /* update stamp */
- gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter), path, &iter);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter), path, &iter);
- if (gtk_tree_model_iter_children (c_model, &children, c_iter))
- gtk_tree_model_filter_update_children (filter, level, elt);
+ if (gtk_tree_model_iter_children (c_model, &children, c_iter))
+ gtk_tree_model_filter_update_children (filter, level, elt);
+ }
done:
if (path)
FilterLevel *level;
FilterLevel *parent_level;
- gint i = 0, offset, index = -1;
+ gint i = 0, offset;
gboolean free_c_path = FALSE;
{
gint level;
gint *v_indices, *c_indices;
+ gboolean common_prefix = TRUE;
level = gtk_tree_path_get_depth (c_path) - 1;
v_indices = gtk_tree_path_get_indices (filter->priv->virtual_root);
c_indices = gtk_tree_path_get_indices (c_path);
- if (v_indices[level] >= c_indices[level])
+ for (i = 0; i < level; i++)
+ if (v_indices[i] != c_indices[i])
+ {
+ common_prefix = FALSE;
+ break;
+ }
+
+ if (common_prefix && v_indices[level] >= c_indices[level])
(v_indices[level])++;
}
}
if (!filter->priv->root)
{
- gtk_tree_model_filter_build_level (filter, NULL, NULL);
- /* that already put the inserted iter in the level */
+ /* build level will pull in the new child */
+ gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
- goto done_and_emit;
+ if (filter->priv->root
+ && FILTER_LEVEL (filter->priv->root)->visible_nodes)
+ goto done_and_emit;
+ else
+ goto done;
}
parent_level = level = FILTER_LEVEL (filter->priv->root);
{
real_path = gtk_tree_model_filter_remove_root (c_path,
filter->priv->virtual_root);
- /* not our kiddo */
+ /* not our child */
if (!real_path)
goto done;
}
if (g_array_index (level->array, FilterElt, i).offset > offset)
break;
+ level->visible_nodes++;
+
g_array_insert_val (level->array, i, felt);
- index = i;
- if (!level->parent_level)
- filter->priv->root_level_visible++;
+ if (level->parent_level || filter->priv->virtual_root)
+ {
+ GtkTreeIter f_iter;
+
+ f_iter.stamp = filter->priv->stamp;
+ f_iter.user_data = level;
+ f_iter.user_data2 = &g_array_index (level->array, FilterElt, i);
+
+ gtk_tree_model_filter_ref_node (GTK_TREE_MODEL (filter), &f_iter);
+ }
}
/* another iteration to update the references of children to parents. */
gtk_tree_model_filter_increment_stamp (filter);
- gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path);
+ gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (data), &iter, path);
+
+ /* get a path taking only visible nodes into account */
+ gtk_tree_path_free (path);
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (data), &iter);
+
gtk_tree_model_row_inserted (GTK_TREE_MODEL (data), path, &iter);
gtk_tree_path_free (path);
GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (data);
GtkTreePath *path;
GtkTreeIter iter;
+ FilterLevel *level;
+ FilterElt *elt;
g_return_if_fail (c_path != NULL && c_iter != NULL);
- /* FIXME: does this code work? */
+ /* If we get row-has-child-toggled on the virtual root, and there is
+ * no root level; try to build it now.
+ */
+ if (filter->priv->virtual_root && !filter->priv->root
+ && !gtk_tree_path_compare (c_path, filter->priv->virtual_root))
+ {
+ gtk_tree_model_filter_build_level (filter, NULL, NULL, TRUE);
+ return;
+ }
if (!gtk_tree_model_filter_visible (filter, c_iter))
return;
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_model_filter_get_iter_full (GTK_TREE_MODEL (data), &iter, path);
gtk_tree_path_free (path);
+
+ level = FILTER_LEVEL (iter.user_data);
+ elt = FILTER_ELT (iter.user_data2);
+
+ g_assert (elt->visible);
+
+ /* If this node is referenced and has children, build the level so we
+ * can monitor it for changes.
+ */
+ if (elt->ref_count > 1 && gtk_tree_model_iter_has_child (c_model, c_iter))
+ gtk_tree_model_filter_build_level (filter, level, elt, TRUE);
+
+ /* get a path taking only visible nodes into account */
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (data), &iter);
+ gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data), path, &iter);
+ gtk_tree_path_free (path);
}
static void
GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (data);
GtkTreePath *path;
GtkTreeIter iter;
- FilterElt *elt;
- FilterLevel *level;
+ FilterElt *elt, *parent = NULL;
+ FilterLevel *level, *parent_level = NULL;
+ gboolean emit_child_toggled = FALSE;
gint offset;
- gboolean emit_signal = TRUE;
gint i;
g_return_if_fail (c_path != NULL);
GtkTreePath *path;
FilterLevel *level = FILTER_LEVEL (filter->priv->root);
+ gtk_tree_model_filter_unref_path (filter, filter->priv->virtual_root);
+ filter->priv->virtual_root_deleted = TRUE;
+
if (!level)
return;
path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, 0);
- for (i = 0; i < level->array->len; i++)
+ for (i = 0; i < level->visible_nodes; i++)
gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path);
gtk_tree_path_free (path);
{
gint level;
gint *v_indices, *c_indices;
+ gboolean common_prefix = TRUE;
level = gtk_tree_path_get_depth (c_path) - 1;
v_indices = gtk_tree_path_get_indices (filter->priv->virtual_root);
c_indices = gtk_tree_path_get_indices (c_path);
- if (v_indices[level] > c_indices[level])
+ for (i = 0; i < level; i++)
+ if (v_indices[i] != c_indices[i])
+ {
+ common_prefix = FALSE;
+ break;
+ }
+
+ if (common_prefix && v_indices[level] > c_indices[level])
(v_indices[level])--;
}
}
if (!path)
{
- /* fixup the offsets */
+ /* The node deleted in the child model is not visible in the
+ * filter model. We will not emit a signal, just fixup the offsets
+ * of the other nodes.
+ */
GtkTreePath *real_path;
if (!filter->priv->root)
i = 0;
if (gtk_tree_path_get_depth (real_path) - 1 >= 1)
{
+ /* find the level where the deletion occurred */
while (i < gtk_tree_path_get_depth (real_path) - 1)
{
gint j;
if (!level)
return;
- /* we need:
- * - the offset of the removed item
- * - the level
- */
+ /* decrease offset of all nodes following the deleted node */
for (i = 0; i < level->array->len; i++)
{
elt = &g_array_index (level->array, FilterElt, i);
return;
}
- gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path);
+ /* a node was deleted, which was in our cache */
+ gtk_tree_model_filter_get_iter_full (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->priv->root_level_visible--;
-
- if (emit_signal)
+ if (elt->visible)
{
- if (level->ref_count == 0 && level != filter->priv->root)
- {
- gtk_tree_model_filter_increment_stamp (filter);
- gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path);
+ /* get a path taking only visible nodes into account */
+ gtk_tree_path_free (path);
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter);
- gtk_tree_path_free (path);
- return;
+ level->visible_nodes--;
+
+ if (level->visible_nodes == 0)
+ {
+ emit_child_toggled = TRUE;
+ parent_level = level->parent_level;
+ parent = level->parent_elt;
}
+ /* emit row_deleted */
gtk_tree_model_filter_increment_stamp (filter);
gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path);
iter.stamp = filter->priv->stamp;
-
- while (elt->ref_count > 0)
- gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter,
- FALSE);
}
+ /* The filter model's reference on the child node is released
+ * below.
+ */
+ while (elt->ref_count > 1)
+ gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter,
+ FALSE);
+
if (level->array->len == 1)
{
/* kill level */
{
FilterElt *tmp;
+ /* release the filter model's reference on the node */
+ if (level->parent_level || filter->priv->virtual_root)
+ gtk_tree_model_filter_unref_node (GTK_TREE_MODEL (filter), &iter);
+ else if (elt->ref_count > 0)
+ gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter,
+ FALSE);
+
/* remove the row */
tmp = bsearch_elt_with_offset (level->array, elt->offset, &i);
}
}
+ if (emit_child_toggled && parent_level)
+ {
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ iter.stamp = filter->priv->stamp;
+ iter.user_data = parent_level;
+ iter.user_data2 = parent;
+
+ /* We set in_row_deleted to TRUE to avoid a level build triggered
+ * by row-has-child-toggled (parent model could call iter_has_child
+ * for example).
+ */
+ filter->priv->in_row_deleted = TRUE;
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter);
+ gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
+ path, &iter);
+ gtk_tree_path_free (path);
+ filter->priv->in_row_deleted = FALSE;
+ }
+
gtk_tree_path_free (path);
}
if (c_path == NULL || gtk_tree_path_get_indices (c_path) == NULL)
{
- if (!filter->priv->root)
- return;
-
length = gtk_tree_model_iter_n_children (c_model, NULL);
if (filter->priv->virtual_root)
/* virtual root anchor reordering */
if (filter->priv->virtual_root &&
- gtk_tree_path_get_depth (c_path) <
- gtk_tree_path_get_depth (filter->priv->virtual_root))
+ gtk_tree_path_is_ancestor (c_path, filter->priv->virtual_root))
{
gint new_pos = -1;
gint length;
c_path,
FALSE,
FALSE);
+
if (!path && filter->priv->virtual_root &&
gtk_tree_path_compare (c_path, filter->priv->virtual_root))
return;
}
else
{
- gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path);
+ gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (data),
+ &iter, path);
level = FILTER_LEVEL (iter.user_data);
elt = FILTER_ELT (iter.user_data2);
}
}
- if (level->array->len < 1)
+ if (!level || level->array->len < 1)
{
gtk_tree_path_free (path);
return;
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);
+ {
+ /* get a path taking only visible nodes into account */
+ gtk_tree_path_free (path);
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (data), &iter);
+
+ gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, &iter,
+ tmp_array);
+ }
/* done */
g_free (tmp_array);
return gtk_tree_model_get_column_type (filter->priv->child_model, index);
}
+/* A special case of _get_iter; this function can also get iters which
+ * are not visible. These iters should ONLY be passed internally, never
+ * pass those along with a signal emission.
+ */
+static gboolean
+gtk_tree_model_filter_get_iter_full (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
+ gint *indices;
+ FilterLevel *level;
+ FilterElt *elt;
+ gint depth, i;
+ g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
+ g_return_val_if_fail (filter->priv->child_model != NULL, FALSE);
+
+ indices = gtk_tree_path_get_indices (path);
+
+ if (filter->priv->root == NULL)
+ gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
+ level = FILTER_LEVEL (filter->priv->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;
+ }
+
+ elt = gtk_tree_model_filter_get_nth (filter, level, indices[i]);
+
+ if (!elt->children)
+ gtk_tree_model_filter_build_level (filter, level, elt, FALSE);
+ level = elt->children;
+ }
+
+ if (!level || indices[i] >= level->array->len)
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
+
+ iter->stamp = filter->priv->stamp;
+ iter->user_data = level;
+
+ elt = gtk_tree_model_filter_get_nth (filter, level, indices[depth - 1]);
+ iter->user_data2 = elt;
+
+ return TRUE;
+}
+
static gboolean
gtk_tree_model_filter_get_iter (GtkTreeModel *model,
GtkTreeIter *iter,
GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
gint *indices;
FilterLevel *level;
+ FilterElt *elt;
gint depth, i;
-
g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
g_return_val_if_fail (filter->priv->child_model != NULL, FALSE);
indices = gtk_tree_path_get_indices (path);
if (filter->priv->root == NULL)
- gtk_tree_model_filter_build_level (filter, NULL, NULL);
+ gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
level = FILTER_LEVEL (filter->priv->root);
depth = gtk_tree_path_get_depth (path);
for (i = 0; i < depth - 1; i++)
{
- if (!level || indices[i] >= level->array->len)
+ if (!level || indices[i] >= level->visible_nodes)
{
return FALSE;
}
- if (!g_array_index (level->array, FilterElt, indices[i]).children)
- gtk_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;
+ elt = gtk_tree_model_filter_get_nth_visible (filter, level, indices[i]);
+
+ if (!elt->children)
+ gtk_tree_model_filter_build_level (filter, level, elt, FALSE);
+ level = elt->children;
}
- if (!level || indices[i] >= level->array->len)
+ if (!level || indices[i] >= level->visible_nodes)
{
iter->stamp = 0;
return FALSE;
iter->stamp = filter->priv->stamp;
iter->user_data = level;
- iter->user_data2 = &g_array_index (level->array, FilterElt,
- indices[depth - 1]);
+
+ elt = gtk_tree_model_filter_get_nth_visible (filter, level,
+ indices[depth - 1]);
+ iter->user_data2 = elt;
return TRUE;
}
level = iter->user_data;
elt = iter->user_data2;
+ if (!elt->visible)
+ return NULL;
+
while (level)
{
- gtk_tree_path_prepend_index (retval,
- elt - FILTER_ELT (level->array->data));
+ int i = 0, index = 0;
+
+ while (&g_array_index (level->array, FilterElt, i) != elt)
+ {
+ if (g_array_index (level->array, FilterElt, i).visible)
+ index++;
+ i++;
+
+ g_assert (i < level->array->len);
+ }
+
+ gtk_tree_path_prepend_index (retval, index);
elt = level->parent_elt;
level = level->parent_level;
}
gtk_tree_model_filter_iter_next (GtkTreeModel *model,
GtkTreeIter *iter)
{
+ int i;
FilterLevel *level;
FilterElt *elt;
level = iter->user_data;
elt = iter->user_data2;
- if (elt - FILTER_ELT (level->array->data) >= level->array->len - 1)
+ i = elt - FILTER_ELT (level->array->data);
+
+ while (i < level->array->len - 1)
{
- iter->stamp = 0;
- return FALSE;
+ i++;
+ elt++;
+
+ if (elt->visible)
+ {
+ iter->user_data2 = elt;
+ return TRUE;
+ }
}
- iter->user_data2 = elt + 1;
+ /* no next visible iter */
+ iter->stamp = 0;
- return TRUE;
+ return FALSE;
}
static gboolean
if (!parent)
{
+ int i = 0;
+
if (!filter->priv->root)
- gtk_tree_model_filter_build_level (filter, NULL, NULL);
+ gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
if (!filter->priv->root)
return FALSE;
level = filter->priv->root;
+
+ if (!level->visible_nodes)
+ return FALSE;
+
iter->stamp = filter->priv->stamp;
iter->user_data = level;
- iter->user_data2 = level->array->data;
+
+ while (i < level->array->len)
+ {
+ if (!g_array_index (level->array, FilterElt, i).visible)
+ {
+ i++;
+ continue;
+ }
+
+ iter->user_data2 = &g_array_index (level->array, FilterElt, i);
+ return TRUE;
+ }
+
+ iter->stamp = 0;
+ return FALSE;
}
else
{
+ int i = 0;
+
if (FILTER_ELT (parent->user_data2)->children == NULL)
gtk_tree_model_filter_build_level (filter,
FILTER_LEVEL (parent->user_data),
- FILTER_ELT (parent->user_data2));
+ FILTER_ELT (parent->user_data2),
+ FALSE);
if (FILTER_ELT (parent->user_data2)->children == NULL)
return FALSE;
- /* empty array? */
- if (FILTER_ELT (parent->user_data2)->children->array->len <= 0)
+ if (FILTER_ELT (parent->user_data2)->children->visible_nodes <= 0)
return FALSE;
iter->stamp = filter->priv->stamp;
iter->user_data = FILTER_ELT (parent->user_data2)->children;
- iter->user_data2 = FILTER_LEVEL (iter->user_data)->array->data;
+
+ level = FILTER_LEVEL (iter->user_data);
+
+ while (i < level->array->len)
+ {
+ if (!g_array_index (level->array, FilterElt, i).visible)
+ {
+ i++;
+ continue;
+ }
+
+ iter->user_data2 = &g_array_index (level->array, FilterElt, i);
+ return TRUE;
+ }
+
+ iter->stamp = 0;
+ return FALSE;
}
- return TRUE;
+ iter->stamp = 0;
+ return FALSE;
}
static gboolean
gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_iter, iter);
elt = FILTER_ELT (iter->user_data2);
+ if (!elt->visible)
+ return FALSE;
+
/* 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->priv->child_model, &child_iter))
gtk_tree_model_filter_build_level (filter, FILTER_LEVEL (iter->user_data),
- elt);
+ elt, FALSE);
- /* FIXME: we should prolly count the visible nodes here, just like in
- * _iter_n_children.
- */
- if (elt->children && elt->children->array->len > 0)
+ if (elt->children && elt->children->visible_nodes > 0)
return TRUE;
return FALSE;
if (!iter)
{
if (!filter->priv->root)
- gtk_tree_model_filter_build_level (filter, NULL, NULL);
+ gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
+
+ if (filter->priv->root)
+ return FILTER_LEVEL (filter->priv->root)->visible_nodes;
- /* count visible nodes */
- return filter->priv->root_level_visible;
+ return 0;
}
elt = FILTER_ELT (iter->user_data2);
+
+ if (!elt->visible)
+ return 0;
+
gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_iter, iter);
if (!elt->children &&
gtk_tree_model_iter_has_child (filter->priv->child_model, &child_iter))
gtk_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++;
+ elt, FALSE);
- return count;
- }
+ if (elt->children)
+ return elt->children->visible_nodes;
return 0;
}
GtkTreeIter *parent,
gint n)
{
+ FilterElt *elt;
FilterLevel *level;
GtkTreeIter children;
if (parent)
g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == parent->stamp, FALSE);
- /* use this instead of has_Child to force us to build the level, if needed */
+ /* use this instead of has_child to force us to build the level, if needed */
if (gtk_tree_model_filter_iter_children (model, &children, parent) == FALSE)
{
iter->stamp = 0;
}
level = children.user_data;
- if (n >= level->array->len)
+ elt = FILTER_ELT (level->array->data);
+
+ if (n >= level->visible_nodes)
{
iter->stamp = 0;
return FALSE;
}
+ elt = gtk_tree_model_filter_get_nth_visible (GTK_TREE_MODEL_FILTER (model),
+ level, n);
+
iter->stamp = GTK_TREE_MODEL_FILTER (model)->priv->stamp;
iter->user_data = level;
- iter->user_data2 = &g_array_index (level->array, FilterElt, n);
+ iter->user_data2 = elt;
return TRUE;
}
FilterElt *parent_elt = level->parent_elt;
/* we were at zero -- time to decrease the zero_ref_count val */
- do
+ while (parent_level)
{
- if (parent_elt)
- parent_elt->zero_ref_count--;
+ parent_elt->zero_ref_count--;
- if (parent_level)
- {
- parent_elt = parent_level->parent_elt;
- parent_level = parent_level->parent_level;
- }
+ parent_elt = parent_level->parent_elt;
+ parent_level = parent_level->parent_level;
}
- while (parent_level);
- filter->priv->zero_ref_count--;
+
+ if (filter->priv->root != level)
+ filter->priv->zero_ref_count--;
}
}
parent_elt = parent_level->parent_elt;
parent_level = parent_level->parent_level;
}
- filter->priv->zero_ref_count++;
+
+ if (filter->priv->root != level)
+ filter->priv->zero_ref_count++;
}
}
filter->priv->root = NULL;
g_object_unref (filter->priv->child_model);
filter->priv->visible_column = -1;
- /* FIXME: destroy more crack here? the funcs? */
+
+ /* FIXME: do we need to destroy more here? */
}
filter->priv->child_model = child_model;
}
}
+static void
+gtk_tree_model_filter_ref_path (GtkTreeModelFilter *filter,
+ GtkTreePath *path)
+{
+ int len;
+ GtkTreePath *p;
+
+ len = gtk_tree_path_get_depth (path);
+ p = gtk_tree_path_copy (path);
+ while (len--)
+ {
+ GtkTreeIter iter;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (filter->priv->child_model), &iter, p);
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (filter->priv->child_model), &iter);
+ gtk_tree_path_up (p);
+ }
+
+ gtk_tree_path_free (p);
+}
+
+static void
+gtk_tree_model_filter_unref_path (GtkTreeModelFilter *filter,
+ GtkTreePath *path)
+{
+ int len;
+ GtkTreePath *p;
+
+ len = gtk_tree_path_get_depth (path);
+ p = gtk_tree_path_copy (path);
+ while (len--)
+ {
+ GtkTreeIter iter;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (filter->priv->child_model), &iter, p);
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (filter->priv->child_model), &iter);
+ gtk_tree_path_up (p);
+ }
+
+ gtk_tree_path_free (p);
+}
+
static void
gtk_tree_model_filter_set_root (GtkTreeModelFilter *filter,
GtkTreePath *root)
GtkTreePath *root)
{
GtkTreeModel *retval;
+ GtkTreeModelFilter *filter;
g_return_val_if_fail (GTK_IS_TREE_MODEL (child_model), NULL);
"virtual-root", root,
NULL);
+ filter = GTK_TREE_MODEL_FILTER (retval);
+ if (filter->priv->virtual_root)
+ {
+ gtk_tree_model_filter_ref_path (filter, filter->priv->virtual_root);
+ filter->priv->virtual_root_deleted = FALSE;
+ }
+
return retval;
}
* @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.
+ * row pointed at by @child_iter. If @filter_iter was not set, %FALSE is
+ * returned.
+ *
+ * Return value: %TRUE, if @filter_iter was set, i.e. if @child_iter is a
+ * valid iterator pointing to a visible row in child model.
*
* Since: 2.4
*/
-void
+gboolean
gtk_tree_model_filter_convert_child_iter_to_iter (GtkTreeModelFilter *filter,
GtkTreeIter *filter_iter,
GtkTreeIter *child_iter)
{
+ gboolean ret;
GtkTreePath *child_path, *path;
- g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
- g_return_if_fail (filter->priv->child_model != NULL);
- g_return_if_fail (filter_iter != NULL);
- g_return_if_fail (child_iter != NULL);
+ g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (filter), FALSE);
+ g_return_val_if_fail (filter->priv->child_model != NULL, FALSE);
+ g_return_val_if_fail (filter_iter != NULL, FALSE);
+ g_return_val_if_fail (child_iter != NULL, FALSE);
filter_iter->stamp = 0;
child_path = gtk_tree_model_get_path (filter->priv->child_model, child_iter);
- g_return_if_fail (child_path != NULL);
+ g_return_val_if_fail (child_path != NULL, FALSE);
path = gtk_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);
+ if (!path)
+ return FALSE;
+
+ ret = gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), filter_iter, path);
gtk_tree_path_free (path);
+
+ return ret;
}
/**
}
}
+/* The path returned can only be used internally in the filter model. */
static GtkTreePath *
gtk_real_tree_model_filter_convert_child_path_to_path (GtkTreeModelFilter *filter,
GtkTreePath *child_path,
child_indices = gtk_tree_path_get_indices (real_path);
if (filter->priv->root == NULL && build_levels)
- gtk_tree_model_filter_build_level (filter, NULL, NULL);
+ gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
level = FILTER_LEVEL (filter->priv->root);
for (i = 0; i < gtk_tree_path_get_depth (real_path); i++)
{
gtk_tree_path_append_index (retval, j);
if (!tmp->children && build_levels)
- gtk_tree_model_filter_build_level (filter, level, tmp);
+ gtk_tree_model_filter_build_level (filter, level, tmp, FALSE);
level = tmp->children;
found_child = TRUE;
}
gtk_tree_path_append_index (retval, j);
if (!tmp->children && build_levels)
- gtk_tree_model_filter_build_level (filter, level, tmp);
+ gtk_tree_model_filter_build_level (filter, level, tmp, FALSE);
level = tmp->children;
found_child = TRUE;
}
* 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.
+ * child model or points to a row which is not visible in @filter, then %NULL
+ * is returned.
*
* Return value: A newly allocated #GtkTreePath, or %NULL.
*
gtk_tree_model_filter_convert_child_path_to_path (GtkTreeModelFilter *filter,
GtkTreePath *child_path)
{
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
/* this function does the sanity checks */
- return gtk_real_tree_model_filter_convert_child_path_to_path (filter,
+ path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
child_path,
TRUE,
TRUE);
+
+ if (!path)
+ return NULL;
+
+ /* get a new path which only takes visible nodes into account.
+ * -- if this gives any performance issues, we can write a special
+ * version of convert_child_path_to_path immediately returning
+ * a visible-nodes-only path.
+ */
+ gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (filter), &iter, path);
+
+ gtk_tree_path_free (path);
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter);
+
+ return path;
}
/**
retval = gtk_tree_path_new ();
filter_indices = gtk_tree_path_get_indices (filter_path);
if (!filter->priv->root)
- gtk_tree_model_filter_build_level (filter, NULL, NULL);
+ gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
level = FILTER_LEVEL (filter->priv->root);
for (i = 0; i < gtk_tree_path_get_depth (filter_path); i++)
{
- gint count = filter_indices[i];
+ FilterElt *elt;
- if (!level || level->array->len <= filter_indices[i])
+ if (!level || level->visible_nodes <= filter_indices[i])
{
gtk_tree_path_free (retval);
return NULL;
}
- if (g_array_index (level->array, FilterElt, count).children == NULL)
- gtk_tree_model_filter_build_level (filter, level, &g_array_index (level->array, FilterElt, count));
+ elt = gtk_tree_model_filter_get_nth_visible (filter, level,
+ filter_indices[i]);
+
+ if (elt->children == NULL)
+ gtk_tree_model_filter_build_level (filter, level, elt, FALSE);
- if (!level || level->array->len <= filter_indices[i])
+ if (!level || level->visible_nodes <= 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;
+ gtk_tree_path_append_index (retval, elt->offset);
+ level = elt->children;
}
/* apply vroot */
* 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.
+ * all unreffed iters will be invalid.
*
* Since: 2.4
*/
{
g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
- if (filter->priv->zero_ref_count)
+ if (filter->priv->zero_ref_count > 0)
gtk_tree_model_filter_clear_cache_helper (filter,
FILTER_LEVEL (filter->priv->root));
}