1 /* eggtreemodelfilter.c
2 * Copyright (C) 2000,2001 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
3 * Copyright (C) 2001,2002 Kristian Rietveld <kris@gtk.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program 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 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
21 #include "eggtreemodelfilter.h"
22 #include <gtk/gtksignal.h>
25 /* FIXME: remove this when we move it to GTK+ */
30 * iter->stamp = filter->stamp
31 * iter->user_data = FilterLevel
32 * iter->user_data2 = FilterElt
35 /* all paths, iters, etc prefixed with c_ are paths, iters, etc relative to the
39 typedef struct _FilterElt FilterElt
;
40 typedef struct _FilterLevel FilterLevel
;
45 FilterLevel
*children
;
57 FilterElt
*parent_elt
;
58 FilterLevel
*parent_level
;
69 #define EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS(filter) \
70 (((EggTreeModelFilter *)filter)->child_flags & GTK_TREE_MODEL_ITERS_PERSIST)
72 #define FILTER_ELT(filter_elt) ((FilterElt *)filter_elt)
73 #define FILTER_LEVEL(filter_level) ((FilterLevel *)filter_level)
75 /* general code (object/interface init, properties, etc) */
76 static void egg_tree_model_filter_init (EggTreeModelFilter
*filter
);
77 static void egg_tree_model_filter_class_init (EggTreeModelFilterClass
*filter_class
);
78 static void egg_tree_model_filter_tree_model_init (GtkTreeModelIface
*iface
);
79 static void egg_tree_model_filter_finalize (GObject
*object
);
80 static void egg_tree_model_filter_set_property (GObject
*object
,
84 static void egg_tree_model_filter_get_property (GObject
*object
,
90 static void egg_tree_model_filter_row_changed (GtkTreeModel
*c_model
,
94 static void egg_tree_model_filter_row_inserted (GtkTreeModel
*c_model
,
98 static void egg_tree_model_filter_row_has_child_toggled (GtkTreeModel
*c_model
,
102 static void egg_tree_model_filter_row_deleted (GtkTreeModel
*c_model
,
105 static void egg_tree_model_filter_rows_reordered (GtkTreeModel
*c_model
,
111 /* GtkTreeModel interface */
112 static guint
egg_tree_model_filter_get_flags (GtkTreeModel
*model
);
113 static gint
egg_tree_model_filter_get_n_columns (GtkTreeModel
*model
);
114 static GType
egg_tree_model_filter_get_column_type (GtkTreeModel
*model
,
116 static gboolean
egg_tree_model_filter_get_iter (GtkTreeModel
*model
,
119 static GtkTreePath
*egg_tree_model_filter_get_path (GtkTreeModel
*model
,
121 static void egg_tree_model_filter_get_value (GtkTreeModel
*model
,
125 static gboolean
egg_tree_model_filter_iter_next (GtkTreeModel
*model
,
127 static gboolean
egg_tree_model_filter_iter_children (GtkTreeModel
*model
,
129 GtkTreeIter
*parent
);
130 static gboolean
egg_tree_model_filter_iter_has_child (GtkTreeModel
*model
,
132 static gint
egg_tree_model_filter_iter_n_children (GtkTreeModel
*model
,
134 static gboolean
egg_tree_model_filter_iter_nth_child (GtkTreeModel
*model
,
138 static gboolean
egg_tree_model_filter_iter_parent (GtkTreeModel
*model
,
141 static void egg_tree_model_filter_ref_node (GtkTreeModel
*model
,
143 static void egg_tree_model_filter_unref_node (GtkTreeModel
*model
,
148 /* private functions */
149 static void egg_tree_model_filter_build_level (EggTreeModelFilter
*filter
,
150 FilterLevel
*parent_level
,
151 FilterElt
*parent_elt
);
152 static void egg_tree_model_filter_free_level (EggTreeModelFilter
*filter
,
153 FilterLevel
*filter_level
);
155 static GtkTreePath
*egg_tree_model_filter_elt_get_path (FilterLevel
*level
,
159 static GtkTreePath
*egg_tree_model_filter_add_root (GtkTreePath
*src
,
161 static GtkTreePath
*egg_tree_model_filter_remove_root (GtkTreePath
*src
,
164 static void egg_tree_model_filter_increment_stamp (EggTreeModelFilter
*filter
);
166 static gboolean
egg_tree_model_filter_visible (EggTreeModelFilter
*filter
,
167 GtkTreeIter
*child_iter
);
168 static void egg_tree_model_filter_clear_cache_helper (EggTreeModelFilter
*filter
,
171 static void egg_tree_model_filter_real_unref_node (GtkTreeModel
*model
,
173 gboolean propagate_unref
);
175 static void egg_tree_model_filter_set_model (EggTreeModelFilter
*filter
,
176 GtkTreeModel
*child_model
);
177 static void egg_tree_model_filter_set_root (EggTreeModelFilter
*filter
,
180 static GtkTreePath
*egg_real_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter
*filter
,
181 GtkTreePath
*child_path
,
182 gboolean build_levels
,
183 gboolean fetch_childs
);
185 static FilterElt
*egg_tree_model_filter_fetch_child (EggTreeModelFilter
*filter
,
189 static void egg_tree_model_filter_remove_node (EggTreeModelFilter
*filter
,
191 gboolean emit_signal
);
192 static void egg_tree_model_filter_update_childs (EggTreeModelFilter
*filter
,
195 static FilterElt
*bsearch_elt_with_offset (GArray
*array
,
200 static GObjectClass
*parent_class
= NULL
;
203 egg_tree_model_filter_get_type (void)
205 static GType tree_model_filter_type
= 0;
207 if (!tree_model_filter_type
)
209 static const GTypeInfo tree_model_filter_info
=
211 sizeof (EggTreeModelFilterClass
),
212 NULL
, /* base_init */
213 NULL
, /* base_finalize */
214 (GClassInitFunc
) egg_tree_model_filter_class_init
,
215 NULL
, /* class_finalize */
216 NULL
, /* class_data */
217 sizeof (EggTreeModelFilter
),
219 (GInstanceInitFunc
) egg_tree_model_filter_init
222 static const GInterfaceInfo tree_model_info
=
224 (GInterfaceInitFunc
) egg_tree_model_filter_tree_model_init
,
229 tree_model_filter_type
= g_type_register_static (G_TYPE_OBJECT
,
230 "EggTreeModelFilter",
231 &tree_model_filter_info
, 0);
233 g_type_add_interface_static (tree_model_filter_type
,
238 return tree_model_filter_type
;
242 egg_tree_model_filter_init (EggTreeModelFilter
*filter
)
244 filter
->visible_column
= -1;
245 filter
->zero_ref_count
= 0;
246 filter
->visible_method_set
= FALSE
;
247 filter
->modify_func_set
= FALSE
;
251 egg_tree_model_filter_class_init (EggTreeModelFilterClass
*filter_class
)
253 GObjectClass
*object_class
;
255 object_class
= (GObjectClass
*) filter_class
;
256 parent_class
= g_type_class_peek_parent (filter_class
);
258 object_class
->set_property
= egg_tree_model_filter_set_property
;
259 object_class
->get_property
= egg_tree_model_filter_get_property
;
261 object_class
->finalize
= egg_tree_model_filter_finalize
;
263 /* Properties -- FIXME: write a better description ... */
264 g_object_class_install_property (object_class
,
266 g_param_spec_object ("child_model",
267 _("The child model"),
268 _("The model for the filtermodel to filter"),
270 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
272 g_object_class_install_property (object_class
,
274 g_param_spec_boxed ("virtual_root",
275 _("The virtual root"),
276 _("The virtual root (relative to the child model) for this filtermodel"),
278 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
282 egg_tree_model_filter_tree_model_init (GtkTreeModelIface
*iface
)
284 iface
->get_flags
= egg_tree_model_filter_get_flags
;
285 iface
->get_n_columns
= egg_tree_model_filter_get_n_columns
;
286 iface
->get_column_type
= egg_tree_model_filter_get_column_type
;
287 iface
->get_iter
= egg_tree_model_filter_get_iter
;
288 iface
->get_path
= egg_tree_model_filter_get_path
;
289 iface
->get_value
= egg_tree_model_filter_get_value
;
290 iface
->iter_next
= egg_tree_model_filter_iter_next
;
291 iface
->iter_children
= egg_tree_model_filter_iter_children
;
292 iface
->iter_has_child
= egg_tree_model_filter_iter_has_child
;
293 iface
->iter_n_children
= egg_tree_model_filter_iter_n_children
;
294 iface
->iter_nth_child
= egg_tree_model_filter_iter_nth_child
;
295 iface
->iter_parent
= egg_tree_model_filter_iter_parent
;
296 iface
->ref_node
= egg_tree_model_filter_ref_node
;
297 iface
->unref_node
= egg_tree_model_filter_unref_node
;
302 egg_tree_model_filter_finalize (GObject
*object
)
304 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*) object
;
306 egg_tree_model_filter_set_model (filter
, NULL
);
308 if (filter
->virtual_root
)
309 gtk_tree_path_free (filter
->virtual_root
);
312 egg_tree_model_filter_free_level (filter
, filter
->root
);
314 if (filter
->modify_types
)
315 g_free (filter
->modify_types
);
318 parent_class
->finalize (object
);
322 egg_tree_model_filter_set_property (GObject
*object
,
327 EggTreeModelFilter
*filter
= EGG_TREE_MODEL_FILTER (object
);
331 case PROP_CHILD_MODEL
:
332 egg_tree_model_filter_set_model (filter
, g_value_get_object (value
));
334 case PROP_VIRTUAL_ROOT
:
335 egg_tree_model_filter_set_root (filter
, g_value_get_boxed (value
));
338 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
344 egg_tree_model_filter_get_property (GObject
*object
,
349 EggTreeModelFilter
*filter
= EGG_TREE_MODEL_FILTER (object
);
353 case PROP_CHILD_MODEL
:
354 g_value_set_object (value
, filter
->child_model
);
356 case PROP_VIRTUAL_ROOT
:
357 g_value_set_boxed (value
, filter
->virtual_root
);
360 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
368 egg_tree_model_filter_build_level (EggTreeModelFilter
*filter
,
369 FilterLevel
*parent_level
,
370 FilterElt
*parent_elt
)
374 FilterLevel
*new_level
;
378 g_assert (filter
->child_model
!= NULL
);
382 if (filter
->virtual_root
)
384 if (gtk_tree_model_get_iter (filter
->child_model
, &root
, filter
->virtual_root
) == FALSE
)
386 length
= gtk_tree_model_iter_n_children (filter
->child_model
, &root
);
388 if (gtk_tree_model_iter_children (filter
->child_model
, &iter
, &root
) == FALSE
)
393 if (!gtk_tree_model_get_iter_first (filter
->child_model
, &iter
))
395 length
= gtk_tree_model_iter_n_children (filter
->child_model
, NULL
);
400 GtkTreeIter parent_iter
;
401 GtkTreeIter child_parent_iter
;
403 parent_iter
.stamp
= filter
->stamp
;
404 parent_iter
.user_data
= parent_level
;
405 parent_iter
.user_data2
= parent_elt
;
407 egg_tree_model_filter_convert_iter_to_child_iter (filter
,
410 if (gtk_tree_model_iter_children (filter
->child_model
, &iter
, &child_parent_iter
) == FALSE
)
413 /* stamp may have changed */
414 egg_tree_model_filter_convert_iter_to_child_iter (filter
,
417 length
= gtk_tree_model_iter_n_children (filter
->child_model
, &child_parent_iter
);
420 g_return_if_fail (length
> 0);
422 new_level
= g_new (FilterLevel
, 1);
423 new_level
->array
= g_array_sized_new (FALSE
, FALSE
,
426 new_level
->ref_count
= 0;
427 new_level
->parent_elt
= parent_elt
;
428 new_level
->parent_level
= parent_level
;
431 parent_elt
->children
= new_level
;
433 filter
->root
= new_level
;
435 /* increase the count of zero ref_counts */
438 parent_elt
->zero_ref_count
++;
440 parent_elt
= parent_level
->parent_elt
;
441 parent_level
= parent_level
->parent_level
;
443 filter
->zero_ref_count
++;
447 if (!new_level
->parent_level
)
448 filter
->root_level_visible
= 0;
452 if (egg_tree_model_filter_visible (filter
, &iter
))
454 FilterElt filter_elt
;
456 filter_elt
.offset
= i
;
457 filter_elt
.zero_ref_count
= 0;
458 filter_elt
.ref_count
= 0;
459 filter_elt
.children
= NULL
;
460 filter_elt
.visible
= TRUE
;
462 if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter
))
463 filter_elt
.iter
= iter
;
465 g_array_append_val (new_level
->array
, filter_elt
);
467 if (!new_level
->parent_level
)
468 filter
->root_level_visible
++;
472 while (gtk_tree_model_iter_next (filter
->child_model
, &iter
));
476 egg_tree_model_filter_free_level (EggTreeModelFilter
*filter
,
477 FilterLevel
*filter_level
)
481 g_assert (filter_level
);
483 if (filter_level
->ref_count
== 0)
485 FilterLevel
*parent_level
= filter_level
->parent_level
;
486 FilterElt
*parent_elt
= filter_level
->parent_elt
;
491 parent_elt
->zero_ref_count
--;
495 parent_elt
= parent_level
->parent_elt
;
496 parent_level
= parent_level
->parent_level
;
499 while (parent_level
);
500 filter
->zero_ref_count
--;
503 for (i
= 0; i
< filter_level
->array
->len
; i
++)
505 if (g_array_index (filter_level
->array
, FilterElt
, i
).children
)
506 egg_tree_model_filter_free_level (filter
,
507 FILTER_LEVEL (g_array_index (filter_level
->array
, FilterElt
, i
).children
));
510 if (!filter_level
->parent_level
)
511 filter
->root_level_visible
= 0;
513 if (filter_level
->parent_elt
)
514 filter_level
->parent_elt
->children
= NULL
;
518 g_array_free (filter_level
->array
, TRUE
);
519 filter_level
->array
= NULL
;
521 g_free (filter_level
);
526 egg_tree_model_filter_elt_get_path (FilterLevel
*level
,
530 FilterLevel
*walker
= level
;
531 FilterElt
*walker2
= elt
;
533 GtkTreePath
*real_path
;
535 g_return_val_if_fail (level
!= NULL
, NULL
);
536 g_return_val_if_fail (elt
!= NULL
, NULL
);
538 path
= gtk_tree_path_new ();
542 gtk_tree_path_prepend_index (path
, walker2
->offset
);
544 walker2
= walker
->parent_elt
;
545 walker
= walker
->parent_level
;
550 real_path
= egg_tree_model_filter_add_root (path
, root
);
551 gtk_tree_path_free (path
);
559 egg_tree_model_filter_add_root (GtkTreePath
*src
,
565 retval
= gtk_tree_path_copy (root
);
567 for (i
= 0; i
< gtk_tree_path_get_depth (src
); i
++)
568 gtk_tree_path_append_index (retval
, gtk_tree_path_get_indices (src
)[i
]);
574 egg_tree_model_filter_remove_root (GtkTreePath
*src
,
582 if (gtk_tree_path_get_depth (src
) <= gtk_tree_path_get_depth (root
))
585 depth
= gtk_tree_path_get_depth (src
);
586 indices
= gtk_tree_path_get_indices (src
);
588 for (i
= 0; i
< gtk_tree_path_get_depth (root
); i
++)
589 if (indices
[i
] != gtk_tree_path_get_indices (root
)[i
])
592 retval
= gtk_tree_path_new ();
594 for (; i
< depth
; i
++)
595 gtk_tree_path_append_index (retval
, indices
[i
]);
601 egg_tree_model_filter_increment_stamp (EggTreeModelFilter
*filter
)
607 while (filter
->stamp
== 0);
609 egg_tree_model_filter_clear_cache (filter
);
613 egg_tree_model_filter_visible (EggTreeModelFilter
*filter
,
614 GtkTreeIter
*child_iter
)
616 if (filter
->visible_func
)
618 return (filter
->visible_func (filter
->child_model
,
620 filter
->visible_data
));
622 else if (filter
->visible_column
>= 0)
626 gtk_tree_model_get_value (filter
->child_model
, child_iter
,
627 filter
->visible_column
, &val
);
629 if (g_value_get_boolean (&val
))
631 g_value_unset (&val
);
635 g_value_unset (&val
);
639 /* no filter thing set, so always visible */
644 egg_tree_model_filter_clear_cache_helper (EggTreeModelFilter
*filter
,
651 for (i
= 0; i
< level
->array
->len
; i
++)
653 if (g_array_index (level
->array
, FilterElt
, i
).zero_ref_count
> 0)
654 egg_tree_model_filter_clear_cache_helper (filter
, g_array_index (level
->array
, FilterElt
, i
).children
);
657 if (level
->ref_count
== 0 && level
!= filter
->root
)
659 egg_tree_model_filter_free_level (filter
, level
);
665 egg_tree_model_filter_fetch_child (EggTreeModelFilter
*filter
,
671 gint start
, middle
, end
;
673 GtkTreePath
*c_path
= NULL
;
675 GtkTreePath
*c_parent_path
= NULL
;
676 GtkTreeIter c_parent_iter
;
679 /* check if child exists and is visible */
680 if (level
->parent_elt
)
683 egg_tree_model_filter_elt_get_path (level
->parent_level
,
685 filter
->virtual_root
);
691 if (filter
->virtual_root
)
692 c_parent_path
= gtk_tree_path_copy (filter
->virtual_root
);
694 c_parent_path
= NULL
;
699 gtk_tree_model_get_iter (filter
->child_model
,
702 len
= gtk_tree_model_iter_n_children (filter
->child_model
,
705 c_path
= gtk_tree_path_copy (c_parent_path
);
706 gtk_tree_path_free (c_parent_path
);
710 len
= gtk_tree_model_iter_n_children (filter
->child_model
, NULL
);
711 c_path
= gtk_tree_path_new ();
714 gtk_tree_path_append_index (c_path
, offset
);
715 gtk_tree_model_get_iter (filter
->child_model
, &c_iter
, c_path
);
716 gtk_tree_path_free (c_path
);
718 if (offset
>= len
|| !egg_tree_model_filter_visible (filter
, &c_iter
))
723 elt
.zero_ref_count
= 0;
726 /* visibility should be FALSE as we don't emit row_inserted */
729 if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter
))
732 /* find index (binary search on offset) */
734 end
= level
->array
->len
;
740 middle
= (start
+ end
) / 2;
742 if (g_array_index (level
->array
, FilterElt
, middle
).offset
<= offset
)
748 if (g_array_index (level
->array
, FilterElt
, middle
).offset
<= offset
)
756 g_array_insert_val (level
->array
, i
, elt
);
759 for (i
= MAX (--i
, 0); i
< level
->array
->len
; i
++)
761 FilterElt
*e
= &(g_array_index (level
->array
, FilterElt
, i
));
763 e
->children
->parent_elt
= e
;
766 return &g_array_index (level
->array
, FilterElt
, *index
);
770 egg_tree_model_filter_remove_node (EggTreeModelFilter
*filter
,
772 gboolean emit_signal
)
774 FilterElt
*elt
, *parent
;
775 FilterLevel
*level
, *parent_level
;
776 gint offset
, i
, length
, level_refcount
;
778 /* FIXME: this function is very ugly. I need to rethink and
779 * rewrite it someday.
782 level
= FILTER_LEVEL (iter
->user_data
);
783 elt
= FILTER_ELT (iter
->user_data2
);
785 parent
= level
->parent_elt
;
786 parent_level
= level
->parent_level
;
787 length
= level
->array
->len
;
788 offset
= elt
->offset
;
791 while (elt
->ref_count
> 0)
792 egg_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter
),
795 level_refcount
= level
->ref_count
;
797 /* do the ref counting first! this touches the stamp */
802 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (filter
), iter
);
803 egg_tree_model_filter_increment_stamp (filter
);
804 gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter
), path
);
805 gtk_tree_path_free (path
);
808 if ((length
== 1 || level_refcount
== 0) &&
809 emit_signal
&& iter
->user_data
!= filter
->root
)
811 /* above code destroyed the level */
812 goto emit_has_child_toggled
;
818 egg_tree_model_filter_free_level (filter
, level
);
821 /* we killed the root */
828 /* remove the node */
829 tmp
= bsearch_elt_with_offset (level
->array
, elt
->offset
, &i
);
833 g_array_remove_index (level
->array
, i
);
835 for (i
= MAX (--i
, 0); i
< level
->array
->len
; i
++)
837 /* NOTE: here we do *not* decrease offsets, because the node was
838 * not removed from the child model
840 elt
= &g_array_index (level
->array
, FilterElt
, i
);
842 elt
->children
->parent_elt
= elt
;
847 emit_has_child_toggled
:
848 /* children are being handled first, so we can check it this way
850 * yes this if-statement is ugly
852 if ((parent
&& parent
->children
&& parent
->children
->array
->len
<= 1) ||
853 (length
== 1 && emit_signal
&& iter
->user_data
!= filter
->root
))
855 /* latest child has been removed, level has been destroyed */
859 piter
.stamp
= filter
->stamp
;
860 piter
.user_data
= parent_level
;
861 piter
.user_data2
= parent
;
863 ppath
= gtk_tree_model_get_path (GTK_TREE_MODEL (filter
), &piter
);
865 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter
),
867 gtk_tree_path_free (ppath
);
872 egg_tree_model_filter_update_childs (EggTreeModelFilter
*filter
,
882 iter
.stamp
= filter
->stamp
;
883 iter
.user_data
= level
;
884 iter
.user_data2
= elt
;
886 egg_tree_model_filter_convert_iter_to_child_iter (filter
, &c_iter
, &iter
);
888 if (gtk_tree_model_iter_has_child (filter
->child_model
, &c_iter
))
890 GtkTreePath
*path
= gtk_tree_model_get_path (GTK_TREE_MODEL (filter
),
892 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter
),
896 gtk_tree_path_free (path
);
901 bsearch_elt_with_offset (GArray
*array
,
905 gint start
, middle
, end
;
916 elt
= &g_array_index (array
, FilterElt
, 0);
918 if (elt
->offset
== offset
)
929 middle
= (start
+ end
) / 2;
931 elt
= &g_array_index (array
, FilterElt
, middle
);
933 if (elt
->offset
< offset
)
935 else if (elt
->offset
> offset
)
941 if (elt
->offset
== offset
)
950 /* TreeModel signals */
952 egg_tree_model_filter_row_changed (GtkTreeModel
*c_model
,
957 EggTreeModelFilter
*filter
= EGG_TREE_MODEL_FILTER (data
);
960 GtkTreeIter real_c_iter
;
961 GtkTreePath
*path
= NULL
;
966 gboolean requested_state
;
967 gboolean current_state
;
968 gboolean free_c_path
= FALSE
;
970 g_return_if_fail (c_path
!= NULL
|| c_iter
!= NULL
);
974 c_path
= gtk_tree_model_get_path (c_model
, c_iter
);
979 real_c_iter
= *c_iter
;
981 gtk_tree_model_get_iter (c_model
, &real_c_iter
, c_path
);
983 /* is this node above the virtual root? */
984 if (filter
->virtual_root
985 && (gtk_tree_path_get_depth (filter
->virtual_root
)
986 >= gtk_tree_path_get_depth (c_path
)))
989 /* what's the requested state? */
990 requested_state
= egg_tree_model_filter_visible (filter
, &real_c_iter
);
992 /* now, let's see whether the item is there */
993 path
= egg_real_tree_model_filter_convert_child_path_to_path (filter
,
1000 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter
), &iter
, path
);
1001 current_state
= FILTER_ELT (iter
.user_data2
)->visible
;
1004 current_state
= FALSE
;
1006 if (current_state
== FALSE
&& requested_state
== FALSE
)
1007 /* no changes required */
1010 if (current_state
== TRUE
&& requested_state
== FALSE
)
1012 /* get rid of this node */
1013 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter
), &iter
, path
);
1014 egg_tree_model_filter_remove_node (filter
, &iter
, TRUE
);
1016 level
= FILTER_LEVEL (iter
.user_data
);
1018 if (!level
->parent_level
)
1019 filter
->root_level_visible
--;
1024 if (current_state
== TRUE
&& requested_state
== TRUE
)
1026 /* progate the signal */
1027 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter
), &iter
, path
);
1028 gtk_tree_model_row_changed (GTK_TREE_MODEL (filter
), path
, &iter
);
1030 level
= FILTER_LEVEL (iter
.user_data
);
1031 elt
= FILTER_ELT (iter
.user_data2
);
1033 /* and update the childs */
1034 if (gtk_tree_model_iter_children (c_model
, &childs
, &real_c_iter
))
1035 egg_tree_model_filter_update_childs (filter
, level
, elt
);
1040 /* only current == FALSE and requested == TRUE is left,
1043 g_return_if_fail (current_state
== FALSE
&& requested_state
== TRUE
);
1045 /* make sure the new item has been pulled in */
1051 egg_tree_model_filter_build_level (filter
, NULL
, NULL
);
1053 root
= FILTER_LEVEL (filter
->root
);
1057 for (i
= 0; i
< root
->array
->len
; i
++)
1058 g_array_index (root
->array
, FilterElt
, i
).visible
= FALSE
;
1059 filter
->root_level_visible
= 0;
1064 path
= egg_real_tree_model_filter_convert_child_path_to_path (filter
,
1069 g_return_if_fail (path
!= NULL
);
1071 egg_tree_model_filter_increment_stamp (filter
);
1072 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter
), &iter
, path
);
1074 level
= FILTER_LEVEL (iter
.user_data
);
1075 elt
= FILTER_ELT (iter
.user_data2
);
1077 elt
->visible
= TRUE
;
1079 if (!level
->parent_level
)
1080 filter
->root_level_visible
++;
1083 gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter
), path
, &iter
);
1085 if (gtk_tree_model_iter_children (c_model
, &childs
, c_iter
))
1086 egg_tree_model_filter_update_childs (filter
, level
, elt
);
1090 gtk_tree_path_free (path
);
1093 gtk_tree_path_free (c_path
);
1097 egg_tree_model_filter_row_inserted (GtkTreeModel
*c_model
,
1098 GtkTreePath
*c_path
,
1099 GtkTreeIter
*c_iter
,
1102 EggTreeModelFilter
*filter
= EGG_TREE_MODEL_FILTER (data
);
1103 GtkTreePath
*path
= NULL
;
1104 GtkTreePath
*real_path
= NULL
;
1107 GtkTreeIter real_c_iter
;
1111 FilterLevel
*parent_level
;
1113 gint i
= 0, offset
, index
= -1;
1115 gboolean free_c_path
= FALSE
;
1117 g_return_if_fail (c_path
!= NULL
|| c_iter
!= NULL
);
1121 c_path
= gtk_tree_model_get_path (c_model
, c_iter
);
1126 real_c_iter
= *c_iter
;
1128 gtk_tree_model_get_iter (c_model
, &real_c_iter
, c_path
);
1130 /* the row has already been inserted. so we need to fixup the
1131 * virtual root here first
1133 if (filter
->virtual_root
)
1135 if (gtk_tree_path_get_depth (filter
->virtual_root
) >=
1136 gtk_tree_path_get_depth (c_path
))
1139 gint
*v_indices
, *c_indices
;
1141 level
= gtk_tree_path_get_depth (c_path
) - 1;
1142 v_indices
= gtk_tree_path_get_indices (filter
->virtual_root
);
1143 c_indices
= gtk_tree_path_get_indices (c_path
);
1145 if (v_indices
[level
] >= c_indices
[level
])
1146 (v_indices
[level
])++;
1152 egg_tree_model_filter_build_level (filter
, NULL
, NULL
);
1153 /* that already put the inserted iter in the level */
1158 parent_level
= level
= FILTER_LEVEL (filter
->root
);
1160 /* subtract virtual root if necessary */
1161 if (filter
->virtual_root
)
1163 real_path
= egg_tree_model_filter_remove_root (c_path
,
1164 filter
->virtual_root
);
1170 real_path
= gtk_tree_path_copy (c_path
);
1172 if (gtk_tree_path_get_depth (real_path
) - 1 >= 1)
1174 /* find the parent level */
1175 while (i
< gtk_tree_path_get_depth (real_path
) - 1)
1180 /* we don't cover this signal */
1183 elt
= bsearch_elt_with_offset (level
->array
,
1184 gtk_tree_path_get_indices (real_path
)[i
],
1188 /* parent is probably being filtered out */
1193 GtkTreePath
*tmppath
;
1194 GtkTreeIter tmpiter
;
1196 tmpiter
.stamp
= filter
->stamp
;
1197 tmpiter
.user_data
= level
;
1198 tmpiter
.user_data2
= elt
;
1200 tmppath
= gtk_tree_model_get_path (GTK_TREE_MODEL (data
),
1205 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data
),
1207 gtk_tree_path_free (tmppath
);
1210 /* not covering this signal */
1214 level
= elt
->children
;
1215 parent_level
= level
;
1223 /* let's try to insert the value */
1224 offset
= gtk_tree_path_get_indices (real_path
)[gtk_tree_path_get_depth (real_path
) - 1];
1226 /* update the offsets, yes if we didn't insert the node above, there will
1227 * be a gap here. This will be filled with the node (via fetch_child) when
1228 * it becomes visible
1230 for (i
= 0; i
< level
->array
->len
; i
++)
1232 FilterElt
*e
= &g_array_index (level
->array
, FilterElt
, i
);
1233 if ((e
->offset
>= offset
))
1237 /* only insert when visible */
1238 if (egg_tree_model_filter_visible (filter
, &real_c_iter
))
1242 if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter
))
1243 felt
.iter
= real_c_iter
;
1245 felt
.offset
= offset
;
1246 felt
.zero_ref_count
= 0;
1248 felt
.visible
= TRUE
;
1249 felt
.children
= NULL
;
1251 for (i
= 0; i
< level
->array
->len
; i
++)
1252 if (g_array_index (level
->array
, FilterElt
, i
).offset
> offset
)
1255 g_array_insert_val (level
->array
, i
, felt
);
1258 if (!level
->parent_level
)
1259 filter
->root_level_visible
++;
1262 /* another iteration to update the references of childs to parents. */
1263 for (i
= 0; i
< level
->array
->len
; i
++)
1265 FilterElt
*e
= &g_array_index (level
->array
, FilterElt
, i
);
1267 e
->children
->parent_elt
= e
;
1270 /* don't emit the signal if we aren't visible */
1271 if (!egg_tree_model_filter_visible (filter
, &real_c_iter
))
1275 /* NOTE: pass c_path here and NOT real_path. This function does
1276 * root subtraction itself
1278 path
= egg_real_tree_model_filter_convert_child_path_to_path (filter
,
1285 egg_tree_model_filter_increment_stamp (filter
);
1287 gtk_tree_model_get_iter (GTK_TREE_MODEL (data
), &iter
, path
);
1288 gtk_tree_model_row_inserted (GTK_TREE_MODEL (data
), path
, &iter
);
1290 gtk_tree_path_free (path
);
1294 gtk_tree_path_free (real_path
);
1297 gtk_tree_path_free (c_path
);
1301 egg_tree_model_filter_row_has_child_toggled (GtkTreeModel
*c_model
,
1302 GtkTreePath
*c_path
,
1303 GtkTreeIter
*c_iter
,
1306 EggTreeModelFilter
*filter
= EGG_TREE_MODEL_FILTER (data
);
1310 g_return_if_fail (c_path
!= NULL
&& c_iter
!= NULL
);
1312 /* FIXME: does this code work? */
1314 if (!egg_tree_model_filter_visible (filter
, c_iter
))
1317 path
= egg_real_tree_model_filter_convert_child_path_to_path (filter
,
1324 gtk_tree_model_get_iter (GTK_TREE_MODEL (data
), &iter
, path
);
1325 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data
), path
, &iter
);
1327 gtk_tree_path_free (path
);
1331 egg_tree_model_filter_row_deleted (GtkTreeModel
*c_model
,
1332 GtkTreePath
*c_path
,
1335 EggTreeModelFilter
*filter
= EGG_TREE_MODEL_FILTER (data
);
1341 gboolean emit_signal
= TRUE
;
1344 g_return_if_fail (c_path
!= NULL
);
1346 /* special case the deletion of an ancestor of the virtual root */
1347 if (filter
->virtual_root
&&
1348 (gtk_tree_path_is_ancestor (c_path
, filter
->virtual_root
) ||
1349 !gtk_tree_path_compare (c_path
, filter
->virtual_root
)))
1353 FilterLevel
*level
= FILTER_LEVEL (filter
->root
);
1358 /* remove everything in the filter model
1360 * For now, we just iterate over the root level and emit a
1361 * row_deleted for each FilterElt. Not sure if this is correct.
1364 egg_tree_model_filter_increment_stamp (filter
);
1365 path
= gtk_tree_path_new ();
1366 gtk_tree_path_append_index (path
, 0);
1368 for (i
= 0; i
< level
->array
->len
; i
++)
1369 gtk_tree_model_row_deleted (GTK_TREE_MODEL (data
), path
);
1371 gtk_tree_path_free (path
);
1372 egg_tree_model_filter_free_level (filter
, filter
->root
);
1377 /* fixup virtual root */
1378 if (filter
->virtual_root
)
1380 if (gtk_tree_path_get_depth (filter
->virtual_root
) >=
1381 gtk_tree_path_get_depth (c_path
))
1384 gint
*v_indices
, *c_indices
;
1386 level
= gtk_tree_path_get_depth (c_path
) - 1;
1387 v_indices
= gtk_tree_path_get_indices (filter
->virtual_root
);
1388 c_indices
= gtk_tree_path_get_indices (c_path
);
1390 if (v_indices
[level
] > c_indices
[level
])
1391 (v_indices
[level
])--;
1395 path
= egg_real_tree_model_filter_convert_child_path_to_path (filter
,
1402 /* fixup the offsets */
1403 GtkTreePath
*real_path
;
1408 level
= FILTER_LEVEL (filter
->root
);
1410 /* subtract vroot if necessary */
1411 if (filter
->virtual_root
)
1413 real_path
= egg_tree_model_filter_remove_root (c_path
,
1414 filter
->virtual_root
);
1415 /* we don't handle this */
1420 real_path
= gtk_tree_path_copy (c_path
);
1423 if (gtk_tree_path_get_depth (real_path
) - 1 >= 1)
1425 while (i
< gtk_tree_path_get_depth (real_path
) - 1)
1431 /* we don't cover this */
1432 gtk_tree_path_free (real_path
);
1436 elt
= bsearch_elt_with_offset (level
->array
,
1437 gtk_tree_path_get_indices (real_path
)[i
],
1441 if (!elt
|| !elt
->children
)
1443 /* parent is filtered out, so no level */
1444 gtk_tree_path_free (real_path
);
1448 level
= elt
->children
;
1453 offset
= gtk_tree_path_get_indices (real_path
)[gtk_tree_path_get_depth (real_path
) - 1];
1454 gtk_tree_path_free (real_path
);
1460 * - the offset of the removed item
1463 for (i
= 0; i
< level
->array
->len
; i
++)
1465 elt
= &g_array_index (level
->array
, FilterElt
, i
);
1466 if (elt
->offset
> offset
)
1469 elt
->children
->parent_elt
= elt
;
1475 gtk_tree_model_get_iter (GTK_TREE_MODEL (data
), &iter
, path
);
1477 level
= FILTER_LEVEL (iter
.user_data
);
1478 elt
= FILTER_ELT (iter
.user_data2
);
1479 offset
= elt
->offset
;
1481 if (!level
->parent_level
&& elt
->visible
)
1482 filter
->root_level_visible
--;
1486 if (level
->ref_count
== 0 && level
!= filter
->root
)
1488 egg_tree_model_filter_increment_stamp (filter
);
1489 gtk_tree_model_row_deleted (GTK_TREE_MODEL (data
), path
);
1491 gtk_tree_path_free (path
);
1495 egg_tree_model_filter_increment_stamp (filter
);
1496 gtk_tree_model_row_deleted (GTK_TREE_MODEL (data
), path
);
1497 iter
.stamp
= filter
->stamp
;
1499 while (elt
->ref_count
> 0)
1500 egg_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data
), &iter
,
1504 if (level
->array
->len
== 1)
1507 egg_tree_model_filter_free_level (filter
, level
);
1513 /* remove the row */
1514 tmp
= bsearch_elt_with_offset (level
->array
, elt
->offset
, &i
);
1516 offset
= tmp
->offset
;
1517 g_array_remove_index (level
->array
, i
);
1519 for (i
= MAX (--i
, 0); i
< level
->array
->len
; i
++)
1521 elt
= &g_array_index (level
->array
, FilterElt
, i
);
1522 if (elt
->offset
> offset
)
1525 elt
->children
->parent_elt
= elt
;
1529 gtk_tree_path_free (path
);
1533 egg_tree_model_filter_rows_reordered (GtkTreeModel
*c_model
,
1534 GtkTreePath
*c_path
,
1535 GtkTreeIter
*c_iter
,
1541 EggTreeModelFilter
*filter
= EGG_TREE_MODEL_FILTER (data
);
1547 gint i
, j
, elt_count
;
1552 g_return_if_fail (new_order
!= NULL
);
1554 if (c_path
== NULL
|| gtk_tree_path_get_indices (c_path
) == NULL
)
1559 length
= gtk_tree_model_iter_n_children (c_model
, NULL
);
1561 if (filter
->virtual_root
)
1565 /* reorder root level of path */
1566 for (i
= 0; i
< length
; i
++)
1567 if (new_order
[i
] == gtk_tree_path_get_indices (filter
->virtual_root
)[0])
1573 gtk_tree_path_get_indices (filter
->virtual_root
)[0] = new_pos
;
1577 path
= gtk_tree_path_new ();
1578 level
= FILTER_LEVEL (filter
->root
);
1582 GtkTreeIter child_iter
;
1584 /* virtual root anchor reordering */
1585 if (filter
->virtual_root
&&
1586 gtk_tree_path_get_depth (c_path
) <
1587 gtk_tree_path_get_depth (filter
->virtual_root
))
1592 GtkTreeIter real_c_iter
;
1594 level
= gtk_tree_path_get_depth (c_path
);
1597 real_c_iter
= *c_iter
;
1599 gtk_tree_model_get_iter (c_model
, &real_c_iter
, c_path
);
1601 length
= gtk_tree_model_iter_n_children (c_model
, &real_c_iter
);
1603 for (i
= 0; i
< length
; i
++)
1604 if (new_order
[i
] == gtk_tree_path_get_indices (filter
->virtual_root
)[level
])
1610 gtk_tree_path_get_indices (filter
->virtual_root
)[level
] = new_pos
;
1614 path
= egg_real_tree_model_filter_convert_child_path_to_path (filter
,
1618 if (!path
&& filter
->virtual_root
&&
1619 gtk_tree_path_compare (c_path
, filter
->virtual_root
))
1622 if (!path
&& !filter
->virtual_root
)
1627 /* root level mode */
1629 gtk_tree_model_get_iter (c_model
, c_iter
, c_path
);
1630 length
= gtk_tree_model_iter_n_children (c_model
, c_iter
);
1631 path
= gtk_tree_path_new ();
1632 level
= FILTER_LEVEL (filter
->root
);
1636 gtk_tree_model_get_iter (GTK_TREE_MODEL (data
), &iter
, path
);
1638 level
= FILTER_LEVEL (iter
.user_data
);
1639 elt
= FILTER_ELT (iter
.user_data2
);
1643 gtk_tree_path_free (path
);
1647 level
= elt
->children
;
1649 egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (filter
), &child_iter
, &iter
);
1650 length
= gtk_tree_model_iter_n_children (c_model
, &child_iter
);
1654 if (level
->array
->len
< 1)
1657 /* NOTE: we do not bail out here if level->array->len < 2 like
1658 * GtkTreeModelSort does. This because we do some special tricky
1662 /* construct a new array */
1663 new_array
= g_array_sized_new (FALSE
, FALSE
, sizeof (FilterElt
),
1665 tmp_array
= g_new (gint
, level
->array
->len
);
1667 for (i
= 0, elt_count
= 0; i
< length
; i
++)
1669 FilterElt
*e
= NULL
;
1670 gint old_offset
= -1;
1672 for (j
= 0; j
< level
->array
->len
; j
++)
1673 if (g_array_index (level
->array
, FilterElt
, j
).offset
== new_order
[i
])
1675 e
= &g_array_index (level
->array
, FilterElt
, j
);
1683 tmp_array
[elt_count
] = old_offset
;
1684 g_array_append_val (new_array
, *e
);
1685 g_array_index (new_array
, FilterElt
, elt_count
).offset
= i
;
1689 g_array_free (level
->array
, TRUE
);
1690 level
->array
= new_array
;
1693 for (i
= 0; i
< level
->array
->len
; i
++)
1695 FilterElt
*e
= &g_array_index (level
->array
, FilterElt
, i
);
1697 e
->children
->parent_elt
= e
;
1700 /* emit rows_reordered */
1701 if (!gtk_tree_path_get_indices (path
))
1702 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data
), path
, NULL
,
1705 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data
), path
, &iter
,
1710 gtk_tree_path_free (path
);
1713 /* TreeModelIface implementation */
1715 egg_tree_model_filter_get_flags (GtkTreeModel
*model
)
1717 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), 0);
1723 egg_tree_model_filter_get_n_columns (GtkTreeModel
*model
)
1725 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
1727 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), 0);
1728 g_return_val_if_fail (filter
->child_model
!= NULL
, 0);
1730 if (filter
->child_model
== NULL
)
1733 /* so we can't modify the modify func after this ... */
1734 filter
->modify_func_set
= TRUE
;
1736 if (filter
->modify_n_columns
> 0)
1737 return filter
->modify_n_columns
;
1739 return gtk_tree_model_get_n_columns (filter
->child_model
);
1743 egg_tree_model_filter_get_column_type (GtkTreeModel
*model
,
1746 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
1748 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), G_TYPE_INVALID
);
1749 g_return_val_if_fail (filter
->child_model
!= NULL
, G_TYPE_INVALID
);
1751 /* so we can't modify the modify func after this ... */
1752 filter
->modify_func_set
= TRUE
;
1754 if (filter
->modify_types
)
1756 g_return_val_if_fail (index
< filter
->modify_n_columns
, G_TYPE_INVALID
);
1758 return filter
->modify_types
[index
];
1761 return gtk_tree_model_get_column_type (filter
->child_model
, index
);
1765 egg_tree_model_filter_get_iter (GtkTreeModel
*model
,
1769 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
1774 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), FALSE
);
1775 g_return_val_if_fail (filter
->child_model
!= NULL
, FALSE
);
1777 indices
= gtk_tree_path_get_indices (path
);
1779 if (filter
->root
== NULL
)
1780 egg_tree_model_filter_build_level (filter
, NULL
, NULL
);
1781 level
= FILTER_LEVEL (filter
->root
);
1783 depth
= gtk_tree_path_get_depth (path
);
1790 for (i
= 0; i
< depth
- 1; i
++)
1792 if (!level
|| indices
[i
] >= level
->array
->len
)
1797 if (!g_array_index (level
->array
, FilterElt
, indices
[i
]).children
)
1798 egg_tree_model_filter_build_level (filter
, level
,
1799 &g_array_index (level
->array
,
1802 level
= g_array_index (level
->array
, FilterElt
, indices
[i
]).children
;
1805 if (!level
|| indices
[i
] >= level
->array
->len
)
1811 iter
->stamp
= filter
->stamp
;
1812 iter
->user_data
= level
;
1813 iter
->user_data2
= &g_array_index (level
->array
, FilterElt
,
1814 indices
[depth
- 1]);
1819 static GtkTreePath
*
1820 egg_tree_model_filter_get_path (GtkTreeModel
*model
,
1823 GtkTreePath
*retval
;
1827 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), NULL
);
1828 g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model
)->child_model
!= NULL
, NULL
);
1829 g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model
)->stamp
== iter
->stamp
, NULL
);
1831 retval
= gtk_tree_path_new ();
1832 level
= iter
->user_data
;
1833 elt
= iter
->user_data2
;
1837 gtk_tree_path_prepend_index (retval
,
1838 elt
- FILTER_ELT (level
->array
->data
));
1839 elt
= level
->parent_elt
;
1840 level
= level
->parent_level
;
1847 egg_tree_model_filter_get_value (GtkTreeModel
*model
,
1852 GtkTreeIter child_iter
;
1853 EggTreeModelFilter
*filter
= EGG_TREE_MODEL_FILTER (model
);
1855 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model
));
1856 g_return_if_fail (EGG_TREE_MODEL_FILTER (model
)->child_model
!= NULL
);
1857 g_return_if_fail (EGG_TREE_MODEL_FILTER (model
)->stamp
== iter
->stamp
);
1859 if (filter
->modify_func
)
1861 g_return_if_fail (column
< filter
->modify_n_columns
);
1863 g_value_init (value
, filter
->modify_types
[column
]);
1864 filter
->modify_func (model
,
1868 filter
->modify_data
);
1873 egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model
), &child_iter
, iter
);
1874 gtk_tree_model_get_value (EGG_TREE_MODEL_FILTER (model
)->child_model
,
1875 &child_iter
, column
, value
);
1879 egg_tree_model_filter_iter_next (GtkTreeModel
*model
,
1885 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), FALSE
);
1886 g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model
)->child_model
!= NULL
, FALSE
);
1887 g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model
)->stamp
== iter
->stamp
, FALSE
);
1889 level
= iter
->user_data
;
1890 elt
= iter
->user_data2
;
1892 if (elt
- FILTER_ELT (level
->array
->data
) >= level
->array
->len
- 1)
1898 iter
->user_data2
= elt
+ 1;
1904 egg_tree_model_filter_iter_children (GtkTreeModel
*model
,
1906 GtkTreeIter
*parent
)
1908 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
1912 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), FALSE
);
1913 g_return_val_if_fail (filter
->child_model
!= NULL
, FALSE
);
1915 g_return_val_if_fail (filter
->stamp
== parent
->stamp
, FALSE
);
1920 egg_tree_model_filter_build_level (filter
, NULL
, NULL
);
1924 level
= filter
->root
;
1925 iter
->stamp
= filter
->stamp
;
1926 iter
->user_data
= level
;
1927 iter
->user_data2
= level
->array
->data
;
1931 if (FILTER_ELT (parent
->user_data2
)->children
== NULL
)
1932 egg_tree_model_filter_build_level (filter
,
1933 FILTER_LEVEL (parent
->user_data
),
1934 FILTER_ELT (parent
->user_data2
));
1935 if (FILTER_ELT (parent
->user_data2
)->children
== NULL
)
1939 if (FILTER_ELT (parent
->user_data2
)->children
->array
->len
<= 0)
1942 iter
->stamp
= filter
->stamp
;
1943 iter
->user_data
= FILTER_ELT (parent
->user_data2
)->children
;
1944 iter
->user_data2
= FILTER_LEVEL (iter
->user_data
)->array
->data
;
1951 egg_tree_model_filter_iter_has_child (GtkTreeModel
*model
,
1954 GtkTreeIter child_iter
;
1955 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
1958 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), FALSE
);
1959 g_return_val_if_fail (filter
->child_model
!= NULL
, FALSE
);
1960 g_return_val_if_fail (filter
->stamp
== iter
->stamp
, FALSE
);
1962 filter
= EGG_TREE_MODEL_FILTER (model
);
1964 egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model
), &child_iter
, iter
);
1965 elt
= FILTER_ELT (iter
->user_data2
);
1967 /* we need to build the level to check if not all children are filtered
1971 && gtk_tree_model_iter_has_child (filter
->child_model
, &child_iter
))
1972 egg_tree_model_filter_build_level (filter
, FILTER_LEVEL (iter
->user_data
),
1975 /* FIXME: we should prolly count the visible nodes here, just like in
1978 if (elt
->children
&& elt
->children
->array
->len
> 0)
1985 egg_tree_model_filter_iter_n_children (GtkTreeModel
*model
,
1988 GtkTreeIter child_iter
;
1989 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
1992 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), 0);
1993 g_return_val_if_fail (filter
->child_model
!= NULL
, 0);
1995 g_return_val_if_fail (filter
->stamp
== iter
->stamp
, 0);
2000 egg_tree_model_filter_build_level (filter
, NULL
, NULL
);
2002 /* count visible nodes */
2003 return filter
->root_level_visible
;
2006 elt
= FILTER_ELT (iter
->user_data2
);
2007 egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model
), &child_iter
, iter
);
2009 if (!elt
->children
&&
2010 gtk_tree_model_iter_has_child (filter
->child_model
, &child_iter
))
2011 egg_tree_model_filter_build_level (filter
,
2012 FILTER_LEVEL (iter
->user_data
),
2015 if (elt
->children
&& elt
->children
->array
->len
)
2019 GArray
*a
= elt
->children
->array
;
2021 /* count visible nodes */
2022 for (i
= 0; i
< a
->len
; i
++)
2023 if (g_array_index (a
, FilterElt
, i
).visible
)
2033 egg_tree_model_filter_iter_nth_child (GtkTreeModel
*model
,
2035 GtkTreeIter
*parent
,
2039 GtkTreeIter children
;
2041 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), FALSE
);
2043 g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model
)->stamp
== parent
->stamp
, FALSE
);
2045 /* use this instead of has_Child to force us to build the level, if needed */
2046 if (egg_tree_model_filter_iter_children (model
, &children
, parent
) == FALSE
)
2052 level
= children
.user_data
;
2053 if (n
>= level
->array
->len
)
2059 iter
->stamp
= EGG_TREE_MODEL_FILTER (model
)->stamp
;
2060 iter
->user_data
= level
;
2061 iter
->user_data2
= &g_array_index (level
->array
, FilterElt
, n
);
2067 egg_tree_model_filter_iter_parent (GtkTreeModel
*model
,
2074 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), FALSE
);
2075 g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model
)->child_model
!= NULL
, FALSE
);
2076 g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model
)->stamp
== child
->stamp
, FALSE
);
2078 level
= child
->user_data
;
2080 if (level
->parent_level
)
2082 iter
->stamp
= EGG_TREE_MODEL_FILTER (model
)->stamp
;
2083 iter
->user_data
= level
->parent_level
;
2084 iter
->user_data2
= level
->parent_elt
;
2093 egg_tree_model_filter_ref_node (GtkTreeModel
*model
,
2096 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
2097 GtkTreeIter child_iter
;
2101 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model
));
2102 g_return_if_fail (EGG_TREE_MODEL_FILTER (model
)->child_model
!= NULL
);
2103 g_return_if_fail (EGG_TREE_MODEL_FILTER (model
)->stamp
== iter
->stamp
);
2105 egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model
), &child_iter
, iter
);
2107 gtk_tree_model_ref_node (filter
->child_model
, &child_iter
);
2109 level
= iter
->user_data
;
2110 elt
= iter
->user_data2
;
2114 if (level
->ref_count
== 1)
2116 FilterLevel
*parent_level
= level
->parent_level
;
2117 FilterElt
*parent_elt
= level
->parent_elt
;
2119 /* we were at zero -- time to decrease the zero_ref_count val */
2123 parent_elt
->zero_ref_count
--;
2127 parent_elt
= parent_level
->parent_elt
;
2128 parent_level
= parent_level
->parent_level
;
2131 while (parent_level
);
2132 filter
->zero_ref_count
--;
2137 egg_tree_model_filter_unref_node (GtkTreeModel
*model
,
2140 egg_tree_model_filter_real_unref_node (model
, iter
, TRUE
);
2144 egg_tree_model_filter_real_unref_node (GtkTreeModel
*model
,
2146 gboolean propagate_unref
)
2148 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
2152 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model
));
2153 g_return_if_fail (filter
->child_model
!= NULL
);
2154 g_return_if_fail (filter
->stamp
== iter
->stamp
);
2156 if (propagate_unref
)
2158 GtkTreeIter child_iter
;
2159 egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model
), &child_iter
, iter
);
2160 gtk_tree_model_unref_node (filter
->child_model
, &child_iter
);
2163 level
= iter
->user_data
;
2164 elt
= iter
->user_data2
;
2166 g_return_if_fail (elt
->ref_count
> 0);
2170 if (level
->ref_count
== 0)
2172 FilterLevel
*parent_level
= level
->parent_level
;
2173 FilterElt
*parent_elt
= level
->parent_elt
;
2175 /* we are at zero -- time to increase the zero_ref_count val */
2176 while (parent_level
)
2178 parent_elt
->zero_ref_count
++;
2180 parent_elt
= parent_level
->parent_elt
;
2181 parent_level
= parent_level
->parent_level
;
2183 filter
->zero_ref_count
++;
2187 /* bits and pieces */
2189 egg_tree_model_filter_set_model (EggTreeModelFilter
*filter
,
2190 GtkTreeModel
*child_model
)
2192 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2194 if (filter
->child_model
)
2196 g_signal_handler_disconnect (G_OBJECT (filter
->child_model
),
2197 filter
->changed_id
);
2198 g_signal_handler_disconnect (G_OBJECT (filter
->child_model
),
2199 filter
->inserted_id
);
2200 g_signal_handler_disconnect (G_OBJECT (filter
->child_model
),
2201 filter
->has_child_toggled_id
);
2202 g_signal_handler_disconnect (G_OBJECT (filter
->child_model
),
2203 filter
->deleted_id
);
2204 g_signal_handler_disconnect (G_OBJECT (filter
->child_model
),
2205 filter
->reordered_id
);
2207 /* reset our state */
2209 egg_tree_model_filter_free_level (filter
, filter
->root
);
2211 filter
->root
= NULL
;
2212 g_object_unref (G_OBJECT (filter
->child_model
));
2213 filter
->visible_column
= -1;
2214 /* FIXME: destroy more crack here? the funcs? */
2217 filter
->child_model
= child_model
;
2221 g_object_ref (G_OBJECT (filter
->child_model
));
2222 filter
->changed_id
=
2223 g_signal_connect (child_model
, "row_changed",
2224 G_CALLBACK (egg_tree_model_filter_row_changed
),
2226 filter
->inserted_id
=
2227 g_signal_connect (child_model
, "row_inserted",
2228 G_CALLBACK (egg_tree_model_filter_row_inserted
),
2230 filter
->has_child_toggled_id
=
2231 g_signal_connect (child_model
, "row_has_child_toggled",
2232 G_CALLBACK (egg_tree_model_filter_row_has_child_toggled
),
2234 filter
->deleted_id
=
2235 g_signal_connect (child_model
, "row_deleted",
2236 G_CALLBACK (egg_tree_model_filter_row_deleted
),
2238 filter
->reordered_id
=
2239 g_signal_connect (child_model
, "rows_reordered",
2240 G_CALLBACK (egg_tree_model_filter_rows_reordered
),
2243 filter
->child_flags
= gtk_tree_model_get_flags (child_model
);
2244 filter
->stamp
= g_random_int ();
2249 egg_tree_model_filter_set_root (EggTreeModelFilter
*filter
,
2252 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2255 filter
->virtual_root
= NULL
;
2257 filter
->virtual_root
= gtk_tree_path_copy (root
);
2263 * egg_tree_model_filter_new:
2264 * @child_model: A #GtkTreeModel.
2265 * @root: A #GtkTreePath or %NULL.
2267 * Creates a new #GtkTreeModel, with @child_model as the child_model
2268 * and @root as the virtual root.
2270 * Return value: A new #GtkTreeModel.
2273 egg_tree_model_filter_new (GtkTreeModel
*child_model
,
2276 GtkTreeModel
*retval
;
2278 g_return_val_if_fail (GTK_IS_TREE_MODEL (child_model
), NULL
);
2280 retval
= GTK_TREE_MODEL (g_object_new (egg_tree_model_filter_get_type (), NULL
));
2282 egg_tree_model_filter_set_model (EGG_TREE_MODEL_FILTER (retval
),
2284 egg_tree_model_filter_set_root (EGG_TREE_MODEL_FILTER (retval
), root
);
2290 * egg_tree_model_filter_get_model:
2291 * @filter: A #EggTreeModelFilter.
2293 * Returns a pointer to the child model of @filter.
2295 * Return value: A pointer to a #GtkTreeModel.
2298 egg_tree_model_filter_get_model (EggTreeModelFilter
*filter
)
2300 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
), NULL
);
2302 return filter
->child_model
;
2306 * egg_tree_model_filter_set_visible_func:
2307 * @filter: A #EggTreeModelFilter.
2308 * @func: A #EggTreeModelFilterVisibleFunc, the visible function.
2309 * @data: User data to pass to the visible function, or %NULL.
2310 * @destroy: Destroy notifier of @data, or %NULL.
2312 * Sets the visible function used when filtering the @filter to be @func. The
2313 * function should return %TRUE if the given row should be visible and
2317 egg_tree_model_filter_set_visible_func (EggTreeModelFilter
*filter
,
2318 EggTreeModelFilterVisibleFunc func
,
2320 GtkDestroyNotify destroy
)
2322 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2323 g_return_if_fail (func
!= NULL
);
2324 g_return_if_fail (filter
->visible_method_set
== FALSE
);
2326 if (filter
->visible_func
)
2328 GtkDestroyNotify d
= filter
->visible_destroy
;
2330 filter
->visible_destroy
= NULL
;
2331 d (filter
->visible_data
);
2334 filter
->visible_func
= func
;
2335 filter
->visible_data
= data
;
2336 filter
->visible_destroy
= destroy
;
2338 filter
->visible_method_set
= TRUE
;
2342 * egg_tree_model_filter_set_modify_func:
2343 * @filter: A #EggTreeModelFilter.
2344 * @n_columns: The number of columns in the filter model.
2345 * @types: The #GType<!-- -->s of the columns.
2346 * @func: A #EggTreeModelFilterModifyFunc, or %NULL.
2347 * @data: User data to pass to the modify function, or %NULL.
2348 * @destroy: Destroy notifier of @data, or %NULL.
2350 * Sets the @filter to have @n_columns columns with @types. If @func
2351 * is not %NULL, it will set @func to be the modify function of @filter.
2354 egg_tree_model_filter_set_modify_func (EggTreeModelFilter
*filter
,
2357 EggTreeModelFilterModifyFunc func
,
2359 GtkDestroyNotify destroy
)
2361 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2362 g_return_if_fail (func
!= NULL
);
2363 g_return_if_fail (filter
->modify_func_set
== FALSE
);
2365 if (filter
->modify_destroy
)
2367 GtkDestroyNotify d
= filter
->modify_destroy
;
2369 filter
->modify_destroy
= NULL
;
2370 d (filter
->modify_data
);
2373 filter
->modify_n_columns
= n_columns
;
2374 filter
->modify_types
= g_new0 (GType
, n_columns
);
2375 memcpy (filter
->modify_types
, types
, sizeof (GType
) * n_columns
);
2376 filter
->modify_func
= func
;
2377 filter
->modify_data
= data
;
2378 filter
->modify_destroy
= destroy
;
2380 filter
->modify_func_set
= TRUE
;
2384 * egg_tree_model_filter_set_visible_column:
2385 * @filter: A #EggTreeModelFilter.
2386 * @column: A #gint which is the column containing the visible information.
2388 * Sets @column of the child_model to be the column where @filter should
2389 * look for visibility information. @columns should be a column of type
2390 * %G_TYPE_BOOLEAN, where %TRUE means that a row is visible, and %FALSE
2394 egg_tree_model_filter_set_visible_column (EggTreeModelFilter
*filter
,
2397 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2398 g_return_if_fail (column
>= 0);
2399 g_return_if_fail (filter
->visible_method_set
== FALSE
);
2401 filter
->visible_column
= column
;
2403 filter
->visible_method_set
= TRUE
;
2409 * egg_tree_model_filter_convert_child_iter_to_iter:
2410 * @filter: A #EggTreeModelFilter.
2411 * @filter_iter: An uninitialized #GtkTreeIter.
2412 * @child_iter: A valid #GtkTreeIter pointing to a row on the child model.
2414 * Sets @filter_iter to point to the row in @filter that corresponds to the
2415 * row pointed at by @child_iter.
2418 egg_tree_model_filter_convert_child_iter_to_iter (EggTreeModelFilter
*filter
,
2419 GtkTreeIter
*filter_iter
,
2420 GtkTreeIter
*child_iter
)
2422 GtkTreePath
*child_path
, *path
;
2424 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2425 g_return_if_fail (filter
->child_model
!= NULL
);
2426 g_return_if_fail (filter_iter
!= NULL
);
2427 g_return_if_fail (child_iter
!= NULL
);
2429 filter_iter
->stamp
= 0;
2431 child_path
= gtk_tree_model_get_path (filter
->child_model
, child_iter
);
2432 g_return_if_fail (child_path
!= NULL
);
2434 path
= egg_tree_model_filter_convert_child_path_to_path (filter
,
2436 gtk_tree_path_free (child_path
);
2437 g_return_if_fail (path
!= NULL
);
2439 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter
), filter_iter
, path
);
2440 gtk_tree_path_free (path
);
2444 * egg_tree_model_filter_convert_iter_to_child_iter:
2445 * @filter: A #EggTreeModelFilter.
2446 * @child_iter: An uninitialized #GtkTreeIter.
2447 * @filter_iter: A valid #GtkTreeIter pointing to a row on @filter.
2449 * Sets @child_iter to point to the row pointed to by @filter_iter.
2452 egg_tree_model_filter_convert_iter_to_child_iter (EggTreeModelFilter
*filter
,
2453 GtkTreeIter
*child_iter
,
2454 GtkTreeIter
*filter_iter
)
2456 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2457 g_return_if_fail (filter
->child_model
!= NULL
);
2458 g_return_if_fail (child_iter
!= NULL
);
2459 g_return_if_fail (filter_iter
!= NULL
);
2460 g_return_if_fail (filter_iter
->stamp
== filter
->stamp
);
2462 if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter
))
2464 *child_iter
= FILTER_ELT (filter_iter
->user_data2
)->iter
;
2470 path
= egg_tree_model_filter_elt_get_path (filter_iter
->user_data
,
2471 filter_iter
->user_data2
,
2472 filter
->virtual_root
);
2473 gtk_tree_model_get_iter (filter
->child_model
, child_iter
, path
);
2474 gtk_tree_path_free (path
);
2478 static GtkTreePath
*
2479 egg_real_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter
*filter
,
2480 GtkTreePath
*child_path
,
2481 gboolean build_levels
,
2482 gboolean fetch_childs
)
2484 gint
*child_indices
;
2485 GtkTreePath
*retval
;
2486 GtkTreePath
*real_path
;
2491 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
), NULL
);
2492 g_return_val_if_fail (filter
->child_model
!= NULL
, NULL
);
2493 g_return_val_if_fail (child_path
!= NULL
, NULL
);
2495 if (!filter
->virtual_root
)
2496 real_path
= gtk_tree_path_copy (child_path
);
2498 real_path
= egg_tree_model_filter_remove_root (child_path
,
2499 filter
->virtual_root
);
2504 retval
= gtk_tree_path_new ();
2505 child_indices
= gtk_tree_path_get_indices (real_path
);
2507 if (filter
->root
== NULL
&& build_levels
)
2508 egg_tree_model_filter_build_level (filter
, NULL
, NULL
);
2509 level
= FILTER_LEVEL (filter
->root
);
2511 for (i
= 0; i
< gtk_tree_path_get_depth (real_path
); i
++)
2514 gboolean found_child
= FALSE
;
2518 gtk_tree_path_free (real_path
);
2519 gtk_tree_path_free (retval
);
2523 tmp
= bsearch_elt_with_offset (level
->array
, child_indices
[i
], &j
);
2526 gtk_tree_path_append_index (retval
, j
);
2527 if (!tmp
->children
&& build_levels
)
2528 egg_tree_model_filter_build_level (filter
, level
, tmp
);
2529 level
= tmp
->children
;
2533 if (!found_child
&& fetch_childs
)
2535 tmp
= egg_tree_model_filter_fetch_child (filter
, level
,
2539 /* didn't find the child, let's try to bring it back */
2540 if (!tmp
|| tmp
->offset
!= child_indices
[i
])
2543 gtk_tree_path_free (real_path
);
2544 gtk_tree_path_free (retval
);
2548 gtk_tree_path_append_index (retval
, j
);
2549 if (!tmp
->children
&& build_levels
)
2550 egg_tree_model_filter_build_level (filter
, level
, tmp
);
2551 level
= tmp
->children
;
2554 else if (!found_child
&& !fetch_childs
)
2557 gtk_tree_path_free (real_path
);
2558 gtk_tree_path_free (retval
);
2563 gtk_tree_path_free (real_path
);
2568 * egg_tree_model_filter_convert_child_path_to_path:
2569 * @filter: A #EggTreeModelFilter.
2570 * @child_path: A #GtkTreePath to convert.
2572 * Converts @child_path to a path relative to @filter. That is, @child_path
2573 * points to a path in the child model. The rerturned path will point to the
2574 * same row in the filtered model. If @child_path isn't a valid path on the
2575 * child model, then %NULL is returned.
2577 * Return value: A newly allocated #GtkTreePath, or %NULL.
2580 egg_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter
*filter
,
2581 GtkTreePath
*child_path
)
2583 /* this function does the sanity checks */
2584 return egg_real_tree_model_filter_convert_child_path_to_path (filter
,
2591 * egg_tree_model_filter_convert_path_to_child_path:
2592 * @filter: A #EggTreeModelFilter.
2593 * @filter_path: A #GtkTreePath to convert.
2595 * Converts @filter_path to a path on the child model of @filter. That is,
2596 * @filter_path points to a location in @filter. The returned path will
2597 * point to the same location in the model not being filtered. If @filter_path
2598 * does not point to a location in the child model, %NULL is returned.
2600 * Return value: A newly allocated #GtkTreePath, or %NULL.
2603 egg_tree_model_filter_convert_path_to_child_path (EggTreeModelFilter
*filter
,
2604 GtkTreePath
*filter_path
)
2606 gint
*filter_indices
;
2607 GtkTreePath
*retval
;
2611 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
), NULL
);
2612 g_return_val_if_fail (filter
->child_model
!= NULL
, NULL
);
2613 g_return_val_if_fail (filter_path
!= NULL
, NULL
);
2616 retval
= gtk_tree_path_new ();
2617 filter_indices
= gtk_tree_path_get_indices (filter_path
);
2619 egg_tree_model_filter_build_level (filter
, NULL
, NULL
);
2620 level
= FILTER_LEVEL (filter
->root
);
2622 for (i
= 0; i
< gtk_tree_path_get_depth (filter_path
); i
++)
2624 gint count
= filter_indices
[i
];
2626 if (!level
|| level
->array
->len
<= filter_indices
[i
])
2628 gtk_tree_path_free (retval
);
2632 if (g_array_index (level
->array
, FilterElt
, count
).children
== NULL
)
2633 egg_tree_model_filter_build_level (filter
, level
, &g_array_index (level
->array
, FilterElt
, count
));
2635 if (!level
|| level
->array
->len
<= filter_indices
[i
])
2637 gtk_tree_path_free (retval
);
2641 gtk_tree_path_append_index (retval
, g_array_index (level
->array
, FilterElt
, count
).offset
);
2642 level
= g_array_index (level
->array
, FilterElt
, count
).children
;
2647 if (filter
->virtual_root
)
2649 GtkTreePath
*real_retval
;
2651 real_retval
= egg_tree_model_filter_add_root (retval
,
2652 filter
->virtual_root
);
2653 gtk_tree_path_free (retval
);
2662 egg_tree_model_filter_refilter_helper (GtkTreeModel
*model
,
2667 /* evil, don't try this at home, but certainly speeds things up */
2668 egg_tree_model_filter_row_changed (model
, path
, iter
, data
);
2674 * egg_tree_model_filter_refilter:
2675 * @filter: A #EggTreeModelFilter.
2677 * Emits ::row_changed for each row in the child model, which causes
2678 * the filter to re-evaluate whether a row is visible or not.
2681 egg_tree_model_filter_refilter (EggTreeModelFilter
*filter
)
2683 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2686 gtk_tree_model_foreach (filter
->child_model
,
2687 egg_tree_model_filter_refilter_helper
,
2692 * egg_tree_model_filter_clear_cache:
2693 * @filter: A #EggTreeModelFilter.
2695 * This function should almost never be called. It clears the @filter
2696 * of any cached iterators that haven't been reffed with
2697 * gtk_tree_model_ref_node(). This might be useful if the child model
2698 * being filtered is static (and doesn't change often) and there has been
2699 * a lot of unreffed access to nodes. As a side effect of this function,
2700 * all unreffed itters will be invalid.
2703 egg_tree_model_filter_clear_cache (EggTreeModelFilter
*filter
)
2705 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2707 if (filter
->zero_ref_count
)
2708 egg_tree_model_filter_clear_cache_helper (filter
,
2709 FILTER_LEVEL (filter
->root
));