Implement AnjutaSyncCommand class in libanjuta.
[anjuta-git-plugin.git] / libegg / eggtreemodelfilter.c
blob6afed96ca9fff7ebda97c2bdc92c49ffbe9a2dc2
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>
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 i_t;
672 gint start, middle, end;
673 gint len;
674 GtkTreePath *c_path = NULL;
675 GtkTreeIter c_iter;
676 GtkTreePath *c_parent_path = NULL;
677 GtkTreeIter c_parent_iter;
678 FilterElt elt;
680 /* check if child exists and is visible */
681 if (level->parent_elt)
683 c_parent_path =
684 egg_tree_model_filter_elt_get_path (level->parent_level,
685 level->parent_elt,
686 filter->virtual_root);
687 if (!c_parent_path)
688 return NULL;
690 else
692 if (filter->virtual_root)
693 c_parent_path = gtk_tree_path_copy (filter->virtual_root);
694 else
695 c_parent_path = NULL;
698 if (c_parent_path)
700 gtk_tree_model_get_iter (filter->child_model,
701 &c_parent_iter,
702 c_parent_path);
703 len = gtk_tree_model_iter_n_children (filter->child_model,
704 &c_parent_iter);
706 c_path = gtk_tree_path_copy (c_parent_path);
707 gtk_tree_path_free (c_parent_path);
709 else
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))
720 return NULL;
722 /* add child */
723 elt.offset = offset;
724 elt.zero_ref_count = 0;
725 elt.ref_count = 0;
726 elt.children = NULL;
727 /* visibility should be FALSE as we don't emit row_inserted */
728 elt.visible = FALSE;
730 if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
731 elt.iter = c_iter;
733 /* find index (binary search on offset) */
734 start = 0;
735 end = level->array->len;
737 if (start != end)
739 while (start != end)
741 middle = (start + end) / 2;
743 if (g_array_index (level->array, FilterElt, middle).offset <= offset)
744 start = middle + 1;
745 else
746 end = middle;
749 if (g_array_index (level->array, FilterElt, middle).offset <= offset)
750 i = middle + 1;
751 else
752 i = middle;
754 else
755 i = 0;
757 g_array_insert_val (level->array, i, elt);
758 *index = i;
760 i_t = i - 1;
761 for (i = MAX (i_t, 0); i < level->array->len; i++)
763 FilterElt *e = &(g_array_index (level->array, FilterElt, i));
764 if (e->children)
765 e->children->parent_elt = e;
768 return &g_array_index (level->array, FilterElt, *index);
771 static void
772 egg_tree_model_filter_remove_node (EggTreeModelFilter *filter,
773 GtkTreeIter *iter,
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;
792 /* ref counting */
793 while (elt->ref_count > 0)
794 egg_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
795 iter, FALSE);
797 level_refcount = level->ref_count;
799 /* do the ref counting first! this touches the stamp */
800 if (emit_signal)
802 GtkTreePath *path;
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;
817 if (length == 1)
819 /* kill the level */
820 egg_tree_model_filter_free_level (filter, level);
822 if (!filter->root)
823 /* we killed the root */
824 return;
826 else
828 FilterElt *tmp;
830 /* remove the node */
831 tmp = bsearch_elt_with_offset (level->array, elt->offset, &i);
833 if (tmp)
835 gint i_t;
836 g_array_remove_index (level->array, i);
838 i_t = i - 1;
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);
845 if (elt->children)
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 */
860 GtkTreeIter piter;
861 GtkTreePath *ppath;
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),
870 ppath, &piter);
871 gtk_tree_path_free (ppath);
875 static void
876 egg_tree_model_filter_update_childs (EggTreeModelFilter *filter,
877 FilterLevel *level,
878 FilterElt *elt)
880 GtkTreeIter c_iter;
881 GtkTreeIter iter;
883 if (!elt->visible)
884 return;
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),
895 &iter);
896 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
897 path,
898 &iter);
899 if (path)
900 gtk_tree_path_free (path);
904 static FilterElt *
905 bsearch_elt_with_offset (GArray *array,
906 gint offset,
907 gint *index)
909 gint start, middle, end;
910 FilterElt *elt;
912 start = 0;
913 end = array->len;
915 if (array->len < 1)
916 return NULL;
918 if (start == end)
920 elt = &g_array_index (array, FilterElt, 0);
922 if (elt->offset == offset)
924 *index = 0;
925 return elt;
927 else
928 return NULL;
931 while (start != end)
933 middle = (start + end) / 2;
935 elt = &g_array_index (array, FilterElt, middle);
937 if (elt->offset < offset)
938 start = middle + 1;
939 else if (elt->offset > offset)
940 end = middle;
941 else
942 break;
945 if (elt->offset == offset)
947 *index = middle;
948 return elt;
951 return NULL;
954 /* TreeModel signals */
955 static void
956 egg_tree_model_filter_row_changed (GtkTreeModel *c_model,
957 GtkTreePath *c_path,
958 GtkTreeIter *c_iter,
959 gpointer data)
961 EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
962 GtkTreeIter iter;
963 GtkTreeIter childs;
964 GtkTreeIter real_c_iter;
965 GtkTreePath *path = NULL;
967 FilterElt *elt;
968 FilterLevel *level;
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);
976 if (!c_path)
978 c_path = gtk_tree_model_get_path (c_model, c_iter);
979 free_c_path = TRUE;
982 if (c_iter)
983 real_c_iter = *c_iter;
984 else
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)))
991 goto done;
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,
998 c_path,
999 FALSE,
1000 FALSE);
1002 if (path)
1004 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path);
1005 current_state = FILTER_ELT (iter.user_data2)->visible;
1007 else
1008 current_state = FALSE;
1010 if (current_state == FALSE && requested_state == FALSE)
1011 /* no changes required */
1012 goto done;
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--;
1025 goto done;
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);
1041 goto done;
1044 /* only current == FALSE and requested == TRUE is left,
1045 * pull in the child
1047 g_return_if_fail (current_state == FALSE && requested_state == TRUE);
1049 /* make sure the new item has been pulled in */
1050 if (!filter->root)
1052 gint i;
1053 FilterLevel *root;
1055 egg_tree_model_filter_build_level (filter, NULL, NULL);
1057 root = FILTER_LEVEL (filter->root);
1059 if (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;
1067 if (!path)
1068 path = egg_real_tree_model_filter_convert_child_path_to_path (filter,
1069 c_path,
1070 TRUE,
1071 TRUE);
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++;
1086 /* update stamp */
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);
1092 done:
1093 if (path)
1094 gtk_tree_path_free (path);
1096 if (free_c_path)
1097 gtk_tree_path_free (c_path);
1100 static void
1101 egg_tree_model_filter_row_inserted (GtkTreeModel *c_model,
1102 GtkTreePath *c_path,
1103 GtkTreeIter *c_iter,
1104 gpointer data)
1106 EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
1107 GtkTreePath *path = NULL;
1108 GtkTreePath *real_path = NULL;
1109 GtkTreeIter iter;
1111 GtkTreeIter real_c_iter;
1113 FilterElt *elt;
1114 FilterLevel *level;
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);
1123 if (!c_path)
1125 c_path = gtk_tree_model_get_path (c_model, c_iter);
1126 free_c_path = TRUE;
1129 if (c_iter)
1130 real_c_iter = *c_iter;
1131 else
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))
1142 gint level;
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])++;
1154 if (!filter->root)
1156 egg_tree_model_filter_build_level (filter, NULL, NULL);
1157 /* that already put the inserted iter in the level */
1159 goto done_and_emit;
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);
1169 /* not our kiddo */
1170 if (!real_path)
1171 goto done;
1173 else
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)
1181 gint j;
1183 if (!level)
1184 /* we don't cover this signal */
1185 goto done;
1187 elt = bsearch_elt_with_offset (level->array,
1188 gtk_tree_path_get_indices (real_path)[i],
1189 &j);
1191 if (!elt)
1192 /* parent is probably being filtered out */
1193 goto done;
1195 if (!elt->children)
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),
1205 &tmpiter);
1207 if (tmppath)
1209 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data),
1210 tmppath, &tmpiter);
1211 gtk_tree_path_free (tmppath);
1214 /* not covering this signal */
1215 goto done;
1218 level = elt->children;
1219 parent_level = level;
1220 i++;
1224 if (!parent_level)
1225 goto done;
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))
1238 e->offset++;
1241 /* only insert when visible */
1242 if (egg_tree_model_filter_visible (filter, &real_c_iter))
1244 FilterElt felt;
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;
1251 felt.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)
1257 break;
1259 g_array_insert_val (level->array, i, felt);
1260 index = i;
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);
1270 if (e->children)
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))
1276 goto done;
1278 done_and_emit:
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,
1283 c_path,
1284 FALSE, TRUE);
1286 if (!path)
1287 goto done;
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);
1296 done:
1297 if (real_path)
1298 gtk_tree_path_free (real_path);
1300 if (free_c_path)
1301 gtk_tree_path_free (c_path);
1304 static void
1305 egg_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model,
1306 GtkTreePath *c_path,
1307 GtkTreeIter *c_iter,
1308 gpointer data)
1310 EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
1311 GtkTreePath *path;
1312 GtkTreeIter iter;
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))
1319 return;
1321 path = egg_real_tree_model_filter_convert_child_path_to_path (filter,
1322 c_path,
1323 FALSE,
1324 TRUE);
1325 if (!path)
1326 return;
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);
1334 static void
1335 egg_tree_model_filter_row_deleted (GtkTreeModel *c_model,
1336 GtkTreePath *c_path,
1337 gpointer data)
1339 EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
1340 GtkTreePath *path;
1341 GtkTreeIter iter;
1342 FilterElt *elt;
1343 FilterLevel *level;
1344 gint offset;
1345 gboolean emit_signal = TRUE;
1346 gint i;
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)))
1355 gint i;
1356 GtkTreePath *path;
1357 FilterLevel *level = FILTER_LEVEL (filter->root);
1359 if (!level)
1360 return;
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);
1378 return;
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))
1387 gint level;
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,
1400 c_path,
1401 FALSE,
1402 FALSE);
1404 if (!path)
1406 /* fixup the offsets */
1407 GtkTreePath *real_path;
1409 if (!filter->root)
1410 return;
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 */
1420 if (!real_path)
1421 return;
1423 else
1424 real_path = gtk_tree_path_copy (c_path);
1426 i = 0;
1427 if (gtk_tree_path_get_depth (real_path) - 1 >= 1)
1429 while (i < gtk_tree_path_get_depth (real_path) - 1)
1431 gint j;
1433 if (!level)
1435 /* we don't cover this */
1436 gtk_tree_path_free (real_path);
1437 return;
1440 elt = bsearch_elt_with_offset (level->array,
1441 gtk_tree_path_get_indices (real_path)[i],
1442 &j);
1445 if (!elt || !elt->children)
1447 /* parent is filtered out, so no level */
1448 gtk_tree_path_free (real_path);
1449 return;
1452 level = elt->children;
1453 i++;
1457 offset = gtk_tree_path_get_indices (real_path)[gtk_tree_path_get_depth (real_path) - 1];
1458 gtk_tree_path_free (real_path);
1460 if (!level)
1461 return;
1463 /* we need:
1464 * - the offset of the removed item
1465 * - the level
1467 for (i = 0; i < level->array->len; i++)
1469 elt = &g_array_index (level->array, FilterElt, i);
1470 if (elt->offset > offset)
1471 elt->offset--;
1472 if (elt->children)
1473 elt->children->parent_elt = elt;
1476 return;
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--;
1488 if (emit_signal)
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);
1496 return;
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,
1505 FALSE);
1508 if (level->array->len == 1)
1510 /* kill level */
1511 egg_tree_model_filter_free_level (filter, level);
1513 else
1515 FilterElt *tmp;
1516 gint i_t;
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);
1524 i_t = i = 1;
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)
1529 elt->offset--;
1530 if (elt->children)
1531 elt->children->parent_elt = elt;
1535 gtk_tree_path_free (path);
1538 static void
1539 egg_tree_model_filter_rows_reordered (GtkTreeModel *c_model,
1540 GtkTreePath *c_path,
1541 GtkTreeIter *c_iter,
1542 gint *new_order,
1543 gpointer data)
1545 FilterElt *elt;
1546 FilterLevel *level;
1547 EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
1549 GtkTreePath *path;
1550 GtkTreeIter iter;
1552 gint *tmp_array;
1553 gint i, j, elt_count;
1554 gint length;
1556 GArray *new_array;
1558 g_return_if_fail (new_order != NULL);
1560 if (c_path == NULL || gtk_tree_path_get_indices (c_path) == NULL)
1562 if (!filter->root)
1563 return;
1565 length = gtk_tree_model_iter_n_children (c_model, NULL);
1567 if (filter->virtual_root)
1569 gint new_pos = -1;
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])
1574 new_pos = i;
1576 if (new_pos < 0)
1577 return;
1579 gtk_tree_path_get_indices (filter->virtual_root)[0] = new_pos;
1580 return;
1583 path = gtk_tree_path_new ();
1584 level = FILTER_LEVEL (filter->root);
1586 else
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))
1595 gint new_pos = -1;
1596 gint length;
1597 gint level;
1598 GtkTreeIter real_c_iter;
1600 level = gtk_tree_path_get_depth (c_path);
1602 if (c_iter)
1603 real_c_iter = *c_iter;
1604 else
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])
1611 new_pos = i;
1613 if (new_pos < 0)
1614 return;
1616 gtk_tree_path_get_indices (filter->virtual_root)[level] = new_pos;
1617 return;
1620 path = egg_real_tree_model_filter_convert_child_path_to_path (filter,
1621 c_path,
1622 FALSE,
1623 FALSE);
1624 if (!path && filter->virtual_root &&
1625 gtk_tree_path_compare (c_path, filter->virtual_root))
1626 return;
1628 if (!path && !filter->virtual_root)
1629 return;
1631 if (!path)
1633 /* root level mode */
1634 if (!c_iter)
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);
1640 else
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);
1647 if (!elt->children)
1649 gtk_tree_path_free (path);
1650 return;
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)
1661 return;
1663 /* NOTE: we do not bail out here if level->array->len < 2 like
1664 * GtkTreeModelSort does. This because we do some special tricky
1665 * reordering.
1668 /* construct a new array */
1669 new_array = g_array_sized_new (FALSE, FALSE, sizeof (FilterElt),
1670 level->array->len);
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);
1682 old_offset = j;
1683 break;
1686 if (!e)
1687 continue;
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;
1692 elt_count++;
1695 g_array_free (level->array, TRUE);
1696 level->array = new_array;
1698 /* fix up stuff */
1699 for (i = 0; i < level->array->len; i++)
1701 FilterElt *e = &g_array_index (level->array, FilterElt, i);
1702 if (e->children)
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,
1709 tmp_array);
1710 else
1711 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, &iter,
1712 tmp_array);
1714 /* done */
1715 g_free (tmp_array);
1716 gtk_tree_path_free (path);
1719 /* TreeModelIface implementation */
1720 static guint
1721 egg_tree_model_filter_get_flags (GtkTreeModel *model)
1723 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0);
1725 return 0;
1728 static gint
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)
1737 return 0;
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);
1748 static GType
1749 egg_tree_model_filter_get_column_type (GtkTreeModel *model,
1750 gint index)
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);
1770 static gboolean
1771 egg_tree_model_filter_get_iter (GtkTreeModel *model,
1772 GtkTreeIter *iter,
1773 GtkTreePath *path)
1775 EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
1776 gint *indices;
1777 FilterLevel *level;
1778 gint depth, i;
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);
1790 if (!depth)
1792 iter->stamp = 0;
1793 return FALSE;
1796 for (i = 0; i < depth - 1; i++)
1798 if (!level || indices[i] >= level->array->len)
1800 return FALSE;
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,
1806 FilterElt,
1807 indices[i]));
1808 level = g_array_index (level->array, FilterElt, indices[i]).children;
1811 if (!level || indices[i] >= level->array->len)
1813 iter->stamp = 0;
1814 return FALSE;
1817 iter->stamp = filter->stamp;
1818 iter->user_data = level;
1819 iter->user_data2 = &g_array_index (level->array, FilterElt,
1820 indices[depth - 1]);
1822 return TRUE;
1825 static GtkTreePath *
1826 egg_tree_model_filter_get_path (GtkTreeModel *model,
1827 GtkTreeIter *iter)
1829 GtkTreePath *retval;
1830 FilterLevel *level;
1831 FilterElt *elt;
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;
1841 while (level)
1843 gtk_tree_path_prepend_index (retval,
1844 elt - FILTER_ELT (level->array->data));
1845 elt = level->parent_elt;
1846 level = level->parent_level;
1849 return retval;
1852 static void
1853 egg_tree_model_filter_get_value (GtkTreeModel *model,
1854 GtkTreeIter *iter,
1855 gint column,
1856 GValue *value)
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,
1871 iter,
1872 value,
1873 column,
1874 filter->modify_data);
1876 return;
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);
1884 static gboolean
1885 egg_tree_model_filter_iter_next (GtkTreeModel *model,
1886 GtkTreeIter *iter)
1888 FilterLevel *level;
1889 FilterElt *elt;
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)
1900 iter->stamp = 0;
1901 return FALSE;
1904 iter->user_data2 = elt + 1;
1906 return TRUE;
1909 static gboolean
1910 egg_tree_model_filter_iter_children (GtkTreeModel *model,
1911 GtkTreeIter *iter,
1912 GtkTreeIter *parent)
1914 EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
1915 FilterLevel *level;
1917 iter->stamp = 0;
1918 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE);
1919 g_return_val_if_fail (filter->child_model != NULL, FALSE);
1920 if (parent)
1921 g_return_val_if_fail (filter->stamp == parent->stamp, FALSE);
1923 if (!parent)
1925 if (!filter->root)
1926 egg_tree_model_filter_build_level (filter, NULL, NULL);
1927 if (!filter->root)
1928 return FALSE;
1930 level = filter->root;
1931 iter->stamp = filter->stamp;
1932 iter->user_data = level;
1933 iter->user_data2 = level->array->data;
1935 else
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)
1942 return FALSE;
1944 /* empty array? */
1945 if (FILTER_ELT (parent->user_data2)->children->array->len <= 0)
1946 return FALSE;
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;
1953 return TRUE;
1956 static gboolean
1957 egg_tree_model_filter_iter_has_child (GtkTreeModel *model,
1958 GtkTreeIter *iter)
1960 GtkTreeIter child_iter;
1961 EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
1962 FilterElt *elt;
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
1974 * out
1976 if (!elt->children
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),
1979 elt);
1981 /* FIXME: we should prolly count the visible nodes here, just like in
1982 * _iter_n_children.
1984 if (elt->children && elt->children->array->len > 0)
1985 return TRUE;
1987 return FALSE;
1990 static gint
1991 egg_tree_model_filter_iter_n_children (GtkTreeModel *model,
1992 GtkTreeIter *iter)
1994 GtkTreeIter child_iter;
1995 EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
1996 FilterElt *elt;
1998 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0);
1999 g_return_val_if_fail (filter->child_model != NULL, 0);
2000 if (iter)
2001 g_return_val_if_fail (filter->stamp == iter->stamp, 0);
2003 if (!iter)
2005 if (!filter->root)
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),
2019 elt);
2021 if (elt->children && elt->children->array->len)
2023 int i = 0;
2024 int count = 0;
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)
2030 count++;
2032 return count;
2035 return 0;
2038 static gboolean
2039 egg_tree_model_filter_iter_nth_child (GtkTreeModel *model,
2040 GtkTreeIter *iter,
2041 GtkTreeIter *parent,
2042 gint n)
2044 FilterLevel *level;
2045 GtkTreeIter children;
2047 g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE);
2048 if (parent)
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)
2054 iter->stamp = 0;
2055 return FALSE;
2058 level = children.user_data;
2059 if (n >= level->array->len)
2061 iter->stamp = 0;
2062 return FALSE;
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);
2069 return TRUE;
2072 static gboolean
2073 egg_tree_model_filter_iter_parent (GtkTreeModel *model,
2074 GtkTreeIter *iter,
2075 GtkTreeIter *child)
2077 FilterLevel *level;
2079 iter->stamp = 0;
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;
2092 return TRUE;
2095 return FALSE;
2098 static void
2099 egg_tree_model_filter_ref_node (GtkTreeModel *model,
2100 GtkTreeIter *iter)
2102 EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
2103 GtkTreeIter child_iter;
2104 FilterLevel *level;
2105 FilterElt *elt;
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;
2118 elt->ref_count++;
2119 level->ref_count++;
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 */
2128 if (parent_elt)
2129 parent_elt->zero_ref_count--;
2131 if (parent_level)
2133 parent_elt = parent_level->parent_elt;
2134 parent_level = parent_level->parent_level;
2137 while (parent_level);
2138 filter->zero_ref_count--;
2142 static void
2143 egg_tree_model_filter_unref_node (GtkTreeModel *model,
2144 GtkTreeIter *iter)
2146 egg_tree_model_filter_real_unref_node (model, iter, TRUE);
2149 static void
2150 egg_tree_model_filter_real_unref_node (GtkTreeModel *model,
2151 GtkTreeIter *iter,
2152 gboolean propagate_unref)
2154 EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
2155 FilterLevel *level;
2156 FilterElt *elt;
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);
2174 elt->ref_count--;
2175 level->ref_count--;
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 */
2194 static void
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 */
2214 if (filter->root)
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;
2225 if (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),
2231 filter);
2232 filter->inserted_id =
2233 g_signal_connect (child_model, "row_inserted",
2234 G_CALLBACK (egg_tree_model_filter_row_inserted),
2235 filter);
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),
2239 filter);
2240 filter->deleted_id =
2241 g_signal_connect (child_model, "row_deleted",
2242 G_CALLBACK (egg_tree_model_filter_row_deleted),
2243 filter);
2244 filter->reordered_id =
2245 g_signal_connect (child_model, "rows_reordered",
2246 G_CALLBACK (egg_tree_model_filter_rows_reordered),
2247 filter);
2249 filter->child_flags = gtk_tree_model_get_flags (child_model);
2250 filter->stamp = g_random_int ();
2254 static void
2255 egg_tree_model_filter_set_root (EggTreeModelFilter *filter,
2256 GtkTreePath *root)
2258 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter));
2260 if (!root)
2261 filter->virtual_root = NULL;
2262 else
2263 filter->virtual_root = gtk_tree_path_copy (root);
2266 /* public API */
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.
2278 GtkTreeModel *
2279 egg_tree_model_filter_new (GtkTreeModel *child_model,
2280 GtkTreePath *root)
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),
2289 child_model);
2290 egg_tree_model_filter_set_root (EGG_TREE_MODEL_FILTER (retval), root);
2292 return retval;
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.
2303 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
2320 * %FALSE otherwise.
2322 void
2323 egg_tree_model_filter_set_visible_func (EggTreeModelFilter *filter,
2324 EggTreeModelFilterVisibleFunc func,
2325 gpointer data,
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.
2359 void
2360 egg_tree_model_filter_set_modify_func (EggTreeModelFilter *filter,
2361 gint n_columns,
2362 GType *types,
2363 EggTreeModelFilterModifyFunc func,
2364 gpointer data,
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
2397 * if not.
2399 void
2400 egg_tree_model_filter_set_visible_column (EggTreeModelFilter *filter,
2401 gint column)
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;
2412 /* conversion */
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.
2423 void
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,
2441 child_path);
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.
2457 void
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;
2472 else
2474 GtkTreePath *path;
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;
2493 FilterLevel *level;
2494 FilterElt *tmp;
2495 gint i;
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);
2503 else
2504 real_path = egg_tree_model_filter_remove_root (child_path,
2505 filter->virtual_root);
2507 if (!real_path)
2508 return NULL;
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++)
2519 gint j;
2520 gboolean found_child = FALSE;
2522 if (!level)
2524 gtk_tree_path_free (real_path);
2525 gtk_tree_path_free (retval);
2526 return NULL;
2529 tmp = bsearch_elt_with_offset (level->array, child_indices[i], &j);
2530 if (tmp)
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;
2536 found_child = TRUE;
2539 if (!found_child && fetch_childs)
2541 tmp = egg_tree_model_filter_fetch_child (filter, level,
2542 child_indices[i],
2543 &j);
2545 /* didn't find the child, let's try to bring it back */
2546 if (!tmp || tmp->offset != child_indices[i])
2548 /* not there */
2549 gtk_tree_path_free (real_path);
2550 gtk_tree_path_free (retval);
2551 return NULL;
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;
2558 found_child = TRUE;
2560 else if (!found_child && !fetch_childs)
2562 /* no path */
2563 gtk_tree_path_free (real_path);
2564 gtk_tree_path_free (retval);
2565 return NULL;
2569 gtk_tree_path_free (real_path);
2570 return retval;
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.
2585 GtkTreePath *
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,
2591 child_path,
2592 TRUE,
2593 TRUE);
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.
2608 GtkTreePath *
2609 egg_tree_model_filter_convert_path_to_child_path (EggTreeModelFilter *filter,
2610 GtkTreePath *filter_path)
2612 gint *filter_indices;
2613 GtkTreePath *retval;
2614 FilterLevel *level;
2615 gint i;
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);
2621 /* convert path */
2622 retval = gtk_tree_path_new ();
2623 filter_indices = gtk_tree_path_get_indices (filter_path);
2624 if (!filter->root)
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);
2635 return NULL;
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);
2644 return NULL;
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;
2651 /* apply vroot */
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);
2661 return real_retval;
2664 return retval;
2667 static gboolean
2668 egg_tree_model_filter_refilter_helper (GtkTreeModel *model,
2669 GtkTreePath *path,
2670 GtkTreeIter *iter,
2671 gpointer data)
2673 /* evil, don't try this at home, but certainly speeds things up */
2674 egg_tree_model_filter_row_changed (model, path, iter, data);
2676 return FALSE;
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.
2686 void
2687 egg_tree_model_filter_refilter (EggTreeModelFilter *filter)
2689 g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter));
2691 /* S L O W */
2692 gtk_tree_model_foreach (filter->child_model,
2693 egg_tree_model_filter_refilter_helper,
2694 filter);
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.
2708 void
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));