*** empty log message ***
[anjuta-git-plugin.git] / libegg / eggtreemodelfilter.c
blobfbe6403b11ccbbbd0a43faac5ca0b7fe2116a3f6
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>
23 #include <string.h>
25 /* FIXME: remove this when we move it to GTK+ */
26 #include "eggintl.h"
28 /* ITER FORMAT:
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
36 * child model.
39 typedef struct _FilterElt FilterElt;
40 typedef struct _FilterLevel FilterLevel;
42 struct _FilterElt
44 GtkTreeIter iter;
45 FilterLevel *children;
46 gint offset;
47 gint ref_count;
48 gint zero_ref_count;
49 gboolean visible;
52 struct _FilterLevel
54 GArray *array;
55 gint ref_count;
57 FilterElt *parent_elt;
58 FilterLevel *parent_level;
61 /* properties */
62 enum
64 PROP_0,
65 PROP_CHILD_MODEL,
66 PROP_VIRTUAL_ROOT
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,
81 guint prop_id,
82 const GValue *value,
83 GParamSpec *pspec);
84 static void egg_tree_model_filter_get_property (GObject *object,
85 guint prop_id,
86 GValue *value,
87 GParamSpec *pspec);
89 /* signal handlers */
90 static void egg_tree_model_filter_row_changed (GtkTreeModel *c_model,
91 GtkTreePath *c_path,
92 GtkTreeIter *c_iter,
93 gpointer data);
94 static void egg_tree_model_filter_row_inserted (GtkTreeModel *c_model,
95 GtkTreePath *c_path,
96 GtkTreeIter *c_iter,
97 gpointer data);
98 static void egg_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model,
99 GtkTreePath *c_path,
100 GtkTreeIter *c_iter,
101 gpointer data);
102 static void egg_tree_model_filter_row_deleted (GtkTreeModel *c_model,
103 GtkTreePath *c_path,
104 gpointer data);
105 static void egg_tree_model_filter_rows_reordered (GtkTreeModel *c_model,
106 GtkTreePath *c_path,
107 GtkTreeIter *c_iter,
108 gint *new_order,
109 gpointer data);
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,
115 gint index);
116 static gboolean egg_tree_model_filter_get_iter (GtkTreeModel *model,
117 GtkTreeIter *iter,
118 GtkTreePath *path);
119 static GtkTreePath *egg_tree_model_filter_get_path (GtkTreeModel *model,
120 GtkTreeIter *iter);
121 static void egg_tree_model_filter_get_value (GtkTreeModel *model,
122 GtkTreeIter *iter,
123 gint column,
124 GValue *value);
125 static gboolean egg_tree_model_filter_iter_next (GtkTreeModel *model,
126 GtkTreeIter *iter);
127 static gboolean egg_tree_model_filter_iter_children (GtkTreeModel *model,
128 GtkTreeIter *iter,
129 GtkTreeIter *parent);
130 static gboolean egg_tree_model_filter_iter_has_child (GtkTreeModel *model,
131 GtkTreeIter *iter);
132 static gint egg_tree_model_filter_iter_n_children (GtkTreeModel *model,
133 GtkTreeIter *iter);
134 static gboolean egg_tree_model_filter_iter_nth_child (GtkTreeModel *model,
135 GtkTreeIter *iter,
136 GtkTreeIter *parent,
137 gint n);
138 static gboolean egg_tree_model_filter_iter_parent (GtkTreeModel *model,
139 GtkTreeIter *iter,
140 GtkTreeIter *child);
141 static void egg_tree_model_filter_ref_node (GtkTreeModel *model,
142 GtkTreeIter *iter);
143 static void egg_tree_model_filter_unref_node (GtkTreeModel *model,
144 GtkTreeIter *iter);
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,
156 FilterElt *elt,
157 GtkTreePath *root);
159 static GtkTreePath *egg_tree_model_filter_add_root (GtkTreePath *src,
160 GtkTreePath *root);
161 static GtkTreePath *egg_tree_model_filter_remove_root (GtkTreePath *src,
162 GtkTreePath *root);
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,
169 FilterLevel *level);
171 static void egg_tree_model_filter_real_unref_node (GtkTreeModel *model,
172 GtkTreeIter *iter,
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,
178 GtkTreePath *root);
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,
186 FilterLevel *level,
187 gint offset,
188 gint *index);
189 static void egg_tree_model_filter_remove_node (EggTreeModelFilter *filter,
190 GtkTreeIter *iter,
191 gboolean emit_signal);
192 static void egg_tree_model_filter_update_childs (EggTreeModelFilter *filter,
193 FilterLevel *level,
194 FilterElt *elt);
195 static FilterElt *bsearch_elt_with_offset (GArray *array,
196 gint offset,
197 gint *index);
200 static GObjectClass *parent_class = NULL;
202 GType
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),
218 0, /* n_preallocs */
219 (GInstanceInitFunc) egg_tree_model_filter_init
222 static const GInterfaceInfo tree_model_info =
224 (GInterfaceInitFunc) egg_tree_model_filter_tree_model_init,
225 NULL,
226 NULL
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,
234 GTK_TYPE_TREE_MODEL,
235 &tree_model_info);
238 return tree_model_filter_type;
241 static void
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;
250 static void
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,
265 PROP_CHILD_MODEL,
266 g_param_spec_object ("child_model",
267 _("The child model"),
268 _("The model for the filtermodel to filter"),
269 GTK_TYPE_TREE_MODEL,
270 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
272 g_object_class_install_property (object_class,
273 PROP_VIRTUAL_ROOT,
274 g_param_spec_boxed ("virtual_root",
275 _("The virtual root"),
276 _("The virtual root (relative to the child model) for this filtermodel"),
277 GTK_TYPE_TREE_PATH,
278 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
281 static void
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;
301 static void
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);
311 if (filter->root)
312 egg_tree_model_filter_free_level (filter, filter->root);
314 if (filter->modify_types)
315 g_free (filter->modify_types);
317 /* must chain up */
318 parent_class->finalize (object);
321 static void
322 egg_tree_model_filter_set_property (GObject *object,
323 guint prop_id,
324 const GValue *value,
325 GParamSpec *pspec)
327 EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (object);
329 switch (prop_id)
331 case PROP_CHILD_MODEL:
332 egg_tree_model_filter_set_model (filter, g_value_get_object (value));
333 break;
334 case PROP_VIRTUAL_ROOT:
335 egg_tree_model_filter_set_root (filter, g_value_get_boxed (value));
336 break;
337 default:
338 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
339 break;
343 static void
344 egg_tree_model_filter_get_property (GObject *object,
345 guint prop_id,
346 GValue *value,
347 GParamSpec *pspec)
349 EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (object);
351 switch (prop_id)
353 case PROP_CHILD_MODEL:
354 g_value_set_object (value, filter->child_model);
355 break;
356 case PROP_VIRTUAL_ROOT:
357 g_value_set_boxed (value, filter->virtual_root);
358 break;
359 default:
360 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
361 break;
365 /* helpers */
367 static void
368 egg_tree_model_filter_build_level (EggTreeModelFilter *filter,
369 FilterLevel *parent_level,
370 FilterElt *parent_elt)
372 GtkTreeIter iter;
373 GtkTreeIter root;
374 FilterLevel *new_level;
375 gint length = 0;
376 gint i;
378 g_assert (filter->child_model != NULL);
380 if (!parent_level)
382 if (filter->virtual_root)
384 if (gtk_tree_model_get_iter (filter->child_model, &root, filter->virtual_root) == FALSE)
385 return;
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)
389 return;
391 else
393 if (!gtk_tree_model_get_iter_first (filter->child_model, &iter))
394 return;
395 length = gtk_tree_model_iter_n_children (filter->child_model, NULL);
398 else
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,
408 &child_parent_iter,
409 &parent_iter);
410 if (gtk_tree_model_iter_children (filter->child_model, &iter, &child_parent_iter) == FALSE)
411 return;
413 /* stamp may have changed */
414 egg_tree_model_filter_convert_iter_to_child_iter (filter,
415 &child_parent_iter,
416 &parent_iter);
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,
424 sizeof (FilterElt),
425 length);
426 new_level->ref_count = 0;
427 new_level->parent_elt = parent_elt;
428 new_level->parent_level = parent_level;
430 if (parent_elt)
431 parent_elt->children = new_level;
432 else
433 filter->root = new_level;
435 /* increase the count of zero ref_counts */
436 while (parent_level)
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++;
445 i = 0;
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++;
470 i++;
472 while (gtk_tree_model_iter_next (filter->child_model, &iter));
475 static void
476 egg_tree_model_filter_free_level (EggTreeModelFilter *filter,
477 FilterLevel *filter_level)
479 gint i;
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;
490 if (parent_elt)
491 parent_elt->zero_ref_count--;
493 if (parent_level)
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;
515 else
516 filter->root = NULL;
518 g_array_free (filter_level->array, TRUE);
519 filter_level->array = NULL;
521 g_free (filter_level);
522 filter_level = NULL;
525 static GtkTreePath *
526 egg_tree_model_filter_elt_get_path (FilterLevel *level,
527 FilterElt *elt,
528 GtkTreePath *root)
530 FilterLevel *walker = level;
531 FilterElt *walker2 = elt;
532 GtkTreePath *path;
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 ();
540 while (walker)
542 gtk_tree_path_prepend_index (path, walker2->offset);
544 walker2 = walker->parent_elt;
545 walker = walker->parent_level;
548 if (root)
550 real_path = egg_tree_model_filter_add_root (path, root);
551 gtk_tree_path_free (path);
552 return real_path;
555 return path;
558 static GtkTreePath *
559 egg_tree_model_filter_add_root (GtkTreePath *src,
560 GtkTreePath *root)
562 GtkTreePath *retval;
563 gint i;
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]);
570 return retval;
573 static GtkTreePath *
574 egg_tree_model_filter_remove_root (GtkTreePath *src,
575 GtkTreePath *root)
577 GtkTreePath *retval;
578 gint i;
579 gint depth;
580 gint *indices;
582 if (gtk_tree_path_get_depth (src) <= gtk_tree_path_get_depth (root))
583 return NULL;
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])
590 return NULL;
592 retval = gtk_tree_path_new ();
594 for (; i < depth; i++)
595 gtk_tree_path_append_index (retval, indices[i]);
597 return retval;
600 static void
601 egg_tree_model_filter_increment_stamp (EggTreeModelFilter *filter)
605 filter->stamp++;
607 while (filter->stamp == 0);
609 egg_tree_model_filter_clear_cache (filter);
612 static gboolean
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,
619 child_iter,
620 filter->visible_data));
622 else if (filter->visible_column >= 0)
624 GValue val = {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);
632 return TRUE;
635 g_value_unset (&val);
636 return FALSE;
639 /* no filter thing set, so always visible */
640 return TRUE;
643 static void
644 egg_tree_model_filter_clear_cache_helper (EggTreeModelFilter *filter,
645 FilterLevel *level)
647 gint i;
649 g_assert (level);
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);
660 return;
664 static FilterElt *
665 egg_tree_model_filter_fetch_child (EggTreeModelFilter *filter,
666 FilterLevel *level,
667 gint offset,
668 gint *index)
670 gint i = 0;
671 gint start, middle, end;
672 gint len;
673 GtkTreePath *c_path = NULL;
674 GtkTreeIter c_iter;
675 GtkTreePath *c_parent_path = NULL;
676 GtkTreeIter c_parent_iter;
677 FilterElt elt;
679 /* check if child exists and is visible */
680 if (level->parent_elt)
682 c_parent_path =
683 egg_tree_model_filter_elt_get_path (level->parent_level,
684 level->parent_elt,
685 filter->virtual_root);
686 if (!c_parent_path)
687 return NULL;
689 else
691 if (filter->virtual_root)
692 c_parent_path = gtk_tree_path_copy (filter->virtual_root);
693 else
694 c_parent_path = NULL;
697 if (c_parent_path)
699 gtk_tree_model_get_iter (filter->child_model,
700 &c_parent_iter,
701 c_parent_path);
702 len = gtk_tree_model_iter_n_children (filter->child_model,
703 &c_parent_iter);
705 c_path = gtk_tree_path_copy (c_parent_path);
706 gtk_tree_path_free (c_parent_path);
708 else
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))
719 return NULL;
721 /* add child */
722 elt.offset = offset;
723 elt.zero_ref_count = 0;
724 elt.ref_count = 0;
725 elt.children = NULL;
726 /* visibility should be FALSE as we don't emit row_inserted */
727 elt.visible = FALSE;
729 if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
730 elt.iter = c_iter;
732 /* find index (binary search on offset) */
733 start = 0;
734 end = level->array->len;
736 if (start != end)
738 while (start != end)
740 middle = (start + end) / 2;
742 if (g_array_index (level->array, FilterElt, middle).offset <= offset)
743 start = middle + 1;
744 else
745 end = middle;
748 if (g_array_index (level->array, FilterElt, middle).offset <= offset)
749 i = middle + 1;
750 else
751 i = middle;
753 else
754 i = 0;
756 g_array_insert_val (level->array, i, elt);
757 *index = i;
759 for (i = MAX (--i, 0); i < level->array->len; i++)
761 FilterElt *e = &(g_array_index (level->array, FilterElt, i));
762 if (e->children)
763 e->children->parent_elt = e;
766 return &g_array_index (level->array, FilterElt, *index);
769 static void
770 egg_tree_model_filter_remove_node (EggTreeModelFilter *filter,
771 GtkTreeIter *iter,
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;
790 /* ref counting */
791 while (elt->ref_count > 0)
792 egg_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
793 iter, FALSE);
795 level_refcount = level->ref_count;
797 /* do the ref counting first! this touches the stamp */
798 if (emit_signal)
800 GtkTreePath *path;
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;
815 if (length == 1)
817 /* kill the level */
818 egg_tree_model_filter_free_level (filter, level);
820 if (!filter->root)
821 /* we killed the root */
822 return;
824 else
826 FilterElt *tmp;
828 /* remove the node */
829 tmp = bsearch_elt_with_offset (level->array, elt->offset, &i);
831 if (tmp)
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);
841 if (elt->children)
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 */
856 GtkTreeIter piter;
857 GtkTreePath *ppath;
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),
866 ppath, &piter);
867 gtk_tree_path_free (ppath);
871 static void
872 egg_tree_model_filter_update_childs (EggTreeModelFilter *filter,
873 FilterLevel *level,
874 FilterElt *elt)
876 GtkTreeIter c_iter;
877 GtkTreeIter iter;
879 if (!elt->visible)
880 return;
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),
891 &iter);
892 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
893 path,
894 &iter);
895 if (path)
896 gtk_tree_path_free (path);
900 static FilterElt *
901 bsearch_elt_with_offset (GArray *array,
902 gint offset,
903 gint *index)
905 gint start, middle, end;
906 FilterElt *elt;
908 start = 0;
909 end = array->len;
911 if (array->len < 1)
912 return NULL;
914 if (start == end)
916 elt = &g_array_index (array, FilterElt, 0);
918 if (elt->offset == offset)
920 *index = 0;
921 return elt;
923 else
924 return NULL;
927 while (start != end)
929 middle = (start + end) / 2;
931 elt = &g_array_index (array, FilterElt, middle);
933 if (elt->offset < offset)
934 start = middle + 1;
935 else if (elt->offset > offset)
936 end = middle;
937 else
938 break;
941 if (elt->offset == offset)
943 *index = middle;
944 return elt;
947 return NULL;
950 /* TreeModel signals */
951 static void
952 egg_tree_model_filter_row_changed (GtkTreeModel *c_model,
953 GtkTreePath *c_path,
954 GtkTreeIter *c_iter,
955 gpointer data)
957 EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
958 GtkTreeIter iter;
959 GtkTreeIter childs;
960 GtkTreeIter real_c_iter;
961 GtkTreePath *path = NULL;
963 FilterElt *elt;
964 FilterLevel *level;
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);
972 if (!c_path)
974 c_path = gtk_tree_model_get_path (c_model, c_iter);
975 free_c_path = TRUE;
978 if (c_iter)
979 real_c_iter = *c_iter;
980 else
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)))
987 goto done;
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,
994 c_path,
995 FALSE,
996 FALSE);
998 if (path)
1000 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path);
1001 current_state = FILTER_ELT (iter.user_data2)->visible;
1003 else
1004 current_state = FALSE;
1006 if (current_state == FALSE && requested_state == FALSE)
1007 /* no changes required */
1008 goto done;
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--;
1021 goto done;
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);
1037 goto done;
1040 /* only current == FALSE and requested == TRUE is left,
1041 * pull in the child
1043 g_return_if_fail (current_state == FALSE && requested_state == TRUE);
1045 /* make sure the new item has been pulled in */
1046 if (!filter->root)
1048 gint i;
1049 FilterLevel *root;
1051 egg_tree_model_filter_build_level (filter, NULL, NULL);
1053 root = FILTER_LEVEL (filter->root);
1055 if (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;
1063 if (!path)
1064 path = egg_real_tree_model_filter_convert_child_path_to_path (filter,
1065 c_path,
1066 TRUE,
1067 TRUE);
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++;
1082 /* update stamp */
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);
1088 done:
1089 if (path)
1090 gtk_tree_path_free (path);
1092 if (free_c_path)
1093 gtk_tree_path_free (c_path);
1096 static void
1097 egg_tree_model_filter_row_inserted (GtkTreeModel *c_model,
1098 GtkTreePath *c_path,
1099 GtkTreeIter *c_iter,
1100 gpointer data)
1102 EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
1103 GtkTreePath *path = NULL;
1104 GtkTreePath *real_path = NULL;
1105 GtkTreeIter iter;
1107 GtkTreeIter real_c_iter;
1109 FilterElt *elt;
1110 FilterLevel *level;
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);
1119 if (!c_path)
1121 c_path = gtk_tree_model_get_path (c_model, c_iter);
1122 free_c_path = TRUE;
1125 if (c_iter)
1126 real_c_iter = *c_iter;
1127 else
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))
1138 gint level;
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])++;
1150 if (!filter->root)
1152 egg_tree_model_filter_build_level (filter, NULL, NULL);
1153 /* that already put the inserted iter in the level */
1155 goto done_and_emit;
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);
1165 /* not our kiddo */
1166 if (!real_path)
1167 goto done;
1169 else
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)
1177 gint j;
1179 if (!level)
1180 /* we don't cover this signal */
1181 goto done;
1183 elt = bsearch_elt_with_offset (level->array,
1184 gtk_tree_path_get_indices (real_path)[i],
1185 &j);
1187 if (!elt)
1188 /* parent is probably being filtered out */
1189 goto done;
1191 if (!elt->children)
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),
1201 &tmpiter);
1203 if (tmppath)
1205 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data),
1206 tmppath, &tmpiter);
1207 gtk_tree_path_free (tmppath);
1210 /* not covering this signal */
1211 goto done;
1214 level = elt->children;
1215 parent_level = level;
1216 i++;
1220 if (!parent_level)
1221 goto done;
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))
1234 e->offset++;
1237 /* only insert when visible */
1238 if (egg_tree_model_filter_visible (filter, &real_c_iter))
1240 FilterElt felt;
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;
1247 felt.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)
1253 break;
1255 g_array_insert_val (level->array, i, felt);
1256 index = i;
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);
1266 if (e->children)
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))
1272 goto done;
1274 done_and_emit:
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,
1279 c_path,
1280 FALSE, TRUE);
1282 if (!path)
1283 goto done;
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);
1292 done:
1293 if (real_path)
1294 gtk_tree_path_free (real_path);
1296 if (free_c_path)
1297 gtk_tree_path_free (c_path);
1300 static void
1301 egg_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model,
1302 GtkTreePath *c_path,
1303 GtkTreeIter *c_iter,
1304 gpointer data)
1306 EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
1307 GtkTreePath *path;
1308 GtkTreeIter iter;
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))
1315 return;
1317 path = egg_real_tree_model_filter_convert_child_path_to_path (filter,
1318 c_path,
1319 FALSE,
1320 TRUE);
1321 if (!path)
1322 return;
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);
1330 static void
1331 egg_tree_model_filter_row_deleted (GtkTreeModel *c_model,
1332 GtkTreePath *c_path,
1333 gpointer data)
1335 EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
1336 GtkTreePath *path;
1337 GtkTreeIter iter;
1338 FilterElt *elt;
1339 FilterLevel *level;
1340 gint offset;
1341 gboolean emit_signal = TRUE;
1342 gint i;
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)))
1351 gint i;
1352 GtkTreePath *path;
1353 FilterLevel *level = FILTER_LEVEL (filter->root);
1355 if (!level)
1356 return;
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);
1374 return;
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))
1383 gint level;
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,
1396 c_path,
1397 FALSE,
1398 FALSE);
1400 if (!path)
1402 /* fixup the offsets */
1403 GtkTreePath *real_path;
1405 if (!filter->root)
1406 return;
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 */
1416 if (!real_path)
1417 return;
1419 else
1420 real_path = gtk_tree_path_copy (c_path);
1422 i = 0;
1423 if (gtk_tree_path_get_depth (real_path) - 1 >= 1)
1425 while (i < gtk_tree_path_get_depth (real_path) - 1)
1427 gint j;
1429 if (!level)
1431 /* we don't cover this */
1432 gtk_tree_path_free (real_path);
1433 return;
1436 elt = bsearch_elt_with_offset (level->array,
1437 gtk_tree_path_get_indices (real_path)[i],
1438 &j);
1441 if (!elt || !elt->children)
1443 /* parent is filtered out, so no level */
1444 gtk_tree_path_free (real_path);
1445 return;
1448 level = elt->children;
1449 i++;
1453 offset = gtk_tree_path_get_indices (real_path)[gtk_tree_path_get_depth (real_path) - 1];
1454 gtk_tree_path_free (real_path);
1456 if (!level)
1457 return;
1459 /* we need:
1460 * - the offset of the removed item
1461 * - the level
1463 for (i = 0; i < level->array->len; i++)
1465 elt = &g_array_index (level->array, FilterElt, i);
1466 if (elt->offset > offset)
1467 elt->offset--;
1468 if (elt->children)
1469 elt->children->parent_elt = elt;
1472 return;
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--;
1484 if (emit_signal)
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);
1492 return;
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,
1501 FALSE);
1504 if (level->array->len == 1)
1506 /* kill level */
1507 egg_tree_model_filter_free_level (filter, level);
1509 else
1511 FilterElt *tmp;
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)
1523 elt->offset--;
1524 if (elt->children)
1525 elt->children->parent_elt = elt;
1529 gtk_tree_path_free (path);
1532 static void
1533 egg_tree_model_filter_rows_reordered (GtkTreeModel *c_model,
1534 GtkTreePath *c_path,
1535 GtkTreeIter *c_iter,
1536 gint *new_order,
1537 gpointer data)
1539 FilterElt *elt;
1540 FilterLevel *level;
1541 EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
1543 GtkTreePath *path;
1544 GtkTreeIter iter;
1546 gint *tmp_array;
1547 gint i, j, elt_count;
1548 gint length;
1550 GArray *new_array;
1552 g_return_if_fail (new_order != NULL);
1554 if (c_path == NULL || gtk_tree_path_get_indices (c_path) == NULL)
1556 if (!filter->root)
1557 return;
1559 length = gtk_tree_model_iter_n_children (c_model, NULL);
1561 if (filter->virtual_root)
1563 gint new_pos = -1;
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])
1568 new_pos = i;
1570 if (new_pos < 0)
1571 return;
1573 gtk_tree_path_get_indices (filter->virtual_root)[0] = new_pos;
1574 return;
1577 path = gtk_tree_path_new ();
1578 level = FILTER_LEVEL (filter->root);
1580 else
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))
1589 gint new_pos = -1;
1590 gint length;
1591 gint level;
1592 GtkTreeIter real_c_iter;
1594 level = gtk_tree_path_get_depth (c_path);
1596 if (c_iter)
1597 real_c_iter = *c_iter;
1598 else
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])
1605 new_pos = i;
1607 if (new_pos < 0)
1608 return;
1610 gtk_tree_path_get_indices (filter->virtual_root)[level] = new_pos;
1611 return;
1614 path = egg_real_tree_model_filter_convert_child_path_to_path (filter,
1615 c_path,
1616 FALSE,
1617 FALSE);
1618 if (!path && filter->virtual_root &&
1619 gtk_tree_path_compare (c_path, filter->virtual_root))
1620 return;
1622 if (!path && !filter->virtual_root)
1623 return;
1625 if (!path)
1627 /* root level mode */
1628 if (!c_iter)
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);
1634 else
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);
1641 if (!elt->children)
1643 gtk_tree_path_free (path);
1644 return;
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)
1655 return;
1657 /* NOTE: we do not bail out here if level->array->len < 2 like
1658 * GtkTreeModelSort does. This because we do some special tricky
1659 * reordering.
1662 /* construct a new array */
1663 new_array = g_array_sized_new (FALSE, FALSE, sizeof (FilterElt),
1664 level->array->len);
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);
1676 old_offset = j;
1677 break;
1680 if (!e)
1681 continue;
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;
1686 elt_count++;
1689 g_array_free (level->array, TRUE);
1690 level->array = new_array;
1692 /* fix up stuff */
1693 for (i = 0; i < level->array->len; i++)
1695 FilterElt *e = &g_array_index (level->array, FilterElt, i);
1696 if (e->children)
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,
1703 tmp_array);
1704 else
1705 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, &iter,
1706 tmp_array);
1708 /* done */
1709 g_free (tmp_array);
1710 gtk_tree_path_free (path);
1713 /* TreeModelIface implementation */
1714 static guint
1715 egg_tree_model_filter_get_flags (GtkTreeModel *model)
1717 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0);
1719 return 0;
1722 static gint
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)
1731 return 0;
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);
1742 static GType
1743 egg_tree_model_filter_get_column_type (GtkTreeModel *model,
1744 gint index)
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);
1764 static gboolean
1765 egg_tree_model_filter_get_iter (GtkTreeModel *model,
1766 GtkTreeIter *iter,
1767 GtkTreePath *path)
1769 EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
1770 gint *indices;
1771 FilterLevel *level;
1772 gint depth, i;
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);
1784 if (!depth)
1786 iter->stamp = 0;
1787 return FALSE;
1790 for (i = 0; i < depth - 1; i++)
1792 if (!level || indices[i] >= level->array->len)
1794 return FALSE;
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,
1800 FilterElt,
1801 indices[i]));
1802 level = g_array_index (level->array, FilterElt, indices[i]).children;
1805 if (!level || indices[i] >= level->array->len)
1807 iter->stamp = 0;
1808 return FALSE;
1811 iter->stamp = filter->stamp;
1812 iter->user_data = level;
1813 iter->user_data2 = &g_array_index (level->array, FilterElt,
1814 indices[depth - 1]);
1816 return TRUE;
1819 static GtkTreePath *
1820 egg_tree_model_filter_get_path (GtkTreeModel *model,
1821 GtkTreeIter *iter)
1823 GtkTreePath *retval;
1824 FilterLevel *level;
1825 FilterElt *elt;
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;
1835 while (level)
1837 gtk_tree_path_prepend_index (retval,
1838 elt - FILTER_ELT (level->array->data));
1839 elt = level->parent_elt;
1840 level = level->parent_level;
1843 return retval;
1846 static void
1847 egg_tree_model_filter_get_value (GtkTreeModel *model,
1848 GtkTreeIter *iter,
1849 gint column,
1850 GValue *value)
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,
1865 iter,
1866 value,
1867 column,
1868 filter->modify_data);
1870 return;
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);
1878 static gboolean
1879 egg_tree_model_filter_iter_next (GtkTreeModel *model,
1880 GtkTreeIter *iter)
1882 FilterLevel *level;
1883 FilterElt *elt;
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)
1894 iter->stamp = 0;
1895 return FALSE;
1898 iter->user_data2 = elt + 1;
1900 return TRUE;
1903 static gboolean
1904 egg_tree_model_filter_iter_children (GtkTreeModel *model,
1905 GtkTreeIter *iter,
1906 GtkTreeIter *parent)
1908 EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
1909 FilterLevel *level;
1911 iter->stamp = 0;
1912 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE);
1913 g_return_val_if_fail (filter->child_model != NULL, FALSE);
1914 if (parent)
1915 g_return_val_if_fail (filter->stamp == parent->stamp, FALSE);
1917 if (!parent)
1919 if (!filter->root)
1920 egg_tree_model_filter_build_level (filter, NULL, NULL);
1921 if (!filter->root)
1922 return FALSE;
1924 level = filter->root;
1925 iter->stamp = filter->stamp;
1926 iter->user_data = level;
1927 iter->user_data2 = level->array->data;
1929 else
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)
1936 return FALSE;
1938 /* empty array? */
1939 if (FILTER_ELT (parent->user_data2)->children->array->len <= 0)
1940 return FALSE;
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;
1947 return TRUE;
1950 static gboolean
1951 egg_tree_model_filter_iter_has_child (GtkTreeModel *model,
1952 GtkTreeIter *iter)
1954 GtkTreeIter child_iter;
1955 EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
1956 FilterElt *elt;
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
1968 * out
1970 if (!elt->children
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),
1973 elt);
1975 /* FIXME: we should prolly count the visible nodes here, just like in
1976 * _iter_n_children.
1978 if (elt->children && elt->children->array->len > 0)
1979 return TRUE;
1981 return FALSE;
1984 static gint
1985 egg_tree_model_filter_iter_n_children (GtkTreeModel *model,
1986 GtkTreeIter *iter)
1988 GtkTreeIter child_iter;
1989 EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
1990 FilterElt *elt;
1992 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0);
1993 g_return_val_if_fail (filter->child_model != NULL, 0);
1994 if (iter)
1995 g_return_val_if_fail (filter->stamp == iter->stamp, 0);
1997 if (!iter)
1999 if (!filter->root)
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),
2013 elt);
2015 if (elt->children && elt->children->array->len)
2017 int i = 0;
2018 int count = 0;
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)
2024 count++;
2026 return count;
2029 return 0;
2032 static gboolean
2033 egg_tree_model_filter_iter_nth_child (GtkTreeModel *model,
2034 GtkTreeIter *iter,
2035 GtkTreeIter *parent,
2036 gint n)
2038 FilterLevel *level;
2039 GtkTreeIter children;
2041 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE);
2042 if (parent)
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)
2048 iter->stamp = 0;
2049 return FALSE;
2052 level = children.user_data;
2053 if (n >= level->array->len)
2055 iter->stamp = 0;
2056 return FALSE;
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);
2063 return TRUE;
2066 static gboolean
2067 egg_tree_model_filter_iter_parent (GtkTreeModel *model,
2068 GtkTreeIter *iter,
2069 GtkTreeIter *child)
2071 FilterLevel *level;
2073 iter->stamp = 0;
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;
2086 return TRUE;
2089 return FALSE;
2092 static void
2093 egg_tree_model_filter_ref_node (GtkTreeModel *model,
2094 GtkTreeIter *iter)
2096 EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
2097 GtkTreeIter child_iter;
2098 FilterLevel *level;
2099 FilterElt *elt;
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;
2112 elt->ref_count++;
2113 level->ref_count++;
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 */
2122 if (parent_elt)
2123 parent_elt->zero_ref_count--;
2125 if (parent_level)
2127 parent_elt = parent_level->parent_elt;
2128 parent_level = parent_level->parent_level;
2131 while (parent_level);
2132 filter->zero_ref_count--;
2136 static void
2137 egg_tree_model_filter_unref_node (GtkTreeModel *model,
2138 GtkTreeIter *iter)
2140 egg_tree_model_filter_real_unref_node (model, iter, TRUE);
2143 static void
2144 egg_tree_model_filter_real_unref_node (GtkTreeModel *model,
2145 GtkTreeIter *iter,
2146 gboolean propagate_unref)
2148 EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
2149 FilterLevel *level;
2150 FilterElt *elt;
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);
2168 elt->ref_count--;
2169 level->ref_count--;
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 */
2188 static void
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 */
2208 if (filter->root)
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;
2219 if (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),
2225 filter);
2226 filter->inserted_id =
2227 g_signal_connect (child_model, "row_inserted",
2228 G_CALLBACK (egg_tree_model_filter_row_inserted),
2229 filter);
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),
2233 filter);
2234 filter->deleted_id =
2235 g_signal_connect (child_model, "row_deleted",
2236 G_CALLBACK (egg_tree_model_filter_row_deleted),
2237 filter);
2238 filter->reordered_id =
2239 g_signal_connect (child_model, "rows_reordered",
2240 G_CALLBACK (egg_tree_model_filter_rows_reordered),
2241 filter);
2243 filter->child_flags = gtk_tree_model_get_flags (child_model);
2244 filter->stamp = g_random_int ();
2248 static void
2249 egg_tree_model_filter_set_root (EggTreeModelFilter *filter,
2250 GtkTreePath *root)
2252 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter));
2254 if (!root)
2255 filter->virtual_root = NULL;
2256 else
2257 filter->virtual_root = gtk_tree_path_copy (root);
2260 /* public API */
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.
2272 GtkTreeModel *
2273 egg_tree_model_filter_new (GtkTreeModel *child_model,
2274 GtkTreePath *root)
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),
2283 child_model);
2284 egg_tree_model_filter_set_root (EGG_TREE_MODEL_FILTER (retval), root);
2286 return retval;
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.
2297 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
2314 * %FALSE otherwise.
2316 void
2317 egg_tree_model_filter_set_visible_func (EggTreeModelFilter *filter,
2318 EggTreeModelFilterVisibleFunc func,
2319 gpointer data,
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.
2353 void
2354 egg_tree_model_filter_set_modify_func (EggTreeModelFilter *filter,
2355 gint n_columns,
2356 GType *types,
2357 EggTreeModelFilterModifyFunc func,
2358 gpointer data,
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
2391 * if not.
2393 void
2394 egg_tree_model_filter_set_visible_column (EggTreeModelFilter *filter,
2395 gint column)
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;
2406 /* conversion */
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.
2417 void
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,
2435 child_path);
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.
2451 void
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;
2466 else
2468 GtkTreePath *path;
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;
2487 FilterLevel *level;
2488 FilterElt *tmp;
2489 gint i;
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);
2497 else
2498 real_path = egg_tree_model_filter_remove_root (child_path,
2499 filter->virtual_root);
2501 if (!real_path)
2502 return NULL;
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++)
2513 gint j;
2514 gboolean found_child = FALSE;
2516 if (!level)
2518 gtk_tree_path_free (real_path);
2519 gtk_tree_path_free (retval);
2520 return NULL;
2523 tmp = bsearch_elt_with_offset (level->array, child_indices[i], &j);
2524 if (tmp)
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;
2530 found_child = TRUE;
2533 if (!found_child && fetch_childs)
2535 tmp = egg_tree_model_filter_fetch_child (filter, level,
2536 child_indices[i],
2537 &j);
2539 /* didn't find the child, let's try to bring it back */
2540 if (!tmp || tmp->offset != child_indices[i])
2542 /* not there */
2543 gtk_tree_path_free (real_path);
2544 gtk_tree_path_free (retval);
2545 return NULL;
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;
2552 found_child = TRUE;
2554 else if (!found_child && !fetch_childs)
2556 /* no path */
2557 gtk_tree_path_free (real_path);
2558 gtk_tree_path_free (retval);
2559 return NULL;
2563 gtk_tree_path_free (real_path);
2564 return retval;
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.
2579 GtkTreePath *
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,
2585 child_path,
2586 TRUE,
2587 TRUE);
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.
2602 GtkTreePath *
2603 egg_tree_model_filter_convert_path_to_child_path (EggTreeModelFilter *filter,
2604 GtkTreePath *filter_path)
2606 gint *filter_indices;
2607 GtkTreePath *retval;
2608 FilterLevel *level;
2609 gint i;
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);
2615 /* convert path */
2616 retval = gtk_tree_path_new ();
2617 filter_indices = gtk_tree_path_get_indices (filter_path);
2618 if (!filter->root)
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);
2629 return NULL;
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);
2638 return NULL;
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;
2645 /* apply vroot */
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);
2655 return real_retval;
2658 return retval;
2661 static gboolean
2662 egg_tree_model_filter_refilter_helper (GtkTreeModel *model,
2663 GtkTreePath *path,
2664 GtkTreeIter *iter,
2665 gpointer data)
2667 /* evil, don't try this at home, but certainly speeds things up */
2668 egg_tree_model_filter_row_changed (model, path, iter, data);
2670 return FALSE;
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.
2680 void
2681 egg_tree_model_filter_refilter (EggTreeModelFilter *filter)
2683 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter));
2685 /* S L O W */
2686 gtk_tree_model_foreach (filter->child_model,
2687 egg_tree_model_filter_refilter_helper,
2688 filter);
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.
2702 void
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));