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., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, 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
,
672 gint start
, middle
, end
;
674 GtkTreePath
*c_path
= NULL
;
676 GtkTreePath
*c_parent_path
= NULL
;
677 GtkTreeIter c_parent_iter
;
680 /* check if child exists and is visible */
681 if (level
->parent_elt
)
684 egg_tree_model_filter_elt_get_path (level
->parent_level
,
686 filter
->virtual_root
);
692 if (filter
->virtual_root
)
693 c_parent_path
= gtk_tree_path_copy (filter
->virtual_root
);
695 c_parent_path
= NULL
;
700 gtk_tree_model_get_iter (filter
->child_model
,
703 len
= gtk_tree_model_iter_n_children (filter
->child_model
,
706 c_path
= gtk_tree_path_copy (c_parent_path
);
707 gtk_tree_path_free (c_parent_path
);
711 len
= gtk_tree_model_iter_n_children (filter
->child_model
, NULL
);
712 c_path
= gtk_tree_path_new ();
715 gtk_tree_path_append_index (c_path
, offset
);
716 gtk_tree_model_get_iter (filter
->child_model
, &c_iter
, c_path
);
717 gtk_tree_path_free (c_path
);
719 if (offset
>= len
|| !egg_tree_model_filter_visible (filter
, &c_iter
))
724 elt
.zero_ref_count
= 0;
727 /* visibility should be FALSE as we don't emit row_inserted */
730 if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter
))
733 /* find index (binary search on offset) */
735 end
= level
->array
->len
;
741 middle
= (start
+ end
) / 2;
743 if (g_array_index (level
->array
, FilterElt
, middle
).offset
<= offset
)
749 if (g_array_index (level
->array
, FilterElt
, middle
).offset
<= offset
)
757 g_array_insert_val (level
->array
, i
, elt
);
761 for (i
= MAX (i_t
, 0); i
< level
->array
->len
; i
++)
763 FilterElt
*e
= &(g_array_index (level
->array
, FilterElt
, i
));
765 e
->children
->parent_elt
= e
;
768 return &g_array_index (level
->array
, FilterElt
, *index
);
772 egg_tree_model_filter_remove_node (EggTreeModelFilter
*filter
,
774 gboolean emit_signal
)
776 FilterElt
*elt
, *parent
;
777 FilterLevel
*level
, *parent_level
;
778 gint offset
, i
, length
, level_refcount
;
780 /* FIXME: this function is very ugly. I need to rethink and
781 * rewrite it someday.
784 level
= FILTER_LEVEL (iter
->user_data
);
785 elt
= FILTER_ELT (iter
->user_data2
);
787 parent
= level
->parent_elt
;
788 parent_level
= level
->parent_level
;
789 length
= level
->array
->len
;
790 offset
= elt
->offset
;
793 while (elt
->ref_count
> 0)
794 egg_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter
),
797 level_refcount
= level
->ref_count
;
799 /* do the ref counting first! this touches the stamp */
804 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (filter
), iter
);
805 egg_tree_model_filter_increment_stamp (filter
);
806 gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter
), path
);
807 gtk_tree_path_free (path
);
810 if ((length
== 1 || level_refcount
== 0) &&
811 emit_signal
&& iter
->user_data
!= filter
->root
)
813 /* above code destroyed the level */
814 goto emit_has_child_toggled
;
820 egg_tree_model_filter_free_level (filter
, level
);
823 /* we killed the root */
830 /* remove the node */
831 tmp
= bsearch_elt_with_offset (level
->array
, elt
->offset
, &i
);
836 g_array_remove_index (level
->array
, i
);
839 for (i
= MAX (i_t
, 0); i
< level
->array
->len
; i
++)
841 /* NOTE: here we do *not* decrease offsets, because the node was
842 * not removed from the child model
844 elt
= &g_array_index (level
->array
, FilterElt
, i
);
846 elt
->children
->parent_elt
= elt
;
851 emit_has_child_toggled
:
852 /* children are being handled first, so we can check it this way
854 * yes this if-statement is ugly
856 if ((parent
&& parent
->children
&& parent
->children
->array
->len
<= 1) ||
857 (length
== 1 && emit_signal
&& iter
->user_data
!= filter
->root
))
859 /* latest child has been removed, level has been destroyed */
863 piter
.stamp
= filter
->stamp
;
864 piter
.user_data
= parent_level
;
865 piter
.user_data2
= parent
;
867 ppath
= gtk_tree_model_get_path (GTK_TREE_MODEL (filter
), &piter
);
869 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter
),
871 gtk_tree_path_free (ppath
);
876 egg_tree_model_filter_update_childs (EggTreeModelFilter
*filter
,
886 iter
.stamp
= filter
->stamp
;
887 iter
.user_data
= level
;
888 iter
.user_data2
= elt
;
890 egg_tree_model_filter_convert_iter_to_child_iter (filter
, &c_iter
, &iter
);
892 if (gtk_tree_model_iter_has_child (filter
->child_model
, &c_iter
))
894 GtkTreePath
*path
= gtk_tree_model_get_path (GTK_TREE_MODEL (filter
),
896 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter
),
900 gtk_tree_path_free (path
);
905 bsearch_elt_with_offset (GArray
*array
,
909 gint start
, middle
, end
;
920 elt
= &g_array_index (array
, FilterElt
, 0);
922 if (elt
->offset
== offset
)
933 middle
= (start
+ end
) / 2;
935 elt
= &g_array_index (array
, FilterElt
, middle
);
937 if (elt
->offset
< offset
)
939 else if (elt
->offset
> offset
)
945 if (elt
->offset
== offset
)
954 /* TreeModel signals */
956 egg_tree_model_filter_row_changed (GtkTreeModel
*c_model
,
961 EggTreeModelFilter
*filter
= EGG_TREE_MODEL_FILTER (data
);
964 GtkTreeIter real_c_iter
;
965 GtkTreePath
*path
= NULL
;
970 gboolean requested_state
;
971 gboolean current_state
;
972 gboolean free_c_path
= FALSE
;
974 g_return_if_fail (c_path
!= NULL
|| c_iter
!= NULL
);
978 c_path
= gtk_tree_model_get_path (c_model
, c_iter
);
983 real_c_iter
= *c_iter
;
985 gtk_tree_model_get_iter (c_model
, &real_c_iter
, c_path
);
987 /* is this node above the virtual root? */
988 if (filter
->virtual_root
989 && (gtk_tree_path_get_depth (filter
->virtual_root
)
990 >= gtk_tree_path_get_depth (c_path
)))
993 /* what's the requested state? */
994 requested_state
= egg_tree_model_filter_visible (filter
, &real_c_iter
);
996 /* now, let's see whether the item is there */
997 path
= egg_real_tree_model_filter_convert_child_path_to_path (filter
,
1004 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter
), &iter
, path
);
1005 current_state
= FILTER_ELT (iter
.user_data2
)->visible
;
1008 current_state
= FALSE
;
1010 if (current_state
== FALSE
&& requested_state
== FALSE
)
1011 /* no changes required */
1014 if (current_state
== TRUE
&& requested_state
== FALSE
)
1016 /* get rid of this node */
1017 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter
), &iter
, path
);
1018 egg_tree_model_filter_remove_node (filter
, &iter
, TRUE
);
1020 level
= FILTER_LEVEL (iter
.user_data
);
1022 if (!level
->parent_level
)
1023 filter
->root_level_visible
--;
1028 if (current_state
== TRUE
&& requested_state
== TRUE
)
1030 /* progate the signal */
1031 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter
), &iter
, path
);
1032 gtk_tree_model_row_changed (GTK_TREE_MODEL (filter
), path
, &iter
);
1034 level
= FILTER_LEVEL (iter
.user_data
);
1035 elt
= FILTER_ELT (iter
.user_data2
);
1037 /* and update the childs */
1038 if (gtk_tree_model_iter_children (c_model
, &childs
, &real_c_iter
))
1039 egg_tree_model_filter_update_childs (filter
, level
, elt
);
1044 /* only current == FALSE and requested == TRUE is left,
1047 g_return_if_fail (current_state
== FALSE
&& requested_state
== TRUE
);
1049 /* make sure the new item has been pulled in */
1055 egg_tree_model_filter_build_level (filter
, NULL
, NULL
);
1057 root
= FILTER_LEVEL (filter
->root
);
1061 for (i
= 0; i
< root
->array
->len
; i
++)
1062 g_array_index (root
->array
, FilterElt
, i
).visible
= FALSE
;
1063 filter
->root_level_visible
= 0;
1068 path
= egg_real_tree_model_filter_convert_child_path_to_path (filter
,
1073 g_return_if_fail (path
!= NULL
);
1075 egg_tree_model_filter_increment_stamp (filter
);
1076 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter
), &iter
, path
);
1078 level
= FILTER_LEVEL (iter
.user_data
);
1079 elt
= FILTER_ELT (iter
.user_data2
);
1081 elt
->visible
= TRUE
;
1083 if (!level
->parent_level
)
1084 filter
->root_level_visible
++;
1087 gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter
), path
, &iter
);
1089 if (gtk_tree_model_iter_children (c_model
, &childs
, c_iter
))
1090 egg_tree_model_filter_update_childs (filter
, level
, elt
);
1094 gtk_tree_path_free (path
);
1097 gtk_tree_path_free (c_path
);
1101 egg_tree_model_filter_row_inserted (GtkTreeModel
*c_model
,
1102 GtkTreePath
*c_path
,
1103 GtkTreeIter
*c_iter
,
1106 EggTreeModelFilter
*filter
= EGG_TREE_MODEL_FILTER (data
);
1107 GtkTreePath
*path
= NULL
;
1108 GtkTreePath
*real_path
= NULL
;
1111 GtkTreeIter real_c_iter
;
1115 FilterLevel
*parent_level
;
1117 gint i
= 0, offset
, index
= -1;
1119 gboolean free_c_path
= FALSE
;
1121 g_return_if_fail (c_path
!= NULL
|| c_iter
!= NULL
);
1125 c_path
= gtk_tree_model_get_path (c_model
, c_iter
);
1130 real_c_iter
= *c_iter
;
1132 gtk_tree_model_get_iter (c_model
, &real_c_iter
, c_path
);
1134 /* the row has already been inserted. so we need to fixup the
1135 * virtual root here first
1137 if (filter
->virtual_root
)
1139 if (gtk_tree_path_get_depth (filter
->virtual_root
) >=
1140 gtk_tree_path_get_depth (c_path
))
1143 gint
*v_indices
, *c_indices
;
1145 level
= gtk_tree_path_get_depth (c_path
) - 1;
1146 v_indices
= gtk_tree_path_get_indices (filter
->virtual_root
);
1147 c_indices
= gtk_tree_path_get_indices (c_path
);
1149 if (v_indices
[level
] >= c_indices
[level
])
1150 (v_indices
[level
])++;
1156 egg_tree_model_filter_build_level (filter
, NULL
, NULL
);
1157 /* that already put the inserted iter in the level */
1162 parent_level
= level
= FILTER_LEVEL (filter
->root
);
1164 /* subtract virtual root if necessary */
1165 if (filter
->virtual_root
)
1167 real_path
= egg_tree_model_filter_remove_root (c_path
,
1168 filter
->virtual_root
);
1174 real_path
= gtk_tree_path_copy (c_path
);
1176 if (gtk_tree_path_get_depth (real_path
) - 1 >= 1)
1178 /* find the parent level */
1179 while (i
< gtk_tree_path_get_depth (real_path
) - 1)
1184 /* we don't cover this signal */
1187 elt
= bsearch_elt_with_offset (level
->array
,
1188 gtk_tree_path_get_indices (real_path
)[i
],
1192 /* parent is probably being filtered out */
1197 GtkTreePath
*tmppath
;
1198 GtkTreeIter tmpiter
;
1200 tmpiter
.stamp
= filter
->stamp
;
1201 tmpiter
.user_data
= level
;
1202 tmpiter
.user_data2
= elt
;
1204 tmppath
= gtk_tree_model_get_path (GTK_TREE_MODEL (data
),
1209 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data
),
1211 gtk_tree_path_free (tmppath
);
1214 /* not covering this signal */
1218 level
= elt
->children
;
1219 parent_level
= level
;
1227 /* let's try to insert the value */
1228 offset
= gtk_tree_path_get_indices (real_path
)[gtk_tree_path_get_depth (real_path
) - 1];
1230 /* update the offsets, yes if we didn't insert the node above, there will
1231 * be a gap here. This will be filled with the node (via fetch_child) when
1232 * it becomes visible
1234 for (i
= 0; i
< level
->array
->len
; i
++)
1236 FilterElt
*e
= &g_array_index (level
->array
, FilterElt
, i
);
1237 if ((e
->offset
>= offset
))
1241 /* only insert when visible */
1242 if (egg_tree_model_filter_visible (filter
, &real_c_iter
))
1246 if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter
))
1247 felt
.iter
= real_c_iter
;
1249 felt
.offset
= offset
;
1250 felt
.zero_ref_count
= 0;
1252 felt
.visible
= TRUE
;
1253 felt
.children
= NULL
;
1255 for (i
= 0; i
< level
->array
->len
; i
++)
1256 if (g_array_index (level
->array
, FilterElt
, i
).offset
> offset
)
1259 g_array_insert_val (level
->array
, i
, felt
);
1262 if (!level
->parent_level
)
1263 filter
->root_level_visible
++;
1266 /* another iteration to update the references of childs to parents. */
1267 for (i
= 0; i
< level
->array
->len
; i
++)
1269 FilterElt
*e
= &g_array_index (level
->array
, FilterElt
, i
);
1271 e
->children
->parent_elt
= e
;
1274 /* don't emit the signal if we aren't visible */
1275 if (!egg_tree_model_filter_visible (filter
, &real_c_iter
))
1279 /* NOTE: pass c_path here and NOT real_path. This function does
1280 * root subtraction itself
1282 path
= egg_real_tree_model_filter_convert_child_path_to_path (filter
,
1289 egg_tree_model_filter_increment_stamp (filter
);
1291 gtk_tree_model_get_iter (GTK_TREE_MODEL (data
), &iter
, path
);
1292 gtk_tree_model_row_inserted (GTK_TREE_MODEL (data
), path
, &iter
);
1294 gtk_tree_path_free (path
);
1298 gtk_tree_path_free (real_path
);
1301 gtk_tree_path_free (c_path
);
1305 egg_tree_model_filter_row_has_child_toggled (GtkTreeModel
*c_model
,
1306 GtkTreePath
*c_path
,
1307 GtkTreeIter
*c_iter
,
1310 EggTreeModelFilter
*filter
= EGG_TREE_MODEL_FILTER (data
);
1314 g_return_if_fail (c_path
!= NULL
&& c_iter
!= NULL
);
1316 /* FIXME: does this code work? */
1318 if (!egg_tree_model_filter_visible (filter
, c_iter
))
1321 path
= egg_real_tree_model_filter_convert_child_path_to_path (filter
,
1328 gtk_tree_model_get_iter (GTK_TREE_MODEL (data
), &iter
, path
);
1329 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data
), path
, &iter
);
1331 gtk_tree_path_free (path
);
1335 egg_tree_model_filter_row_deleted (GtkTreeModel
*c_model
,
1336 GtkTreePath
*c_path
,
1339 EggTreeModelFilter
*filter
= EGG_TREE_MODEL_FILTER (data
);
1345 gboolean emit_signal
= TRUE
;
1348 g_return_if_fail (c_path
!= NULL
);
1350 /* special case the deletion of an ancestor of the virtual root */
1351 if (filter
->virtual_root
&&
1352 (gtk_tree_path_is_ancestor (c_path
, filter
->virtual_root
) ||
1353 !gtk_tree_path_compare (c_path
, filter
->virtual_root
)))
1357 FilterLevel
*level
= FILTER_LEVEL (filter
->root
);
1362 /* remove everything in the filter model
1364 * For now, we just iterate over the root level and emit a
1365 * row_deleted for each FilterElt. Not sure if this is correct.
1368 egg_tree_model_filter_increment_stamp (filter
);
1369 path
= gtk_tree_path_new ();
1370 gtk_tree_path_append_index (path
, 0);
1372 for (i
= 0; i
< level
->array
->len
; i
++)
1373 gtk_tree_model_row_deleted (GTK_TREE_MODEL (data
), path
);
1375 gtk_tree_path_free (path
);
1376 egg_tree_model_filter_free_level (filter
, filter
->root
);
1381 /* fixup virtual root */
1382 if (filter
->virtual_root
)
1384 if (gtk_tree_path_get_depth (filter
->virtual_root
) >=
1385 gtk_tree_path_get_depth (c_path
))
1388 gint
*v_indices
, *c_indices
;
1390 level
= gtk_tree_path_get_depth (c_path
) - 1;
1391 v_indices
= gtk_tree_path_get_indices (filter
->virtual_root
);
1392 c_indices
= gtk_tree_path_get_indices (c_path
);
1394 if (v_indices
[level
] > c_indices
[level
])
1395 (v_indices
[level
])--;
1399 path
= egg_real_tree_model_filter_convert_child_path_to_path (filter
,
1406 /* fixup the offsets */
1407 GtkTreePath
*real_path
;
1412 level
= FILTER_LEVEL (filter
->root
);
1414 /* subtract vroot if necessary */
1415 if (filter
->virtual_root
)
1417 real_path
= egg_tree_model_filter_remove_root (c_path
,
1418 filter
->virtual_root
);
1419 /* we don't handle this */
1424 real_path
= gtk_tree_path_copy (c_path
);
1427 if (gtk_tree_path_get_depth (real_path
) - 1 >= 1)
1429 while (i
< gtk_tree_path_get_depth (real_path
) - 1)
1435 /* we don't cover this */
1436 gtk_tree_path_free (real_path
);
1440 elt
= bsearch_elt_with_offset (level
->array
,
1441 gtk_tree_path_get_indices (real_path
)[i
],
1445 if (!elt
|| !elt
->children
)
1447 /* parent is filtered out, so no level */
1448 gtk_tree_path_free (real_path
);
1452 level
= elt
->children
;
1457 offset
= gtk_tree_path_get_indices (real_path
)[gtk_tree_path_get_depth (real_path
) - 1];
1458 gtk_tree_path_free (real_path
);
1464 * - the offset of the removed item
1467 for (i
= 0; i
< level
->array
->len
; i
++)
1469 elt
= &g_array_index (level
->array
, FilterElt
, i
);
1470 if (elt
->offset
> offset
)
1473 elt
->children
->parent_elt
= elt
;
1479 gtk_tree_model_get_iter (GTK_TREE_MODEL (data
), &iter
, path
);
1481 level
= FILTER_LEVEL (iter
.user_data
);
1482 elt
= FILTER_ELT (iter
.user_data2
);
1483 offset
= elt
->offset
;
1485 if (!level
->parent_level
&& elt
->visible
)
1486 filter
->root_level_visible
--;
1490 if (level
->ref_count
== 0 && level
!= filter
->root
)
1492 egg_tree_model_filter_increment_stamp (filter
);
1493 gtk_tree_model_row_deleted (GTK_TREE_MODEL (data
), path
);
1495 gtk_tree_path_free (path
);
1499 egg_tree_model_filter_increment_stamp (filter
);
1500 gtk_tree_model_row_deleted (GTK_TREE_MODEL (data
), path
);
1501 iter
.stamp
= filter
->stamp
;
1503 while (elt
->ref_count
> 0)
1504 egg_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data
), &iter
,
1508 if (level
->array
->len
== 1)
1511 egg_tree_model_filter_free_level (filter
, level
);
1518 /* remove the row */
1519 tmp
= bsearch_elt_with_offset (level
->array
, elt
->offset
, &i
);
1521 offset
= tmp
->offset
;
1522 g_array_remove_index (level
->array
, i
);
1525 for (i
= MAX (i_t
, 0); i
< level
->array
->len
; i
++)
1527 elt
= &g_array_index (level
->array
, FilterElt
, i
);
1528 if (elt
->offset
> offset
)
1531 elt
->children
->parent_elt
= elt
;
1535 gtk_tree_path_free (path
);
1539 egg_tree_model_filter_rows_reordered (GtkTreeModel
*c_model
,
1540 GtkTreePath
*c_path
,
1541 GtkTreeIter
*c_iter
,
1547 EggTreeModelFilter
*filter
= EGG_TREE_MODEL_FILTER (data
);
1553 gint i
, j
, elt_count
;
1558 g_return_if_fail (new_order
!= NULL
);
1560 if (c_path
== NULL
|| gtk_tree_path_get_indices (c_path
) == NULL
)
1565 length
= gtk_tree_model_iter_n_children (c_model
, NULL
);
1567 if (filter
->virtual_root
)
1571 /* reorder root level of path */
1572 for (i
= 0; i
< length
; i
++)
1573 if (new_order
[i
] == gtk_tree_path_get_indices (filter
->virtual_root
)[0])
1579 gtk_tree_path_get_indices (filter
->virtual_root
)[0] = new_pos
;
1583 path
= gtk_tree_path_new ();
1584 level
= FILTER_LEVEL (filter
->root
);
1588 GtkTreeIter child_iter
;
1590 /* virtual root anchor reordering */
1591 if (filter
->virtual_root
&&
1592 gtk_tree_path_get_depth (c_path
) <
1593 gtk_tree_path_get_depth (filter
->virtual_root
))
1598 GtkTreeIter real_c_iter
;
1600 level
= gtk_tree_path_get_depth (c_path
);
1603 real_c_iter
= *c_iter
;
1605 gtk_tree_model_get_iter (c_model
, &real_c_iter
, c_path
);
1607 length
= gtk_tree_model_iter_n_children (c_model
, &real_c_iter
);
1609 for (i
= 0; i
< length
; i
++)
1610 if (new_order
[i
] == gtk_tree_path_get_indices (filter
->virtual_root
)[level
])
1616 gtk_tree_path_get_indices (filter
->virtual_root
)[level
] = new_pos
;
1620 path
= egg_real_tree_model_filter_convert_child_path_to_path (filter
,
1624 if (!path
&& filter
->virtual_root
&&
1625 gtk_tree_path_compare (c_path
, filter
->virtual_root
))
1628 if (!path
&& !filter
->virtual_root
)
1633 /* root level mode */
1635 gtk_tree_model_get_iter (c_model
, c_iter
, c_path
);
1636 length
= gtk_tree_model_iter_n_children (c_model
, c_iter
);
1637 path
= gtk_tree_path_new ();
1638 level
= FILTER_LEVEL (filter
->root
);
1642 gtk_tree_model_get_iter (GTK_TREE_MODEL (data
), &iter
, path
);
1644 level
= FILTER_LEVEL (iter
.user_data
);
1645 elt
= FILTER_ELT (iter
.user_data2
);
1649 gtk_tree_path_free (path
);
1653 level
= elt
->children
;
1655 egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (filter
), &child_iter
, &iter
);
1656 length
= gtk_tree_model_iter_n_children (c_model
, &child_iter
);
1660 if (level
->array
->len
< 1)
1663 /* NOTE: we do not bail out here if level->array->len < 2 like
1664 * GtkTreeModelSort does. This because we do some special tricky
1668 /* construct a new array */
1669 new_array
= g_array_sized_new (FALSE
, FALSE
, sizeof (FilterElt
),
1671 tmp_array
= g_new (gint
, level
->array
->len
);
1673 for (i
= 0, elt_count
= 0; i
< length
; i
++)
1675 FilterElt
*e
= NULL
;
1676 gint old_offset
= -1;
1678 for (j
= 0; j
< level
->array
->len
; j
++)
1679 if (g_array_index (level
->array
, FilterElt
, j
).offset
== new_order
[i
])
1681 e
= &g_array_index (level
->array
, FilterElt
, j
);
1689 tmp_array
[elt_count
] = old_offset
;
1690 g_array_append_val (new_array
, *e
);
1691 g_array_index (new_array
, FilterElt
, elt_count
).offset
= i
;
1695 g_array_free (level
->array
, TRUE
);
1696 level
->array
= new_array
;
1699 for (i
= 0; i
< level
->array
->len
; i
++)
1701 FilterElt
*e
= &g_array_index (level
->array
, FilterElt
, i
);
1703 e
->children
->parent_elt
= e
;
1706 /* emit rows_reordered */
1707 if (!gtk_tree_path_get_indices (path
))
1708 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data
), path
, NULL
,
1711 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data
), path
, &iter
,
1716 gtk_tree_path_free (path
);
1719 /* TreeModelIface implementation */
1721 egg_tree_model_filter_get_flags (GtkTreeModel
*model
)
1723 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), 0);
1729 egg_tree_model_filter_get_n_columns (GtkTreeModel
*model
)
1731 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
1733 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), 0);
1734 g_return_val_if_fail (filter
->child_model
!= NULL
, 0);
1736 if (filter
->child_model
== NULL
)
1739 /* so we can't modify the modify func after this ... */
1740 filter
->modify_func_set
= TRUE
;
1742 if (filter
->modify_n_columns
> 0)
1743 return filter
->modify_n_columns
;
1745 return gtk_tree_model_get_n_columns (filter
->child_model
);
1749 egg_tree_model_filter_get_column_type (GtkTreeModel
*model
,
1752 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
1754 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), G_TYPE_INVALID
);
1755 g_return_val_if_fail (filter
->child_model
!= NULL
, G_TYPE_INVALID
);
1757 /* so we can't modify the modify func after this ... */
1758 filter
->modify_func_set
= TRUE
;
1760 if (filter
->modify_types
)
1762 g_return_val_if_fail (index
< filter
->modify_n_columns
, G_TYPE_INVALID
);
1764 return filter
->modify_types
[index
];
1767 return gtk_tree_model_get_column_type (filter
->child_model
, index
);
1771 egg_tree_model_filter_get_iter (GtkTreeModel
*model
,
1775 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
1780 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), FALSE
);
1781 g_return_val_if_fail (filter
->child_model
!= NULL
, FALSE
);
1783 indices
= gtk_tree_path_get_indices (path
);
1785 if (filter
->root
== NULL
)
1786 egg_tree_model_filter_build_level (filter
, NULL
, NULL
);
1787 level
= FILTER_LEVEL (filter
->root
);
1789 depth
= gtk_tree_path_get_depth (path
);
1796 for (i
= 0; i
< depth
- 1; i
++)
1798 if (!level
|| indices
[i
] >= level
->array
->len
)
1803 if (!g_array_index (level
->array
, FilterElt
, indices
[i
]).children
)
1804 egg_tree_model_filter_build_level (filter
, level
,
1805 &g_array_index (level
->array
,
1808 level
= g_array_index (level
->array
, FilterElt
, indices
[i
]).children
;
1811 if (!level
|| indices
[i
] >= level
->array
->len
)
1817 iter
->stamp
= filter
->stamp
;
1818 iter
->user_data
= level
;
1819 iter
->user_data2
= &g_array_index (level
->array
, FilterElt
,
1820 indices
[depth
- 1]);
1825 static GtkTreePath
*
1826 egg_tree_model_filter_get_path (GtkTreeModel
*model
,
1829 GtkTreePath
*retval
;
1833 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), NULL
);
1834 g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model
)->child_model
!= NULL
, NULL
);
1835 g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model
)->stamp
== iter
->stamp
, NULL
);
1837 retval
= gtk_tree_path_new ();
1838 level
= iter
->user_data
;
1839 elt
= iter
->user_data2
;
1843 gtk_tree_path_prepend_index (retval
,
1844 elt
- FILTER_ELT (level
->array
->data
));
1845 elt
= level
->parent_elt
;
1846 level
= level
->parent_level
;
1853 egg_tree_model_filter_get_value (GtkTreeModel
*model
,
1858 GtkTreeIter child_iter
;
1859 EggTreeModelFilter
*filter
= EGG_TREE_MODEL_FILTER (model
);
1861 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model
));
1862 g_return_if_fail (EGG_TREE_MODEL_FILTER (model
)->child_model
!= NULL
);
1863 g_return_if_fail (EGG_TREE_MODEL_FILTER (model
)->stamp
== iter
->stamp
);
1865 if (filter
->modify_func
)
1867 g_return_if_fail (column
< filter
->modify_n_columns
);
1869 g_value_init (value
, filter
->modify_types
[column
]);
1870 filter
->modify_func (model
,
1874 filter
->modify_data
);
1879 egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model
), &child_iter
, iter
);
1880 gtk_tree_model_get_value (EGG_TREE_MODEL_FILTER (model
)->child_model
,
1881 &child_iter
, column
, value
);
1885 egg_tree_model_filter_iter_next (GtkTreeModel
*model
,
1891 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), FALSE
);
1892 g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model
)->child_model
!= NULL
, FALSE
);
1893 g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model
)->stamp
== iter
->stamp
, FALSE
);
1895 level
= iter
->user_data
;
1896 elt
= iter
->user_data2
;
1898 if (elt
- FILTER_ELT (level
->array
->data
) >= level
->array
->len
- 1)
1904 iter
->user_data2
= elt
+ 1;
1910 egg_tree_model_filter_iter_children (GtkTreeModel
*model
,
1912 GtkTreeIter
*parent
)
1914 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
1918 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), FALSE
);
1919 g_return_val_if_fail (filter
->child_model
!= NULL
, FALSE
);
1921 g_return_val_if_fail (filter
->stamp
== parent
->stamp
, FALSE
);
1926 egg_tree_model_filter_build_level (filter
, NULL
, NULL
);
1930 level
= filter
->root
;
1931 iter
->stamp
= filter
->stamp
;
1932 iter
->user_data
= level
;
1933 iter
->user_data2
= level
->array
->data
;
1937 if (FILTER_ELT (parent
->user_data2
)->children
== NULL
)
1938 egg_tree_model_filter_build_level (filter
,
1939 FILTER_LEVEL (parent
->user_data
),
1940 FILTER_ELT (parent
->user_data2
));
1941 if (FILTER_ELT (parent
->user_data2
)->children
== NULL
)
1945 if (FILTER_ELT (parent
->user_data2
)->children
->array
->len
<= 0)
1948 iter
->stamp
= filter
->stamp
;
1949 iter
->user_data
= FILTER_ELT (parent
->user_data2
)->children
;
1950 iter
->user_data2
= FILTER_LEVEL (iter
->user_data
)->array
->data
;
1957 egg_tree_model_filter_iter_has_child (GtkTreeModel
*model
,
1960 GtkTreeIter child_iter
;
1961 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
1964 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), FALSE
);
1965 g_return_val_if_fail (filter
->child_model
!= NULL
, FALSE
);
1966 g_return_val_if_fail (filter
->stamp
== iter
->stamp
, FALSE
);
1968 filter
= EGG_TREE_MODEL_FILTER (model
);
1970 egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model
), &child_iter
, iter
);
1971 elt
= FILTER_ELT (iter
->user_data2
);
1973 /* we need to build the level to check if not all children are filtered
1977 && gtk_tree_model_iter_has_child (filter
->child_model
, &child_iter
))
1978 egg_tree_model_filter_build_level (filter
, FILTER_LEVEL (iter
->user_data
),
1981 /* FIXME: we should prolly count the visible nodes here, just like in
1984 if (elt
->children
&& elt
->children
->array
->len
> 0)
1991 egg_tree_model_filter_iter_n_children (GtkTreeModel
*model
,
1994 GtkTreeIter child_iter
;
1995 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
1998 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), 0);
1999 g_return_val_if_fail (filter
->child_model
!= NULL
, 0);
2001 g_return_val_if_fail (filter
->stamp
== iter
->stamp
, 0);
2006 egg_tree_model_filter_build_level (filter
, NULL
, NULL
);
2008 /* count visible nodes */
2009 return filter
->root_level_visible
;
2012 elt
= FILTER_ELT (iter
->user_data2
);
2013 egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model
), &child_iter
, iter
);
2015 if (!elt
->children
&&
2016 gtk_tree_model_iter_has_child (filter
->child_model
, &child_iter
))
2017 egg_tree_model_filter_build_level (filter
,
2018 FILTER_LEVEL (iter
->user_data
),
2021 if (elt
->children
&& elt
->children
->array
->len
)
2025 GArray
*a
= elt
->children
->array
;
2027 /* count visible nodes */
2028 for (i
= 0; i
< a
->len
; i
++)
2029 if (g_array_index (a
, FilterElt
, i
).visible
)
2039 egg_tree_model_filter_iter_nth_child (GtkTreeModel
*model
,
2041 GtkTreeIter
*parent
,
2045 GtkTreeIter children
;
2047 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), FALSE
);
2049 g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model
)->stamp
== parent
->stamp
, FALSE
);
2051 /* use this instead of has_Child to force us to build the level, if needed */
2052 if (egg_tree_model_filter_iter_children (model
, &children
, parent
) == FALSE
)
2058 level
= children
.user_data
;
2059 if (n
>= level
->array
->len
)
2065 iter
->stamp
= EGG_TREE_MODEL_FILTER (model
)->stamp
;
2066 iter
->user_data
= level
;
2067 iter
->user_data2
= &g_array_index (level
->array
, FilterElt
, n
);
2073 egg_tree_model_filter_iter_parent (GtkTreeModel
*model
,
2080 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model
), FALSE
);
2081 g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model
)->child_model
!= NULL
, FALSE
);
2082 g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model
)->stamp
== child
->stamp
, FALSE
);
2084 level
= child
->user_data
;
2086 if (level
->parent_level
)
2088 iter
->stamp
= EGG_TREE_MODEL_FILTER (model
)->stamp
;
2089 iter
->user_data
= level
->parent_level
;
2090 iter
->user_data2
= level
->parent_elt
;
2099 egg_tree_model_filter_ref_node (GtkTreeModel
*model
,
2102 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
2103 GtkTreeIter child_iter
;
2107 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model
));
2108 g_return_if_fail (EGG_TREE_MODEL_FILTER (model
)->child_model
!= NULL
);
2109 g_return_if_fail (EGG_TREE_MODEL_FILTER (model
)->stamp
== iter
->stamp
);
2111 egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model
), &child_iter
, iter
);
2113 gtk_tree_model_ref_node (filter
->child_model
, &child_iter
);
2115 level
= iter
->user_data
;
2116 elt
= iter
->user_data2
;
2120 if (level
->ref_count
== 1)
2122 FilterLevel
*parent_level
= level
->parent_level
;
2123 FilterElt
*parent_elt
= level
->parent_elt
;
2125 /* we were at zero -- time to decrease the zero_ref_count val */
2129 parent_elt
->zero_ref_count
--;
2133 parent_elt
= parent_level
->parent_elt
;
2134 parent_level
= parent_level
->parent_level
;
2137 while (parent_level
);
2138 filter
->zero_ref_count
--;
2143 egg_tree_model_filter_unref_node (GtkTreeModel
*model
,
2146 egg_tree_model_filter_real_unref_node (model
, iter
, TRUE
);
2150 egg_tree_model_filter_real_unref_node (GtkTreeModel
*model
,
2152 gboolean propagate_unref
)
2154 EggTreeModelFilter
*filter
= (EggTreeModelFilter
*)model
;
2158 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model
));
2159 g_return_if_fail (filter
->child_model
!= NULL
);
2160 g_return_if_fail (filter
->stamp
== iter
->stamp
);
2162 if (propagate_unref
)
2164 GtkTreeIter child_iter
;
2165 egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model
), &child_iter
, iter
);
2166 gtk_tree_model_unref_node (filter
->child_model
, &child_iter
);
2169 level
= iter
->user_data
;
2170 elt
= iter
->user_data2
;
2172 g_return_if_fail (elt
->ref_count
> 0);
2176 if (level
->ref_count
== 0)
2178 FilterLevel
*parent_level
= level
->parent_level
;
2179 FilterElt
*parent_elt
= level
->parent_elt
;
2181 /* we are at zero -- time to increase the zero_ref_count val */
2182 while (parent_level
)
2184 parent_elt
->zero_ref_count
++;
2186 parent_elt
= parent_level
->parent_elt
;
2187 parent_level
= parent_level
->parent_level
;
2189 filter
->zero_ref_count
++;
2193 /* bits and pieces */
2195 egg_tree_model_filter_set_model (EggTreeModelFilter
*filter
,
2196 GtkTreeModel
*child_model
)
2198 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2200 if (filter
->child_model
)
2202 g_signal_handler_disconnect (G_OBJECT (filter
->child_model
),
2203 filter
->changed_id
);
2204 g_signal_handler_disconnect (G_OBJECT (filter
->child_model
),
2205 filter
->inserted_id
);
2206 g_signal_handler_disconnect (G_OBJECT (filter
->child_model
),
2207 filter
->has_child_toggled_id
);
2208 g_signal_handler_disconnect (G_OBJECT (filter
->child_model
),
2209 filter
->deleted_id
);
2210 g_signal_handler_disconnect (G_OBJECT (filter
->child_model
),
2211 filter
->reordered_id
);
2213 /* reset our state */
2215 egg_tree_model_filter_free_level (filter
, filter
->root
);
2217 filter
->root
= NULL
;
2218 g_object_unref (G_OBJECT (filter
->child_model
));
2219 filter
->visible_column
= -1;
2220 /* FIXME: destroy more crack here? the funcs? */
2223 filter
->child_model
= child_model
;
2227 g_object_ref (G_OBJECT (filter
->child_model
));
2228 filter
->changed_id
=
2229 g_signal_connect (child_model
, "row_changed",
2230 G_CALLBACK (egg_tree_model_filter_row_changed
),
2232 filter
->inserted_id
=
2233 g_signal_connect (child_model
, "row_inserted",
2234 G_CALLBACK (egg_tree_model_filter_row_inserted
),
2236 filter
->has_child_toggled_id
=
2237 g_signal_connect (child_model
, "row_has_child_toggled",
2238 G_CALLBACK (egg_tree_model_filter_row_has_child_toggled
),
2240 filter
->deleted_id
=
2241 g_signal_connect (child_model
, "row_deleted",
2242 G_CALLBACK (egg_tree_model_filter_row_deleted
),
2244 filter
->reordered_id
=
2245 g_signal_connect (child_model
, "rows_reordered",
2246 G_CALLBACK (egg_tree_model_filter_rows_reordered
),
2249 filter
->child_flags
= gtk_tree_model_get_flags (child_model
);
2250 filter
->stamp
= g_random_int ();
2255 egg_tree_model_filter_set_root (EggTreeModelFilter
*filter
,
2258 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2261 filter
->virtual_root
= NULL
;
2263 filter
->virtual_root
= gtk_tree_path_copy (root
);
2269 * egg_tree_model_filter_new:
2270 * @child_model: A #GtkTreeModel.
2271 * @root: A #GtkTreePath or %NULL.
2273 * Creates a new #GtkTreeModel, with @child_model as the child_model
2274 * and @root as the virtual root.
2276 * Return value: A new #GtkTreeModel.
2279 egg_tree_model_filter_new (GtkTreeModel
*child_model
,
2282 GtkTreeModel
*retval
;
2284 g_return_val_if_fail (GTK_IS_TREE_MODEL (child_model
), NULL
);
2286 retval
= GTK_TREE_MODEL (g_object_new (egg_tree_model_filter_get_type (), NULL
));
2288 egg_tree_model_filter_set_model (EGG_TREE_MODEL_FILTER (retval
),
2290 egg_tree_model_filter_set_root (EGG_TREE_MODEL_FILTER (retval
), root
);
2296 * egg_tree_model_filter_get_model:
2297 * @filter: A #EggTreeModelFilter.
2299 * Returns a pointer to the child model of @filter.
2301 * Return value: A pointer to a #GtkTreeModel.
2304 egg_tree_model_filter_get_model (EggTreeModelFilter
*filter
)
2306 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
), NULL
);
2308 return filter
->child_model
;
2312 * egg_tree_model_filter_set_visible_func:
2313 * @filter: A #EggTreeModelFilter.
2314 * @func: A #EggTreeModelFilterVisibleFunc, the visible function.
2315 * @data: User data to pass to the visible function, or %NULL.
2316 * @destroy: Destroy notifier of @data, or %NULL.
2318 * Sets the visible function used when filtering the @filter to be @func. The
2319 * function should return %TRUE if the given row should be visible and
2323 egg_tree_model_filter_set_visible_func (EggTreeModelFilter
*filter
,
2324 EggTreeModelFilterVisibleFunc func
,
2326 GtkDestroyNotify destroy
)
2328 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2329 g_return_if_fail (func
!= NULL
);
2330 g_return_if_fail (filter
->visible_method_set
== FALSE
);
2332 if (filter
->visible_func
)
2334 GtkDestroyNotify d
= filter
->visible_destroy
;
2336 filter
->visible_destroy
= NULL
;
2337 d (filter
->visible_data
);
2340 filter
->visible_func
= func
;
2341 filter
->visible_data
= data
;
2342 filter
->visible_destroy
= destroy
;
2344 filter
->visible_method_set
= TRUE
;
2348 * egg_tree_model_filter_set_modify_func:
2349 * @filter: A #EggTreeModelFilter.
2350 * @n_columns: The number of columns in the filter model.
2351 * @types: The #GType<!-- -->s of the columns.
2352 * @func: A #EggTreeModelFilterModifyFunc, or %NULL.
2353 * @data: User data to pass to the modify function, or %NULL.
2354 * @destroy: Destroy notifier of @data, or %NULL.
2356 * Sets the @filter to have @n_columns columns with @types. If @func
2357 * is not %NULL, it will set @func to be the modify function of @filter.
2360 egg_tree_model_filter_set_modify_func (EggTreeModelFilter
*filter
,
2363 EggTreeModelFilterModifyFunc func
,
2365 GtkDestroyNotify destroy
)
2367 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2368 g_return_if_fail (func
!= NULL
);
2369 g_return_if_fail (filter
->modify_func_set
== FALSE
);
2371 if (filter
->modify_destroy
)
2373 GtkDestroyNotify d
= filter
->modify_destroy
;
2375 filter
->modify_destroy
= NULL
;
2376 d (filter
->modify_data
);
2379 filter
->modify_n_columns
= n_columns
;
2380 filter
->modify_types
= g_new0 (GType
, n_columns
);
2381 memcpy (filter
->modify_types
, types
, sizeof (GType
) * n_columns
);
2382 filter
->modify_func
= func
;
2383 filter
->modify_data
= data
;
2384 filter
->modify_destroy
= destroy
;
2386 filter
->modify_func_set
= TRUE
;
2390 * egg_tree_model_filter_set_visible_column:
2391 * @filter: A #EggTreeModelFilter.
2392 * @column: A #gint which is the column containing the visible information.
2394 * Sets @column of the child_model to be the column where @filter should
2395 * look for visibility information. @columns should be a column of type
2396 * %G_TYPE_BOOLEAN, where %TRUE means that a row is visible, and %FALSE
2400 egg_tree_model_filter_set_visible_column (EggTreeModelFilter
*filter
,
2403 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2404 g_return_if_fail (column
>= 0);
2405 g_return_if_fail (filter
->visible_method_set
== FALSE
);
2407 filter
->visible_column
= column
;
2409 filter
->visible_method_set
= TRUE
;
2415 * egg_tree_model_filter_convert_child_iter_to_iter:
2416 * @filter: A #EggTreeModelFilter.
2417 * @filter_iter: An uninitialized #GtkTreeIter.
2418 * @child_iter: A valid #GtkTreeIter pointing to a row on the child model.
2420 * Sets @filter_iter to point to the row in @filter that corresponds to the
2421 * row pointed at by @child_iter.
2424 egg_tree_model_filter_convert_child_iter_to_iter (EggTreeModelFilter
*filter
,
2425 GtkTreeIter
*filter_iter
,
2426 GtkTreeIter
*child_iter
)
2428 GtkTreePath
*child_path
, *path
;
2430 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2431 g_return_if_fail (filter
->child_model
!= NULL
);
2432 g_return_if_fail (filter_iter
!= NULL
);
2433 g_return_if_fail (child_iter
!= NULL
);
2435 filter_iter
->stamp
= 0;
2437 child_path
= gtk_tree_model_get_path (filter
->child_model
, child_iter
);
2438 g_return_if_fail (child_path
!= NULL
);
2440 path
= egg_tree_model_filter_convert_child_path_to_path (filter
,
2442 gtk_tree_path_free (child_path
);
2443 g_return_if_fail (path
!= NULL
);
2445 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter
), filter_iter
, path
);
2446 gtk_tree_path_free (path
);
2450 * egg_tree_model_filter_convert_iter_to_child_iter:
2451 * @filter: A #EggTreeModelFilter.
2452 * @child_iter: An uninitialized #GtkTreeIter.
2453 * @filter_iter: A valid #GtkTreeIter pointing to a row on @filter.
2455 * Sets @child_iter to point to the row pointed to by @filter_iter.
2458 egg_tree_model_filter_convert_iter_to_child_iter (EggTreeModelFilter
*filter
,
2459 GtkTreeIter
*child_iter
,
2460 GtkTreeIter
*filter_iter
)
2462 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2463 g_return_if_fail (filter
->child_model
!= NULL
);
2464 g_return_if_fail (child_iter
!= NULL
);
2465 g_return_if_fail (filter_iter
!= NULL
);
2466 g_return_if_fail (filter_iter
->stamp
== filter
->stamp
);
2468 if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter
))
2470 *child_iter
= FILTER_ELT (filter_iter
->user_data2
)->iter
;
2476 path
= egg_tree_model_filter_elt_get_path (filter_iter
->user_data
,
2477 filter_iter
->user_data2
,
2478 filter
->virtual_root
);
2479 gtk_tree_model_get_iter (filter
->child_model
, child_iter
, path
);
2480 gtk_tree_path_free (path
);
2484 static GtkTreePath
*
2485 egg_real_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter
*filter
,
2486 GtkTreePath
*child_path
,
2487 gboolean build_levels
,
2488 gboolean fetch_childs
)
2490 gint
*child_indices
;
2491 GtkTreePath
*retval
;
2492 GtkTreePath
*real_path
;
2497 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
), NULL
);
2498 g_return_val_if_fail (filter
->child_model
!= NULL
, NULL
);
2499 g_return_val_if_fail (child_path
!= NULL
, NULL
);
2501 if (!filter
->virtual_root
)
2502 real_path
= gtk_tree_path_copy (child_path
);
2504 real_path
= egg_tree_model_filter_remove_root (child_path
,
2505 filter
->virtual_root
);
2510 retval
= gtk_tree_path_new ();
2511 child_indices
= gtk_tree_path_get_indices (real_path
);
2513 if (filter
->root
== NULL
&& build_levels
)
2514 egg_tree_model_filter_build_level (filter
, NULL
, NULL
);
2515 level
= FILTER_LEVEL (filter
->root
);
2517 for (i
= 0; i
< gtk_tree_path_get_depth (real_path
); i
++)
2520 gboolean found_child
= FALSE
;
2524 gtk_tree_path_free (real_path
);
2525 gtk_tree_path_free (retval
);
2529 tmp
= bsearch_elt_with_offset (level
->array
, child_indices
[i
], &j
);
2532 gtk_tree_path_append_index (retval
, j
);
2533 if (!tmp
->children
&& build_levels
)
2534 egg_tree_model_filter_build_level (filter
, level
, tmp
);
2535 level
= tmp
->children
;
2539 if (!found_child
&& fetch_childs
)
2541 tmp
= egg_tree_model_filter_fetch_child (filter
, level
,
2545 /* didn't find the child, let's try to bring it back */
2546 if (!tmp
|| tmp
->offset
!= child_indices
[i
])
2549 gtk_tree_path_free (real_path
);
2550 gtk_tree_path_free (retval
);
2554 gtk_tree_path_append_index (retval
, j
);
2555 if (!tmp
->children
&& build_levels
)
2556 egg_tree_model_filter_build_level (filter
, level
, tmp
);
2557 level
= tmp
->children
;
2560 else if (!found_child
&& !fetch_childs
)
2563 gtk_tree_path_free (real_path
);
2564 gtk_tree_path_free (retval
);
2569 gtk_tree_path_free (real_path
);
2574 * egg_tree_model_filter_convert_child_path_to_path:
2575 * @filter: A #EggTreeModelFilter.
2576 * @child_path: A #GtkTreePath to convert.
2578 * Converts @child_path to a path relative to @filter. That is, @child_path
2579 * points to a path in the child model. The rerturned path will point to the
2580 * same row in the filtered model. If @child_path isn't a valid path on the
2581 * child model, then %NULL is returned.
2583 * Return value: A newly allocated #GtkTreePath, or %NULL.
2586 egg_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter
*filter
,
2587 GtkTreePath
*child_path
)
2589 /* this function does the sanity checks */
2590 return egg_real_tree_model_filter_convert_child_path_to_path (filter
,
2597 * egg_tree_model_filter_convert_path_to_child_path:
2598 * @filter: A #EggTreeModelFilter.
2599 * @filter_path: A #GtkTreePath to convert.
2601 * Converts @filter_path to a path on the child model of @filter. That is,
2602 * @filter_path points to a location in @filter. The returned path will
2603 * point to the same location in the model not being filtered. If @filter_path
2604 * does not point to a location in the child model, %NULL is returned.
2606 * Return value: A newly allocated #GtkTreePath, or %NULL.
2609 egg_tree_model_filter_convert_path_to_child_path (EggTreeModelFilter
*filter
,
2610 GtkTreePath
*filter_path
)
2612 gint
*filter_indices
;
2613 GtkTreePath
*retval
;
2617 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
), NULL
);
2618 g_return_val_if_fail (filter
->child_model
!= NULL
, NULL
);
2619 g_return_val_if_fail (filter_path
!= NULL
, NULL
);
2622 retval
= gtk_tree_path_new ();
2623 filter_indices
= gtk_tree_path_get_indices (filter_path
);
2625 egg_tree_model_filter_build_level (filter
, NULL
, NULL
);
2626 level
= FILTER_LEVEL (filter
->root
);
2628 for (i
= 0; i
< gtk_tree_path_get_depth (filter_path
); i
++)
2630 gint count
= filter_indices
[i
];
2632 if (!level
|| level
->array
->len
<= filter_indices
[i
])
2634 gtk_tree_path_free (retval
);
2638 if (g_array_index (level
->array
, FilterElt
, count
).children
== NULL
)
2639 egg_tree_model_filter_build_level (filter
, level
, &g_array_index (level
->array
, FilterElt
, count
));
2641 if (!level
|| level
->array
->len
<= filter_indices
[i
])
2643 gtk_tree_path_free (retval
);
2647 gtk_tree_path_append_index (retval
, g_array_index (level
->array
, FilterElt
, count
).offset
);
2648 level
= g_array_index (level
->array
, FilterElt
, count
).children
;
2653 if (filter
->virtual_root
)
2655 GtkTreePath
*real_retval
;
2657 real_retval
= egg_tree_model_filter_add_root (retval
,
2658 filter
->virtual_root
);
2659 gtk_tree_path_free (retval
);
2668 egg_tree_model_filter_refilter_helper (GtkTreeModel
*model
,
2673 /* evil, don't try this at home, but certainly speeds things up */
2674 egg_tree_model_filter_row_changed (model
, path
, iter
, data
);
2680 * egg_tree_model_filter_refilter:
2681 * @filter: A #EggTreeModelFilter.
2683 * Emits ::row_changed for each row in the child model, which causes
2684 * the filter to re-evaluate whether a row is visible or not.
2687 egg_tree_model_filter_refilter (EggTreeModelFilter
*filter
)
2689 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2692 gtk_tree_model_foreach (filter
->child_model
,
2693 egg_tree_model_filter_refilter_helper
,
2698 * egg_tree_model_filter_clear_cache:
2699 * @filter: A #EggTreeModelFilter.
2701 * This function should almost never be called. It clears the @filter
2702 * of any cached iterators that haven't been reffed with
2703 * gtk_tree_model_ref_node(). This might be useful if the child model
2704 * being filtered is static (and doesn't change often) and there has been
2705 * a lot of unreffed access to nodes. As a side effect of this function,
2706 * all unreffed itters will be invalid.
2709 egg_tree_model_filter_clear_cache (EggTreeModelFilter
*filter
)
2711 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter
));
2713 if (filter
->zero_ref_count
)
2714 egg_tree_model_filter_clear_cache_helper (filter
,
2715 FILTER_LEVEL (filter
->root
));