1 /* gtktreemodelfilter.c
2 * Copyright (C) 2000,2001 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
3 * Copyright (C) 2001-2003 Kristian Rietveld <kris@gtk.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 #include "gtktreemodelfilter.h"
24 #include "gtktreednd.h"
25 #include "gtkprivate.h"
30 * SECTION:gtktreemodelfilter
31 * @Short_description: A GtkTreeModel which hides parts of an underlying tree model
32 * @Title: GtkTreeModelFilter
33 * @See_also:#GtkTreeModelSort
35 * A #GtkTreeModelFilter is a tree model which wraps another tree model,
36 * and can do the following things:
39 * Filter specific rows, based on data from a "visible column", a column
40 * storing booleans indicating whether the row should be filtered or not,
41 * or based on the return value of a "visible function", which gets a
42 * model, iter and user_data and returns a boolean indicating whether the
43 * row should be filtered or not.
46 * Modify the "appearance" of the model, using a modify function.
47 * This is extremely powerful and allows for just changing
48 * some values and also for creating a completely different model based on
49 * the given child model.
52 * Set a different root node, also known as a "virtual root". You can pass in
53 * a #GtkTreePath indicating the root node for the filter at construction time.
61 * iter->stamp = filter->priv->stamp
62 * iter->user_data = FilterLevel
63 * iter->user_data2 = FilterElt
66 /* all paths, iters, etc prefixed with c_ are paths, iters, etc relative to the
71 * There are three model/views involved, so there are two mappings:
72 * * this model -> child model: mapped via offset in FilterElt.
73 * * this model -> parent model (or view): mapped via the array index
76 * Note that there are two kinds of paths relative to the filter model
77 * (those generated from the array indices): paths taking non-visible
78 * nodes into account, and paths which don't. Paths which take
79 * non-visible nodes into account should only be used internally and
80 * NEVER be passed along with a signal emission.
82 * The filter model has a reference on every node that is not in the root
83 * level and has a parent with ref_count > 1. Exception is a virtual root
84 * level; all nodes in the virtual root level are referenced too.
87 typedef struct _FilterElt FilterElt;
88 typedef struct _FilterLevel FilterLevel;
93 FilterLevel *children;
106 gint parent_elt_index;
107 FilterLevel *parent_level;
111 struct _GtkTreeModelFilterPrivate
113 GtkTreeModel *child_model;
115 GtkTreePath *virtual_root;
122 GtkTreeModelFilterVisibleFunc visible_func;
123 gpointer visible_data;
124 GDestroyNotify visible_destroy;
127 GtkTreeModelFilterModifyFunc modify_func;
128 gpointer modify_data;
129 GDestroyNotify modify_destroy;
130 gint modify_n_columns;
132 guint visible_method_set : 1;
133 guint modify_func_set : 1;
135 guint in_row_deleted : 1;
136 guint virtual_root_deleted : 1;
141 gulong has_child_toggled_id;
154 /* Set this to 0 to disable caching of child iterators. This
155 * allows for more stringent testing. It is recommended to set this
156 * to one when refactoring this code and running the unit tests to
160 # define GTK_TREE_MODEL_FILTER_CACHE_CHILD_ITERS(filter) \
161 (((GtkTreeModelFilter *)filter)->priv->child_flags & GTK_TREE_MODEL_ITERS_PERSIST)
163 # define GTK_TREE_MODEL_FILTER_CACHE_CHILD_ITERS(filter) (FALSE)
166 #define FILTER_ELT(filter_elt) ((FilterElt *)filter_elt)
167 #define FILTER_LEVEL(filter_level) ((FilterLevel *)filter_level)
169 #define FILTER_LEVEL_PARENT_ELT(level) (&g_array_index (FILTER_LEVEL ((level))->parent_level->array, FilterElt, FILTER_LEVEL ((level))->parent_elt_index))
170 #define FILTER_LEVEL_ELT_INDEX(level, elt) (FILTER_ELT ((elt)) - FILTER_ELT (FILTER_LEVEL ((level))->array->data))
172 /* general code (object/interface init, properties, etc) */
173 static void gtk_tree_model_filter_tree_model_init (GtkTreeModelIface *iface);
174 static void gtk_tree_model_filter_drag_source_init (GtkTreeDragSourceIface *iface);
175 static void gtk_tree_model_filter_finalize (GObject *object);
176 static void gtk_tree_model_filter_set_property (GObject *object,
180 static void gtk_tree_model_filter_get_property (GObject *object,
185 /* signal handlers */
186 static void gtk_tree_model_filter_row_changed (GtkTreeModel *c_model,
190 static void gtk_tree_model_filter_row_inserted (GtkTreeModel *c_model,
194 static void gtk_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model,
198 static void gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
201 static void gtk_tree_model_filter_rows_reordered (GtkTreeModel *c_model,
207 /* GtkTreeModel interface */
208 static GtkTreeModelFlags gtk_tree_model_filter_get_flags (GtkTreeModel *model);
209 static gint gtk_tree_model_filter_get_n_columns (GtkTreeModel *model);
210 static GType gtk_tree_model_filter_get_column_type (GtkTreeModel *model,
212 static gboolean gtk_tree_model_filter_get_iter_full (GtkTreeModel *model,
215 static gboolean gtk_tree_model_filter_get_iter (GtkTreeModel *model,
218 static GtkTreePath *gtk_tree_model_filter_get_path (GtkTreeModel *model,
220 static void gtk_tree_model_filter_get_value (GtkTreeModel *model,
224 static gboolean gtk_tree_model_filter_iter_next (GtkTreeModel *model,
226 static gboolean gtk_tree_model_filter_iter_previous (GtkTreeModel *model,
228 static gboolean gtk_tree_model_filter_iter_children (GtkTreeModel *model,
230 GtkTreeIter *parent);
231 static gboolean gtk_tree_model_filter_iter_has_child (GtkTreeModel *model,
233 static gint gtk_tree_model_filter_iter_n_children (GtkTreeModel *model,
235 static gboolean gtk_tree_model_filter_iter_nth_child (GtkTreeModel *model,
239 static gboolean gtk_tree_model_filter_iter_parent (GtkTreeModel *model,
242 static void gtk_tree_model_filter_ref_node (GtkTreeModel *model,
244 static void gtk_tree_model_filter_unref_node (GtkTreeModel *model,
247 /* TreeDragSource interface */
248 static gboolean gtk_tree_model_filter_row_draggable (GtkTreeDragSource *drag_source,
250 static gboolean gtk_tree_model_filter_drag_data_get (GtkTreeDragSource *drag_source,
252 GtkSelectionData *selection_data);
253 static gboolean gtk_tree_model_filter_drag_data_delete (GtkTreeDragSource *drag_source,
256 /* private functions */
257 static void gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
258 FilterLevel *parent_level,
259 gint parent_elt_index,
260 gboolean emit_inserted);
262 static void gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
263 FilterLevel *filter_level,
266 static GtkTreePath *gtk_tree_model_filter_elt_get_path (FilterLevel *level,
270 static GtkTreePath *gtk_tree_model_filter_add_root (GtkTreePath *src,
272 static GtkTreePath *gtk_tree_model_filter_remove_root (GtkTreePath *src,
275 static void gtk_tree_model_filter_increment_stamp (GtkTreeModelFilter *filter);
277 static void gtk_tree_model_filter_real_modify (GtkTreeModelFilter *self,
278 GtkTreeModel *child_model,
282 static gboolean gtk_tree_model_filter_real_visible (GtkTreeModelFilter *filter,
283 GtkTreeModel *child_model,
284 GtkTreeIter *child_iter);
285 static gboolean gtk_tree_model_filter_visible (GtkTreeModelFilter *filter,
286 GtkTreeIter *child_iter);
287 static void gtk_tree_model_filter_clear_cache_helper (GtkTreeModelFilter *filter,
290 static void gtk_tree_model_filter_real_unref_node (GtkTreeModel *model,
292 gboolean propagate_unref);
294 static void gtk_tree_model_filter_set_model (GtkTreeModelFilter *filter,
295 GtkTreeModel *child_model);
296 static void gtk_tree_model_filter_ref_path (GtkTreeModelFilter *filter,
298 static void gtk_tree_model_filter_unref_path (GtkTreeModelFilter *filter,
301 static void gtk_tree_model_filter_set_root (GtkTreeModelFilter *filter,
304 static GtkTreePath *gtk_real_tree_model_filter_convert_child_path_to_path (GtkTreeModelFilter *filter,
305 GtkTreePath *child_path,
306 gboolean build_levels,
307 gboolean fetch_children);
309 static FilterElt *gtk_tree_model_filter_get_nth (GtkTreeModelFilter *filter,
312 static gboolean gtk_tree_model_filter_elt_is_visible_in_target (FilterLevel *level,
314 static FilterElt *gtk_tree_model_filter_get_nth_visible (GtkTreeModelFilter *filter,
318 static FilterElt *gtk_tree_model_filter_insert_elt_in_level (GtkTreeModelFilter *filter,
323 static FilterElt *gtk_tree_model_filter_fetch_child (GtkTreeModelFilter *filter,
327 static void gtk_tree_model_filter_remove_elt_from_level (GtkTreeModelFilter *filter,
330 static void gtk_tree_model_filter_update_children (GtkTreeModelFilter *filter,
333 static FilterElt *bsearch_elt_with_offset (GArray *array,
336 static void gtk_tree_model_filter_emit_row_inserted_for_path (GtkTreeModelFilter *filter,
337 GtkTreeModel *c_model,
339 GtkTreeIter *c_iter);
342 G_DEFINE_TYPE_WITH_CODE (GtkTreeModelFilter, gtk_tree_model_filter, G_TYPE_OBJECT,
343 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
344 gtk_tree_model_filter_tree_model_init)
345 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
346 gtk_tree_model_filter_drag_source_init))
349 gtk_tree_model_filter_init (GtkTreeModelFilter *filter)
351 filter->priv = G_TYPE_INSTANCE_GET_PRIVATE (filter,
352 GTK_TYPE_TREE_MODEL_FILTER,
353 GtkTreeModelFilterPrivate);
355 filter->priv->visible_column = -1;
356 filter->priv->zero_ref_count = 0;
357 filter->priv->visible_method_set = FALSE;
358 filter->priv->modify_func_set = FALSE;
359 filter->priv->in_row_deleted = FALSE;
360 filter->priv->virtual_root_deleted = FALSE;
364 gtk_tree_model_filter_class_init (GtkTreeModelFilterClass *filter_class)
366 GObjectClass *object_class;
368 object_class = (GObjectClass *) filter_class;
370 object_class->set_property = gtk_tree_model_filter_set_property;
371 object_class->get_property = gtk_tree_model_filter_get_property;
373 object_class->finalize = gtk_tree_model_filter_finalize;
375 filter_class->visible = gtk_tree_model_filter_real_visible;
376 filter_class->modify = gtk_tree_model_filter_real_modify;
378 /* Properties -- FIXME: disabled translations for now, until I can come up with a
381 g_object_class_install_property (object_class,
383 g_param_spec_object ("child-model",
385 ("The model for the filtermodel to filter"),
387 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
389 g_object_class_install_property (object_class,
391 g_param_spec_boxed ("virtual-root",
392 ("The virtual root"),
393 ("The virtual root (relative to the child model) for this filtermodel"),
395 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
397 g_type_class_add_private (object_class, sizeof (GtkTreeModelFilterPrivate));
401 gtk_tree_model_filter_tree_model_init (GtkTreeModelIface *iface)
403 iface->get_flags = gtk_tree_model_filter_get_flags;
404 iface->get_n_columns = gtk_tree_model_filter_get_n_columns;
405 iface->get_column_type = gtk_tree_model_filter_get_column_type;
406 iface->get_iter = gtk_tree_model_filter_get_iter;
407 iface->get_path = gtk_tree_model_filter_get_path;
408 iface->get_value = gtk_tree_model_filter_get_value;
409 iface->iter_next = gtk_tree_model_filter_iter_next;
410 iface->iter_previous = gtk_tree_model_filter_iter_previous;
411 iface->iter_children = gtk_tree_model_filter_iter_children;
412 iface->iter_has_child = gtk_tree_model_filter_iter_has_child;
413 iface->iter_n_children = gtk_tree_model_filter_iter_n_children;
414 iface->iter_nth_child = gtk_tree_model_filter_iter_nth_child;
415 iface->iter_parent = gtk_tree_model_filter_iter_parent;
416 iface->ref_node = gtk_tree_model_filter_ref_node;
417 iface->unref_node = gtk_tree_model_filter_unref_node;
421 gtk_tree_model_filter_drag_source_init (GtkTreeDragSourceIface *iface)
423 iface->row_draggable = gtk_tree_model_filter_row_draggable;
424 iface->drag_data_delete = gtk_tree_model_filter_drag_data_delete;
425 iface->drag_data_get = gtk_tree_model_filter_drag_data_get;
430 gtk_tree_model_filter_finalize (GObject *object)
432 GtkTreeModelFilter *filter = (GtkTreeModelFilter *) object;
434 if (filter->priv->virtual_root && !filter->priv->virtual_root_deleted)
436 gtk_tree_model_filter_unref_path (filter, filter->priv->virtual_root,
438 filter->priv->virtual_root_deleted = TRUE;
441 gtk_tree_model_filter_set_model (filter, NULL);
443 if (filter->priv->virtual_root)
444 gtk_tree_path_free (filter->priv->virtual_root);
446 if (filter->priv->root)
447 gtk_tree_model_filter_free_level (filter, filter->priv->root, TRUE);
449 g_free (filter->priv->modify_types);
451 if (filter->priv->modify_destroy)
452 filter->priv->modify_destroy (filter->priv->modify_data);
454 if (filter->priv->visible_destroy)
455 filter->priv->visible_destroy (filter->priv->visible_data);
458 G_OBJECT_CLASS (gtk_tree_model_filter_parent_class)->finalize (object);
462 gtk_tree_model_filter_set_property (GObject *object,
467 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (object);
471 case PROP_CHILD_MODEL:
472 gtk_tree_model_filter_set_model (filter, g_value_get_object (value));
474 case PROP_VIRTUAL_ROOT:
475 gtk_tree_model_filter_set_root (filter, g_value_get_boxed (value));
478 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
484 gtk_tree_model_filter_get_property (GObject *object,
489 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (object);
493 case PROP_CHILD_MODEL:
494 g_value_set_object (value, filter->priv->child_model);
496 case PROP_VIRTUAL_ROOT:
497 g_value_set_boxed (value, filter->priv->virtual_root);
500 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
508 gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
509 FilterLevel *parent_level,
510 gint parent_elt_index,
511 gboolean emit_inserted)
514 GtkTreeIter first_node;
516 FilterElt *parent_elt = NULL;
517 FilterLevel *new_level;
521 g_assert (filter->priv->child_model != NULL);
523 if (filter->priv->in_row_deleted)
528 if (filter->priv->virtual_root)
530 if (gtk_tree_model_get_iter (filter->priv->child_model, &root, filter->priv->virtual_root) == FALSE)
532 length = gtk_tree_model_iter_n_children (filter->priv->child_model, &root);
534 if (gtk_tree_model_iter_children (filter->priv->child_model, &iter, &root) == FALSE)
539 if (!gtk_tree_model_get_iter_first (filter->priv->child_model, &iter))
541 length = gtk_tree_model_iter_n_children (filter->priv->child_model, NULL);
546 GtkTreeIter parent_iter;
547 GtkTreeIter child_parent_iter;
549 parent_elt = &g_array_index (parent_level->array, FilterElt, parent_elt_index);
551 parent_iter.stamp = filter->priv->stamp;
552 parent_iter.user_data = parent_level;
553 parent_iter.user_data2 = parent_elt;
555 gtk_tree_model_filter_convert_iter_to_child_iter (filter,
558 if (gtk_tree_model_iter_children (filter->priv->child_model, &iter, &child_parent_iter) == FALSE)
561 /* stamp may have changed */
562 gtk_tree_model_filter_convert_iter_to_child_iter (filter,
565 length = gtk_tree_model_iter_n_children (filter->priv->child_model, &child_parent_iter);
568 g_return_if_fail (length > 0);
570 new_level = g_new (FilterLevel, 1);
571 new_level->array = g_array_sized_new (FALSE, FALSE,
574 new_level->ref_count = 0;
575 new_level->visible_nodes = 0;
576 new_level->parent_elt_index = parent_elt_index;
577 new_level->parent_level = parent_level;
579 if (parent_elt_index >= 0)
580 parent_elt->children = new_level;
582 filter->priv->root = new_level;
584 /* increase the count of zero ref_counts */
587 g_array_index (parent_level->array, FilterElt, parent_elt_index).zero_ref_count++;
589 parent_elt_index = parent_level->parent_elt_index;
590 parent_level = parent_level->parent_level;
592 if (new_level != filter->priv->root)
593 filter->priv->zero_ref_count++;
601 if (gtk_tree_model_filter_visible (filter, &iter))
604 FilterElt filter_elt;
606 filter_elt.offset = i;
607 filter_elt.zero_ref_count = 0;
608 filter_elt.ref_count = 0;
609 filter_elt.children = NULL;
610 filter_elt.visible = TRUE;
612 if (GTK_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
613 filter_elt.iter = iter;
615 g_array_append_val (new_level->array, filter_elt);
616 new_level->visible_nodes++;
618 f_iter.stamp = filter->priv->stamp;
619 f_iter.user_data = new_level;
620 f_iter.user_data2 = &(g_array_index (new_level->array, FilterElt, new_level->array->len - 1));
622 if (new_level->parent_level || filter->priv->virtual_root)
623 gtk_tree_model_filter_ref_node (GTK_TREE_MODEL (filter), &f_iter);
628 GtkTreeIter children;
630 f_path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter),
632 gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter),
634 gtk_tree_path_free (f_path);
636 if (gtk_tree_model_iter_children (filter->priv->child_model,
638 gtk_tree_model_filter_update_children (filter,
640 FILTER_ELT (f_iter.user_data2));
645 while (gtk_tree_model_iter_next (filter->priv->child_model, &iter));
647 if (new_level->array->len == 0
648 && (new_level != filter->priv->root || filter->priv->virtual_root))
650 /* If none of the nodes are visible, we will just pull in the
651 * first node of the level and keep a reference on it. We need this
652 * to make sure that we get all signals for this level.
654 FilterElt filter_elt;
657 filter_elt.offset = 0;
658 filter_elt.zero_ref_count = 0;
659 filter_elt.ref_count = 0;
660 filter_elt.children = NULL;
661 filter_elt.visible = FALSE;
663 if (GTK_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
664 filter_elt.iter = first_node;
666 g_array_append_val (new_level->array, filter_elt);
668 f_iter.stamp = filter->priv->stamp;
669 f_iter.user_data = new_level;
670 f_iter.user_data2 = &(g_array_index (new_level->array, FilterElt, new_level->array->len - 1));
672 gtk_tree_model_filter_ref_node (GTK_TREE_MODEL (filter), &f_iter);
674 else if (new_level->array->len == 0)
675 gtk_tree_model_filter_free_level (filter, new_level, TRUE);
679 gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
680 FilterLevel *filter_level,
685 g_assert (filter_level);
687 for (i = 0; i < filter_level->array->len; i++)
689 if (g_array_index (filter_level->array, FilterElt, i).children)
690 gtk_tree_model_filter_free_level (filter,
691 FILTER_LEVEL (g_array_index (filter_level->array, FilterElt, i).children),
695 (filter_level->parent_level || filter->priv->virtual_root))
699 f_iter.stamp = filter->priv->stamp;
700 f_iter.user_data = filter_level;
701 f_iter.user_data2 = &(g_array_index (filter_level->array, FilterElt, i));
703 gtk_tree_model_filter_unref_node (GTK_TREE_MODEL (filter), &f_iter);
707 if (filter_level->ref_count == 0)
709 FilterLevel *parent_level = filter_level->parent_level;
710 gint parent_elt_index = filter_level->parent_elt_index;
714 g_array_index (parent_level->array, FilterElt, parent_elt_index).zero_ref_count--;
716 parent_elt_index = parent_level->parent_elt_index;
717 parent_level = parent_level->parent_level;
720 if (filter_level != filter->priv->root)
721 filter->priv->zero_ref_count--;
724 if (filter_level->parent_elt_index >= 0)
725 FILTER_LEVEL_PARENT_ELT (filter_level)->children = NULL;
727 filter->priv->root = NULL;
729 g_array_free (filter_level->array, TRUE);
730 filter_level->array = NULL;
732 g_free (filter_level);
736 /* Creates paths suitable for accessing the child model. */
738 gtk_tree_model_filter_elt_get_path (FilterLevel *level,
742 FilterLevel *walker = level;
743 FilterElt *walker2 = elt;
745 GtkTreePath *real_path;
747 g_return_val_if_fail (level != NULL, NULL);
748 g_return_val_if_fail (elt != NULL, NULL);
750 path = gtk_tree_path_new ();
754 gtk_tree_path_prepend_index (path, walker2->offset);
756 if (!walker->parent_level)
759 walker2 = FILTER_LEVEL_PARENT_ELT (walker);
760 walker = walker->parent_level;
765 real_path = gtk_tree_model_filter_add_root (path, root);
766 gtk_tree_path_free (path);
774 gtk_tree_model_filter_add_root (GtkTreePath *src,
780 retval = gtk_tree_path_copy (root);
782 for (i = 0; i < gtk_tree_path_get_depth (src); i++)
783 gtk_tree_path_append_index (retval, gtk_tree_path_get_indices (src)[i]);
789 gtk_tree_model_filter_remove_root (GtkTreePath *src,
797 if (gtk_tree_path_get_depth (src) <= gtk_tree_path_get_depth (root))
800 depth = gtk_tree_path_get_depth (src);
801 indices = gtk_tree_path_get_indices (src);
803 for (i = 0; i < gtk_tree_path_get_depth (root); i++)
804 if (indices[i] != gtk_tree_path_get_indices (root)[i])
807 retval = gtk_tree_path_new ();
809 for (; i < depth; i++)
810 gtk_tree_path_append_index (retval, indices[i]);
816 gtk_tree_model_filter_increment_stamp (GtkTreeModelFilter *filter)
820 filter->priv->stamp++;
822 while (filter->priv->stamp == 0);
824 gtk_tree_model_filter_clear_cache (filter);
828 gtk_tree_model_filter_real_visible (GtkTreeModelFilter *filter,
829 GtkTreeModel *child_model,
830 GtkTreeIter *child_iter)
832 if (filter->priv->visible_func)
834 return filter->priv->visible_func (child_model,
836 filter->priv->visible_data)
839 else if (filter->priv->visible_column >= 0)
843 gtk_tree_model_get_value (child_model, child_iter,
844 filter->priv->visible_column, &val);
846 if (g_value_get_boolean (&val))
848 g_value_unset (&val);
852 g_value_unset (&val);
856 /* no visible function set, so always visible */
861 gtk_tree_model_filter_visible (GtkTreeModelFilter *self,
862 GtkTreeIter *child_iter)
864 return GTK_TREE_MODEL_FILTER_GET_CLASS (self)->visible (self,
865 self->priv->child_model, child_iter);
869 gtk_tree_model_filter_clear_cache_helper (GtkTreeModelFilter *filter,
876 for (i = 0; i < level->array->len; i++)
878 if (g_array_index (level->array, FilterElt, i).zero_ref_count > 0)
879 gtk_tree_model_filter_clear_cache_helper (filter, g_array_index (level->array, FilterElt, i).children);
882 if (level->ref_count == 0 && level != filter->priv->root)
884 gtk_tree_model_filter_free_level (filter, level, TRUE);
890 gtk_tree_model_filter_get_nth (GtkTreeModelFilter *filter,
894 if (level->array->len <= n)
897 return &g_array_index (level->array, FilterElt, n);
901 gtk_tree_model_filter_elt_is_visible_in_target (FilterLevel *level,
909 if (level->parent_elt_index == -1)
914 elt_index = level->parent_elt_index;
915 level = level->parent_level;
918 && !g_array_index (level->array, FilterElt, elt_index).visible)
926 /* If a change has occurred in path (inserted, changed or deleted),
927 * then this function is used to check all its ancestors. An ancestor
928 * could have changed state as a result and this needs to be propagated
929 * to the objects monitoring the filter model.
932 gtk_tree_model_filter_check_ancestors (GtkTreeModelFilter *filter,
936 int *indices = gtk_tree_path_get_indices (path);
939 GtkTreeIter c_iter, tmp_iter;
941 level = FILTER_LEVEL (filter->priv->root);
946 if (filter->priv->virtual_root)
947 gtk_tree_model_get_iter (filter->priv->child_model, &c_iter,
948 filter->priv->virtual_root);
951 gtk_tree_model_iter_nth_child (filter->priv->child_model, &c_iter,
952 filter->priv->virtual_root ? &tmp_iter : NULL,
955 while (i < gtk_tree_path_get_depth (path) - 1)
958 gboolean requested_state;
960 elt = bsearch_elt_with_offset (level->array,
961 gtk_tree_path_get_indices (path)[i],
964 requested_state = gtk_tree_model_filter_visible (filter, &c_iter);
971 if (requested_state == FALSE)
974 /* The elt does not exist in this level (so it is not
975 * visible), but should now be visible. We emit the
976 * row-inserted and row-has-child-toggled signals.
978 elt = gtk_tree_model_filter_insert_elt_in_level (filter,
984 /* insert_elt_in_level defaults to FALSE */
986 level->visible_nodes++;
988 c_path = gtk_tree_model_get_path (filter->priv->child_model,
991 gtk_tree_model_filter_emit_row_inserted_for_path (filter,
992 filter->priv->child_model,
996 gtk_tree_path_free (c_path);
998 /* We can immediately return, because this node was not visible
999 * before and its children will be checked for in response to
1000 * the emitted row-has-child-toggled signal.
1004 else if (elt->visible)
1006 if (!requested_state)
1008 /* A node has turned invisible. Remove it from the level
1009 * and emit row-deleted. Since this node is being
1010 * deleted. it makes no sense to look further up the
1013 gtk_tree_model_filter_remove_elt_from_level (filter,
1018 /* Otherwise continue up the chain */
1020 else if (!elt->visible)
1022 if (requested_state)
1024 /* A node is already in the cache, but invisible. This
1025 * is usually a node on which a reference is kept by
1026 * the filter model, or a node fetched on the filter's
1027 * request, and thus not shown. Therefore, we will
1028 * not emit row-inserted for this node. Instead,
1029 * we signal to its parent that a change has occurred.
1032 GtkTreePath *f_path;
1034 elt->visible = TRUE;
1035 level->visible_nodes++;
1037 f_iter.stamp = filter->priv->stamp;
1038 f_iter.user_data = level->parent_level;
1039 f_iter.user_data2 = FILTER_LEVEL_PARENT_ELT(level);
1041 f_path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter),
1043 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
1045 gtk_tree_path_free (f_path);
1047 /* We can immediately return, because this node was not visible
1048 * before and the parent will check its children, including
1049 * this node, in response to the emitted row-has-child-toggled
1055 /* Not visible, so no need to continue. */
1061 /* If an elt does not have children, these are not visible.
1062 * Therefore, any signals emitted for these children will
1063 * be ignored, so we do not have to emit them.
1068 level = elt->children;
1072 gtk_tree_model_iter_nth_child (filter->priv->child_model, &c_iter,
1073 &tmp_iter, indices[i]);
1078 gtk_tree_model_filter_get_nth_visible (GtkTreeModelFilter *filter,
1085 if (level->visible_nodes <= n)
1088 elt = FILTER_ELT (level->array->data);
1089 while (!elt->visible)
1099 while (!elt->visible)
1106 gtk_tree_model_filter_insert_elt_in_level (GtkTreeModelFilter *filter,
1107 GtkTreeIter *c_iter,
1113 gint start, middle, end;
1116 if (GTK_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
1119 elt.offset = offset;
1120 elt.zero_ref_count = 0;
1122 elt.children = NULL;
1123 /* visibility should be FALSE as we don't emit row_inserted */
1124 elt.visible = FALSE;
1126 /* find index (binary search on offset) */
1128 end = level->array->len;
1132 while (start != end)
1134 middle = (start + end) / 2;
1136 if (g_array_index (level->array, FilterElt, middle).offset <= offset)
1142 if (g_array_index (level->array, FilterElt, middle).offset <= offset)
1150 g_array_insert_val (level->array, i, elt);
1153 for (i = 0; i < level->array->len; i++)
1155 FilterElt *e = &(g_array_index (level->array, FilterElt, i));
1157 e->children->parent_elt_index = i;
1160 if (level->parent_level || filter->priv->virtual_root)
1164 f_iter.stamp = filter->priv->stamp;
1165 f_iter.user_data = level;
1166 f_iter.user_data2 = &g_array_index (level->array, FilterElt, *index);
1168 gtk_tree_model_filter_ref_node (GTK_TREE_MODEL (filter), &f_iter);
1171 return &g_array_index (level->array, FilterElt, *index);
1175 gtk_tree_model_filter_fetch_child (GtkTreeModelFilter *filter,
1181 GtkTreePath *c_path = NULL;
1183 GtkTreePath *c_parent_path = NULL;
1184 GtkTreeIter c_parent_iter;
1186 /* check if child exists and is visible */
1187 if (level->parent_elt_index >= 0)
1190 gtk_tree_model_filter_elt_get_path (level->parent_level,
1191 FILTER_LEVEL_PARENT_ELT (level),
1192 filter->priv->virtual_root);
1198 if (filter->priv->virtual_root)
1199 c_parent_path = gtk_tree_path_copy (filter->priv->virtual_root);
1201 c_parent_path = NULL;
1206 gtk_tree_model_get_iter (filter->priv->child_model,
1209 len = gtk_tree_model_iter_n_children (filter->priv->child_model,
1212 c_path = gtk_tree_path_copy (c_parent_path);
1213 gtk_tree_path_free (c_parent_path);
1217 len = gtk_tree_model_iter_n_children (filter->priv->child_model, NULL);
1218 c_path = gtk_tree_path_new ();
1221 gtk_tree_path_append_index (c_path, offset);
1222 gtk_tree_model_get_iter (filter->priv->child_model, &c_iter, c_path);
1223 gtk_tree_path_free (c_path);
1225 if (offset >= len || !gtk_tree_model_filter_visible (filter, &c_iter))
1228 return gtk_tree_model_filter_insert_elt_in_level (filter, &c_iter,
1234 gtk_tree_model_filter_remove_elt_from_level (GtkTreeModelFilter *filter,
1239 FilterLevel *parent_level;
1240 gint i, length, parent_elt_index;
1242 GtkTreePath *path = NULL;
1244 gboolean emit_child_toggled = FALSE;
1246 iter.stamp = filter->priv->stamp;
1247 iter.user_data = level;
1248 iter.user_data2 = elt;
1250 path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter);
1252 parent_elt_index = level->parent_elt_index;
1253 if (parent_elt_index >= 0)
1254 parent = FILTER_LEVEL_PARENT_ELT (level);
1257 parent_level = level->parent_level;
1259 length = level->array->len;
1261 /* first register the node to be invisible */
1262 level->visible_nodes--;
1263 elt->visible = FALSE;
1265 /* we distinguish a couple of cases:
1266 * - root level, length > 1: emit row-deleted and remove.
1267 * - root level, length == 1: emit row-deleted and keep in cache.
1268 * - level, length == 1: parent->ref_count > 1: emit row-deleted and keep.
1269 * - level, length > 1: emit row-deleted and remove.
1270 * - else, remove level.
1272 * if level != root level and visible nodes == 0, emit row-has-child-toggled.
1275 if (level != filter->priv->root
1276 && level->visible_nodes == 0
1279 emit_child_toggled = TRUE;
1285 /* We emit row-deleted, and remove the node from the cache.
1286 * If it has any children, these will be removed here as well.
1290 gtk_tree_model_filter_free_level (filter, elt->children, TRUE);
1292 gtk_tree_model_filter_increment_stamp (filter);
1293 iter.stamp = filter->priv->stamp;
1294 gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter), path);
1296 while (elt->ref_count > 1)
1297 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
1300 if (parent_level || filter->priv->virtual_root)
1301 gtk_tree_model_filter_unref_node (GTK_TREE_MODEL (filter), &iter);
1302 else if (elt->ref_count > 0)
1303 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
1306 /* remove the node */
1307 tmp = bsearch_elt_with_offset (level->array, elt->offset, &i);
1311 g_array_remove_index (level->array, i);
1314 for (i = MAX (i, 0); i < level->array->len; i++)
1316 /* NOTE: here we do *not* decrease offsets, because the node was
1317 * not removed from the child model
1319 elt = &g_array_index (level->array, FilterElt, i);
1321 elt->children->parent_elt_index = i;
1325 else if ((length == 1 && parent && parent->ref_count > 1)
1326 || (length == 1 && level == filter->priv->root))
1328 /* We emit row-deleted, but keep the node in the cache and
1329 * referenced. Its children will be removed.
1334 gtk_tree_model_filter_free_level (filter, elt->children, TRUE);
1335 elt->children = NULL;
1338 gtk_tree_model_filter_increment_stamp (filter);
1339 gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter), path);
1343 /* Blow level away, including any child levels */
1345 gtk_tree_model_filter_increment_stamp (filter);
1346 iter.stamp = filter->priv->stamp;
1347 gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter), path);
1349 while (elt->ref_count > 1)
1350 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
1353 gtk_tree_model_filter_free_level (filter, level, TRUE);
1356 gtk_tree_path_free (path);
1358 if (emit_child_toggled)
1363 piter.stamp = filter->priv->stamp;
1364 piter.user_data = parent_level;
1365 piter.user_data2 = parent;
1367 ppath = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &piter);
1369 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
1371 gtk_tree_path_free (ppath);
1376 gtk_tree_model_filter_update_children (GtkTreeModelFilter *filter,
1386 iter.stamp = filter->priv->stamp;
1387 iter.user_data = level;
1388 iter.user_data2 = elt;
1390 gtk_tree_model_filter_convert_iter_to_child_iter (filter, &c_iter, &iter);
1392 if (gtk_tree_model_iter_has_child (filter->priv->child_model, &c_iter))
1394 GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter),
1396 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
1400 gtk_tree_path_free (path);
1405 bsearch_elt_with_offset (GArray *array,
1409 gint start, middle, end;
1420 elt = &g_array_index (array, FilterElt, 0);
1422 if (elt->offset == offset)
1433 middle = (start + end) / 2;
1435 elt = &g_array_index (array, FilterElt, middle);
1437 if (elt->offset < offset)
1439 else if (elt->offset > offset)
1444 while (start != end);
1446 if (elt->offset == offset)
1455 /* Path is relative to the child model (this is on search on elt offset)
1456 * but with the virtual root already removed if necesssary.
1459 find_elt_with_offset (GtkTreeModelFilter *filter,
1461 FilterLevel **level_,
1466 FilterLevel *parent_level = NULL;
1467 FilterElt *elt = NULL;
1469 level = FILTER_LEVEL (filter->priv->root);
1471 while (i < gtk_tree_path_get_depth (path))
1478 elt = bsearch_elt_with_offset (level->array,
1479 gtk_tree_path_get_indices (path)[i],
1485 parent_level = level;
1486 level = elt->children;
1491 *level_ = parent_level;
1499 /* TreeModel signals */
1501 gtk_tree_model_filter_emit_row_inserted_for_path (GtkTreeModelFilter *filter,
1502 GtkTreeModel *c_model,
1503 GtkTreePath *c_path,
1504 GtkTreeIter *c_iter)
1509 GtkTreeIter iter, children;
1510 gboolean signals_emitted = FALSE;
1512 if (!filter->priv->root)
1514 /* The root level has not been exposed to the view yet, so we
1515 * need to emit signals for any node that is being inserted.
1517 gtk_tree_model_filter_build_level (filter, NULL, -1, TRUE);
1519 /* Check if the root level was built. Then child levels
1520 * that matter have also been built (due to update_children,
1521 * which triggers iter_n_children).
1523 if (filter->priv->root &&
1524 FILTER_LEVEL (filter->priv->root)->visible_nodes)
1525 signals_emitted = TRUE;
1528 /* We need to disallow to build new levels, because we are then pulling
1529 * in a child in an invisible level. We only want to find path if it
1530 * is in a visible level (and thus has a parent that is visible).
1532 path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
1538 /* parent is probably being filtered out */
1541 gtk_tree_model_filter_increment_stamp (filter);
1543 gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (filter), &iter, path);
1545 level = FILTER_LEVEL (iter.user_data);
1546 elt = FILTER_ELT (iter.user_data2);
1548 /* Make sure elt is visible. elt can already be visible in case
1549 * it was pulled in above, so avoid increasing level->visible_nodes twice.
1553 elt->visible = TRUE;
1554 level->visible_nodes++;
1557 /* Check whether the node and all of its parents are visible */
1558 if (gtk_tree_model_filter_elt_is_visible_in_target (level, elt))
1560 /* visibility changed -- reget path */
1561 gtk_tree_path_free (path);
1562 path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter);
1564 if (!signals_emitted)
1565 gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter), path, &iter);
1567 if (level->parent_level && level->visible_nodes == 1)
1569 /* We know that this is the first visible node in this level, so
1570 * we need to emit row-has-child-toggled on the parent. This
1571 * does not apply to the root level.
1574 gtk_tree_path_up (path);
1575 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path);
1577 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
1582 if (!signals_emitted
1583 && gtk_tree_model_iter_children (c_model, &children, c_iter))
1584 gtk_tree_model_filter_update_children (filter, level, elt);
1587 gtk_tree_path_free (path);
1591 gtk_tree_model_filter_row_changed (GtkTreeModel *c_model,
1592 GtkTreePath *c_path,
1593 GtkTreeIter *c_iter,
1596 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (data);
1598 GtkTreeIter children;
1599 GtkTreeIter real_c_iter;
1600 GtkTreePath *path = NULL;
1601 GtkTreePath *real_path = NULL;
1606 gboolean requested_state;
1607 gboolean current_state;
1608 gboolean free_c_path = FALSE;
1610 g_return_if_fail (c_path != NULL || c_iter != NULL);
1614 c_path = gtk_tree_model_get_path (c_model, c_iter);
1618 if (filter->priv->virtual_root)
1619 real_path = gtk_tree_model_filter_remove_root (c_path,
1620 filter->priv->virtual_root);
1622 real_path = gtk_tree_path_copy (c_path);
1625 real_c_iter = *c_iter;
1627 gtk_tree_model_get_iter (c_model, &real_c_iter, c_path);
1629 /* is this node above the virtual root? */
1630 if (filter->priv->virtual_root &&
1631 (gtk_tree_path_get_depth (filter->priv->virtual_root)
1632 >= gtk_tree_path_get_depth (c_path)))
1635 /* what's the requested state? */
1636 requested_state = gtk_tree_model_filter_visible (filter, &real_c_iter);
1638 /* now, let's see whether the item is there */
1639 path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
1646 gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (filter),
1648 current_state = FILTER_ELT (iter.user_data2)->visible;
1651 current_state = FALSE;
1653 if (current_state == FALSE && requested_state == FALSE)
1654 /* no changes required */
1657 if (current_state == TRUE && requested_state == FALSE)
1659 gtk_tree_model_filter_remove_elt_from_level (filter,
1660 FILTER_LEVEL (iter.user_data),
1661 FILTER_ELT (iter.user_data2));
1664 gtk_tree_model_filter_check_ancestors (filter, real_path);
1669 if (current_state == TRUE && requested_state == TRUE)
1671 /* propagate the signal; also get a path taking only visible
1672 * nodes into account.
1674 gtk_tree_path_free (path);
1675 path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter);
1677 level = FILTER_LEVEL (iter.user_data);
1678 elt = FILTER_ELT (iter.user_data2);
1680 if (gtk_tree_model_filter_elt_is_visible_in_target (level, elt))
1682 gtk_tree_model_row_changed (GTK_TREE_MODEL (filter), path, &iter);
1684 /* and update the children */
1685 if (gtk_tree_model_iter_children (c_model, &children, &real_c_iter))
1686 gtk_tree_model_filter_update_children (filter, level, elt);
1690 gtk_tree_model_filter_check_ancestors (filter, real_path);
1695 /* only current == FALSE and requested == TRUE is left,
1698 g_return_if_fail (current_state == FALSE && requested_state == TRUE);
1701 gtk_tree_model_filter_check_ancestors (filter, real_path);
1703 gtk_tree_model_filter_emit_row_inserted_for_path (filter, c_model,
1708 gtk_tree_path_free (path);
1711 gtk_tree_path_free (real_path);
1714 gtk_tree_path_free (c_path);
1718 gtk_tree_model_filter_row_inserted (GtkTreeModel *c_model,
1719 GtkTreePath *c_path,
1720 GtkTreeIter *c_iter,
1723 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (data);
1724 GtkTreePath *real_path = NULL;
1726 GtkTreeIter real_c_iter;
1728 FilterElt *elt = NULL;
1729 FilterLevel *level = NULL;
1730 FilterLevel *parent_level = NULL;
1734 gboolean free_c_path = FALSE;
1735 gboolean emit_row_inserted = FALSE;
1737 g_return_if_fail (c_path != NULL || c_iter != NULL);
1741 c_path = gtk_tree_model_get_path (c_model, c_iter);
1746 real_c_iter = *c_iter;
1748 gtk_tree_model_get_iter (c_model, &real_c_iter, c_path);
1750 /* the row has already been inserted. so we need to fixup the
1751 * virtual root here first
1753 if (filter->priv->virtual_root)
1755 if (gtk_tree_path_get_depth (filter->priv->virtual_root) >=
1756 gtk_tree_path_get_depth (c_path))
1759 gint *v_indices, *c_indices;
1760 gboolean common_prefix = TRUE;
1762 level = gtk_tree_path_get_depth (c_path) - 1;
1763 v_indices = gtk_tree_path_get_indices (filter->priv->virtual_root);
1764 c_indices = gtk_tree_path_get_indices (c_path);
1766 for (i = 0; i < level; i++)
1767 if (v_indices[i] != c_indices[i])
1769 common_prefix = FALSE;
1773 if (common_prefix && v_indices[level] >= c_indices[level])
1774 (v_indices[level])++;
1778 /* subtract virtual root if necessary */
1779 if (filter->priv->virtual_root)
1781 real_path = gtk_tree_model_filter_remove_root (c_path,
1782 filter->priv->virtual_root);
1788 real_path = gtk_tree_path_copy (c_path);
1790 if (!filter->priv->root)
1792 /* If c_iter is in the root level and is not visible, then there
1793 * is no point in building the root level.
1794 * FIXME: For trees, this can likely be optimized by checking
1795 * whether the node and none of its ancestors are visible.
1797 if (!filter->priv->virtual_root &&
1798 gtk_tree_path_get_depth (c_path) == 1 &&
1799 !gtk_tree_model_filter_visible (filter, c_iter))
1802 /* The root level has not been exposed to the view yet, so we
1803 * need to emit signals for any node that is being inserted.
1805 gtk_tree_model_filter_build_level (filter, NULL, -1, TRUE);
1807 /* Check if the root level was built. Then child levels
1808 * that matter have also been built (due to update_children,
1809 * which triggers iter_n_children).
1811 if (filter->priv->root &&
1812 FILTER_LEVEL (filter->priv->root)->visible_nodes)
1814 emit_row_inserted = FALSE;
1819 if (gtk_tree_path_get_depth (real_path) - 1 >= 1)
1821 gboolean found = FALSE;
1822 GtkTreePath *parent = gtk_tree_path_copy (real_path);
1823 gtk_tree_path_up (parent);
1825 found = find_elt_with_offset (filter, parent, &parent_level, &elt);
1827 gtk_tree_path_free (parent);
1830 /* Parent is not in the cache and probably being filtered out */
1833 level = elt->children;
1836 level = FILTER_LEVEL (filter->priv->root);
1840 if (elt && elt->visible)
1842 /* The level in which the new node should be inserted does not
1843 * exist, but the parent, elt, does. If elt is visible, emit
1844 * row-has-child-toggled.
1846 GtkTreePath *tmppath;
1847 GtkTreeIter tmpiter;
1849 tmpiter.stamp = filter->priv->stamp;
1850 tmpiter.user_data = parent_level;
1851 tmpiter.user_data2 = elt;
1853 tmppath = gtk_tree_model_get_path (GTK_TREE_MODEL (filter),
1858 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
1860 gtk_tree_path_free (tmppath);
1866 /* let's try to insert the value */
1867 offset = gtk_tree_path_get_indices (real_path)[gtk_tree_path_get_depth (real_path) - 1];
1869 /* update the offsets, yes if we didn't insert the node above, there will
1870 * be a gap here. This will be filled with the node (via fetch_child) when
1871 * it becomes visible
1873 for (i = 0; i < level->array->len; i++)
1875 FilterElt *e = &g_array_index (level->array, FilterElt, i);
1876 if ((e->offset >= offset))
1880 /* only insert when visible */
1881 if (gtk_tree_model_filter_visible (filter, &real_c_iter))
1885 felt = gtk_tree_model_filter_insert_elt_in_level (filter,
1890 /* insert_elt_in_level defaults to FALSE */
1891 felt->visible = TRUE;
1892 level->visible_nodes++;
1894 emit_row_inserted = TRUE;
1898 gtk_tree_model_filter_check_ancestors (filter, real_path);
1900 if (emit_row_inserted)
1901 gtk_tree_model_filter_emit_row_inserted_for_path (filter, c_model,
1905 gtk_tree_path_free (real_path);
1908 gtk_tree_path_free (c_path);
1912 gtk_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model,
1913 GtkTreePath *c_path,
1914 GtkTreeIter *c_iter,
1917 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (data);
1922 gboolean requested_state;
1924 g_return_if_fail (c_path != NULL && c_iter != NULL);
1926 /* If we get row-has-child-toggled on the virtual root, and there is
1927 * no root level; try to build it now.
1929 if (filter->priv->virtual_root && !filter->priv->root
1930 && !gtk_tree_path_compare (c_path, filter->priv->virtual_root))
1932 gtk_tree_model_filter_build_level (filter, NULL, -1, TRUE);
1936 /* For all other levels, there is a chance that the visibility state
1937 * of the parent has changed now.
1940 path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
1947 gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (data), &iter, path);
1949 level = FILTER_LEVEL (iter.user_data);
1950 elt = FILTER_ELT (iter.user_data2);
1952 gtk_tree_path_free (path);
1954 requested_state = gtk_tree_model_filter_visible (filter, c_iter);
1956 if (!elt->visible && !requested_state)
1958 /* The parent node currently is not visible and will not become
1959 * visible, so we will not pass on the row-has-child-toggled event.
1963 else if (elt->visible && !requested_state)
1965 /* The node is no longer visible, so it has to be removed.
1966 * _remove_elt_from_level() takes care of emitting row-has-child-toggled
1969 gtk_tree_model_filter_remove_elt_from_level (filter, level, elt);
1973 else if (!elt->visible && requested_state)
1975 elt->visible = TRUE;
1976 level->visible_nodes++;
1978 /* Only insert if the parent is visible in the target */
1979 if (gtk_tree_model_filter_elt_is_visible_in_target (level, elt))
1981 path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter);
1982 gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter), path, &iter);
1983 gtk_tree_path_free (path);
1985 /* We do not update children now, because that will happen
1990 /* For the remaining possibility, elt->visible && requested_state
1991 * no action is required.
1994 /* If this node is referenced and has children, build the level so we
1995 * can monitor it for changes.
1997 if (elt->ref_count > 1 && gtk_tree_model_iter_has_child (c_model, c_iter))
1998 gtk_tree_model_filter_build_level (filter, level,
1999 FILTER_LEVEL_ELT_INDEX (level, elt),
2002 /* get a path taking only visible nodes into account */
2003 path = gtk_tree_model_get_path (GTK_TREE_MODEL (data), &iter);
2004 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data), path, &iter);
2005 gtk_tree_path_free (path);
2009 gtk_tree_model_filter_virtual_root_deleted (GtkTreeModelFilter *filter,
2010 GtkTreePath *c_path)
2014 FilterLevel *level = FILTER_LEVEL (filter->priv->root);
2016 /* The virtual root (or one of its ancestors) has been deleted. This
2017 * means that all content for our model is now gone. We deal with
2018 * this by removing everything in the filter model: we just iterate
2019 * over the root level and emit a row-deleted for each FilterElt.
2020 * (FIXME: Should we emit row-deleted for child nodes as well? This
2021 * has never been fully clear in TreeModel).
2024 /* We unref the path of the virtual root, up to and not including the
2025 * deleted node which can no longer be unreffed.
2027 gtk_tree_model_filter_unref_path (filter, filter->priv->virtual_root,
2028 gtk_tree_path_get_depth (c_path) - 1);
2029 filter->priv->virtual_root_deleted = TRUE;
2034 gtk_tree_model_filter_increment_stamp (filter);
2035 path = gtk_tree_path_new ();
2036 gtk_tree_path_append_index (path, 0);
2038 for (i = 0; i < level->visible_nodes; i++)
2039 gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter), path);
2041 gtk_tree_path_free (path);
2043 /* We should not propagate the unref here. An unref for any of these
2044 * nodes will fail, since the respective nodes in the child model are
2047 gtk_tree_model_filter_free_level (filter, filter->priv->root, FALSE);
2051 gtk_tree_model_filter_adjust_virtual_root (GtkTreeModelFilter *filter,
2052 GtkTreePath *c_path)
2056 gint *v_indices, *c_indices;
2057 gboolean common_prefix = TRUE;
2059 level = gtk_tree_path_get_depth (c_path) - 1;
2060 v_indices = gtk_tree_path_get_indices (filter->priv->virtual_root);
2061 c_indices = gtk_tree_path_get_indices (c_path);
2063 for (i = 0; i < level; i++)
2064 if (v_indices[i] != c_indices[i])
2066 common_prefix = FALSE;
2070 if (common_prefix && v_indices[level] > c_indices[level])
2071 (v_indices[level])--;
2075 gtk_tree_model_filter_row_deleted_invisible_node (GtkTreeModelFilter *filter,
2076 GtkTreePath *c_path)
2080 GtkTreePath *real_path;
2084 /* The node deleted in the child model is not visible in the
2085 * filter model. We will not emit a signal, just fixup the offsets
2086 * of the other nodes.
2089 if (!filter->priv->root)
2092 level = FILTER_LEVEL (filter->priv->root);
2094 /* subtract vroot if necessary */
2095 if (filter->priv->virtual_root)
2097 real_path = gtk_tree_model_filter_remove_root (c_path,
2098 filter->priv->virtual_root);
2099 /* we don't handle this */
2104 real_path = gtk_tree_path_copy (c_path);
2106 if (gtk_tree_path_get_depth (real_path) - 1 >= 1)
2108 gboolean found = FALSE;
2109 GtkTreePath *parent = gtk_tree_path_copy (real_path);
2110 gtk_tree_path_up (parent);
2112 found = find_elt_with_offset (filter, parent, &level, &elt);
2114 gtk_tree_path_free (parent);
2118 /* parent is filtered out, so no level */
2119 gtk_tree_path_free (real_path);
2123 level = elt->children;
2126 offset = gtk_tree_path_get_indices (real_path)[gtk_tree_path_get_depth (real_path) - 1];
2127 gtk_tree_path_free (real_path);
2132 /* decrease offset of all nodes following the deleted node */
2133 for (i = 0; i < level->array->len; i++)
2135 elt = &g_array_index (level->array, FilterElt, i);
2136 if (elt->offset > offset)
2139 elt->children->parent_elt_index = i;
2144 gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
2145 GtkTreePath *c_path,
2148 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (data);
2152 FilterLevel *level, *parent_level = NULL;
2153 gboolean emit_child_toggled = FALSE;
2154 gboolean emit_row_deleted = FALSE;
2157 gint parent_elt_index = -1;
2159 g_return_if_fail (c_path != NULL);
2161 /* special case the deletion of an ancestor of the virtual root */
2162 if (filter->priv->virtual_root &&
2163 (gtk_tree_path_is_ancestor (c_path, filter->priv->virtual_root) ||
2164 !gtk_tree_path_compare (c_path, filter->priv->virtual_root)))
2166 gtk_tree_model_filter_virtual_root_deleted (filter, c_path);
2170 /* adjust the virtual root for the deleted row */
2171 if (filter->priv->virtual_root &&
2172 gtk_tree_path_get_depth (filter->priv->virtual_root) >=
2173 gtk_tree_path_get_depth (c_path))
2174 gtk_tree_model_filter_adjust_virtual_root (filter, c_path);
2176 path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
2183 gtk_tree_model_filter_row_deleted_invisible_node (filter, c_path);
2187 /* a node was deleted, which was in our cache */
2188 gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (data), &iter, path);
2190 level = FILTER_LEVEL (iter.user_data);
2191 elt = FILTER_ELT (iter.user_data2);
2192 offset = elt->offset;
2196 /* get a path taking only visible nodes into account */
2197 gtk_tree_path_free (path);
2198 path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter);
2200 level->visible_nodes--;
2202 if (level->visible_nodes == 0)
2204 emit_child_toggled = TRUE;
2205 parent_level = level->parent_level;
2206 parent_elt_index = level->parent_elt_index;
2209 emit_row_deleted = TRUE;
2212 /* Release the references on this node, without propagation because
2213 * the node does not exist anymore in the child model. The filter
2214 * model's references on the node in case of level->parent or use
2215 * of a virtual root are automatically destroyed by the child model.
2217 while (elt->ref_count > 0)
2218 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter, FALSE);
2220 if (level->array->len == 1)
2223 gtk_tree_model_filter_free_level (filter, level, FALSE);
2229 /* remove the row */
2230 tmp = bsearch_elt_with_offset (level->array, elt->offset, &i);
2232 offset = tmp->offset;
2233 g_array_remove_index (level->array, i);
2236 for (i = MAX (i, 0); i < level->array->len; i++)
2238 elt = &g_array_index (level->array, FilterElt, i);
2239 if (elt->offset > offset)
2242 elt->children->parent_elt_index = i;
2246 if (emit_row_deleted)
2248 /* emit row_deleted */
2249 gtk_tree_model_filter_increment_stamp (filter);
2250 gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path);
2251 iter.stamp = filter->priv->stamp;
2254 if (emit_child_toggled && parent_level)
2259 iter2.stamp = filter->priv->stamp;
2260 iter2.user_data = parent_level;
2261 iter2.user_data2 = &g_array_index (parent_level->array, FilterElt, parent_elt_index);
2263 /* We set in_row_deleted to TRUE to avoid a level build triggered
2264 * by row-has-child-toggled (parent model could call iter_has_child
2267 filter->priv->in_row_deleted = TRUE;
2268 path2 = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter2);
2269 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
2271 gtk_tree_path_free (path2);
2272 filter->priv->in_row_deleted = FALSE;
2275 if (filter->priv->virtual_root)
2277 GtkTreePath *real_path;
2279 real_path = gtk_tree_model_filter_remove_root (c_path,
2280 filter->priv->root);
2283 gtk_tree_model_filter_check_ancestors (filter, real_path);
2284 gtk_tree_path_free (real_path);
2288 gtk_tree_model_filter_check_ancestors (filter, c_path);
2290 gtk_tree_path_free (path);
2294 gtk_tree_model_filter_rows_reordered (GtkTreeModel *c_model,
2295 GtkTreePath *c_path,
2296 GtkTreeIter *c_iter,
2302 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (data);
2308 gint i, j, elt_count;
2313 g_return_if_fail (new_order != NULL);
2315 if (c_path == NULL || gtk_tree_path_get_depth (c_path) == 0)
2317 length = gtk_tree_model_iter_n_children (c_model, NULL);
2319 if (filter->priv->virtual_root)
2323 /* reorder root level of path */
2324 for (i = 0; i < length; i++)
2325 if (new_order[i] == gtk_tree_path_get_indices (filter->priv->virtual_root)[0])
2331 gtk_tree_path_get_indices (filter->priv->virtual_root)[0] = new_pos;
2335 path = gtk_tree_path_new ();
2336 level = FILTER_LEVEL (filter->priv->root);
2340 GtkTreeIter child_iter;
2342 /* virtual root anchor reordering */
2343 if (filter->priv->virtual_root &&
2344 gtk_tree_path_is_ancestor (c_path, filter->priv->virtual_root))
2349 GtkTreeIter real_c_iter;
2351 level = gtk_tree_path_get_depth (c_path);
2354 real_c_iter = *c_iter;
2356 gtk_tree_model_get_iter (c_model, &real_c_iter, c_path);
2358 length = gtk_tree_model_iter_n_children (c_model, &real_c_iter);
2360 for (i = 0; i < length; i++)
2361 if (new_order[i] == gtk_tree_path_get_indices (filter->priv->virtual_root)[level])
2367 gtk_tree_path_get_indices (filter->priv->virtual_root)[level] = new_pos;
2371 path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
2376 if (!path && filter->priv->virtual_root &&
2377 gtk_tree_path_compare (c_path, filter->priv->virtual_root))
2380 if (!path && !filter->priv->virtual_root)
2385 /* root level mode */
2387 gtk_tree_model_get_iter (c_model, c_iter, c_path);
2388 length = gtk_tree_model_iter_n_children (c_model, c_iter);
2389 path = gtk_tree_path_new ();
2390 level = FILTER_LEVEL (filter->priv->root);
2394 gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (data),
2397 level = FILTER_LEVEL (iter.user_data);
2398 elt = FILTER_ELT (iter.user_data2);
2402 gtk_tree_path_free (path);
2406 level = elt->children;
2408 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (filter), &child_iter, &iter);
2409 length = gtk_tree_model_iter_n_children (c_model, &child_iter);
2413 if (!level || level->array->len < 1)
2415 gtk_tree_path_free (path);
2419 /* NOTE: we do not bail out here if level->array->len < 2 like
2420 * GtkTreeModelSort does. This because we do some special tricky
2424 /* construct a new array */
2425 new_array = g_array_sized_new (FALSE, FALSE, sizeof (FilterElt),
2427 tmp_array = g_new (gint, level->array->len);
2429 for (i = 0, elt_count = 0; i < length; i++)
2431 FilterElt *e = NULL;
2432 gint old_offset = -1;
2434 for (j = 0; j < level->array->len; j++)
2435 if (g_array_index (level->array, FilterElt, j).offset == new_order[i])
2437 e = &g_array_index (level->array, FilterElt, j);
2445 tmp_array[elt_count] = old_offset;
2446 g_array_append_val (new_array, *e);
2447 g_array_index (new_array, FilterElt, elt_count).offset = i;
2451 g_array_free (level->array, TRUE);
2452 level->array = new_array;
2455 for (i = 0; i < level->array->len; i++)
2457 FilterElt *e = &g_array_index (level->array, FilterElt, i);
2459 e->children->parent_elt_index = i;
2462 /* emit rows_reordered */
2463 if (!gtk_tree_path_get_indices (path))
2464 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, NULL,
2468 /* get a path taking only visible nodes into account */
2469 gtk_tree_path_free (path);
2470 path = gtk_tree_model_get_path (GTK_TREE_MODEL (data), &iter);
2472 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, &iter,
2478 gtk_tree_path_free (path);
2481 /* TreeModelIface implementation */
2482 static GtkTreeModelFlags
2483 gtk_tree_model_filter_get_flags (GtkTreeModel *model)
2485 GtkTreeModelFlags flags;
2487 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), 0);
2488 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL, 0);
2490 flags = gtk_tree_model_get_flags (GTK_TREE_MODEL_FILTER (model)->priv->child_model);
2492 if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
2493 return GTK_TREE_MODEL_LIST_ONLY;
2499 gtk_tree_model_filter_get_n_columns (GtkTreeModel *model)
2501 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
2503 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), 0);
2504 g_return_val_if_fail (filter->priv->child_model != NULL, 0);
2506 if (filter->priv->child_model == NULL)
2509 /* so we can't modify the modify func after this ... */
2510 filter->priv->modify_func_set = TRUE;
2512 if (filter->priv->modify_n_columns > 0)
2513 return filter->priv->modify_n_columns;
2515 return gtk_tree_model_get_n_columns (filter->priv->child_model);
2519 gtk_tree_model_filter_get_column_type (GtkTreeModel *model,
2522 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
2524 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), G_TYPE_INVALID);
2525 g_return_val_if_fail (filter->priv->child_model != NULL, G_TYPE_INVALID);
2527 /* so we can't modify the modify func after this ... */
2528 filter->priv->modify_func_set = TRUE;
2530 if (filter->priv->modify_types)
2532 g_return_val_if_fail (index < filter->priv->modify_n_columns, G_TYPE_INVALID);
2534 return filter->priv->modify_types[index];
2537 return gtk_tree_model_get_column_type (filter->priv->child_model, index);
2540 /* A special case of _get_iter; this function can also get iters which
2541 * are not visible. These iters should ONLY be passed internally, never
2542 * pass those along with a signal emission.
2545 gtk_tree_model_filter_get_iter_full (GtkTreeModel *model,
2549 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
2554 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
2555 g_return_val_if_fail (filter->priv->child_model != NULL, FALSE);
2557 indices = gtk_tree_path_get_indices (path);
2559 if (filter->priv->root == NULL)
2560 gtk_tree_model_filter_build_level (filter, NULL, -1, FALSE);
2561 level = FILTER_LEVEL (filter->priv->root);
2563 depth = gtk_tree_path_get_depth (path);
2570 for (i = 0; i < depth - 1; i++)
2572 if (!level || indices[i] >= level->array->len)
2578 elt = gtk_tree_model_filter_get_nth (filter, level, indices[i]);
2581 gtk_tree_model_filter_build_level (filter, level,
2582 FILTER_LEVEL_ELT_INDEX (level, elt),
2584 level = elt->children;
2587 if (!level || indices[i] >= level->array->len)
2593 iter->stamp = filter->priv->stamp;
2594 iter->user_data = level;
2596 elt = gtk_tree_model_filter_get_nth (filter, level, indices[depth - 1]);
2597 iter->user_data2 = elt;
2603 gtk_tree_model_filter_get_iter (GtkTreeModel *model,
2607 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
2612 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
2613 g_return_val_if_fail (filter->priv->child_model != NULL, FALSE);
2615 indices = gtk_tree_path_get_indices (path);
2617 if (filter->priv->root == NULL)
2618 gtk_tree_model_filter_build_level (filter, NULL, -1, FALSE);
2619 level = FILTER_LEVEL (filter->priv->root);
2621 depth = gtk_tree_path_get_depth (path);
2628 for (i = 0; i < depth - 1; i++)
2630 if (!level || indices[i] >= level->visible_nodes)
2636 elt = gtk_tree_model_filter_get_nth_visible (filter, level, indices[i]);
2639 gtk_tree_model_filter_build_level (filter, level,
2640 FILTER_LEVEL_ELT_INDEX (level, elt),
2642 level = elt->children;
2645 if (!level || indices[i] >= level->visible_nodes)
2651 iter->stamp = filter->priv->stamp;
2652 iter->user_data = level;
2654 elt = gtk_tree_model_filter_get_nth_visible (filter, level,
2655 indices[depth - 1]);
2656 iter->user_data2 = elt;
2661 static GtkTreePath *
2662 gtk_tree_model_filter_get_path (GtkTreeModel *model,
2665 GtkTreePath *retval;
2670 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), NULL);
2671 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL, NULL);
2672 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == iter->stamp, NULL);
2674 level = iter->user_data;
2675 elt = iter->user_data2;
2676 elt_index = FILTER_LEVEL_ELT_INDEX (level, elt);
2681 retval = gtk_tree_path_new ();
2685 int i = 0, index = 0;
2687 while (i < elt_index)
2689 if (g_array_index (level->array, FilterElt, i).visible)
2693 g_assert (i < level->array->len);
2696 gtk_tree_path_prepend_index (retval, index);
2697 elt_index = level->parent_elt_index;
2698 level = level->parent_level;
2705 gtk_tree_model_filter_real_modify (GtkTreeModelFilter *self,
2706 GtkTreeModel *child_model,
2711 if (self->priv->modify_func)
2713 g_return_if_fail (column < self->priv->modify_n_columns);
2715 g_value_init (value, self->priv->modify_types[column]);
2716 self->priv->modify_func (GTK_TREE_MODEL (self),
2720 self->priv->modify_data);
2724 GtkTreeIter child_iter;
2726 gtk_tree_model_filter_convert_iter_to_child_iter (
2727 GTK_TREE_MODEL_FILTER (self), &child_iter, iter);
2728 gtk_tree_model_get_value (child_model,
2729 &child_iter, column, value);
2734 gtk_tree_model_filter_get_value (GtkTreeModel *model,
2739 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (model);
2741 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (model));
2742 g_return_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL);
2743 g_return_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == iter->stamp);
2745 GTK_TREE_MODEL_FILTER_GET_CLASS (model)->modify (filter,
2746 filter->priv->child_model, iter, value, column);
2750 gtk_tree_model_filter_iter_next (GtkTreeModel *model,
2757 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
2758 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL, FALSE);
2759 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == iter->stamp, FALSE);
2761 level = iter->user_data;
2762 elt = iter->user_data2;
2764 i = elt - FILTER_ELT (level->array->data);
2766 while (i < level->array->len - 1)
2773 iter->user_data2 = elt;
2778 /* no next visible iter */
2785 gtk_tree_model_filter_iter_previous (GtkTreeModel *model,
2792 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
2793 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL, FALSE);
2794 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == iter->stamp, FALSE);
2796 level = iter->user_data;
2797 elt = iter->user_data2;
2799 i = elt - FILTER_ELT (level->array->data);
2808 iter->user_data2 = elt;
2813 /* no previous visible iter */
2820 gtk_tree_model_filter_iter_children (GtkTreeModel *model,
2822 GtkTreeIter *parent)
2824 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
2828 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
2829 g_return_val_if_fail (filter->priv->child_model != NULL, FALSE);
2831 g_return_val_if_fail (filter->priv->stamp == parent->stamp, FALSE);
2837 if (!filter->priv->root)
2838 gtk_tree_model_filter_build_level (filter, NULL, -1, FALSE);
2839 if (!filter->priv->root)
2842 level = filter->priv->root;
2844 if (!level->visible_nodes)
2847 iter->stamp = filter->priv->stamp;
2848 iter->user_data = level;
2850 while (i < level->array->len)
2852 if (!g_array_index (level->array, FilterElt, i).visible)
2858 iter->user_data2 = &g_array_index (level->array, FilterElt, i);
2870 elt = FILTER_ELT (parent->user_data2);
2872 if (elt->children == NULL)
2873 gtk_tree_model_filter_build_level (filter,
2874 FILTER_LEVEL (parent->user_data),
2875 FILTER_LEVEL_ELT_INDEX (parent->user_data, elt),
2878 if (elt->children == NULL)
2881 if (elt->children->visible_nodes <= 0)
2884 iter->stamp = filter->priv->stamp;
2885 iter->user_data = elt->children;
2887 level = FILTER_LEVEL (iter->user_data);
2889 while (i < level->array->len)
2891 if (!g_array_index (level->array, FilterElt, i).visible)
2897 iter->user_data2 = &g_array_index (level->array, FilterElt, i);
2910 gtk_tree_model_filter_iter_has_child (GtkTreeModel *model,
2913 GtkTreeIter child_iter;
2914 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
2917 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
2918 g_return_val_if_fail (filter->priv->child_model != NULL, FALSE);
2919 g_return_val_if_fail (filter->priv->stamp == iter->stamp, FALSE);
2921 filter = GTK_TREE_MODEL_FILTER (model);
2923 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_iter, iter);
2924 elt = FILTER_ELT (iter->user_data2);
2929 /* we need to build the level to check if not all children are filtered
2933 && gtk_tree_model_iter_has_child (filter->priv->child_model, &child_iter))
2934 gtk_tree_model_filter_build_level (filter, FILTER_LEVEL (iter->user_data),
2935 FILTER_LEVEL_ELT_INDEX (iter->user_data, elt),
2938 if (elt->children && elt->children->visible_nodes > 0)
2945 gtk_tree_model_filter_iter_n_children (GtkTreeModel *model,
2948 GtkTreeIter child_iter;
2949 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
2952 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), 0);
2953 g_return_val_if_fail (filter->priv->child_model != NULL, 0);
2955 g_return_val_if_fail (filter->priv->stamp == iter->stamp, 0);
2959 if (!filter->priv->root)
2960 gtk_tree_model_filter_build_level (filter, NULL, -1, FALSE);
2962 if (filter->priv->root)
2963 return FILTER_LEVEL (filter->priv->root)->visible_nodes;
2968 elt = FILTER_ELT (iter->user_data2);
2973 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_iter, iter);
2975 if (!elt->children &&
2976 gtk_tree_model_iter_has_child (filter->priv->child_model, &child_iter))
2977 gtk_tree_model_filter_build_level (filter,
2978 FILTER_LEVEL (iter->user_data),
2979 FILTER_LEVEL_ELT_INDEX (iter->user_data, elt),
2983 return elt->children->visible_nodes;
2989 gtk_tree_model_filter_iter_nth_child (GtkTreeModel *model,
2991 GtkTreeIter *parent,
2996 GtkTreeIter children;
2998 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
3000 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == parent->stamp, FALSE);
3002 /* use this instead of has_child to force us to build the level, if needed */
3003 if (gtk_tree_model_filter_iter_children (model, &children, parent) == FALSE)
3009 level = children.user_data;
3010 elt = FILTER_ELT (level->array->data);
3012 if (n >= level->visible_nodes)
3018 elt = gtk_tree_model_filter_get_nth_visible (GTK_TREE_MODEL_FILTER (model),
3021 iter->stamp = GTK_TREE_MODEL_FILTER (model)->priv->stamp;
3022 iter->user_data = level;
3023 iter->user_data2 = elt;
3029 gtk_tree_model_filter_iter_parent (GtkTreeModel *model,
3036 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
3037 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL, FALSE);
3038 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == child->stamp, FALSE);
3040 level = child->user_data;
3042 if (level->parent_level)
3044 iter->stamp = GTK_TREE_MODEL_FILTER (model)->priv->stamp;
3045 iter->user_data = level->parent_level;
3046 iter->user_data2 = FILTER_LEVEL_PARENT_ELT (level);
3055 gtk_tree_model_filter_ref_node (GtkTreeModel *model,
3058 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
3059 GtkTreeIter child_iter;
3063 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (model));
3064 g_return_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL);
3065 g_return_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == iter->stamp);
3067 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_iter, iter);
3069 gtk_tree_model_ref_node (filter->priv->child_model, &child_iter);
3071 level = iter->user_data;
3072 elt = iter->user_data2;
3076 if (level->ref_count == 1)
3078 FilterLevel *parent_level = level->parent_level;
3079 gint parent_elt_index = level->parent_elt_index;
3081 /* we were at zero -- time to decrease the zero_ref_count val */
3082 while (parent_level)
3084 g_array_index (parent_level->array, FilterElt, parent_elt_index).zero_ref_count--;
3086 parent_elt_index = parent_level->parent_elt_index;
3087 parent_level = parent_level->parent_level;
3090 if (filter->priv->root != level)
3091 filter->priv->zero_ref_count--;
3096 gtk_tree_model_filter_unref_node (GtkTreeModel *model,
3099 gtk_tree_model_filter_real_unref_node (model, iter, TRUE);
3103 gtk_tree_model_filter_real_unref_node (GtkTreeModel *model,
3105 gboolean propagate_unref)
3107 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
3111 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (model));
3112 g_return_if_fail (filter->priv->child_model != NULL);
3113 g_return_if_fail (filter->priv->stamp == iter->stamp);
3115 if (propagate_unref)
3117 GtkTreeIter child_iter;
3118 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_iter, iter);
3119 gtk_tree_model_unref_node (filter->priv->child_model, &child_iter);
3122 level = iter->user_data;
3123 elt = iter->user_data2;
3125 g_return_if_fail (elt->ref_count > 0);
3129 if (level->ref_count == 0)
3131 FilterLevel *parent_level = level->parent_level;
3132 gint parent_elt_index = level->parent_elt_index;
3134 /* we are at zero -- time to increase the zero_ref_count val */
3135 while (parent_level)
3137 g_array_index (parent_level->array, FilterElt, parent_elt_index).zero_ref_count++;
3139 parent_elt_index = parent_level->parent_elt_index;
3140 parent_level = parent_level->parent_level;
3143 if (filter->priv->root != level)
3144 filter->priv->zero_ref_count++;
3148 /* TreeDragSource interface implementation */
3150 gtk_tree_model_filter_row_draggable (GtkTreeDragSource *drag_source,
3153 GtkTreeModelFilter *tree_model_filter = (GtkTreeModelFilter *)drag_source;
3154 GtkTreePath *child_path;
3157 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (drag_source), FALSE);
3158 g_return_val_if_fail (path != NULL, FALSE);
3160 child_path = gtk_tree_model_filter_convert_path_to_child_path (tree_model_filter, path);
3161 draggable = gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (tree_model_filter->priv->child_model), child_path);
3162 gtk_tree_path_free (child_path);
3168 gtk_tree_model_filter_drag_data_get (GtkTreeDragSource *drag_source,
3170 GtkSelectionData *selection_data)
3172 GtkTreeModelFilter *tree_model_filter = (GtkTreeModelFilter *)drag_source;
3173 GtkTreePath *child_path;
3176 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (drag_source), FALSE);
3177 g_return_val_if_fail (path != NULL, FALSE);
3179 child_path = gtk_tree_model_filter_convert_path_to_child_path (tree_model_filter, path);
3180 gotten = gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (tree_model_filter->priv->child_model), child_path, selection_data);
3181 gtk_tree_path_free (child_path);
3187 gtk_tree_model_filter_drag_data_delete (GtkTreeDragSource *drag_source,
3190 GtkTreeModelFilter *tree_model_filter = (GtkTreeModelFilter *)drag_source;
3191 GtkTreePath *child_path;
3194 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (drag_source), FALSE);
3195 g_return_val_if_fail (path != NULL, FALSE);
3197 child_path = gtk_tree_model_filter_convert_path_to_child_path (tree_model_filter, path);
3198 deleted = gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (tree_model_filter->priv->child_model), child_path);
3199 gtk_tree_path_free (child_path);
3204 /* bits and pieces */
3206 gtk_tree_model_filter_set_model (GtkTreeModelFilter *filter,
3207 GtkTreeModel *child_model)
3209 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
3211 if (filter->priv->child_model)
3213 g_signal_handler_disconnect (filter->priv->child_model,
3214 filter->priv->changed_id);
3215 g_signal_handler_disconnect (filter->priv->child_model,
3216 filter->priv->inserted_id);
3217 g_signal_handler_disconnect (filter->priv->child_model,
3218 filter->priv->has_child_toggled_id);
3219 g_signal_handler_disconnect (filter->priv->child_model,
3220 filter->priv->deleted_id);
3221 g_signal_handler_disconnect (filter->priv->child_model,
3222 filter->priv->reordered_id);
3224 /* reset our state */
3225 if (filter->priv->root)
3226 gtk_tree_model_filter_free_level (filter, filter->priv->root, TRUE);
3228 filter->priv->root = NULL;
3229 g_object_unref (filter->priv->child_model);
3230 filter->priv->visible_column = -1;
3232 /* FIXME: do we need to destroy more here? */
3235 filter->priv->child_model = child_model;
3239 g_object_ref (filter->priv->child_model);
3240 filter->priv->changed_id =
3241 g_signal_connect (child_model, "row-changed",
3242 G_CALLBACK (gtk_tree_model_filter_row_changed),
3244 filter->priv->inserted_id =
3245 g_signal_connect (child_model, "row-inserted",
3246 G_CALLBACK (gtk_tree_model_filter_row_inserted),
3248 filter->priv->has_child_toggled_id =
3249 g_signal_connect (child_model, "row-has-child-toggled",
3250 G_CALLBACK (gtk_tree_model_filter_row_has_child_toggled),
3252 filter->priv->deleted_id =
3253 g_signal_connect (child_model, "row-deleted",
3254 G_CALLBACK (gtk_tree_model_filter_row_deleted),
3256 filter->priv->reordered_id =
3257 g_signal_connect (child_model, "rows-reordered",
3258 G_CALLBACK (gtk_tree_model_filter_rows_reordered),
3261 filter->priv->child_flags = gtk_tree_model_get_flags (child_model);
3262 filter->priv->stamp = g_random_int ();
3267 gtk_tree_model_filter_ref_path (GtkTreeModelFilter *filter,
3273 len = gtk_tree_path_get_depth (path);
3274 p = gtk_tree_path_copy (path);
3279 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter->priv->child_model), &iter, p);
3280 gtk_tree_model_ref_node (GTK_TREE_MODEL (filter->priv->child_model), &iter);
3281 gtk_tree_path_up (p);
3284 gtk_tree_path_free (p);
3288 gtk_tree_model_filter_unref_path (GtkTreeModelFilter *filter,
3298 len = gtk_tree_path_get_depth (path);
3300 p = gtk_tree_path_copy (path);
3305 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter->priv->child_model), &iter, p);
3306 gtk_tree_model_unref_node (GTK_TREE_MODEL (filter->priv->child_model), &iter);
3307 gtk_tree_path_up (p);
3310 gtk_tree_path_free (p);
3314 gtk_tree_model_filter_set_root (GtkTreeModelFilter *filter,
3317 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
3320 filter->priv->virtual_root = NULL;
3322 filter->priv->virtual_root = gtk_tree_path_copy (root);
3328 * gtk_tree_model_filter_new:
3329 * @child_model: A #GtkTreeModel.
3330 * @root: (allow-none): A #GtkTreePath or %NULL.
3332 * Creates a new #GtkTreeModel, with @child_model as the child_model
3333 * and @root as the virtual root.
3335 * Return value: (transfer full): A new #GtkTreeModel.
3340 gtk_tree_model_filter_new (GtkTreeModel *child_model,
3343 GtkTreeModel *retval;
3344 GtkTreeModelFilter *filter;
3346 g_return_val_if_fail (GTK_IS_TREE_MODEL (child_model), NULL);
3348 retval = g_object_new (GTK_TYPE_TREE_MODEL_FILTER,
3349 "child-model", child_model,
3350 "virtual-root", root,
3353 filter = GTK_TREE_MODEL_FILTER (retval);
3354 if (filter->priv->virtual_root)
3356 gtk_tree_model_filter_ref_path (filter, filter->priv->virtual_root);
3357 filter->priv->virtual_root_deleted = FALSE;
3364 * gtk_tree_model_filter_get_model:
3365 * @filter: A #GtkTreeModelFilter.
3367 * Returns a pointer to the child model of @filter.
3369 * Return value: (transfer none): A pointer to a #GtkTreeModel.
3374 gtk_tree_model_filter_get_model (GtkTreeModelFilter *filter)
3376 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (filter), NULL);
3378 return filter->priv->child_model;
3382 * gtk_tree_model_filter_set_visible_func:
3383 * @filter: A #GtkTreeModelFilter.
3384 * @func: A #GtkTreeModelFilterVisibleFunc, the visible function.
3385 * @data: (allow-none): User data to pass to the visible function, or %NULL.
3386 * @destroy: (allow-none): Destroy notifier of @data, or %NULL.
3388 * Sets the visible function used when filtering the @filter to be @func. The
3389 * function should return %TRUE if the given row should be visible and
3392 * If the condition calculated by the function changes over time (e.g. because
3393 * it depends on some global parameters), you must call
3394 * gtk_tree_model_filter_refilter() to keep the visibility information of
3395 * the model uptodate.
3397 * Note that @func is called whenever a row is inserted, when it may still be
3398 * empty. The visible function should therefore take special care of empty
3399 * rows, like in the example below.
3401 * <informalexample><programlisting>
3403 * visible_func (GtkTreeModel *model,
3404 * GtkTreeIter *iter,
3407 * /* Visible if row is non-empty and first column is "HI" */
3409 * gboolean visible = FALSE;
3411 * gtk_tree_model_get (model, iter, 0, &str, -1);
3412 * if (str && strcmp (str, "HI") == 0)
3418 * </programlisting></informalexample>
3423 gtk_tree_model_filter_set_visible_func (GtkTreeModelFilter *filter,
3424 GtkTreeModelFilterVisibleFunc func,
3426 GDestroyNotify destroy)
3428 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
3429 g_return_if_fail (func != NULL);
3430 g_return_if_fail (filter->priv->visible_method_set == FALSE);
3432 filter->priv->visible_func = func;
3433 filter->priv->visible_data = data;
3434 filter->priv->visible_destroy = destroy;
3436 filter->priv->visible_method_set = TRUE;
3440 * gtk_tree_model_filter_set_modify_func:
3441 * @filter: A #GtkTreeModelFilter.
3442 * @n_columns: The number of columns in the filter model.
3443 * @types: (array length=n_columns): The #GType<!-- -->s of the columns.
3444 * @func: A #GtkTreeModelFilterModifyFunc
3445 * @data: (allow-none): User data to pass to the modify function, or %NULL.
3446 * @destroy: (allow-none): Destroy notifier of @data, or %NULL.
3448 * With the @n_columns and @types parameters, you give an array of column
3449 * types for this model (which will be exposed to the parent model/view).
3450 * The @func, @data and @destroy parameters are for specifying the modify
3451 * function. The modify function will get called for <emphasis>each</emphasis>
3452 * data access, the goal of the modify function is to return the data which
3453 * should be displayed at the location specified using the parameters of the
3459 gtk_tree_model_filter_set_modify_func (GtkTreeModelFilter *filter,
3462 GtkTreeModelFilterModifyFunc func,
3464 GDestroyNotify destroy)
3466 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
3467 g_return_if_fail (func != NULL);
3468 g_return_if_fail (filter->priv->modify_func_set == FALSE);
3470 if (filter->priv->modify_destroy)
3472 GDestroyNotify d = filter->priv->modify_destroy;
3474 filter->priv->modify_destroy = NULL;
3475 d (filter->priv->modify_data);
3478 filter->priv->modify_n_columns = n_columns;
3479 filter->priv->modify_types = g_new0 (GType, n_columns);
3480 memcpy (filter->priv->modify_types, types, sizeof (GType) * n_columns);
3481 filter->priv->modify_func = func;
3482 filter->priv->modify_data = data;
3483 filter->priv->modify_destroy = destroy;
3485 filter->priv->modify_func_set = TRUE;
3489 * gtk_tree_model_filter_set_visible_column:
3490 * @filter: A #GtkTreeModelFilter.
3491 * @column: A #gint which is the column containing the visible information.
3493 * Sets @column of the child_model to be the column where @filter should
3494 * look for visibility information. @columns should be a column of type
3495 * %G_TYPE_BOOLEAN, where %TRUE means that a row is visible, and %FALSE
3501 gtk_tree_model_filter_set_visible_column (GtkTreeModelFilter *filter,
3504 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
3505 g_return_if_fail (column >= 0);
3506 g_return_if_fail (filter->priv->visible_method_set == FALSE);
3508 filter->priv->visible_column = column;
3510 filter->priv->visible_method_set = TRUE;
3516 * gtk_tree_model_filter_convert_child_iter_to_iter:
3517 * @filter: A #GtkTreeModelFilter.
3518 * @filter_iter: (out): An uninitialized #GtkTreeIter.
3519 * @child_iter: A valid #GtkTreeIter pointing to a row on the child model.
3521 * Sets @filter_iter to point to the row in @filter that corresponds to the
3522 * row pointed at by @child_iter. If @filter_iter was not set, %FALSE is
3525 * Return value: %TRUE, if @filter_iter was set, i.e. if @child_iter is a
3526 * valid iterator pointing to a visible row in child model.
3531 gtk_tree_model_filter_convert_child_iter_to_iter (GtkTreeModelFilter *filter,
3532 GtkTreeIter *filter_iter,
3533 GtkTreeIter *child_iter)
3536 GtkTreePath *child_path, *path;
3538 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (filter), FALSE);
3539 g_return_val_if_fail (filter->priv->child_model != NULL, FALSE);
3540 g_return_val_if_fail (filter_iter != NULL, FALSE);
3541 g_return_val_if_fail (child_iter != NULL, FALSE);
3542 g_return_val_if_fail (filter_iter != child_iter, FALSE);
3544 filter_iter->stamp = 0;
3546 child_path = gtk_tree_model_get_path (filter->priv->child_model, child_iter);
3547 g_return_val_if_fail (child_path != NULL, FALSE);
3549 path = gtk_tree_model_filter_convert_child_path_to_path (filter,
3551 gtk_tree_path_free (child_path);
3556 ret = gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), filter_iter, path);
3557 gtk_tree_path_free (path);
3563 * gtk_tree_model_filter_convert_iter_to_child_iter:
3564 * @filter: A #GtkTreeModelFilter.
3565 * @child_iter: (out): An uninitialized #GtkTreeIter.
3566 * @filter_iter: A valid #GtkTreeIter pointing to a row on @filter.
3568 * Sets @child_iter to point to the row pointed to by @filter_iter.
3573 gtk_tree_model_filter_convert_iter_to_child_iter (GtkTreeModelFilter *filter,
3574 GtkTreeIter *child_iter,
3575 GtkTreeIter *filter_iter)
3577 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
3578 g_return_if_fail (filter->priv->child_model != NULL);
3579 g_return_if_fail (child_iter != NULL);
3580 g_return_if_fail (filter_iter != NULL);
3581 g_return_if_fail (filter_iter->stamp == filter->priv->stamp);
3582 g_return_if_fail (filter_iter != child_iter);
3584 if (GTK_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
3586 *child_iter = FILTER_ELT (filter_iter->user_data2)->iter;
3591 gboolean valid = FALSE;
3593 path = gtk_tree_model_filter_elt_get_path (filter_iter->user_data,
3594 filter_iter->user_data2,
3595 filter->priv->virtual_root);
3596 valid = gtk_tree_model_get_iter (filter->priv->child_model, child_iter,
3598 gtk_tree_path_free (path);
3600 g_return_if_fail (valid == TRUE);
3604 /* The path returned can only be used internally in the filter model. */
3605 static GtkTreePath *
3606 gtk_real_tree_model_filter_convert_child_path_to_path (GtkTreeModelFilter *filter,
3607 GtkTreePath *child_path,
3608 gboolean build_levels,
3609 gboolean fetch_children)
3611 gint *child_indices;
3612 GtkTreePath *retval;
3613 GtkTreePath *real_path;
3618 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (filter), NULL);
3619 g_return_val_if_fail (filter->priv->child_model != NULL, NULL);
3620 g_return_val_if_fail (child_path != NULL, NULL);
3622 if (!filter->priv->virtual_root)
3623 real_path = gtk_tree_path_copy (child_path);
3625 real_path = gtk_tree_model_filter_remove_root (child_path,
3626 filter->priv->virtual_root);
3631 retval = gtk_tree_path_new ();
3632 child_indices = gtk_tree_path_get_indices (real_path);
3634 if (filter->priv->root == NULL && build_levels)
3635 gtk_tree_model_filter_build_level (filter, NULL, -1, FALSE);
3636 level = FILTER_LEVEL (filter->priv->root);
3638 for (i = 0; i < gtk_tree_path_get_depth (real_path); i++)
3641 gboolean found_child = FALSE;
3645 gtk_tree_path_free (real_path);
3646 gtk_tree_path_free (retval);
3650 tmp = bsearch_elt_with_offset (level->array, child_indices[i], &j);
3653 gtk_tree_path_append_index (retval, j);
3654 if (!tmp->children && build_levels)
3655 gtk_tree_model_filter_build_level (filter, level,
3656 FILTER_LEVEL_ELT_INDEX (level, tmp),
3658 level = tmp->children;
3662 if (!found_child && fetch_children)
3664 tmp = gtk_tree_model_filter_fetch_child (filter, level,
3668 /* didn't find the child, let's try to bring it back */
3669 if (!tmp || tmp->offset != child_indices[i])
3672 gtk_tree_path_free (real_path);
3673 gtk_tree_path_free (retval);
3677 gtk_tree_path_append_index (retval, j);
3678 if (!tmp->children && build_levels)
3679 gtk_tree_model_filter_build_level (filter, level,
3680 FILTER_LEVEL_ELT_INDEX (level, tmp),
3682 level = tmp->children;
3685 else if (!found_child && !fetch_children)
3688 gtk_tree_path_free (real_path);
3689 gtk_tree_path_free (retval);
3694 gtk_tree_path_free (real_path);
3699 * gtk_tree_model_filter_convert_child_path_to_path:
3700 * @filter: A #GtkTreeModelFilter.
3701 * @child_path: A #GtkTreePath to convert.
3703 * Converts @child_path to a path relative to @filter. That is, @child_path
3704 * points to a path in the child model. The rerturned path will point to the
3705 * same row in the filtered model. If @child_path isn't a valid path on the
3706 * child model or points to a row which is not visible in @filter, then %NULL
3709 * Return value: A newly allocated #GtkTreePath, or %NULL.
3714 gtk_tree_model_filter_convert_child_path_to_path (GtkTreeModelFilter *filter,
3715 GtkTreePath *child_path)
3720 /* this function does the sanity checks */
3721 path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
3729 /* get a new path which only takes visible nodes into account.
3730 * -- if this gives any performance issues, we can write a special
3731 * version of convert_child_path_to_path immediately returning
3732 * a visible-nodes-only path.
3734 gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (filter), &iter, path);
3736 gtk_tree_path_free (path);
3737 path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter);
3743 * gtk_tree_model_filter_convert_path_to_child_path:
3744 * @filter: A #GtkTreeModelFilter.
3745 * @filter_path: A #GtkTreePath to convert.
3747 * Converts @filter_path to a path on the child model of @filter. That is,
3748 * @filter_path points to a location in @filter. The returned path will
3749 * point to the same location in the model not being filtered. If @filter_path
3750 * does not point to a location in the child model, %NULL is returned.
3752 * Return value: A newly allocated #GtkTreePath, or %NULL.
3757 gtk_tree_model_filter_convert_path_to_child_path (GtkTreeModelFilter *filter,
3758 GtkTreePath *filter_path)
3760 gint *filter_indices;
3761 GtkTreePath *retval;
3765 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (filter), NULL);
3766 g_return_val_if_fail (filter->priv->child_model != NULL, NULL);
3767 g_return_val_if_fail (filter_path != NULL, NULL);
3770 retval = gtk_tree_path_new ();
3771 filter_indices = gtk_tree_path_get_indices (filter_path);
3772 if (!filter->priv->root)
3773 gtk_tree_model_filter_build_level (filter, NULL, -1, FALSE);
3774 level = FILTER_LEVEL (filter->priv->root);
3776 for (i = 0; i < gtk_tree_path_get_depth (filter_path); i++)
3780 if (!level || level->visible_nodes <= filter_indices[i])
3782 gtk_tree_path_free (retval);
3786 elt = gtk_tree_model_filter_get_nth_visible (filter, level,
3789 if (elt->children == NULL)
3790 gtk_tree_model_filter_build_level (filter, level,
3791 FILTER_LEVEL_ELT_INDEX (level, elt),
3794 if (!level || level->visible_nodes <= filter_indices[i])
3796 gtk_tree_path_free (retval);
3800 gtk_tree_path_append_index (retval, elt->offset);
3801 level = elt->children;
3806 if (filter->priv->virtual_root)
3808 GtkTreePath *real_retval;
3810 real_retval = gtk_tree_model_filter_add_root (retval,
3811 filter->priv->virtual_root);
3812 gtk_tree_path_free (retval);
3821 gtk_tree_model_filter_refilter_helper (GtkTreeModel *model,
3826 /* evil, don't try this at home, but certainly speeds things up */
3827 gtk_tree_model_filter_row_changed (model, path, iter, data);
3833 * gtk_tree_model_filter_refilter:
3834 * @filter: A #GtkTreeModelFilter.
3836 * Emits ::row_changed for each row in the child model, which causes
3837 * the filter to re-evaluate whether a row is visible or not.
3842 gtk_tree_model_filter_refilter (GtkTreeModelFilter *filter)
3844 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
3847 gtk_tree_model_foreach (filter->priv->child_model,
3848 gtk_tree_model_filter_refilter_helper,
3853 * gtk_tree_model_filter_clear_cache:
3854 * @filter: A #GtkTreeModelFilter.
3856 * This function should almost never be called. It clears the @filter
3857 * of any cached iterators that haven't been reffed with
3858 * gtk_tree_model_ref_node(). This might be useful if the child model
3859 * being filtered is static (and doesn't change often) and there has been
3860 * a lot of unreffed access to nodes. As a side effect of this function,
3861 * all unreffed iters will be invalid.
3866 gtk_tree_model_filter_clear_cache (GtkTreeModelFilter *filter)
3868 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
3870 if (filter->priv->zero_ref_count > 0)
3871 gtk_tree_model_filter_clear_cache_helper (filter,
3872 FILTER_LEVEL (filter->priv->root));