1/* gtktreemodelfilter.c
2 * Copyright (C) 2000,2001 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
3 * Copyright (C) 2001-2003 Kristian Rietveld <kris@gtk.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "config.h"
20#include "gtktreemodelfilter.h"
21#include "gtkintl.h"
22#include "gtktreednd.h"
23#include "gtkprivate.h"
24#include <string.h>
25
26
27/**
28 * GtkTreeModelFilter:
29 *
30 * A `GtkTreeModel` which hides parts of an underlying tree model
31 *
32 * A `GtkTreeModelFilter` is a tree model which wraps another tree model,
33 * and can do the following things:
34 *
35 * - Filter specific rows, based on data from a “visible column”, a column
36 * storing booleans indicating whether the row should be filtered or not,
37 * or based on the return value of a “visible function”, which gets a
38 * model, iter and user_data and returns a boolean indicating whether the
39 * row should be filtered or not.
40 *
41 * - Modify the “appearance” of the model, using a modify function.
42 * This is extremely powerful and allows for just changing some
43 * values and also for creating a completely different model based
44 * on the given child model.
45 *
46 * - Set a different root node, also known as a “virtual root”. You can pass
47 * in a `GtkTreePath` indicating the root node for the filter at construction
48 * time.
49 *
50 * The basic API is similar to `GtkTreeModelSort`. For an example on its usage,
51 * see the section on `GtkTreeModelSort`.
52 *
53 * When using `GtkTreeModelFilter`, it is important to realize that
54 * `GtkTreeModelFilter` maintains an internal cache of all nodes which are
55 * visible in its clients. The cache is likely to be a subtree of the tree
56 * exposed by the child model. `GtkTreeModelFilter` will not cache the entire
57 * child model when unnecessary to not compromise the caching mechanism
58 * that is exposed by the reference counting scheme. If the child model
59 * implements reference counting, unnecessary signals may not be emitted
60 * because of reference counting rule 3, see the `GtkTreeModel`
61 * documentation. (Note that e.g. `GtkTreeStore` does not implement
62 * reference counting and will always emit all signals, even when
63 * the receiving node is not visible).
64 *
65 * Because of this, limitations for possible visible functions do apply.
66 * In general, visible functions should only use data or properties from
67 * the node for which the visibility state must be determined, its siblings
68 * or its parents. Usually, having a dependency on the state of any child
69 * node is not possible, unless references are taken on these explicitly.
70 * When no such reference exists, no signals may be received for these child
71 * nodes (see reference counting rule number 3 in the `GtkTreeModel` section).
72 *
73 * Determining the visibility state of a given node based on the state
74 * of its child nodes is a frequently occurring use case. Therefore,
75 * `GtkTreeModelFilter` explicitly supports this. For example, when a node
76 * does not have any children, you might not want the node to be visible.
77 * As soon as the first row is added to the node’s child level (or the
78 * last row removed), the node’s visibility should be updated.
79 *
80 * This introduces a dependency from the node on its child nodes. In order
81 * to accommodate this, `GtkTreeModelFilter` must make sure the necessary
82 * signals are received from the child model. This is achieved by building,
83 * for all nodes which are exposed as visible nodes to `GtkTreeModelFilter`'s
84 * clients, the child level (if any) and take a reference on the first node
85 * in this level. Furthermore, for every row-inserted, row-changed or
86 * row-deleted signal (also these which were not handled because the node
87 * was not cached), `GtkTreeModelFilter` will check if the visibility state
88 * of any parent node has changed.
89 *
90 * Beware, however, that this explicit support is limited to these two
91 * cases. For example, if you want a node to be visible only if two nodes
92 * in a child’s child level (2 levels deeper) are visible, you are on your
93 * own. In this case, either rely on `GtkTreeStore` to emit all signals
94 * because it does not implement reference counting, or for models that
95 * do implement reference counting, obtain references on these child levels
96 * yourself.
97 */
98
99/* Notes on this implementation of GtkTreeModelFilter
100 * ==================================================
101 *
102 * Warnings
103 * --------
104 *
105 * In this code there is a potential for confusion as to whether an iter,
106 * path or value refers to the GtkTreeModelFilter model, or to the child
107 * model that has been set. As a convention, variables referencing the
108 * child model will have a c_ prefix before them (ie. c_iter, c_value,
109 * c_path). In case the c_ prefixed names are already in use, an f_
110 * prefix is used. Conversion of iterators and paths between
111 * GtkTreeModelFilter and the child model is done through the various
112 * gtk_tree_model_filter_convert_* functions.
113 *
114 * Even though the GtkTreeModelSort and GtkTreeModelFilter have very
115 * similar data structures, many assumptions made in the GtkTreeModelSort
116 * code do *not* apply in the GtkTreeModelFilter case. Reference counting
117 * in particular is more complicated in GtkTreeModelFilter, because
118 * we explicitly support reliance on the state of a node’s children as
119 * outlined in the public API documentation. Because of these differences,
120 * you are strongly recommended to first read through these notes before
121 * making any modification to the code.
122 *
123 * Iterator format
124 * ---------------
125 *
126 * The iterator format of iterators handed out by GtkTreeModelFilter is
127 * as follows:
128 *
129 * iter->stamp = filter->priv->stamp
130 * iter->user_data = FilterLevel
131 * iter->user_data2 = FilterElt
132 *
133 * Internal data structure
134 * -----------------------
135 *
136 * Using FilterLevel and FilterElt, GtkTreeModelFilter maintains a “cache”
137 * of the mapping from GtkTreeModelFilter nodes to nodes in the child model.
138 * This is to avoid re-creating a level each time (which involves computing
139 * visibility for each node in that level) an operation is requested on
140 * GtkTreeModelFilter, such as get iter, get path and get value.
141 *
142 * A FilterElt corresponds to a single node. The FilterElt can either be
143 * visible or invisible in the model that is exposed to the clients of this
144 * GtkTreeModelFilter. The visibility state is stored in the “visible_siter”
145 * field, which is NULL when the node is not visible. The FilterLevel keeps
146 * a reference to the parent FilterElt and its FilterLevel (if any). The
147 * FilterElt can have a “children” pointer set, which points at a child
148 * level (a sub level).
149 *
150 * In a FilterLevel, two separate GSequences are maintained. One contains
151 * all nodes of this FilterLevel, regardless of the visibility state of
152 * the node. Another contains only visible nodes. A visible FilterElt
153 * is thus present in both the full and the visible GSequence. The
154 * GSequence allows for fast access, addition and removal of nodes.
155 *
156 * It is important to recognize the two different mappings that play
157 * a part in this code:
158 * I. The mapping from the client to this model. The order in which
159 * nodes are stored in the *visible* GSequence is the order in
160 * which the nodes are exposed to clients of the GtkTreeModelFilter.
161 * II. The mapping from this model to its child model. Each FilterElt
162 * contains an “offset” field which is the offset of the
163 * corresponding node in the child model.
164 *
165 * Throughout the code, two kinds of paths relative to the GtkTreeModelFilter
166 * (those generated from the sequence positions) are used. There are paths
167 * which take non-visible nodes into account (generated from the full
168 * sequences) and paths which don’t (generated from the visible sequences).
169 * Paths which have been generated from the full sequences should only be
170 * used internally and NEVER be passed along with a signal emisson.
171 *
172 * Reference counting
173 * ------------------
174 *
175 * GtkTreeModelFilter forwards all reference and unreference operations
176 * to the corresponding node in the child model. In addition,
177 * GtkTreeModelFilter will also add references of its own. The full reference
178 * count of each node (i.e. all forwarded references and these by the
179 * filter model) is maintained internally in the “ref_count” fields in
180 * FilterElt and FilterLevel. Because there is a need to determine whether
181 * a node should be visible for the client, the reference count of only
182 * the forwarded references is maintained as well, in the “ext_ref_count”
183 * fields.
184 *
185 * In a few cases, GtkTreeModelFilter takes additional references on
186 * nodes. The first case is that a reference is taken on the parent
187 * (if any) of each level. This happens in gtk_tree_model_filter_build_level()
188 * and the reference is released again in gtk_tree_model_filter_free_level().
189 * This ensures that for all references which are taken by the filter
190 * model, all parent nodes are referenced according to reference counting
191 * rule 1 in the GtkTreeModel documentation.
192 *
193 * A second case is required to support visible functions which depend on
194 * the state of a node’s children (see the public API documentation for
195 * GtkTreeModelFilter above). We build the child level of each node that
196 * could be visible in the client (i.e. the level has an ext_ref_count > 0;
197 * not the elt, because the elt might be invisible and thus unreferenced
198 * by the client). For each node that becomes visible, due to insertion or
199 * changes in visibility state, it is checked whether node has children, if
200 * so the child level is built.
201 *
202 * A reference is taken on the first node of each level so that the child
203 * model will emit all signals for this level, due to reference counting
204 * rule 3 in the GtkTreeModel documentation. If due to changes in the level,
205 * another node becomes the first node (e.g. due to insertion or reordering),
206 * this reference is transferred from the old to the new first node.
207 *
208 * When a level has an *external* reference count of zero (which means that
209 * none of the nodes in the level is referenced by the clients), the level
210 * has a “zero ref count” on all its parents. As soon as the level reaches
211 * an *external* reference count of zero, the zero ref count value is
212 * incremented by one for all parents of this level. Due to the additional
213 * references taken by the filter model, it is important to base the
214 * zero ref count on the external reference count instead of on the full
215 * reference count of the node.
216 *
217 * The zero ref count value aids in determining which portions of the
218 * cache are possibly unused and could be removed. If a FilterElt has
219 * a zero ref count of one, then its child level is unused. However, the
220 * child level can only be removed from the cache if the FilterElt's
221 * parent level has an external ref count of zero. (Not the parent elt,
222 * because an invisible parent elt with external ref count == 0 might still
223 * become visible because of a state change in its child level!). Otherwise,
224 * monitoring this level is necessary to possibly update the visibility state
225 * of the parent. This is an important difference from GtkTreeModelSort!
226 *
227 * Signals are only required for levels with an external ref count > 0.
228 * This due to reference counting rule 3, see the GtkTreeModel
229 * documentation. In the GtkTreeModelFilter we try hard to stick to this
230 * rule and not emit redundant signals (though redundant emissions of
231 * row-has-child-toggled could appear frequently; it does happen that
232 * we simply forward the signal emitted by e.g. GtkTreeStore but also
233 * emit our own copy).
234 */
235
236
237typedef struct _FilterElt FilterElt;
238typedef struct _FilterLevel FilterLevel;
239
240struct _FilterElt
241{
242 GtkTreeIter iter;
243 FilterLevel *children;
244 int offset;
245 int ref_count;
246 int ext_ref_count;
247 int zero_ref_count;
248 GSequenceIter *visible_siter; /* iter into visible_seq */
249};
250
251struct _FilterLevel
252{
253 GSequence *seq;
254 GSequence *visible_seq;
255 int ref_count;
256 int ext_ref_count;
257
258 FilterElt *parent_elt;
259 FilterLevel *parent_level;
260};
261
262
263struct _GtkTreeModelFilterPrivate
264{
265 GtkTreeModel *child_model;
266 gpointer root;
267 GtkTreePath *virtual_root;
268
269 int stamp;
270 guint child_flags;
271 int zero_ref_count;
272 int visible_column;
273
274 GtkTreeModelFilterVisibleFunc visible_func;
275 gpointer visible_data;
276 GDestroyNotify visible_destroy;
277
278 GType *modify_types;
279 GtkTreeModelFilterModifyFunc modify_func;
280 gpointer modify_data;
281 GDestroyNotify modify_destroy;
282 int modify_n_columns;
283
284 guint visible_method_set : 1;
285 guint modify_func_set : 1;
286
287 guint in_row_deleted : 1;
288 guint virtual_root_deleted : 1;
289
290 /* signal ids */
291 gulong changed_id;
292 gulong inserted_id;
293 gulong has_child_toggled_id;
294 gulong deleted_id;
295 gulong reordered_id;
296};
297
298/* properties */
299enum
300{
301 PROP_0,
302 PROP_CHILD_MODEL,
303 PROP_VIRTUAL_ROOT
304};
305
306/* Set this to 0 to disable caching of child iterators. This
307 * allows for more stringent testing. It is recommended to set this
308 * to one when refactoring this code and running the unit tests to
309 * catch more errors.
310 */
311#if 1
312# define GTK_TREE_MODEL_FILTER_CACHE_CHILD_ITERS(filter) \
313 (((GtkTreeModelFilter *)filter)->priv->child_flags & GTK_TREE_MODEL_ITERS_PERSIST)
314#else
315# define GTK_TREE_MODEL_FILTER_CACHE_CHILD_ITERS(filter) (FALSE)
316#endif
317
318/* Defining this constant enables more assertions, which will be
319 * helpful when debugging the code.
320 */
321#undef MODEL_FILTER_DEBUG
322
323#define FILTER_ELT(filter_elt) ((FilterElt *)filter_elt)
324#define FILTER_LEVEL(filter_level) ((FilterLevel *)filter_level)
325#define GET_ELT(siter) ((FilterElt*) (siter ? g_sequence_get (siter) : NULL))
326
327/* general code (object/interface init, properties, etc) */
328static void gtk_tree_model_filter_tree_model_init (GtkTreeModelIface *iface);
329static void gtk_tree_model_filter_drag_source_init (GtkTreeDragSourceIface *iface);
330static void gtk_tree_model_filter_finalize (GObject *object);
331static void gtk_tree_model_filter_set_property (GObject *object,
332 guint prop_id,
333 const GValue *value,
334 GParamSpec *pspec);
335static void gtk_tree_model_filter_get_property (GObject *object,
336 guint prop_id,
337 GValue *value,
338 GParamSpec *pspec);
339
340/* signal handlers */
341static void gtk_tree_model_filter_row_changed (GtkTreeModel *c_model,
342 GtkTreePath *c_path,
343 GtkTreeIter *c_iter,
344 gpointer data);
345static void gtk_tree_model_filter_row_inserted (GtkTreeModel *c_model,
346 GtkTreePath *c_path,
347 GtkTreeIter *c_iter,
348 gpointer data);
349static void gtk_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model,
350 GtkTreePath *c_path,
351 GtkTreeIter *c_iter,
352 gpointer data);
353static void gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
354 GtkTreePath *c_path,
355 gpointer data);
356static void gtk_tree_model_filter_rows_reordered (GtkTreeModel *c_model,
357 GtkTreePath *c_path,
358 GtkTreeIter *c_iter,
359 int *new_order,
360 gpointer data);
361
362/* GtkTreeModel interface */
363static GtkTreeModelFlags gtk_tree_model_filter_get_flags (GtkTreeModel *model);
364static int gtk_tree_model_filter_get_n_columns (GtkTreeModel *model);
365static GType gtk_tree_model_filter_get_column_type (GtkTreeModel *model,
366 int index);
367static gboolean gtk_tree_model_filter_get_iter_full (GtkTreeModel *model,
368 GtkTreeIter *iter,
369 GtkTreePath *path);
370static gboolean gtk_tree_model_filter_get_iter (GtkTreeModel *model,
371 GtkTreeIter *iter,
372 GtkTreePath *path);
373static GtkTreePath *gtk_tree_model_filter_get_path (GtkTreeModel *model,
374 GtkTreeIter *iter);
375static void gtk_tree_model_filter_get_value (GtkTreeModel *model,
376 GtkTreeIter *iter,
377 int column,
378 GValue *value);
379static gboolean gtk_tree_model_filter_iter_next (GtkTreeModel *model,
380 GtkTreeIter *iter);
381static gboolean gtk_tree_model_filter_iter_previous (GtkTreeModel *model,
382 GtkTreeIter *iter);
383static gboolean gtk_tree_model_filter_iter_children (GtkTreeModel *model,
384 GtkTreeIter *iter,
385 GtkTreeIter *parent);
386static gboolean gtk_tree_model_filter_iter_has_child (GtkTreeModel *model,
387 GtkTreeIter *iter);
388static int gtk_tree_model_filter_iter_n_children (GtkTreeModel *model,
389 GtkTreeIter *iter);
390static gboolean gtk_tree_model_filter_iter_nth_child (GtkTreeModel *model,
391 GtkTreeIter *iter,
392 GtkTreeIter *parent,
393 int n);
394static gboolean gtk_tree_model_filter_iter_parent (GtkTreeModel *model,
395 GtkTreeIter *iter,
396 GtkTreeIter *child);
397static void gtk_tree_model_filter_ref_node (GtkTreeModel *model,
398 GtkTreeIter *iter);
399static void gtk_tree_model_filter_unref_node (GtkTreeModel *model,
400 GtkTreeIter *iter);
401
402/* TreeDragSource interface */
403static gboolean gtk_tree_model_filter_row_draggable (GtkTreeDragSource *drag_source,
404 GtkTreePath *path);
405static GdkContentProvider *
406 gtk_tree_model_filter_drag_data_get (GtkTreeDragSource *drag_source,
407 GtkTreePath *path);
408static gboolean gtk_tree_model_filter_drag_data_delete (GtkTreeDragSource *drag_source,
409 GtkTreePath *path);
410
411/* private functions */
412static void gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
413 FilterLevel *parent_level,
414 FilterElt *parent_elt,
415 gboolean emit_inserted);
416
417static void gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
418 FilterLevel *filter_level,
419 gboolean unref_self,
420 gboolean unref_parent,
421 gboolean unref_external);
422
423static GtkTreePath *gtk_tree_model_filter_elt_get_path (FilterLevel *level,
424 FilterElt *elt,
425 GtkTreePath *root);
426
427static GtkTreePath *gtk_tree_model_filter_add_root (GtkTreePath *src,
428 GtkTreePath *root);
429static GtkTreePath *gtk_tree_model_filter_remove_root (GtkTreePath *src,
430 GtkTreePath *root);
431
432static void gtk_tree_model_filter_increment_stamp (GtkTreeModelFilter *filter);
433
434static void gtk_tree_model_filter_real_modify (GtkTreeModelFilter *self,
435 GtkTreeModel *child_model,
436 GtkTreeIter *iter,
437 GValue *value,
438 int column);
439static gboolean gtk_tree_model_filter_real_visible (GtkTreeModelFilter *filter,
440 GtkTreeModel *child_model,
441 GtkTreeIter *child_iter);
442static gboolean gtk_tree_model_filter_visible (GtkTreeModelFilter *filter,
443 GtkTreeIter *child_iter);
444static void gtk_tree_model_filter_clear_cache_helper (GtkTreeModelFilter *filter,
445 FilterLevel *level);
446
447static void gtk_tree_model_filter_real_ref_node (GtkTreeModel *model,
448 GtkTreeIter *iter,
449 gboolean external);
450static void gtk_tree_model_filter_real_unref_node (GtkTreeModel *model,
451 GtkTreeIter *iter,
452 gboolean external,
453 gboolean propagate_unref);
454
455static void gtk_tree_model_filter_set_model (GtkTreeModelFilter *filter,
456 GtkTreeModel *child_model);
457static void gtk_tree_model_filter_ref_path (GtkTreeModelFilter *filter,
458 GtkTreePath *path);
459static void gtk_tree_model_filter_unref_path (GtkTreeModelFilter *filter,
460 GtkTreePath *path,
461 int depth);
462static void gtk_tree_model_filter_set_root (GtkTreeModelFilter *filter,
463 GtkTreePath *root);
464
465static GtkTreePath *gtk_real_tree_model_filter_convert_child_path_to_path (GtkTreeModelFilter *filter,
466 GtkTreePath *child_path,
467 gboolean build_levels,
468 gboolean fetch_children);
469
470static gboolean gtk_tree_model_filter_elt_is_visible_in_target (FilterLevel *level,
471 FilterElt *elt);
472
473static FilterElt *gtk_tree_model_filter_insert_elt_in_level (GtkTreeModelFilter *filter,
474 GtkTreeIter *c_iter,
475 FilterLevel *level,
476 int offset,
477 int *index);
478static FilterElt *gtk_tree_model_filter_fetch_child (GtkTreeModelFilter *filter,
479 FilterLevel *level,
480 int offset,
481 int *index);
482static void gtk_tree_model_filter_remove_elt_from_level (GtkTreeModelFilter *filter,
483 FilterLevel *level,
484 FilterElt *elt);
485static void gtk_tree_model_filter_update_children (GtkTreeModelFilter *filter,
486 FilterLevel *level,
487 FilterElt *elt);
488static void gtk_tree_model_filter_emit_row_inserted_for_path (GtkTreeModelFilter *filter,
489 GtkTreeModel *c_model,
490 GtkTreePath *c_path,
491 GtkTreeIter *c_iter);
492
493
494G_DEFINE_TYPE_WITH_CODE (GtkTreeModelFilter, gtk_tree_model_filter, G_TYPE_OBJECT,
495 G_ADD_PRIVATE (GtkTreeModelFilter)
496 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
497 gtk_tree_model_filter_tree_model_init)
498 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
499 gtk_tree_model_filter_drag_source_init))
500
501static void
502gtk_tree_model_filter_init (GtkTreeModelFilter *filter)
503{
504 filter->priv = gtk_tree_model_filter_get_instance_private (self: filter);
505 filter->priv->visible_column = -1;
506 filter->priv->zero_ref_count = 0;
507 filter->priv->visible_method_set = FALSE;
508 filter->priv->modify_func_set = FALSE;
509 filter->priv->in_row_deleted = FALSE;
510 filter->priv->virtual_root_deleted = FALSE;
511}
512
513static void
514gtk_tree_model_filter_class_init (GtkTreeModelFilterClass *filter_class)
515{
516 GObjectClass *object_class;
517
518 object_class = (GObjectClass *) filter_class;
519
520 object_class->set_property = gtk_tree_model_filter_set_property;
521 object_class->get_property = gtk_tree_model_filter_get_property;
522
523 object_class->finalize = gtk_tree_model_filter_finalize;
524
525 filter_class->visible = gtk_tree_model_filter_real_visible;
526 filter_class->modify = gtk_tree_model_filter_real_modify;
527
528 g_object_class_install_property (oclass: object_class,
529 property_id: PROP_CHILD_MODEL,
530 pspec: g_param_spec_object (name: "child-model",
531 P_("The child model"),
532 P_("The model for the filtermodel to filter"),
533 GTK_TYPE_TREE_MODEL,
534 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
535
536 g_object_class_install_property (oclass: object_class,
537 property_id: PROP_VIRTUAL_ROOT,
538 pspec: g_param_spec_boxed (name: "virtual-root",
539 P_("The virtual root"),
540 P_("The virtual root (relative to the child model) for this filtermodel"),
541 GTK_TYPE_TREE_PATH,
542 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
543}
544
545static void
546gtk_tree_model_filter_tree_model_init (GtkTreeModelIface *iface)
547{
548 iface->get_flags = gtk_tree_model_filter_get_flags;
549 iface->get_n_columns = gtk_tree_model_filter_get_n_columns;
550 iface->get_column_type = gtk_tree_model_filter_get_column_type;
551 iface->get_iter = gtk_tree_model_filter_get_iter;
552 iface->get_path = gtk_tree_model_filter_get_path;
553 iface->get_value = gtk_tree_model_filter_get_value;
554 iface->iter_next = gtk_tree_model_filter_iter_next;
555 iface->iter_previous = gtk_tree_model_filter_iter_previous;
556 iface->iter_children = gtk_tree_model_filter_iter_children;
557 iface->iter_has_child = gtk_tree_model_filter_iter_has_child;
558 iface->iter_n_children = gtk_tree_model_filter_iter_n_children;
559 iface->iter_nth_child = gtk_tree_model_filter_iter_nth_child;
560 iface->iter_parent = gtk_tree_model_filter_iter_parent;
561 iface->ref_node = gtk_tree_model_filter_ref_node;
562 iface->unref_node = gtk_tree_model_filter_unref_node;
563}
564
565static void
566gtk_tree_model_filter_drag_source_init (GtkTreeDragSourceIface *iface)
567{
568 iface->row_draggable = gtk_tree_model_filter_row_draggable;
569 iface->drag_data_delete = gtk_tree_model_filter_drag_data_delete;
570 iface->drag_data_get = gtk_tree_model_filter_drag_data_get;
571}
572
573
574static void
575gtk_tree_model_filter_finalize (GObject *object)
576{
577 GtkTreeModelFilter *filter = (GtkTreeModelFilter *) object;
578
579 if (filter->priv->virtual_root && !filter->priv->virtual_root_deleted)
580 {
581 gtk_tree_model_filter_unref_path (filter, path: filter->priv->virtual_root,
582 depth: -1);
583 filter->priv->virtual_root_deleted = TRUE;
584 }
585
586 gtk_tree_model_filter_set_model (filter, NULL);
587
588 if (filter->priv->virtual_root)
589 gtk_tree_path_free (path: filter->priv->virtual_root);
590
591 if (filter->priv->root)
592 gtk_tree_model_filter_free_level (filter, filter_level: filter->priv->root, TRUE, TRUE, FALSE);
593
594 g_free (mem: filter->priv->modify_types);
595
596 if (filter->priv->modify_destroy)
597 filter->priv->modify_destroy (filter->priv->modify_data);
598
599 if (filter->priv->visible_destroy)
600 filter->priv->visible_destroy (filter->priv->visible_data);
601
602 /* must chain up */
603 G_OBJECT_CLASS (gtk_tree_model_filter_parent_class)->finalize (object);
604}
605
606static void
607gtk_tree_model_filter_set_property (GObject *object,
608 guint prop_id,
609 const GValue *value,
610 GParamSpec *pspec)
611{
612 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (object);
613
614 switch (prop_id)
615 {
616 case PROP_CHILD_MODEL:
617 gtk_tree_model_filter_set_model (filter, child_model: g_value_get_object (value));
618 break;
619 case PROP_VIRTUAL_ROOT:
620 gtk_tree_model_filter_set_root (filter, root: g_value_get_boxed (value));
621 break;
622 default:
623 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
624 break;
625 }
626}
627
628static void
629gtk_tree_model_filter_get_property (GObject *object,
630 guint prop_id,
631 GValue *value,
632 GParamSpec *pspec)
633{
634 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (object);
635
636 switch (prop_id)
637 {
638 case PROP_CHILD_MODEL:
639 g_value_set_object (value, v_object: filter->priv->child_model);
640 break;
641 case PROP_VIRTUAL_ROOT:
642 g_value_set_boxed (value, v_boxed: filter->priv->virtual_root);
643 break;
644 default:
645 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
646 break;
647 }
648}
649
650/* helpers */
651
652static FilterElt *
653filter_elt_new (void)
654{
655 return g_slice_new (FilterElt);
656}
657
658static void
659filter_elt_free (gpointer elt)
660{
661 g_slice_free (FilterElt, elt);
662}
663
664static int
665filter_elt_cmp (gconstpointer a,
666 gconstpointer b,
667 gpointer user_data)
668{
669 const FilterElt *elt_a = a;
670 const FilterElt *elt_b = b;
671
672 if (elt_a->offset > elt_b->offset)
673 return +1;
674 else if (elt_a->offset < elt_b->offset)
675 return -1;
676 else
677 return 0;
678}
679
680static FilterElt *
681lookup_elt_with_offset (GSequence *seq,
682 int offset,
683 GSequenceIter **ret_siter)
684{
685 GSequenceIter *siter;
686 FilterElt dummy;
687
688 dummy.offset = offset;
689 siter = g_sequence_lookup (seq, data: &dummy, cmp_func: filter_elt_cmp, NULL);
690
691 if (ret_siter)
692 *ret_siter = siter;
693
694 return GET_ELT (siter);
695}
696
697static void
698increase_offset_iter (gpointer data,
699 gpointer user_data)
700{
701 FilterElt *elt = data;
702 int offset = GPOINTER_TO_INT (user_data);
703
704 if (elt->offset >= offset)
705 elt->offset++;
706}
707
708static void
709decrease_offset_iter (gpointer data,
710 gpointer user_data)
711{
712 FilterElt *elt = data;
713 int offset = GPOINTER_TO_INT (user_data);
714
715 if (elt->offset > offset)
716 elt->offset--;
717}
718
719static void
720gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
721 FilterLevel *parent_level,
722 FilterElt *parent_elt,
723 gboolean emit_inserted)
724{
725 GtkTreeIter iter;
726 GtkTreeIter first_node;
727 GtkTreeIter root;
728 FilterLevel *new_level;
729 FilterLevel *tmp_level;
730 FilterElt *tmp_elt;
731 GtkTreeIter f_iter;
732 int length = 0;
733 int i;
734 gboolean empty = TRUE;
735
736 g_assert (filter->priv->child_model != NULL);
737
738 /* Avoid building a level that already exists */
739 if (parent_level)
740 g_assert (parent_elt->children == NULL);
741 else
742 g_assert (filter->priv->root == NULL);
743
744 if (filter->priv->in_row_deleted)
745 return;
746
747 if (!parent_level)
748 {
749 if (filter->priv->virtual_root)
750 {
751 if (gtk_tree_model_get_iter (tree_model: filter->priv->child_model, iter: &root, path: filter->priv->virtual_root) == FALSE)
752 return;
753 length = gtk_tree_model_iter_n_children (tree_model: filter->priv->child_model, iter: &root);
754
755 if (gtk_tree_model_iter_children (tree_model: filter->priv->child_model, iter: &iter, parent: &root) == FALSE)
756 return;
757 }
758 else
759 {
760 if (!gtk_tree_model_get_iter_first (tree_model: filter->priv->child_model, iter: &iter))
761 return;
762 length = gtk_tree_model_iter_n_children (tree_model: filter->priv->child_model, NULL);
763 }
764 }
765 else
766 {
767 GtkTreeIter parent_iter;
768 GtkTreeIter child_parent_iter;
769
770 parent_iter.stamp = filter->priv->stamp;
771 parent_iter.user_data = parent_level;
772 parent_iter.user_data2 = parent_elt;
773
774 gtk_tree_model_filter_convert_iter_to_child_iter (filter,
775 child_iter: &child_parent_iter,
776 filter_iter: &parent_iter);
777 if (gtk_tree_model_iter_children (tree_model: filter->priv->child_model, iter: &iter, parent: &child_parent_iter) == FALSE)
778 return;
779
780 /* stamp may have changed */
781 gtk_tree_model_filter_convert_iter_to_child_iter (filter,
782 child_iter: &child_parent_iter,
783 filter_iter: &parent_iter);
784 length = gtk_tree_model_iter_n_children (tree_model: filter->priv->child_model, iter: &child_parent_iter);
785
786 /* Take a reference on the parent */
787 gtk_tree_model_filter_real_ref_node (GTK_TREE_MODEL (filter),
788 iter: &parent_iter, FALSE);
789 }
790
791 g_return_if_fail (length > 0);
792
793 new_level = g_new (FilterLevel, 1);
794 new_level->seq = g_sequence_new (data_destroy: filter_elt_free);
795 new_level->visible_seq = g_sequence_new (NULL);
796 new_level->ref_count = 0;
797 new_level->ext_ref_count = 0;
798 new_level->parent_elt = parent_elt;
799 new_level->parent_level = parent_level;
800
801 if (parent_elt)
802 parent_elt->children = new_level;
803 else
804 filter->priv->root = new_level;
805
806 /* increase the count of zero ref_counts */
807 tmp_level = parent_level;
808 tmp_elt = parent_elt;
809
810 while (tmp_level)
811 {
812 tmp_elt->zero_ref_count++;
813
814 tmp_elt = tmp_level->parent_elt;
815 tmp_level = tmp_level->parent_level;
816 }
817 if (new_level != filter->priv->root)
818 filter->priv->zero_ref_count++;
819
820 i = 0;
821
822 first_node = iter;
823
824 do
825 {
826 if (gtk_tree_model_filter_visible (filter, child_iter: &iter))
827 {
828 FilterElt *filter_elt;
829
830 filter_elt = filter_elt_new ();
831 filter_elt->offset = i;
832 filter_elt->zero_ref_count = 0;
833 filter_elt->ref_count = 0;
834 filter_elt->ext_ref_count = 0;
835 filter_elt->children = NULL;
836 filter_elt->visible_siter = NULL;
837
838 if (GTK_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
839 filter_elt->iter = iter;
840
841 g_sequence_append (seq: new_level->seq, data: filter_elt);
842 filter_elt->visible_siter = g_sequence_append (seq: new_level->visible_seq, data: filter_elt);
843 empty = FALSE;
844
845 if (emit_inserted)
846 {
847 GtkTreePath *f_path;
848 GtkTreeIter children;
849
850 f_iter.stamp = filter->priv->stamp;
851 f_iter.user_data = new_level;
852 f_iter.user_data2 = filter_elt;
853
854 f_path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter),
855 iter: &f_iter);
856 gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter),
857 path: f_path, iter: &f_iter);
858 gtk_tree_path_free (path: f_path);
859
860 if (gtk_tree_model_iter_children (tree_model: filter->priv->child_model,
861 iter: &children, parent: &iter))
862 gtk_tree_model_filter_update_children (filter,
863 level: new_level,
864 FILTER_ELT (f_iter.user_data2));
865 }
866 }
867 i++;
868 }
869 while (gtk_tree_model_iter_next (tree_model: filter->priv->child_model, iter: &iter));
870
871 /* The level does not contain any visible nodes. However, changes in
872 * this level might affect the parent node, which can either be visible
873 * or invisible. Therefore, this level can only be removed again,
874 * if the parent level has an external reference count of zero. That is,
875 * if this level changes state, no signals are required in the parent
876 * level.
877 */
878 if (empty &&
879 (parent_level && parent_level->ext_ref_count == 0))
880 {
881 gtk_tree_model_filter_free_level (filter, filter_level: new_level, FALSE, TRUE, FALSE);
882 return;
883 }
884
885 /* If none of the nodes are visible, we will just pull in the
886 * first node of the level.
887 */
888 if (empty)
889 {
890 FilterElt *filter_elt;
891
892 filter_elt = filter_elt_new ();
893 filter_elt->offset = 0;
894 filter_elt->zero_ref_count = 0;
895 filter_elt->ref_count = 0;
896 filter_elt->ext_ref_count = 0;
897 filter_elt->children = NULL;
898 filter_elt->visible_siter = NULL;
899
900 if (GTK_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
901 filter_elt->iter = first_node;
902
903 g_sequence_append (seq: new_level->seq, data: filter_elt);
904 }
905
906 /* Keep a reference on the first node of this level. We need this
907 * to make sure that we get all signals for this level.
908 */
909 f_iter.stamp = filter->priv->stamp;
910 f_iter.user_data = new_level;
911 f_iter.user_data2 = g_sequence_get (iter: g_sequence_get_begin_iter (seq: new_level->seq));
912
913 gtk_tree_model_filter_real_ref_node (GTK_TREE_MODEL (filter), iter: &f_iter, FALSE);
914}
915
916static void
917gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
918 FilterLevel *filter_level,
919 gboolean unref_self,
920 gboolean unref_parent,
921 gboolean unref_external)
922{
923 GSequenceIter *siter;
924 GSequenceIter *end_siter;
925
926 g_assert (filter_level);
927
928 end_siter = g_sequence_get_end_iter (seq: filter_level->seq);
929 for (siter = g_sequence_get_begin_iter (seq: filter_level->seq);
930 siter != end_siter;
931 siter = g_sequence_iter_next (iter: siter))
932 {
933 FilterElt *elt = g_sequence_get (iter: siter);
934
935 if (elt->children)
936 {
937 /* If we recurse and unref_self == FALSE, then unref_parent
938 * must also be FALSE (otherwise a still unref a node in this
939 * level).
940 */
941 gtk_tree_model_filter_free_level (filter,
942 FILTER_LEVEL (elt->children),
943 unref_self,
944 unref_parent: unref_self == FALSE ? FALSE : unref_parent,
945 unref_external);
946 }
947
948 if (unref_external)
949 {
950 GtkTreeIter f_iter;
951
952 f_iter.stamp = filter->priv->stamp;
953 f_iter.user_data = filter_level;
954 f_iter.user_data2 = elt;
955
956 while (elt->ext_ref_count > 0)
957 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
958 iter: &f_iter,
959 TRUE, propagate_unref: unref_self);
960 }
961 }
962
963 /* Release the reference on the first item.
964 */
965 if (unref_self)
966 {
967 GtkTreeIter f_iter;
968
969 f_iter.stamp = filter->priv->stamp;
970 f_iter.user_data = filter_level;
971 f_iter.user_data2 = g_sequence_get (iter: g_sequence_get_begin_iter (seq: filter_level->seq));
972
973 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
974 iter: &f_iter, FALSE, TRUE);
975 }
976
977 if (filter_level->ext_ref_count == 0)
978 {
979 FilterLevel *parent_level = filter_level->parent_level;
980 FilterElt *parent_elt = filter_level->parent_elt;
981
982 while (parent_level)
983 {
984 parent_elt->zero_ref_count--;
985
986 parent_elt = parent_level->parent_elt;
987 parent_level = parent_level->parent_level;
988 }
989
990 if (filter_level != filter->priv->root)
991 filter->priv->zero_ref_count--;
992 }
993
994#ifdef MODEL_FILTER_DEBUG
995 if (filter_level == filter->priv->root)
996 g_assert (filter->priv->zero_ref_count == 0);
997#endif
998
999 if (filter_level->parent_elt)
1000 {
1001 /* Release reference on parent */
1002 GtkTreeIter parent_iter;
1003
1004 parent_iter.stamp = filter->priv->stamp;
1005 parent_iter.user_data = filter_level->parent_level;
1006 parent_iter.user_data2 = filter_level->parent_elt;
1007
1008 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
1009 iter: &parent_iter, FALSE, propagate_unref: unref_parent);
1010
1011 filter_level->parent_elt->children = NULL;
1012 }
1013 else
1014 filter->priv->root = NULL;
1015
1016 g_sequence_free (seq: filter_level->seq);
1017 g_sequence_free (seq: filter_level->visible_seq);
1018 g_free (mem: filter_level);
1019}
1020
1021/* prune_level() is like free_level(), however instead of being fully
1022 * freed, the level is pruned to a level with only the first node used
1023 * for monitoring. For now it is only being called from
1024 * gtk_tree_model_filter_remove_elt_from_level(), which is the reason
1025 * this function is lacking a “gboolean unref” argument.
1026 */
1027static void
1028gtk_tree_model_filter_prune_level (GtkTreeModelFilter *filter,
1029 FilterLevel *level)
1030{
1031 GSequenceIter *siter;
1032 GSequenceIter *end_siter;
1033 FilterElt *elt;
1034 GtkTreeIter f_iter;
1035
1036 /* This function is called when the parent of level became invisible.
1037 * All external ref counts of the children need to be dropped.
1038 * All children except the first one can be removed.
1039 */
1040
1041 /* Any child levels can be freed */
1042 end_siter = g_sequence_get_end_iter (seq: level->seq);
1043 for (siter = g_sequence_get_begin_iter (seq: level->seq);
1044 siter != end_siter;
1045 siter = g_sequence_iter_next (iter: siter))
1046 {
1047 elt = g_sequence_get (iter: siter);
1048
1049 if (elt->children)
1050 gtk_tree_model_filter_free_level (filter,
1051 FILTER_LEVEL (elt->children),
1052 TRUE, TRUE, TRUE);
1053 }
1054
1055 /* For the first item, only drop the external references */
1056 elt = g_sequence_get (iter: g_sequence_get_begin_iter (seq: level->seq));
1057
1058 f_iter.stamp = filter->priv->stamp;
1059 f_iter.user_data = level;
1060 f_iter.user_data2 = elt;
1061
1062 while (elt->ext_ref_count > 0)
1063 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
1064 iter: &f_iter, TRUE, TRUE);
1065
1066 if (elt->visible_siter)
1067 {
1068 g_sequence_remove (iter: elt->visible_siter);
1069 elt->visible_siter = NULL;
1070 }
1071
1072 /* Remove the other elts */
1073 end_siter = g_sequence_get_end_iter (seq: level->seq);
1074 siter = g_sequence_get_begin_iter (seq: level->seq);
1075 siter = g_sequence_iter_next (iter: siter);
1076 for (; siter != end_siter; siter = g_sequence_iter_next (iter: siter))
1077 {
1078 elt = g_sequence_get (iter: siter);
1079
1080 f_iter.stamp = filter->priv->stamp;
1081 f_iter.user_data = level;
1082 f_iter.user_data2 = elt;
1083
1084 while (elt->ext_ref_count > 0)
1085 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
1086 iter: &f_iter, TRUE, TRUE);
1087 /* In this case, we do remove reference counts we've added ourselves,
1088 * since the node will be removed from the data structures.
1089 */
1090 while (elt->ref_count > 0)
1091 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
1092 iter: &f_iter, FALSE, TRUE);
1093
1094 if (elt->visible_siter)
1095 {
1096 g_sequence_remove (iter: elt->visible_siter);
1097 elt->visible_siter = NULL;
1098 }
1099 }
1100
1101 /* Remove [begin + 1, end] */
1102 siter = g_sequence_get_begin_iter (seq: level->seq);
1103 siter = g_sequence_iter_next (iter: siter);
1104
1105 g_sequence_remove_range (begin: siter, end: end_siter);
1106
1107 /* The level must have reached an ext ref count of zero by now, though
1108 * we only assert on this in debugging mode.
1109 */
1110#ifdef MODEL_FILTER_DEBUG
1111 g_assert (level->ext_ref_count == 0);
1112#endif
1113}
1114
1115static void
1116gtk_tree_model_filter_level_transfer_first_ref (GtkTreeModelFilter *filter,
1117 FilterLevel *level,
1118 GSequenceIter *from_iter,
1119 GSequenceIter *to_iter)
1120{
1121 GtkTreeIter f_iter;
1122
1123 f_iter.stamp = filter->priv->stamp;
1124 f_iter.user_data = level;
1125 f_iter.user_data2 = g_sequence_get (iter: to_iter);
1126
1127 gtk_tree_model_filter_real_ref_node (GTK_TREE_MODEL (filter),
1128 iter: &f_iter, FALSE);
1129
1130 f_iter.stamp = filter->priv->stamp;
1131 f_iter.user_data = level;
1132 f_iter.user_data2 = g_sequence_get (iter: from_iter);
1133
1134 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
1135 iter: &f_iter, FALSE, TRUE);
1136}
1137
1138static void
1139gtk_tree_model_filter_level_transfer_first_ref_with_index (GtkTreeModelFilter *filter,
1140 FilterLevel *level,
1141 int from_index,
1142 int to_index)
1143{
1144 gtk_tree_model_filter_level_transfer_first_ref (filter, level,
1145 from_iter: g_sequence_get_iter_at_pos (seq: level->seq, pos: from_index),
1146 to_iter: g_sequence_get_iter_at_pos (seq: level->seq, pos: to_index));
1147}
1148
1149/* Creates paths suitable for accessing the child model. */
1150static GtkTreePath *
1151gtk_tree_model_filter_elt_get_path (FilterLevel *level,
1152 FilterElt *elt,
1153 GtkTreePath *root)
1154{
1155 FilterLevel *walker = level;
1156 FilterElt *walker2 = elt;
1157 GtkTreePath *path;
1158 GtkTreePath *real_path;
1159
1160 g_return_val_if_fail (level != NULL, NULL);
1161 g_return_val_if_fail (elt != NULL, NULL);
1162
1163 path = gtk_tree_path_new ();
1164
1165 while (walker)
1166 {
1167 gtk_tree_path_prepend_index (path, index_: walker2->offset);
1168
1169 walker2 = walker->parent_elt;
1170 walker = walker->parent_level;
1171 }
1172
1173 if (root)
1174 {
1175 real_path = gtk_tree_model_filter_add_root (src: path, root);
1176 gtk_tree_path_free (path);
1177 return real_path;
1178 }
1179
1180 return path;
1181}
1182
1183static GtkTreePath *
1184gtk_tree_model_filter_add_root (GtkTreePath *src,
1185 GtkTreePath *root)
1186{
1187 GtkTreePath *retval;
1188 int i;
1189
1190 retval = gtk_tree_path_copy (path: root);
1191
1192 for (i = 0; i < gtk_tree_path_get_depth (path: src); i++)
1193 gtk_tree_path_append_index (path: retval, index_: gtk_tree_path_get_indices (path: src)[i]);
1194
1195 return retval;
1196}
1197
1198static GtkTreePath *
1199gtk_tree_model_filter_remove_root (GtkTreePath *src,
1200 GtkTreePath *root)
1201{
1202 GtkTreePath *retval;
1203 int i;
1204 int depth;
1205 int *indices;
1206
1207 if (gtk_tree_path_get_depth (path: src) <= gtk_tree_path_get_depth (path: root))
1208 return NULL;
1209
1210 depth = gtk_tree_path_get_depth (path: src);
1211 indices = gtk_tree_path_get_indices (path: src);
1212
1213 for (i = 0; i < gtk_tree_path_get_depth (path: root); i++)
1214 if (indices[i] != gtk_tree_path_get_indices (path: root)[i])
1215 return NULL;
1216
1217 retval = gtk_tree_path_new ();
1218
1219 for (; i < depth; i++)
1220 gtk_tree_path_append_index (path: retval, index_: indices[i]);
1221
1222 return retval;
1223}
1224
1225static void
1226gtk_tree_model_filter_increment_stamp (GtkTreeModelFilter *filter)
1227{
1228 do
1229 {
1230 filter->priv->stamp++;
1231 }
1232 while (filter->priv->stamp == 0);
1233
1234 gtk_tree_model_filter_clear_cache (filter);
1235}
1236
1237static gboolean
1238gtk_tree_model_filter_real_visible (GtkTreeModelFilter *filter,
1239 GtkTreeModel *child_model,
1240 GtkTreeIter *child_iter)
1241{
1242 if (filter->priv->visible_func)
1243 {
1244 return filter->priv->visible_func (child_model,
1245 child_iter,
1246 filter->priv->visible_data)
1247 ? TRUE : FALSE;
1248 }
1249 else if (filter->priv->visible_column >= 0)
1250 {
1251 GValue val = G_VALUE_INIT;
1252
1253 gtk_tree_model_get_value (tree_model: child_model, iter: child_iter,
1254 column: filter->priv->visible_column, value: &val);
1255
1256 if (g_value_get_boolean (value: &val))
1257 {
1258 g_value_unset (value: &val);
1259 return TRUE;
1260 }
1261
1262 g_value_unset (value: &val);
1263 return FALSE;
1264 }
1265
1266 /* no visible function set, so always visible */
1267 return TRUE;
1268}
1269
1270static gboolean
1271gtk_tree_model_filter_visible (GtkTreeModelFilter *self,
1272 GtkTreeIter *child_iter)
1273{
1274 return GTK_TREE_MODEL_FILTER_GET_CLASS (self)->visible (self,
1275 self->priv->child_model, child_iter);
1276}
1277
1278static void
1279gtk_tree_model_filter_clear_cache_helper_iter (gpointer data,
1280 gpointer user_data)
1281{
1282 GtkTreeModelFilter *filter = user_data;
1283 FilterElt *elt = data;
1284
1285#ifdef MODEL_FILTER_DEBUG
1286 g_assert (elt->zero_ref_count >= 0);
1287#endif
1288
1289 if (elt->zero_ref_count > 0)
1290 gtk_tree_model_filter_clear_cache_helper (filter, level: elt->children);
1291}
1292
1293static void
1294gtk_tree_model_filter_clear_cache_helper (GtkTreeModelFilter *filter,
1295 FilterLevel *level)
1296{
1297 g_assert (level);
1298
1299 g_sequence_foreach (seq: level->seq, func: gtk_tree_model_filter_clear_cache_helper_iter, user_data: filter);
1300
1301 /* If the level's ext_ref_count is zero, it means the level is not visible
1302 * and can be removed. But, since we support monitoring a child level
1303 * of a parent for changes (these might affect the parent), we will only
1304 * free the level if the parent level also has an external ref
1305 * count of zero. In that case, changes concerning our parent are
1306 * not requested.
1307 *
1308 * The root level is always visible, so an exception holds for levels
1309 * with the root level as parent level: these have to remain cached.
1310 */
1311 if (level->ext_ref_count == 0 && level != filter->priv->root &&
1312 level->parent_level && level->parent_level != filter->priv->root &&
1313 level->parent_level->ext_ref_count == 0)
1314 {
1315 gtk_tree_model_filter_free_level (filter, filter_level: level, TRUE, TRUE, FALSE);
1316 return;
1317 }
1318}
1319
1320static gboolean
1321gtk_tree_model_filter_elt_is_visible_in_target (FilterLevel *level,
1322 FilterElt *elt)
1323{
1324 if (!elt->visible_siter)
1325 return FALSE;
1326
1327 if (!level->parent_elt)
1328 return TRUE;
1329
1330 do
1331 {
1332 elt = level->parent_elt;
1333 level = level->parent_level;
1334
1335 if (elt && !elt->visible_siter)
1336 return FALSE;
1337 }
1338 while (level);
1339
1340 return TRUE;
1341}
1342
1343/* If a change has occurred in path (inserted, changed or deleted),
1344 * then this function is used to check all its ancestors. An ancestor
1345 * could have changed state as a result and this needs to be propagated
1346 * to the objects monitoring the filter model.
1347 */
1348static void
1349gtk_tree_model_filter_check_ancestors (GtkTreeModelFilter *filter,
1350 GtkTreePath *path)
1351{
1352 int i = 0;
1353 int *indices = gtk_tree_path_get_indices (path);
1354 FilterElt *elt;
1355 FilterLevel *level;
1356 GtkTreeIter c_iter, tmp_iter, *root_iter;
1357
1358 level = FILTER_LEVEL (filter->priv->root);
1359
1360 if (!level)
1361 return;
1362
1363 root_iter = NULL;
1364 if (filter->priv->virtual_root &&
1365 gtk_tree_model_get_iter (tree_model: filter->priv->child_model, iter: &tmp_iter,
1366 path: filter->priv->virtual_root))
1367 root_iter = &tmp_iter;
1368 gtk_tree_model_iter_nth_child (tree_model: filter->priv->child_model, iter: &c_iter,
1369 parent: root_iter,
1370 n: indices[i]);
1371
1372 while (i < gtk_tree_path_get_depth (path) - 1)
1373 {
1374 gboolean requested_state;
1375
1376 elt = lookup_elt_with_offset (seq: level->seq,
1377 offset: gtk_tree_path_get_indices (path)[i], NULL);
1378
1379 requested_state = gtk_tree_model_filter_visible (self: filter, child_iter: &c_iter);
1380
1381 if (!elt)
1382 {
1383 int index;
1384 GtkTreePath *c_path;
1385
1386 if (requested_state == FALSE)
1387 return;
1388
1389 /* The elt does not exist in this level (so it is not
1390 * visible), but should now be visible. We emit the
1391 * row-inserted and row-has-child-toggled signals.
1392 */
1393 elt = gtk_tree_model_filter_insert_elt_in_level (filter,
1394 c_iter: &c_iter,
1395 level,
1396 offset: indices[i],
1397 index: &index);
1398
1399 /* insert_elt_in_level defaults to FALSE */
1400 elt->visible_siter = g_sequence_insert_sorted (seq: level->visible_seq,
1401 data: elt,
1402 cmp_func: filter_elt_cmp, NULL);
1403
1404 c_path = gtk_tree_model_get_path (tree_model: filter->priv->child_model,
1405 iter: &c_iter);
1406
1407 gtk_tree_model_filter_emit_row_inserted_for_path (filter,
1408 c_model: filter->priv->child_model,
1409 c_path,
1410 c_iter: &c_iter);
1411
1412 gtk_tree_path_free (path: c_path);
1413
1414 /* We can immediately return, because this node was not visible
1415 * before and its children will be checked for in response to
1416 * the emitted row-has-child-toggled signal.
1417 */
1418 return;
1419 }
1420 else if (elt->visible_siter)
1421 {
1422 if (!requested_state)
1423 {
1424 /* A node has turned invisible. Remove it from the level
1425 * and emit row-deleted. Since this node is being
1426 * deleted. it makes no sense to look further up the
1427 * chain.
1428 */
1429 gtk_tree_model_filter_remove_elt_from_level (filter,
1430 level, elt);
1431 return;
1432 }
1433
1434 /* Otherwise continue up the chain */
1435 }
1436 else if (!elt->visible_siter)
1437 {
1438 if (requested_state)
1439 {
1440 /* A node is already in the cache, but invisible. This
1441 * is usually a node on which a reference is kept by
1442 * the filter model, or a node fetched on the filter's
1443 * request, and thus not shown. Therefore, we will
1444 * not emit row-inserted for this node. Instead,
1445 * we signal to its parent that a change has occurred.
1446 *
1447 * Exception: root level, in this case, we must emit
1448 * row-inserted.
1449 */
1450 if (level->parent_level)
1451 {
1452 GtkTreeIter f_iter;
1453 GtkTreePath *f_path;
1454
1455 elt->visible_siter = g_sequence_insert_sorted (seq: level->visible_seq, data: elt,
1456 cmp_func: filter_elt_cmp, NULL);
1457
1458 f_iter.stamp = filter->priv->stamp;
1459 f_iter.user_data = level->parent_level;
1460 f_iter.user_data2 = level->parent_elt;
1461
1462 f_path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter),
1463 iter: &f_iter);
1464 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
1465 path: f_path, iter: &f_iter);
1466 gtk_tree_path_free (path: f_path);
1467 }
1468 else
1469 {
1470 GtkTreePath *c_path;
1471
1472 elt->visible_siter = g_sequence_insert_sorted (seq: level->visible_seq, data: elt,
1473 cmp_func: filter_elt_cmp, NULL);
1474
1475 c_path = gtk_tree_model_get_path (tree_model: filter->priv->child_model,
1476 iter: &c_iter);
1477
1478 gtk_tree_model_filter_emit_row_inserted_for_path (filter,
1479 c_model: filter->priv->child_model,
1480 c_path,
1481 c_iter: &c_iter);
1482
1483 gtk_tree_path_free (path: c_path);
1484 }
1485
1486 /* We can immediately return, because this node was not visible
1487 * before and the parent will check its children, including
1488 * this node, in response to the emitted row-has-child-toggled
1489 * signal.
1490 */
1491 return;
1492 }
1493
1494 /* Not visible, so no need to continue. */
1495 return;
1496 }
1497
1498 if (!elt->children)
1499 {
1500 /* If an elt does not have children, these are not visible.
1501 * Therefore, any signals emitted for these children will
1502 * be ignored, so we do not have to emit them.
1503 */
1504 return;
1505 }
1506
1507 level = elt->children;
1508 i++;
1509
1510 tmp_iter = c_iter;
1511 gtk_tree_model_iter_nth_child (tree_model: filter->priv->child_model, iter: &c_iter,
1512 parent: &tmp_iter, n: indices[i]);
1513 }
1514}
1515
1516static FilterElt *
1517gtk_tree_model_filter_insert_elt_in_level (GtkTreeModelFilter *filter,
1518 GtkTreeIter *c_iter,
1519 FilterLevel *level,
1520 int offset,
1521 int *index)
1522{
1523 FilterElt *elt;
1524 GSequenceIter *siter;
1525
1526 elt = filter_elt_new ();
1527
1528 if (GTK_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
1529 elt->iter = *c_iter;
1530
1531 elt->offset = offset;
1532 elt->zero_ref_count = 0;
1533 elt->ref_count = 0;
1534 elt->ext_ref_count = 0;
1535 elt->children = NULL;
1536
1537 /* Because we don't emit row_inserted, the node is invisible and thus
1538 * not inserted in visible_seq
1539 */
1540 elt->visible_siter = NULL;
1541
1542 siter = g_sequence_insert_sorted (seq: level->seq, data: elt, cmp_func: filter_elt_cmp, NULL);
1543 *index = g_sequence_iter_get_position (iter: siter);
1544
1545 /* If the insert location is zero, we need to move our reference
1546 * on the old first node to the new first node.
1547 */
1548 if (*index == 0)
1549 gtk_tree_model_filter_level_transfer_first_ref_with_index (filter, level,
1550 from_index: 1, to_index: 0);
1551
1552 return elt;
1553}
1554
1555static FilterElt *
1556gtk_tree_model_filter_fetch_child (GtkTreeModelFilter *filter,
1557 FilterLevel *level,
1558 int offset,
1559 int *index)
1560{
1561 int len;
1562 GtkTreePath *c_path = NULL;
1563 GtkTreeIter c_iter;
1564 GtkTreePath *c_parent_path = NULL;
1565 GtkTreeIter c_parent_iter;
1566
1567 /* check if child exists and is visible */
1568 if (level->parent_elt)
1569 {
1570 c_parent_path =
1571 gtk_tree_model_filter_elt_get_path (level: level->parent_level,
1572 elt: level->parent_elt,
1573 root: filter->priv->virtual_root);
1574 if (!c_parent_path)
1575 return NULL;
1576 }
1577 else
1578 {
1579 if (filter->priv->virtual_root)
1580 c_parent_path = gtk_tree_path_copy (path: filter->priv->virtual_root);
1581 else
1582 c_parent_path = NULL;
1583 }
1584
1585 if (c_parent_path)
1586 {
1587 gtk_tree_model_get_iter (tree_model: filter->priv->child_model,
1588 iter: &c_parent_iter,
1589 path: c_parent_path);
1590 len = gtk_tree_model_iter_n_children (tree_model: filter->priv->child_model,
1591 iter: &c_parent_iter);
1592
1593 c_path = gtk_tree_path_copy (path: c_parent_path);
1594 gtk_tree_path_free (path: c_parent_path);
1595 }
1596 else
1597 {
1598 len = gtk_tree_model_iter_n_children (tree_model: filter->priv->child_model, NULL);
1599 c_path = gtk_tree_path_new ();
1600 }
1601
1602 gtk_tree_path_append_index (path: c_path, index_: offset);
1603 gtk_tree_model_get_iter (tree_model: filter->priv->child_model, iter: &c_iter, path: c_path);
1604 gtk_tree_path_free (path: c_path);
1605
1606 if (offset >= len || !gtk_tree_model_filter_visible (self: filter, child_iter: &c_iter))
1607 return NULL;
1608
1609 return gtk_tree_model_filter_insert_elt_in_level (filter, c_iter: &c_iter,
1610 level, offset,
1611 index);
1612}
1613
1614/* Note that this function is never called from the row-deleted handler.
1615 * This means that this function is only used for removing elements
1616 * which are still present in the child model. As a result, we must
1617 * take care to properly release the references the filter model has
1618 * on the child model nodes.
1619 */
1620static void
1621gtk_tree_model_filter_remove_elt_from_level (GtkTreeModelFilter *filter,
1622 FilterLevel *level,
1623 FilterElt *elt)
1624{
1625 FilterElt *parent;
1626 FilterLevel *parent_level;
1627 int length, orig_level_ext_ref_count;
1628 GtkTreeIter iter;
1629 GtkTreePath *path = NULL;
1630
1631 gboolean emit_child_toggled = FALSE;
1632
1633 /* We need to know about the level's ext ref count before removal
1634 * of this node.
1635 */
1636 orig_level_ext_ref_count = level->ext_ref_count;
1637
1638 iter.stamp = filter->priv->stamp;
1639 iter.user_data = level;
1640 iter.user_data2 = elt;
1641
1642 parent = level->parent_elt;
1643 parent_level = level->parent_level;
1644
1645 if (!parent || orig_level_ext_ref_count > 0)
1646 path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter: &iter);
1647 else
1648 /* If the level is not visible, the parent is potentially invisible
1649 * too. Either way, as no signal will be emitted, there is no use
1650 * for a path.
1651 */
1652 path = NULL;
1653
1654 length = g_sequence_get_length (seq: level->seq);
1655
1656 /* first register the node to be invisible */
1657 g_sequence_remove (iter: elt->visible_siter);
1658 elt->visible_siter = NULL;
1659
1660 /*
1661 * If level != root level and the number of visible nodes is 0 (ie. this
1662 * is the last node to be removed from the level), emit
1663 * row-has-child-toggled.
1664 */
1665
1666 if (level != filter->priv->root
1667 && g_sequence_get_length (seq: level->visible_seq) == 0
1668 && parent
1669 && parent->visible_siter)
1670 emit_child_toggled = TRUE;
1671
1672 /* Distinguish:
1673 * - length > 1: in this case, the node is removed from the level
1674 * and row-deleted is emitted.
1675 * - length == 1: in this case, we need to decide whether to keep
1676 * the level or to free it.
1677 */
1678 if (length > 1)
1679 {
1680 GSequenceIter *siter;
1681
1682 /* We emit row-deleted, and remove the node from the cache.
1683 * If it has any children, these will be removed here as well.
1684 */
1685
1686 /* FIXME: I am not 100% sure it is always save to fully free the
1687 * level here. Perhaps the state of the parent level, etc. has to
1688 * be checked to make the right decision, like is done below for
1689 * the case length == 1.
1690 */
1691 if (elt->children)
1692 gtk_tree_model_filter_free_level (filter, filter_level: elt->children, TRUE, TRUE, TRUE);
1693
1694 /* If the first node is being removed, transfer, the reference */
1695 if (elt == g_sequence_get (iter: g_sequence_get_begin_iter (seq: level->seq)))
1696 {
1697 gtk_tree_model_filter_level_transfer_first_ref_with_index (filter, level,
1698 from_index: 0, to_index: 1);
1699 }
1700
1701 while (elt->ext_ref_count > 0)
1702 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
1703 iter: &iter, TRUE, TRUE);
1704 /* In this case, we do remove reference counts we've added ourselves,
1705 * since the node will be removed from the data structures.
1706 */
1707 while (elt->ref_count > 0)
1708 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
1709 iter: &iter, FALSE, TRUE);
1710
1711 /* remove the node */
1712 lookup_elt_with_offset (seq: level->seq, offset: elt->offset, ret_siter: &siter);
1713 g_sequence_remove (iter: siter);
1714
1715 gtk_tree_model_filter_increment_stamp (filter);
1716
1717 /* Only if the node is in the root level (parent == NULL) or
1718 * the level is visible, a row-deleted signal is necessary.
1719 */
1720 if (!parent || orig_level_ext_ref_count > 0)
1721 gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter), path);
1722 }
1723 else
1724 {
1725 /* There is only one node left in this level */
1726#ifdef MODEL_FILTER_DEBUG
1727 g_assert (length == 1);
1728#endif
1729
1730 /* The row is signalled as deleted to the client. We have to
1731 * drop the remaining external reference count here, the client
1732 * will not do it.
1733 *
1734 * We keep the reference counts we've obtained ourselves.
1735 */
1736 while (elt->ext_ref_count > 0)
1737 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
1738 iter: &iter, TRUE, TRUE);
1739
1740 /* This level is still required if:
1741 * - it is the root level
1742 * - its parent level is the root level
1743 * - its parent level has an external ref count > 0
1744 */
1745 if (! (level == filter->priv->root ||
1746 level->parent_level == filter->priv->root ||
1747 level->parent_level->ext_ref_count > 0))
1748 {
1749 /* Otherwise, the level can be removed */
1750 gtk_tree_model_filter_free_level (filter, filter_level: level, TRUE, TRUE, TRUE);
1751 }
1752 else
1753 {
1754 /* Level is kept, but we turn our attention to a child level.
1755 *
1756 * If level is not the root level, it is a child level with
1757 * an ext ref count that is now 0. That means that any child level
1758 * of elt can be removed.
1759 */
1760 if (level != filter->priv->root)
1761 {
1762#ifdef MODEL_FILTER_DEBUG
1763 g_assert (level->ext_ref_count == 0);
1764#endif
1765 if (elt->children)
1766 gtk_tree_model_filter_free_level (filter, filter_level: elt->children,
1767 TRUE, TRUE, TRUE);
1768 }
1769 else
1770 {
1771 /* In this case, we want to keep the level with the first
1772 * node pulled in to monitor for signals.
1773 */
1774 if (elt->children)
1775 gtk_tree_model_filter_prune_level (filter, level: elt->children);
1776 }
1777 }
1778
1779 if (!parent || orig_level_ext_ref_count > 0)
1780 gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter), path);
1781 }
1782
1783 gtk_tree_path_free (path);
1784
1785 if (emit_child_toggled && parent->ext_ref_count > 0)
1786 {
1787 GtkTreeIter piter;
1788 GtkTreePath *ppath;
1789
1790 piter.stamp = filter->priv->stamp;
1791 piter.user_data = parent_level;
1792 piter.user_data2 = parent;
1793
1794 ppath = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter: &piter);
1795
1796 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
1797 path: ppath, iter: &piter);
1798 gtk_tree_path_free (path: ppath);
1799 }
1800}
1801
1802/* This function is called after the given node has become visible.
1803 * When the node has children, we should build the level and
1804 * take a reference on the first child.
1805 */
1806static void
1807gtk_tree_model_filter_update_children (GtkTreeModelFilter *filter,
1808 FilterLevel *level,
1809 FilterElt *elt)
1810{
1811 GtkTreeIter c_iter;
1812 GtkTreeIter iter;
1813
1814 if (!elt->visible_siter)
1815 return;
1816
1817 iter.stamp = filter->priv->stamp;
1818 iter.user_data = level;
1819 iter.user_data2 = elt;
1820
1821 gtk_tree_model_filter_convert_iter_to_child_iter (filter, child_iter: &c_iter, filter_iter: &iter);
1822
1823 if ((!level->parent_level || level->parent_level->ext_ref_count > 0) &&
1824 gtk_tree_model_iter_has_child (tree_model: filter->priv->child_model, iter: &c_iter))
1825 {
1826 if (!elt->children)
1827 gtk_tree_model_filter_build_level (filter, parent_level: level, parent_elt: elt, FALSE);
1828
1829 if (elt->ext_ref_count > 0 && elt->children &&
1830 g_sequence_get_length (seq: elt->children->seq))
1831 {
1832 GtkTreePath *path;
1833 path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter: &iter);
1834 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
1835 path,
1836 iter: &iter);
1837 if (path)
1838 gtk_tree_path_free (path);
1839 }
1840 }
1841}
1842
1843/* Path is relative to the child model (this is on search on elt offset)
1844 * but with the virtual root already removed if necesssary.
1845 */
1846static gboolean
1847find_elt_with_offset (GtkTreeModelFilter *filter,
1848 GtkTreePath *path,
1849 FilterLevel **level_,
1850 FilterElt **elt_)
1851{
1852 int i = 0;
1853 FilterLevel *level;
1854 FilterLevel *parent_level = NULL;
1855 FilterElt *elt = NULL;
1856
1857 level = FILTER_LEVEL (filter->priv->root);
1858
1859 while (i < gtk_tree_path_get_depth (path))
1860 {
1861 if (!level)
1862 return FALSE;
1863
1864 elt = lookup_elt_with_offset (seq: level->seq,
1865 offset: gtk_tree_path_get_indices (path)[i],
1866 NULL);
1867
1868 if (!elt)
1869 return FALSE;
1870
1871 parent_level = level;
1872 level = elt->children;
1873 i++;
1874 }
1875
1876 if (level_)
1877 *level_ = parent_level;
1878
1879 if (elt_)
1880 *elt_ = elt;
1881
1882 return TRUE;
1883}
1884
1885/* TreeModel signals */
1886static void
1887gtk_tree_model_filter_emit_row_inserted_for_path (GtkTreeModelFilter *filter,
1888 GtkTreeModel *c_model,
1889 GtkTreePath *c_path,
1890 GtkTreeIter *c_iter)
1891{
1892 FilterLevel *level;
1893 FilterElt *elt;
1894 GtkTreePath *path;
1895 GtkTreeIter iter, children;
1896 gboolean signals_emitted = FALSE;
1897
1898 if (!filter->priv->root)
1899 {
1900 /* The root level has not been exposed to the view yet, so we
1901 * need to emit signals for any node that is being inserted.
1902 */
1903 gtk_tree_model_filter_build_level (filter, NULL, NULL, TRUE);
1904
1905 /* Check if the root level was built. Then child levels
1906 * that matter have also been built (due to update_children,
1907 * which triggers iter_n_children).
1908 */
1909 if (filter->priv->root &&
1910 g_sequence_get_length (FILTER_LEVEL (filter->priv->root)->visible_seq) > 0)
1911 signals_emitted = TRUE;
1912 }
1913
1914 gtk_tree_model_filter_increment_stamp (filter);
1915
1916 /* We need to disallow to build new levels, because we are then pulling
1917 * in a child in an invisible level. We only want to find path if it
1918 * is in a visible level (and thus has a parent that is visible).
1919 */
1920 path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
1921 child_path: c_path,
1922 FALSE,
1923 TRUE);
1924
1925 if (!path)
1926 /* parent is probably being filtered out */
1927 return;
1928
1929 gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (filter), iter: &iter, path);
1930
1931 level = FILTER_LEVEL (iter.user_data);
1932 elt = FILTER_ELT (iter.user_data2);
1933
1934 /* Make sure elt is visible. elt can already be visible in case
1935 * it was pulled in above, so avoid inserted it into visible_seq twice.
1936 */
1937 if (!elt->visible_siter)
1938 {
1939 elt->visible_siter = g_sequence_insert_sorted (seq: level->visible_seq,
1940 data: elt, cmp_func: filter_elt_cmp,
1941 NULL);
1942 }
1943
1944 /* Check whether the node and all of its parents are visible */
1945 if (gtk_tree_model_filter_elt_is_visible_in_target (level, elt))
1946 {
1947 /* visibility changed -- reget path */
1948 gtk_tree_path_free (path);
1949 path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter: &iter);
1950
1951 if (!signals_emitted &&
1952 (!level->parent_level || level->ext_ref_count > 0))
1953 gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter), path, iter: &iter);
1954
1955 if (level->parent_level && level->parent_elt->ext_ref_count > 0 &&
1956 g_sequence_get_length (seq: level->visible_seq) == 1)
1957 {
1958 /* We know that this is the first visible node in this level, so
1959 * we need to emit row-has-child-toggled on the parent. This
1960 * does not apply to the root level.
1961 */
1962
1963 gtk_tree_path_up (path);
1964 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), iter: &iter, path);
1965
1966 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
1967 path,
1968 iter: &iter);
1969 }
1970
1971 if (!signals_emitted
1972 && gtk_tree_model_iter_children (tree_model: c_model, iter: &children, parent: c_iter))
1973 gtk_tree_model_filter_update_children (filter, level, elt);
1974 }
1975
1976 gtk_tree_path_free (path);
1977}
1978
1979static void
1980gtk_tree_model_filter_row_changed (GtkTreeModel *c_model,
1981 GtkTreePath *c_path,
1982 GtkTreeIter *c_iter,
1983 gpointer data)
1984{
1985 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (data);
1986 GtkTreeIter iter;
1987 GtkTreeIter children;
1988 GtkTreeIter real_c_iter;
1989 GtkTreePath *path = NULL;
1990 GtkTreePath *real_path = NULL;
1991
1992 FilterElt *elt;
1993 FilterLevel *level;
1994
1995 gboolean requested_state;
1996 gboolean current_state;
1997 gboolean free_c_path = FALSE;
1998
1999 g_return_if_fail (c_path != NULL || c_iter != NULL);
2000
2001 if (!c_path)
2002 {
2003 c_path = gtk_tree_model_get_path (tree_model: c_model, iter: c_iter);
2004 free_c_path = TRUE;
2005 }
2006
2007 if (filter->priv->virtual_root)
2008 real_path = gtk_tree_model_filter_remove_root (src: c_path,
2009 root: filter->priv->virtual_root);
2010 else
2011 real_path = gtk_tree_path_copy (path: c_path);
2012
2013 if (c_iter)
2014 real_c_iter = *c_iter;
2015 else
2016 gtk_tree_model_get_iter (tree_model: c_model, iter: &real_c_iter, path: c_path);
2017
2018 /* is this node above the virtual root? */
2019 if (filter->priv->virtual_root &&
2020 (gtk_tree_path_get_depth (path: filter->priv->virtual_root)
2021 >= gtk_tree_path_get_depth (path: c_path)))
2022 goto done;
2023
2024 /* what's the requested state? */
2025 requested_state = gtk_tree_model_filter_visible (self: filter, child_iter: &real_c_iter);
2026
2027 /* now, let's see whether the item is there */
2028 path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
2029 child_path: c_path,
2030 FALSE,
2031 FALSE);
2032
2033 if (path)
2034 {
2035 gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (filter),
2036 iter: &iter, path);
2037 current_state = FILTER_ELT (iter.user_data2)->visible_siter != NULL;
2038 }
2039 else
2040 current_state = FALSE;
2041
2042 if (current_state == FALSE && requested_state == FALSE)
2043 /* no changes required */
2044 goto done;
2045
2046 if (current_state == TRUE && requested_state == FALSE)
2047 {
2048 gtk_tree_model_filter_remove_elt_from_level (filter,
2049 FILTER_LEVEL (iter.user_data),
2050 FILTER_ELT (iter.user_data2));
2051
2052 if (real_path)
2053 gtk_tree_model_filter_check_ancestors (filter, path: real_path);
2054
2055 goto done;
2056 }
2057
2058 if (current_state == TRUE && requested_state == TRUE)
2059 {
2060 level = FILTER_LEVEL (iter.user_data);
2061 elt = FILTER_ELT (iter.user_data2);
2062
2063 if (gtk_tree_model_filter_elt_is_visible_in_target (level, elt))
2064 {
2065 /* propagate the signal; also get a path taking only visible
2066 * nodes into account.
2067 */
2068 gtk_tree_path_free (path);
2069 path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter: &iter);
2070
2071 if (level->ext_ref_count > 0)
2072 gtk_tree_model_row_changed (GTK_TREE_MODEL (filter), path, iter: &iter);
2073
2074 /* and update the children */
2075 if (gtk_tree_model_iter_children (tree_model: c_model, iter: &children, parent: &real_c_iter))
2076 gtk_tree_model_filter_update_children (filter, level, elt);
2077 }
2078
2079 if (real_path)
2080 gtk_tree_model_filter_check_ancestors (filter, path: real_path);
2081
2082 goto done;
2083 }
2084
2085 /* only current == FALSE and requested == TRUE is left,
2086 * pull in the child
2087 */
2088 g_return_if_fail (current_state == FALSE && requested_state == TRUE);
2089
2090 if (real_path)
2091 gtk_tree_model_filter_check_ancestors (filter, path: real_path);
2092
2093 gtk_tree_model_filter_emit_row_inserted_for_path (filter, c_model,
2094 c_path, c_iter);
2095
2096done:
2097 if (path)
2098 gtk_tree_path_free (path);
2099
2100 if (real_path)
2101 gtk_tree_path_free (path: real_path);
2102
2103 if (free_c_path)
2104 gtk_tree_path_free (path: c_path);
2105}
2106
2107static void
2108gtk_tree_model_filter_row_inserted (GtkTreeModel *c_model,
2109 GtkTreePath *c_path,
2110 GtkTreeIter *c_iter,
2111 gpointer data)
2112{
2113 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (data);
2114 GtkTreePath *real_path = NULL;
2115
2116 GtkTreeIter real_c_iter;
2117
2118 FilterElt *elt = NULL;
2119 FilterLevel *level = NULL;
2120 FilterLevel *parent_level = NULL;
2121 GSequenceIter *siter;
2122 FilterElt dummy;
2123
2124 int i = 0, offset;
2125
2126 gboolean free_c_path = FALSE;
2127 gboolean emit_row_inserted = FALSE;
2128
2129 g_return_if_fail (c_path != NULL || c_iter != NULL);
2130
2131 if (!c_path)
2132 {
2133 c_path = gtk_tree_model_get_path (tree_model: c_model, iter: c_iter);
2134 free_c_path = TRUE;
2135 }
2136
2137 if (c_iter)
2138 real_c_iter = *c_iter;
2139 else
2140 gtk_tree_model_get_iter (tree_model: c_model, iter: &real_c_iter, path: c_path);
2141
2142 /* the row has already been inserted. so we need to fixup the
2143 * virtual root here first
2144 */
2145 if (filter->priv->virtual_root)
2146 {
2147 if (gtk_tree_path_get_depth (path: filter->priv->virtual_root) >=
2148 gtk_tree_path_get_depth (path: c_path))
2149 {
2150 int depth;
2151 int *v_indices, *c_indices;
2152 gboolean common_prefix = TRUE;
2153
2154 depth = gtk_tree_path_get_depth (path: c_path) - 1;
2155 v_indices = gtk_tree_path_get_indices (path: filter->priv->virtual_root);
2156 c_indices = gtk_tree_path_get_indices (path: c_path);
2157
2158 for (i = 0; i < depth; i++)
2159 if (v_indices[i] != c_indices[i])
2160 {
2161 common_prefix = FALSE;
2162 break;
2163 }
2164
2165 if (common_prefix && v_indices[depth] >= c_indices[depth])
2166 (v_indices[depth])++;
2167 }
2168 }
2169
2170 /* subtract virtual root if necessary */
2171 if (filter->priv->virtual_root)
2172 {
2173 real_path = gtk_tree_model_filter_remove_root (src: c_path,
2174 root: filter->priv->virtual_root);
2175 /* not our child */
2176 if (!real_path)
2177 goto done;
2178 }
2179 else
2180 real_path = gtk_tree_path_copy (path: c_path);
2181
2182 if (!filter->priv->root)
2183 {
2184 /* The root level has not been exposed to the view yet, so we
2185 * need to emit signals for any node that is being inserted.
2186 */
2187 gtk_tree_model_filter_build_level (filter, NULL, NULL, TRUE);
2188
2189 /* Check if the root level was built. Then child levels
2190 * that matter have also been built (due to update_children,
2191 * which triggers iter_n_children).
2192 */
2193 if (filter->priv->root)
2194 {
2195 emit_row_inserted = FALSE;
2196 goto done;
2197 }
2198 }
2199
2200 if (gtk_tree_path_get_depth (path: real_path) - 1 >= 1)
2201 {
2202 gboolean found = FALSE;
2203 GtkTreePath *parent = gtk_tree_path_copy (path: real_path);
2204 gtk_tree_path_up (path: parent);
2205
2206 found = find_elt_with_offset (filter, path: parent, level_: &parent_level, elt_: &elt);
2207
2208 gtk_tree_path_free (path: parent);
2209
2210 if (!found)
2211 /* Parent is not in the cache and probably being filtered out */
2212 goto done;
2213
2214 level = elt->children;
2215 }
2216 else
2217 level = FILTER_LEVEL (filter->priv->root);
2218
2219 if (!level)
2220 {
2221 if (elt && elt->visible_siter)
2222 {
2223 /* The level in which the new node should be inserted does not
2224 * exist, but the parent, elt, does. If elt is visible, emit
2225 * row-has-child-toggled.
2226 */
2227 GtkTreePath *tmppath;
2228 GtkTreeIter tmpiter;
2229
2230 tmpiter.stamp = filter->priv->stamp;
2231 tmpiter.user_data = parent_level;
2232 tmpiter.user_data2 = elt;
2233
2234 tmppath = gtk_tree_model_get_path (GTK_TREE_MODEL (filter),
2235 iter: &tmpiter);
2236
2237 if (tmppath)
2238 {
2239 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
2240 path: tmppath, iter: &tmpiter);
2241 gtk_tree_path_free (path: tmppath);
2242 }
2243 }
2244 goto done;
2245 }
2246
2247 /* let's try to insert the value */
2248 offset = gtk_tree_path_get_indices (path: real_path)[gtk_tree_path_get_depth (path: real_path) - 1];
2249
2250 /* update the offsets, yes if we didn't insert the node above, there will
2251 * be a gap here. This will be filled with the node (via fetch_child) when
2252 * it becomes visible
2253 */
2254 dummy.offset = offset;
2255 siter = g_sequence_search (seq: level->seq, data: &dummy, cmp_func: filter_elt_cmp, NULL);
2256 siter = g_sequence_iter_prev (iter: siter);
2257 g_sequence_foreach_range (begin: siter, end: g_sequence_get_end_iter (seq: level->seq),
2258 func: increase_offset_iter, GINT_TO_POINTER (offset));
2259
2260 /* only insert when visible */
2261 if (gtk_tree_model_filter_visible (self: filter, child_iter: &real_c_iter))
2262 {
2263 FilterElt *felt;
2264
2265 felt = gtk_tree_model_filter_insert_elt_in_level (filter,
2266 c_iter: &real_c_iter,
2267 level, offset,
2268 index: &i);
2269
2270 /* insert_elt_in_level defaults to FALSE */
2271 felt->visible_siter = g_sequence_insert_sorted (seq: level->visible_seq,
2272 data: felt,
2273 cmp_func: filter_elt_cmp, NULL);
2274 emit_row_inserted = TRUE;
2275 }
2276
2277done:
2278 if (real_path)
2279 gtk_tree_model_filter_check_ancestors (filter, path: real_path);
2280
2281 if (emit_row_inserted)
2282 gtk_tree_model_filter_emit_row_inserted_for_path (filter, c_model,
2283 c_path, c_iter);
2284
2285 if (real_path)
2286 gtk_tree_path_free (path: real_path);
2287
2288 if (free_c_path)
2289 gtk_tree_path_free (path: c_path);
2290}
2291
2292static void
2293gtk_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model,
2294 GtkTreePath *c_path,
2295 GtkTreeIter *c_iter,
2296 gpointer data)
2297{
2298 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (data);
2299 GtkTreePath *path;
2300 GtkTreeIter iter;
2301 FilterLevel *level;
2302 FilterElt *elt;
2303 gboolean requested_state;
2304
2305 g_return_if_fail (c_path != NULL && c_iter != NULL);
2306
2307 /* If we get row-has-child-toggled on the virtual root, and there is
2308 * no root level; try to build it now.
2309 */
2310 if (filter->priv->virtual_root && !filter->priv->root
2311 && !gtk_tree_path_compare (a: c_path, b: filter->priv->virtual_root))
2312 {
2313 gtk_tree_model_filter_build_level (filter, NULL, NULL, TRUE);
2314 return;
2315 }
2316
2317 /* For all other levels, there is a chance that the visibility state
2318 * of the parent has changed now.
2319 */
2320
2321 path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
2322 child_path: c_path,
2323 FALSE,
2324 TRUE);
2325 if (!path)
2326 return;
2327
2328 gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (data), iter: &iter, path);
2329
2330 level = FILTER_LEVEL (iter.user_data);
2331 elt = FILTER_ELT (iter.user_data2);
2332
2333 gtk_tree_path_free (path);
2334
2335 requested_state = gtk_tree_model_filter_visible (self: filter, child_iter: c_iter);
2336
2337 if (!elt->visible_siter && !requested_state)
2338 {
2339 /* The parent node currently is not visible and will not become
2340 * visible, so we will not pass on the row-has-child-toggled event.
2341 */
2342 return;
2343 }
2344 else if (elt->visible_siter && !requested_state)
2345 {
2346 /* The node is no longer visible, so it has to be removed.
2347 * _remove_elt_from_level() takes care of emitting row-has-child-toggled
2348 * when required.
2349 */
2350 gtk_tree_model_filter_remove_elt_from_level (filter, level, elt);
2351
2352 return;
2353 }
2354 else if (!elt->visible_siter && requested_state)
2355 {
2356 elt->visible_siter = g_sequence_insert_sorted (seq: level->visible_seq,
2357 data: elt, cmp_func: filter_elt_cmp,
2358 NULL);
2359
2360 /* Only insert if the parent is visible in the target */
2361 if (gtk_tree_model_filter_elt_is_visible_in_target (level, elt))
2362 {
2363 path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter: &iter);
2364 gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter), path, iter: &iter);
2365 gtk_tree_path_free (path);
2366
2367 /* We do not update children now, because that will happen
2368 * below.
2369 */
2370 }
2371 }
2372 /* For the remaining possibility, elt->visible && requested_state
2373 * no action is required.
2374 */
2375
2376 /* If this node is referenced and has children, build the level so we
2377 * can monitor it for changes.
2378 */
2379 if (elt->ref_count > 1 && !elt->children &&
2380 gtk_tree_model_iter_has_child (tree_model: c_model, iter: c_iter))
2381 gtk_tree_model_filter_build_level (filter, parent_level: level, parent_elt: elt, FALSE);
2382
2383 /* get a path taking only visible nodes into account */
2384 path = gtk_tree_model_get_path (GTK_TREE_MODEL (data), iter: &iter);
2385 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data), path, iter: &iter);
2386 gtk_tree_path_free (path);
2387}
2388
2389static void
2390gtk_tree_model_filter_virtual_root_deleted (GtkTreeModelFilter *filter,
2391 GtkTreePath *c_path)
2392{
2393 int i, nodes;
2394 GtkTreePath *path;
2395 FilterLevel *level = FILTER_LEVEL (filter->priv->root);
2396
2397 /* The virtual root (or one of its ancestors) has been deleted. This
2398 * means that all content for our model is now gone. We deal with
2399 * this by removing everything in the filter model: we just iterate
2400 * over the root level and emit a row-deleted for each FilterElt.
2401 * (FIXME: Should we emit row-deleted for child nodes as well? This
2402 * has never been fully clear in TreeModel).
2403 */
2404
2405 /* We unref the path of the virtual root, up to and not including the
2406 * deleted node which can no longer be unreffed.
2407 */
2408 gtk_tree_model_filter_unref_path (filter, path: filter->priv->virtual_root,
2409 depth: gtk_tree_path_get_depth (path: c_path) - 1);
2410 filter->priv->virtual_root_deleted = TRUE;
2411
2412 if (!level)
2413 return;
2414
2415 nodes = g_sequence_get_length (seq: level->visible_seq);
2416
2417 /* We should not propagate the unref here. An unref for any of these
2418 * nodes will fail, since the respective nodes in the child model are
2419 * no longer there.
2420 */
2421 gtk_tree_model_filter_free_level (filter, filter_level: filter->priv->root, FALSE, TRUE, FALSE);
2422
2423 gtk_tree_model_filter_increment_stamp (filter);
2424
2425 path = gtk_tree_path_new ();
2426 gtk_tree_path_append_index (path, index_: 0);
2427
2428 for (i = 0; i < nodes; i++)
2429 gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter), path);
2430
2431 gtk_tree_path_free (path);
2432}
2433
2434static void
2435gtk_tree_model_filter_adjust_virtual_root (GtkTreeModelFilter *filter,
2436 GtkTreePath *c_path)
2437{
2438 int i;
2439 int level;
2440 int *v_indices, *c_indices;
2441 gboolean common_prefix = TRUE;
2442
2443 level = gtk_tree_path_get_depth (path: c_path) - 1;
2444 v_indices = gtk_tree_path_get_indices (path: filter->priv->virtual_root);
2445 c_indices = gtk_tree_path_get_indices (path: c_path);
2446
2447 for (i = 0; i < level; i++)
2448 if (v_indices[i] != c_indices[i])
2449 {
2450 common_prefix = FALSE;
2451 break;
2452 }
2453
2454 if (common_prefix && v_indices[level] > c_indices[level])
2455 (v_indices[level])--;
2456}
2457
2458static void
2459gtk_tree_model_filter_row_deleted_invisible_node (GtkTreeModelFilter *filter,
2460 GtkTreePath *c_path)
2461{
2462 int offset;
2463 GtkTreePath *real_path;
2464 FilterLevel *level;
2465 FilterElt *elt;
2466 FilterElt dummy;
2467 GSequenceIter *siter;
2468
2469 /* The node deleted in the child model is not visible in the
2470 * filter model. We will not emit a signal, just fixup the offsets
2471 * of the other nodes.
2472 */
2473
2474 if (!filter->priv->root)
2475 return;
2476
2477 level = FILTER_LEVEL (filter->priv->root);
2478
2479 /* subtract vroot if necessary */
2480 if (filter->priv->virtual_root)
2481 {
2482 real_path = gtk_tree_model_filter_remove_root (src: c_path,
2483 root: filter->priv->virtual_root);
2484 /* we don't handle this */
2485 if (!real_path)
2486 return;
2487 }
2488 else
2489 real_path = gtk_tree_path_copy (path: c_path);
2490
2491 if (gtk_tree_path_get_depth (path: real_path) - 1 >= 1)
2492 {
2493 gboolean found = FALSE;
2494 GtkTreePath *parent = gtk_tree_path_copy (path: real_path);
2495 gtk_tree_path_up (path: parent);
2496
2497 found = find_elt_with_offset (filter, path: parent, level_: &level, elt_: &elt);
2498
2499 gtk_tree_path_free (path: parent);
2500
2501 if (!found)
2502 {
2503 /* parent is filtered out, so no level */
2504 gtk_tree_path_free (path: real_path);
2505 return;
2506 }
2507
2508 level = elt->children;
2509 }
2510
2511 offset = gtk_tree_path_get_indices (path: real_path)[gtk_tree_path_get_depth (path: real_path) - 1];
2512 gtk_tree_path_free (path: real_path);
2513
2514 if (!level)
2515 return;
2516
2517 /* decrease offset of all nodes following the deleted node */
2518 dummy.offset = offset;
2519 siter = g_sequence_search (seq: level->seq, data: &dummy, cmp_func: filter_elt_cmp, NULL);
2520 g_sequence_foreach_range (begin: siter, end: g_sequence_get_end_iter (seq: level->seq),
2521 func: decrease_offset_iter, GINT_TO_POINTER (offset));
2522}
2523
2524static void
2525gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
2526 GtkTreePath *c_path,
2527 gpointer data)
2528{
2529 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (data);
2530 GtkTreePath *path;
2531 GtkTreeIter iter;
2532 FilterElt *elt, *parent_elt = NULL;
2533 FilterLevel *level, *parent_level = NULL;
2534 GSequenceIter *siter;
2535 gboolean emit_child_toggled = FALSE;
2536 gboolean emit_row_deleted = FALSE;
2537 int offset;
2538 int orig_level_ext_ref_count;
2539
2540 g_return_if_fail (c_path != NULL);
2541
2542 /* special case the deletion of an ancestor of the virtual root */
2543 if (filter->priv->virtual_root &&
2544 (gtk_tree_path_is_ancestor (path: c_path, descendant: filter->priv->virtual_root) ||
2545 !gtk_tree_path_compare (a: c_path, b: filter->priv->virtual_root)))
2546 {
2547 gtk_tree_model_filter_virtual_root_deleted (filter, c_path);
2548 return;
2549 }
2550
2551 /* adjust the virtual root for the deleted row */
2552 if (filter->priv->virtual_root &&
2553 gtk_tree_path_get_depth (path: filter->priv->virtual_root) >=
2554 gtk_tree_path_get_depth (path: c_path))
2555 gtk_tree_model_filter_adjust_virtual_root (filter, c_path);
2556
2557 path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
2558 child_path: c_path,
2559 FALSE,
2560 FALSE);
2561
2562 if (!path)
2563 {
2564 gtk_tree_model_filter_row_deleted_invisible_node (filter, c_path);
2565 return;
2566 }
2567
2568 /* a node was deleted, which was in our cache */
2569 gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (data), iter: &iter, path);
2570
2571 level = FILTER_LEVEL (iter.user_data);
2572 elt = FILTER_ELT (iter.user_data2);
2573 offset = elt->offset;
2574 orig_level_ext_ref_count = level->ext_ref_count;
2575
2576 if (elt->visible_siter)
2577 {
2578 /* get a path taking only visible nodes into account */
2579 gtk_tree_path_free (path);
2580 path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter: &iter);
2581
2582 if (g_sequence_get_length (seq: level->visible_seq) == 1)
2583 {
2584 emit_child_toggled = TRUE;
2585 parent_level = level->parent_level;
2586 parent_elt = level->parent_elt;
2587 }
2588
2589 emit_row_deleted = TRUE;
2590 }
2591
2592 /* Release the references on this node, without propagation because
2593 * the node does not exist anymore in the child model. The filter
2594 * model's references on the node in case of level->parent or use
2595 * of a virtual root are automatically destroyed by the child model.
2596 */
2597 while (elt->ext_ref_count > 0)
2598 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), iter: &iter,
2599 TRUE, FALSE);
2600
2601 if (elt->children)
2602 /* If this last node has children, then the recursion in free_level
2603 * will release this reference.
2604 */
2605 while (elt->ref_count > 1)
2606 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), iter: &iter,
2607 FALSE, FALSE);
2608 else
2609 while (elt->ref_count > 0)
2610 gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), iter: &iter,
2611 FALSE, FALSE);
2612
2613
2614 if (g_sequence_get_length (seq: level->seq) == 1)
2615 {
2616 /* kill level */
2617 gtk_tree_model_filter_free_level (filter, filter_level: level, FALSE, TRUE, FALSE);
2618 }
2619 else
2620 {
2621 GSequenceIter *tmp;
2622 gboolean is_first;
2623
2624 lookup_elt_with_offset (seq: level->seq, offset: elt->offset, ret_siter: &siter);
2625 is_first = g_sequence_get_begin_iter (seq: level->seq) == siter;
2626
2627 if (elt->children)
2628 gtk_tree_model_filter_free_level (filter, filter_level: elt->children,
2629 FALSE, FALSE, FALSE);
2630
2631 /* remove the row */
2632 if (elt->visible_siter)
2633 g_sequence_remove (iter: elt->visible_siter);
2634 tmp = g_sequence_iter_next (iter: siter);
2635 g_sequence_remove (iter: siter);
2636 g_sequence_foreach_range (begin: tmp, end: g_sequence_get_end_iter (seq: level->seq),
2637 func: decrease_offset_iter, GINT_TO_POINTER (offset));
2638
2639 /* Take a reference on the new first node. The first node previously
2640 * keeping this reference has been removed above.
2641 */
2642 if (is_first)
2643 {
2644 GtkTreeIter f_iter;
2645
2646 f_iter.stamp = filter->priv->stamp;
2647 f_iter.user_data = level;
2648 f_iter.user_data2 = g_sequence_get (iter: g_sequence_get_begin_iter (seq: level->seq));
2649
2650 gtk_tree_model_filter_real_ref_node (GTK_TREE_MODEL (filter),
2651 iter: &f_iter, FALSE);
2652 }
2653 }
2654
2655 if (emit_row_deleted)
2656 {
2657 /* emit row_deleted */
2658 gtk_tree_model_filter_increment_stamp (filter);
2659
2660 if (!parent_elt || orig_level_ext_ref_count > 0)
2661 gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path);
2662 }
2663
2664 if (emit_child_toggled && parent_level)
2665 {
2666 GtkTreeIter iter2;
2667 GtkTreePath *path2;
2668
2669 iter2.stamp = filter->priv->stamp;
2670 iter2.user_data = parent_level;
2671 iter2.user_data2 = parent_elt;
2672
2673 /* We set in_row_deleted to TRUE to avoid a level build triggered
2674 * by row-has-child-toggled (parent model could call iter_has_child
2675 * for example).
2676 */
2677 filter->priv->in_row_deleted = TRUE;
2678 path2 = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter: &iter2);
2679 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
2680 path: path2, iter: &iter2);
2681 gtk_tree_path_free (path: path2);
2682 filter->priv->in_row_deleted = FALSE;
2683 }
2684
2685 if (filter->priv->virtual_root)
2686 {
2687 GtkTreePath *real_path;
2688
2689 real_path = gtk_tree_model_filter_remove_root (src: c_path,
2690 root: filter->priv->virtual_root);
2691 if (real_path)
2692 {
2693 gtk_tree_model_filter_check_ancestors (filter, path: real_path);
2694 gtk_tree_path_free (path: real_path);
2695 }
2696 }
2697 else
2698 gtk_tree_model_filter_check_ancestors (filter, path: c_path);
2699
2700 gtk_tree_path_free (path);
2701}
2702
2703static void
2704gtk_tree_model_filter_rows_reordered (GtkTreeModel *c_model,
2705 GtkTreePath *c_path,
2706 GtkTreeIter *c_iter,
2707 int *new_order,
2708 gpointer data)
2709{
2710 FilterElt *elt;
2711 FilterLevel *level;
2712 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (data);
2713
2714 GtkTreePath *path;
2715 GtkTreeIter iter;
2716
2717 GSequence *tmp_seq;
2718 GSequenceIter *tmp_end_iter;
2719 GSequenceIter *old_first_siter = NULL;
2720 int *tmp_array;
2721 int i, elt_count;
2722 int length;
2723
2724 g_return_if_fail (new_order != NULL);
2725
2726 if (c_path == NULL || gtk_tree_path_get_depth (path: c_path) == 0)
2727 {
2728 length = gtk_tree_model_iter_n_children (tree_model: c_model, NULL);
2729
2730 if (filter->priv->virtual_root)
2731 {
2732 int new_pos = -1;
2733
2734 /* reorder root level of path */
2735 for (i = 0; i < length; i++)
2736 if (new_order[i] == gtk_tree_path_get_indices (path: filter->priv->virtual_root)[0])
2737 new_pos = i;
2738
2739 if (new_pos < 0)
2740 return;
2741
2742 gtk_tree_path_get_indices (path: filter->priv->virtual_root)[0] = new_pos;
2743 return;
2744 }
2745
2746 path = gtk_tree_path_new ();
2747 level = FILTER_LEVEL (filter->priv->root);
2748 }
2749 else
2750 {
2751 GtkTreeIter child_iter;
2752
2753 /* virtual root anchor reordering */
2754 if (filter->priv->virtual_root &&
2755 gtk_tree_path_is_ancestor (path: c_path, descendant: filter->priv->virtual_root))
2756 {
2757 int new_pos = -1;
2758 int len;
2759 int depth;
2760 GtkTreeIter real_c_iter;
2761
2762 depth = gtk_tree_path_get_depth (path: c_path);
2763
2764 if (c_iter)
2765 real_c_iter = *c_iter;
2766 else
2767 gtk_tree_model_get_iter (tree_model: c_model, iter: &real_c_iter, path: c_path);
2768
2769 len = gtk_tree_model_iter_n_children (tree_model: c_model, iter: &real_c_iter);
2770
2771 for (i = 0; i < len; i++)
2772 if (new_order[i] == gtk_tree_path_get_indices (path: filter->priv->virtual_root)[depth])
2773 new_pos = i;
2774
2775 if (new_pos < 0)
2776 return;
2777
2778 gtk_tree_path_get_indices (path: filter->priv->virtual_root)[depth] = new_pos;
2779 return;
2780 }
2781
2782 path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
2783 child_path: c_path,
2784 FALSE,
2785 FALSE);
2786
2787 if (!path && filter->priv->virtual_root &&
2788 gtk_tree_path_compare (a: c_path, b: filter->priv->virtual_root))
2789 return;
2790
2791 if (!path && !filter->priv->virtual_root)
2792 return;
2793
2794 if (!path)
2795 {
2796 /* root level mode */
2797 if (!c_iter)
2798 gtk_tree_model_get_iter (tree_model: c_model, iter: c_iter, path: c_path);
2799 length = gtk_tree_model_iter_n_children (tree_model: c_model, iter: c_iter);
2800 path = gtk_tree_path_new ();
2801 level = FILTER_LEVEL (filter->priv->root);
2802 }
2803 else
2804 {
2805 gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (data),
2806 iter: &iter, path);
2807
2808 elt = FILTER_ELT (iter.user_data2);
2809
2810 if (!elt->children)
2811 {
2812 gtk_tree_path_free (path);
2813 return;
2814 }
2815
2816 level = elt->children;
2817
2818 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (filter), child_iter: &child_iter, filter_iter: &iter);
2819 length = gtk_tree_model_iter_n_children (tree_model: c_model, iter: &child_iter);
2820 }
2821 }
2822
2823 if (!level || g_sequence_get_length (seq: level->seq) < 1)
2824 {
2825 gtk_tree_path_free (path);
2826 return;
2827 }
2828
2829 /* NOTE: we do not bail out here if level->seq->len < 2 like
2830 * GtkTreeModelSort does. This because we do some special tricky
2831 * reordering.
2832 */
2833
2834 tmp_seq = g_sequence_new (data_destroy: filter_elt_free);
2835 tmp_end_iter = g_sequence_get_end_iter (seq: tmp_seq);
2836 tmp_array = g_new (int, g_sequence_get_length (level->visible_seq));
2837 elt_count = 0;
2838
2839 old_first_siter = g_sequence_get_iter_at_pos (seq: level->seq, pos: 0);
2840
2841 for (i = 0; i < length; i++)
2842 {
2843 GSequenceIter *siter;
2844
2845 elt = lookup_elt_with_offset (seq: level->seq, offset: new_order[i], ret_siter: &siter);
2846 if (elt == NULL)
2847 continue;
2848
2849 /* Only for visible items an entry should be present in the order array
2850 * to be emitted.
2851 */
2852 if (elt->visible_siter)
2853 tmp_array[elt_count++] = g_sequence_iter_get_position (iter: elt->visible_siter);
2854
2855 /* Steal elt from level->seq and append it to tmp_seq */
2856 g_sequence_move (src: siter, dest: tmp_end_iter);
2857 elt->offset = i;
2858 }
2859
2860 g_warn_if_fail (g_sequence_get_length (level->seq) == 0);
2861 g_sequence_free (seq: level->seq);
2862 level->seq = tmp_seq;
2863 g_sequence_sort (seq: level->visible_seq, cmp_func: filter_elt_cmp, NULL);
2864
2865 /* Transfer the reference from the old item at position 0 to the
2866 * new item at position 0, unless the old item at position 0 is also
2867 * at position 0 in the new sequence.
2868 */
2869 if (g_sequence_iter_get_position (iter: old_first_siter) != 0)
2870 gtk_tree_model_filter_level_transfer_first_ref (filter,
2871 level,
2872 from_iter: old_first_siter,
2873 to_iter: g_sequence_get_iter_at_pos (seq: level->seq, pos: 0));
2874
2875 /* emit rows_reordered */
2876 if (g_sequence_get_length (seq: level->visible_seq) > 0)
2877 {
2878 if (!gtk_tree_path_get_indices (path))
2879 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, NULL,
2880 new_order: tmp_array);
2881 else
2882 {
2883 /* get a path taking only visible nodes into account */
2884 gtk_tree_path_free (path);
2885 path = gtk_tree_model_get_path (GTK_TREE_MODEL (data), iter: &iter);
2886
2887 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, iter: &iter,
2888 new_order: tmp_array);
2889 }
2890 }
2891
2892 /* done */
2893 g_free (mem: tmp_array);
2894 gtk_tree_path_free (path);
2895}
2896
2897/* TreeModelIface implementation */
2898static GtkTreeModelFlags
2899gtk_tree_model_filter_get_flags (GtkTreeModel *model)
2900{
2901 GtkTreeModelFlags flags;
2902
2903 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), 0);
2904 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL, 0);
2905
2906 flags = gtk_tree_model_get_flags (GTK_TREE_MODEL_FILTER (model)->priv->child_model);
2907
2908 if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
2909 return GTK_TREE_MODEL_LIST_ONLY;
2910
2911 return 0;
2912}
2913
2914static int
2915gtk_tree_model_filter_get_n_columns (GtkTreeModel *model)
2916{
2917 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
2918
2919 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), 0);
2920 g_return_val_if_fail (filter->priv->child_model != NULL, 0);
2921
2922 if (filter->priv->child_model == NULL)
2923 return 0;
2924
2925 /* so we can't set the modify func after this ... */
2926 filter->priv->modify_func_set = TRUE;
2927
2928 if (filter->priv->modify_n_columns > 0)
2929 return filter->priv->modify_n_columns;
2930
2931 return gtk_tree_model_get_n_columns (tree_model: filter->priv->child_model);
2932}
2933
2934static GType
2935gtk_tree_model_filter_get_column_type (GtkTreeModel *model,
2936 int index)
2937{
2938 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
2939
2940 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), G_TYPE_INVALID);
2941 g_return_val_if_fail (filter->priv->child_model != NULL, G_TYPE_INVALID);
2942
2943 /* so we can't set the modify func after this ... */
2944 filter->priv->modify_func_set = TRUE;
2945
2946 if (filter->priv->modify_types)
2947 {
2948 g_return_val_if_fail (index < filter->priv->modify_n_columns, G_TYPE_INVALID);
2949
2950 return filter->priv->modify_types[index];
2951 }
2952
2953 return gtk_tree_model_get_column_type (tree_model: filter->priv->child_model, index_: index);
2954}
2955
2956/* A special case of _get_iter; this function can also get iters which
2957 * are not visible. These iters should ONLY be passed internally, never
2958 * pass those along with a signal emission.
2959 */
2960static gboolean
2961gtk_tree_model_filter_get_iter_full (GtkTreeModel *model,
2962 GtkTreeIter *iter,
2963 GtkTreePath *path)
2964{
2965 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
2966 int *indices;
2967 FilterLevel *level;
2968 FilterElt *elt;
2969 int depth, i;
2970 GSequenceIter *siter;
2971
2972 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
2973 g_return_val_if_fail (filter->priv->child_model != NULL, FALSE);
2974
2975 indices = gtk_tree_path_get_indices (path);
2976
2977 if (filter->priv->root == NULL)
2978 gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
2979 level = FILTER_LEVEL (filter->priv->root);
2980
2981 depth = gtk_tree_path_get_depth (path);
2982 if (!depth)
2983 {
2984 iter->stamp = 0;
2985 return FALSE;
2986 }
2987
2988 for (i = 0; i < depth - 1; i++)
2989 {
2990 if (!level || indices[i] >= g_sequence_get_length (seq: level->seq))
2991 {
2992 iter->stamp = 0;
2993 return FALSE;
2994 }
2995
2996 siter = g_sequence_get_iter_at_pos (seq: level->seq, pos: indices[i]);
2997 if (g_sequence_iter_is_end (iter: siter))
2998 {
2999 iter->stamp = 0;
3000 return FALSE;
3001 }
3002
3003 elt = GET_ELT (siter);
3004 g_assert (elt);
3005
3006 if (!elt->children)
3007 gtk_tree_model_filter_build_level (filter, parent_level: level, parent_elt: elt, FALSE);
3008 level = elt->children;
3009 }
3010
3011 if (!level || indices[i] >= g_sequence_get_length (seq: level->seq))
3012 {
3013 iter->stamp = 0;
3014 return FALSE;
3015 }
3016
3017 iter->stamp = filter->priv->stamp;
3018 iter->user_data = level;
3019
3020 siter = g_sequence_get_iter_at_pos (seq: level->seq, pos: indices[depth - 1]);
3021 if (g_sequence_iter_is_end (iter: siter))
3022 {
3023 iter->stamp = 0;
3024 return FALSE;
3025 }
3026 iter->user_data2 = GET_ELT (siter);
3027
3028 return TRUE;
3029}
3030
3031static gboolean
3032gtk_tree_model_filter_get_iter (GtkTreeModel *model,
3033 GtkTreeIter *iter,
3034 GtkTreePath *path)
3035{
3036 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
3037 int *indices;
3038 FilterLevel *level;
3039 FilterElt *elt;
3040 GSequenceIter *siter;
3041 int depth, i;
3042
3043 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
3044 g_return_val_if_fail (filter->priv->child_model != NULL, FALSE);
3045
3046 indices = gtk_tree_path_get_indices (path);
3047
3048 if (filter->priv->root == NULL)
3049 gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
3050 level = FILTER_LEVEL (filter->priv->root);
3051
3052 depth = gtk_tree_path_get_depth (path);
3053 if (!depth)
3054 {
3055 iter->stamp = 0;
3056 return FALSE;
3057 }
3058
3059 for (i = 0; i < depth - 1; i++)
3060 {
3061 if (!level || indices[i] >= g_sequence_get_length (seq: level->visible_seq))
3062 {
3063 iter->stamp = 0;
3064 return FALSE;
3065 }
3066
3067 siter = g_sequence_get_iter_at_pos (seq: level->visible_seq, pos: indices[i]);
3068 if (g_sequence_iter_is_end (iter: siter))
3069 {
3070 iter->stamp = 0;
3071 return FALSE;
3072 }
3073
3074 elt = GET_ELT (siter);
3075 g_assert (elt);
3076 if (!elt->children)
3077 gtk_tree_model_filter_build_level (filter, parent_level: level, parent_elt: elt, FALSE);
3078 level = elt->children;
3079 }
3080
3081 if (!level || indices[i] >= g_sequence_get_length (seq: level->visible_seq))
3082 {
3083 iter->stamp = 0;
3084 return FALSE;
3085 }
3086
3087 iter->stamp = filter->priv->stamp;
3088 iter->user_data = level;
3089
3090 siter = g_sequence_get_iter_at_pos (seq: level->visible_seq, pos: indices[depth - 1]);
3091 if (g_sequence_iter_is_end (iter: siter))
3092 {
3093 iter->stamp = 0;
3094 return FALSE;
3095 }
3096 iter->user_data2 = GET_ELT (siter);
3097
3098 return TRUE;
3099}
3100
3101static GtkTreePath *
3102gtk_tree_model_filter_get_path (GtkTreeModel *model,
3103 GtkTreeIter *iter)
3104{
3105 GtkTreePath *retval;
3106 FilterLevel *level;
3107 FilterElt *elt;
3108
3109 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), NULL);
3110 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL, NULL);
3111 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == iter->stamp, NULL);
3112
3113 level = iter->user_data;
3114 elt = iter->user_data2;
3115
3116 if (!elt->visible_siter)
3117 return NULL;
3118
3119 retval = gtk_tree_path_new ();
3120
3121 while (level)
3122 {
3123 int index;
3124
3125 index = g_sequence_iter_get_position (iter: elt->visible_siter);
3126 gtk_tree_path_prepend_index (path: retval, index_: index);
3127
3128 elt = level->parent_elt;
3129 level = level->parent_level;
3130 }
3131
3132 return retval;
3133}
3134
3135static void
3136gtk_tree_model_filter_real_modify (GtkTreeModelFilter *self,
3137 GtkTreeModel *child_model,
3138 GtkTreeIter *iter,
3139 GValue *value,
3140 int column)
3141{
3142 if (self->priv->modify_func)
3143 {
3144 g_return_if_fail (column < self->priv->modify_n_columns);
3145
3146 g_value_init (value, g_type: self->priv->modify_types[column]);
3147 self->priv->modify_func (GTK_TREE_MODEL (self),
3148 iter, value, column,
3149 self->priv->modify_data);
3150 }
3151 else
3152 {
3153 GtkTreeIter child_iter;
3154
3155 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (self),
3156 child_iter: &child_iter, filter_iter: iter);
3157 gtk_tree_model_get_value (tree_model: child_model, iter: &child_iter, column, value);
3158 }
3159}
3160
3161static void
3162gtk_tree_model_filter_get_value (GtkTreeModel *model,
3163 GtkTreeIter *iter,
3164 int column,
3165 GValue *value)
3166{
3167 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (model);
3168
3169 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (model));
3170 g_return_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL);
3171 g_return_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == iter->stamp);
3172
3173 GTK_TREE_MODEL_FILTER_GET_CLASS (model)->modify (filter,
3174 filter->priv->child_model, iter, value, column);
3175}
3176
3177static gboolean
3178gtk_tree_model_filter_iter_next (GtkTreeModel *model,
3179 GtkTreeIter *iter)
3180{
3181 FilterElt *elt;
3182 GSequenceIter *siter;
3183
3184 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
3185 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL, FALSE);
3186 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == iter->stamp, FALSE);
3187
3188 elt = iter->user_data2;
3189
3190 siter = g_sequence_iter_next (iter: elt->visible_siter);
3191 if (g_sequence_iter_is_end (iter: siter))
3192 {
3193 iter->stamp = 0;
3194 return FALSE;
3195 }
3196
3197 iter->user_data2 = GET_ELT (siter);
3198
3199 return TRUE;
3200}
3201
3202static gboolean
3203gtk_tree_model_filter_iter_previous (GtkTreeModel *model,
3204 GtkTreeIter *iter)
3205{
3206 FilterElt *elt;
3207 GSequenceIter *siter;
3208
3209 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
3210 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL, FALSE);
3211 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == iter->stamp, FALSE);
3212
3213 elt = iter->user_data2;
3214
3215 if (g_sequence_iter_is_begin (iter: elt->visible_siter))
3216 {
3217 iter->stamp = 0;
3218 return FALSE;
3219 }
3220 siter = g_sequence_iter_prev (iter: elt->visible_siter);
3221
3222 iter->user_data2 = GET_ELT (siter);
3223
3224 return TRUE;
3225}
3226
3227static gboolean
3228gtk_tree_model_filter_iter_children (GtkTreeModel *model,
3229 GtkTreeIter *iter,
3230 GtkTreeIter *parent)
3231{
3232 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
3233 FilterLevel *level;
3234 GSequenceIter *siter;
3235
3236 iter->stamp = 0;
3237 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
3238 g_return_val_if_fail (filter->priv->child_model != NULL, FALSE);
3239 if (parent)
3240 g_return_val_if_fail (filter->priv->stamp == parent->stamp, FALSE);
3241
3242 if (!parent)
3243 {
3244 if (!filter->priv->root)
3245 gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
3246 if (!filter->priv->root)
3247 return FALSE;
3248
3249 level = filter->priv->root;
3250 siter = g_sequence_get_begin_iter (seq: level->visible_seq);
3251 if (g_sequence_iter_is_end (iter: siter))
3252 {
3253 iter->stamp = 0;
3254 return FALSE;
3255 }
3256
3257 iter->stamp = filter->priv->stamp;
3258 iter->user_data = level;
3259 iter->user_data2 = GET_ELT (siter);
3260
3261 return TRUE;
3262 }
3263 else
3264 {
3265 if (FILTER_ELT (parent->user_data2)->children == NULL)
3266 gtk_tree_model_filter_build_level (filter,
3267 FILTER_LEVEL (parent->user_data),
3268 FILTER_ELT (parent->user_data2),
3269 FALSE);
3270 if (FILTER_ELT (parent->user_data2)->children == NULL)
3271 return FALSE;
3272
3273 level = FILTER_ELT (parent->user_data2)->children;
3274 siter = g_sequence_get_begin_iter (seq: level->visible_seq);
3275 if (g_sequence_iter_is_end (iter: siter))
3276 {
3277 iter->stamp = 0;
3278 return FALSE;
3279 }
3280
3281 iter->stamp = filter->priv->stamp;
3282 iter->user_data = level;
3283 iter->user_data2 = GET_ELT (siter);
3284
3285 return TRUE;
3286 }
3287}
3288
3289static gboolean
3290gtk_tree_model_filter_iter_has_child (GtkTreeModel *model,
3291 GtkTreeIter *iter)
3292{
3293 GtkTreeIter child_iter;
3294 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
3295 FilterElt *elt;
3296
3297 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
3298 g_return_val_if_fail (filter->priv->child_model != NULL, FALSE);
3299 g_return_val_if_fail (filter->priv->stamp == iter->stamp, FALSE);
3300
3301 filter = GTK_TREE_MODEL_FILTER (model);
3302
3303 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), child_iter: &child_iter, filter_iter: iter);
3304 elt = FILTER_ELT (iter->user_data2);
3305
3306 if (!elt->visible_siter)
3307 return FALSE;
3308
3309 /* we need to build the level to check if not all children are filtered
3310 * out
3311 */
3312 if (!elt->children
3313 && gtk_tree_model_iter_has_child (tree_model: filter->priv->child_model, iter: &child_iter))
3314 gtk_tree_model_filter_build_level (filter, FILTER_LEVEL (iter->user_data),
3315 parent_elt: elt, FALSE);
3316
3317 if (elt->children && g_sequence_get_length (seq: elt->children->visible_seq) > 0)
3318 return TRUE;
3319
3320 return FALSE;
3321}
3322
3323static int
3324gtk_tree_model_filter_iter_n_children (GtkTreeModel *model,
3325 GtkTreeIter *iter)
3326{
3327 GtkTreeIter child_iter;
3328 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
3329 FilterElt *elt;
3330
3331 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), 0);
3332 g_return_val_if_fail (filter->priv->child_model != NULL, 0);
3333 if (iter)
3334 g_return_val_if_fail (filter->priv->stamp == iter->stamp, 0);
3335
3336 if (!iter)
3337 {
3338 if (!filter->priv->root)
3339 gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
3340
3341 if (filter->priv->root)
3342 return g_sequence_get_length (FILTER_LEVEL (filter->priv->root)->visible_seq);
3343
3344 return 0;
3345 }
3346
3347 elt = FILTER_ELT (iter->user_data2);
3348
3349 if (!elt->visible_siter)
3350 return 0;
3351
3352 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), child_iter: &child_iter, filter_iter: iter);
3353
3354 if (!elt->children &&
3355 gtk_tree_model_iter_has_child (tree_model: filter->priv->child_model, iter: &child_iter))
3356 gtk_tree_model_filter_build_level (filter,
3357 FILTER_LEVEL (iter->user_data),
3358 parent_elt: elt, FALSE);
3359
3360 if (elt->children)
3361 return g_sequence_get_length (seq: elt->children->visible_seq);
3362
3363 return 0;
3364}
3365
3366static gboolean
3367gtk_tree_model_filter_iter_nth_child (GtkTreeModel *model,
3368 GtkTreeIter *iter,
3369 GtkTreeIter *parent,
3370 int n)
3371{
3372 FilterLevel *level;
3373 GtkTreeIter children;
3374 GSequenceIter *siter;
3375
3376 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
3377 if (parent)
3378 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == parent->stamp, FALSE);
3379
3380 /* use this instead of has_child to force us to build the level, if needed */
3381 if (gtk_tree_model_filter_iter_children (model, iter: &children, parent) == FALSE)
3382 {
3383 iter->stamp = 0;
3384 return FALSE;
3385 }
3386
3387 level = children.user_data;
3388 siter = g_sequence_get_iter_at_pos (seq: level->visible_seq, pos: n);
3389 if (g_sequence_iter_is_end (iter: siter))
3390 return FALSE;
3391
3392 iter->stamp = GTK_TREE_MODEL_FILTER (model)->priv->stamp;
3393 iter->user_data = level;
3394 iter->user_data2 = GET_ELT (siter);
3395
3396 return TRUE;
3397}
3398
3399static gboolean
3400gtk_tree_model_filter_iter_parent (GtkTreeModel *model,
3401 GtkTreeIter *iter,
3402 GtkTreeIter *child)
3403{
3404 FilterLevel *level;
3405
3406 iter->stamp = 0;
3407 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
3408 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL, FALSE);
3409 g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == child->stamp, FALSE);
3410
3411 level = child->user_data;
3412
3413 if (level->parent_level)
3414 {
3415 iter->stamp = GTK_TREE_MODEL_FILTER (model)->priv->stamp;
3416 iter->user_data = level->parent_level;
3417 iter->user_data2 = level->parent_elt;
3418
3419 return TRUE;
3420 }
3421
3422 return FALSE;
3423}
3424
3425static void
3426gtk_tree_model_filter_ref_node (GtkTreeModel *model,
3427 GtkTreeIter *iter)
3428{
3429 gtk_tree_model_filter_real_ref_node (model, iter, TRUE);
3430}
3431
3432static void
3433gtk_tree_model_filter_real_ref_node (GtkTreeModel *model,
3434 GtkTreeIter *iter,
3435 gboolean external)
3436{
3437 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
3438 GtkTreeIter child_iter;
3439 FilterLevel *level;
3440 FilterElt *elt;
3441
3442 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (model));
3443 g_return_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL);
3444 g_return_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == iter->stamp);
3445
3446 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), child_iter: &child_iter, filter_iter: iter);
3447
3448 gtk_tree_model_ref_node (tree_model: filter->priv->child_model, iter: &child_iter);
3449
3450 level = iter->user_data;
3451 elt = iter->user_data2;
3452
3453 elt->ref_count++;
3454 level->ref_count++;
3455
3456 if (external)
3457 {
3458 elt->ext_ref_count++;
3459 level->ext_ref_count++;
3460
3461 if (level->ext_ref_count == 1)
3462 {
3463 FilterLevel *parent_level = level->parent_level;
3464 FilterElt *parent_elt = level->parent_elt;
3465
3466 /* we were at zero -- time to decrease the zero_ref_count val */
3467 while (parent_level)
3468 {
3469 parent_elt->zero_ref_count--;
3470
3471 parent_elt = parent_level->parent_elt;
3472 parent_level = parent_level->parent_level;
3473 }
3474
3475 if (filter->priv->root != level)
3476 filter->priv->zero_ref_count--;
3477
3478#ifdef MODEL_FILTER_DEBUG
3479 g_assert (filter->priv->zero_ref_count >= 0);
3480 if (filter->priv->zero_ref_count > 0)
3481 g_assert (filter->priv->root != NULL);
3482#endif
3483 }
3484 }
3485
3486#ifdef MODEL_FILTER_DEBUG
3487 g_assert (elt->ref_count >= elt->ext_ref_count);
3488 g_assert (elt->ref_count >= 0);
3489 g_assert (elt->ext_ref_count >= 0);
3490#endif
3491}
3492
3493static void
3494gtk_tree_model_filter_unref_node (GtkTreeModel *model,
3495 GtkTreeIter *iter)
3496{
3497 gtk_tree_model_filter_real_unref_node (model, iter, TRUE, TRUE);
3498}
3499
3500static void
3501gtk_tree_model_filter_real_unref_node (GtkTreeModel *model,
3502 GtkTreeIter *iter,
3503 gboolean external,
3504 gboolean propagate_unref)
3505{
3506 GtkTreeModelFilter *filter = (GtkTreeModelFilter *)model;
3507 FilterLevel *level;
3508 FilterElt *elt;
3509
3510 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (model));
3511 g_return_if_fail (filter->priv->child_model != NULL);
3512 g_return_if_fail (filter->priv->stamp == iter->stamp);
3513
3514 if (propagate_unref)
3515 {
3516 GtkTreeIter child_iter;
3517 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), child_iter: &child_iter, filter_iter: iter);
3518 gtk_tree_model_unref_node (tree_model: filter->priv->child_model, iter: &child_iter);
3519 }
3520
3521 level = iter->user_data;
3522 elt = iter->user_data2;
3523
3524 g_return_if_fail (elt->ref_count > 0);
3525#ifdef MODEL_FILTER_DEBUG
3526 g_assert (elt->ref_count >= elt->ext_ref_count);
3527 g_assert (elt->ref_count >= 0);
3528 g_assert (elt->ext_ref_count >= 0);
3529#endif
3530
3531 elt->ref_count--;
3532 level->ref_count--;
3533
3534 if (external)
3535 {
3536 elt->ext_ref_count--;
3537 level->ext_ref_count--;
3538
3539 if (level->ext_ref_count == 0)
3540 {
3541 FilterLevel *parent_level = level->parent_level;
3542 FilterElt *parent_elt = level->parent_elt;
3543
3544 /* we are at zero -- time to increase the zero_ref_count val */
3545 while (parent_level)
3546 {
3547 parent_elt->zero_ref_count++;
3548
3549 parent_elt = parent_level->parent_elt;
3550 parent_level = parent_level->parent_level;
3551 }
3552
3553 if (filter->priv->root != level)
3554 filter->priv->zero_ref_count++;
3555
3556#ifdef MODEL_FILTER_DEBUG
3557 g_assert (filter->priv->zero_ref_count >= 0);
3558 if (filter->priv->zero_ref_count > 0)
3559 g_assert (filter->priv->root != NULL);
3560#endif
3561 }
3562 }
3563
3564#ifdef MODEL_FILTER_DEBUG
3565 g_assert (elt->ref_count >= elt->ext_ref_count);
3566 g_assert (elt->ref_count >= 0);
3567 g_assert (elt->ext_ref_count >= 0);
3568#endif
3569}
3570
3571/* TreeDragSource interface implementation */
3572static gboolean
3573gtk_tree_model_filter_row_draggable (GtkTreeDragSource *drag_source,
3574 GtkTreePath *path)
3575{
3576 GtkTreeModelFilter *tree_model_filter = (GtkTreeModelFilter *)drag_source;
3577 GtkTreePath *child_path;
3578 gboolean draggable;
3579
3580 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (drag_source), FALSE);
3581 g_return_val_if_fail (path != NULL, FALSE);
3582
3583 child_path = gtk_tree_model_filter_convert_path_to_child_path (filter: tree_model_filter, filter_path: path);
3584 draggable = gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (tree_model_filter->priv->child_model), path: child_path);
3585 gtk_tree_path_free (path: child_path);
3586
3587 return draggable;
3588}
3589
3590static GdkContentProvider *
3591gtk_tree_model_filter_drag_data_get (GtkTreeDragSource *drag_source,
3592 GtkTreePath *path)
3593{
3594 GtkTreeModelFilter *tree_model_filter = (GtkTreeModelFilter *)drag_source;
3595 GtkTreePath *child_path;
3596 GdkContentProvider *gotten;
3597
3598 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (drag_source), NULL);
3599 g_return_val_if_fail (path != NULL, NULL);
3600
3601 child_path = gtk_tree_model_filter_convert_path_to_child_path (filter: tree_model_filter, filter_path: path);
3602 gotten = gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (tree_model_filter->priv->child_model), path: child_path);
3603 gtk_tree_path_free (path: child_path);
3604
3605 return gotten;
3606}
3607
3608static gboolean
3609gtk_tree_model_filter_drag_data_delete (GtkTreeDragSource *drag_source,
3610 GtkTreePath *path)
3611{
3612 GtkTreeModelFilter *tree_model_filter = (GtkTreeModelFilter *)drag_source;
3613 GtkTreePath *child_path;
3614 gboolean deleted;
3615
3616 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (drag_source), FALSE);
3617 g_return_val_if_fail (path != NULL, FALSE);
3618
3619 child_path = gtk_tree_model_filter_convert_path_to_child_path (filter: tree_model_filter, filter_path: path);
3620 deleted = gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (tree_model_filter->priv->child_model), path: child_path);
3621 gtk_tree_path_free (path: child_path);
3622
3623 return deleted;
3624}
3625
3626/* bits and pieces */
3627static void
3628gtk_tree_model_filter_set_model (GtkTreeModelFilter *filter,
3629 GtkTreeModel *child_model)
3630{
3631 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
3632
3633 if (filter->priv->child_model)
3634 {
3635 g_signal_handler_disconnect (instance: filter->priv->child_model,
3636 handler_id: filter->priv->changed_id);
3637 g_signal_handler_disconnect (instance: filter->priv->child_model,
3638 handler_id: filter->priv->inserted_id);
3639 g_signal_handler_disconnect (instance: filter->priv->child_model,
3640 handler_id: filter->priv->has_child_toggled_id);
3641 g_signal_handler_disconnect (instance: filter->priv->child_model,
3642 handler_id: filter->priv->deleted_id);
3643 g_signal_handler_disconnect (instance: filter->priv->child_model,
3644 handler_id: filter->priv->reordered_id);
3645
3646 /* reset our state */
3647 if (filter->priv->root)
3648 gtk_tree_model_filter_free_level (filter, filter_level: filter->priv->root,
3649 TRUE, TRUE, FALSE);
3650
3651 filter->priv->root = NULL;
3652 g_object_unref (object: filter->priv->child_model);
3653 filter->priv->visible_column = -1;
3654
3655 /* FIXME: do we need to destroy more here? */
3656 }
3657
3658 filter->priv->child_model = child_model;
3659
3660 if (child_model)
3661 {
3662 g_object_ref (filter->priv->child_model);
3663 filter->priv->changed_id =
3664 g_signal_connect (child_model, "row-changed",
3665 G_CALLBACK (gtk_tree_model_filter_row_changed),
3666 filter);
3667 filter->priv->inserted_id =
3668 g_signal_connect (child_model, "row-inserted",
3669 G_CALLBACK (gtk_tree_model_filter_row_inserted),
3670 filter);
3671 filter->priv->has_child_toggled_id =
3672 g_signal_connect (child_model, "row-has-child-toggled",
3673 G_CALLBACK (gtk_tree_model_filter_row_has_child_toggled),
3674 filter);
3675 filter->priv->deleted_id =
3676 g_signal_connect (child_model, "row-deleted",
3677 G_CALLBACK (gtk_tree_model_filter_row_deleted),
3678 filter);
3679 filter->priv->reordered_id =
3680 g_signal_connect (child_model, "rows-reordered",
3681 G_CALLBACK (gtk_tree_model_filter_rows_reordered),
3682 filter);
3683
3684 filter->priv->child_flags = gtk_tree_model_get_flags (tree_model: child_model);
3685 filter->priv->stamp = g_random_int ();
3686 }
3687}
3688
3689static void
3690gtk_tree_model_filter_ref_path (GtkTreeModelFilter *filter,
3691 GtkTreePath *path)
3692{
3693 int len;
3694 GtkTreePath *p;
3695
3696 len = gtk_tree_path_get_depth (path);
3697 p = gtk_tree_path_copy (path);
3698 while (len--)
3699 {
3700 GtkTreeIter iter;
3701
3702 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter->priv->child_model), iter: &iter, path: p);
3703 gtk_tree_model_ref_node (GTK_TREE_MODEL (filter->priv->child_model), iter: &iter);
3704 gtk_tree_path_up (path: p);
3705 }
3706
3707 gtk_tree_path_free (path: p);
3708}
3709
3710static void
3711gtk_tree_model_filter_unref_path (GtkTreeModelFilter *filter,
3712 GtkTreePath *path,
3713 int depth)
3714{
3715 int len;
3716 GtkTreePath *p;
3717
3718 if (depth != -1)
3719 len = depth;
3720 else
3721 len = gtk_tree_path_get_depth (path);
3722
3723 p = gtk_tree_path_copy (path);
3724 while (len--)
3725 {
3726 GtkTreeIter iter;
3727
3728 gtk_tree_model_get_iter (GTK_TREE_MODEL (filter->priv->child_model), iter: &iter, path: p);
3729 gtk_tree_model_unref_node (GTK_TREE_MODEL (filter->priv->child_model), iter: &iter);
3730 gtk_tree_path_up (path: p);
3731 }
3732
3733 gtk_tree_path_free (path: p);
3734}
3735
3736static void
3737gtk_tree_model_filter_set_root (GtkTreeModelFilter *filter,
3738 GtkTreePath *root)
3739{
3740 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
3741
3742 if (root)
3743 {
3744 filter->priv->virtual_root = gtk_tree_path_copy (path: root);
3745 gtk_tree_model_filter_ref_path (filter, path: filter->priv->virtual_root);
3746 filter->priv->virtual_root_deleted = FALSE;
3747 }
3748 else
3749 filter->priv->virtual_root = NULL;
3750}
3751
3752/* public API */
3753
3754/**
3755 * gtk_tree_model_filter_new:
3756 * @child_model: A `GtkTreeModel`.
3757 * @root: (nullable): A `GtkTreePath`
3758 *
3759 * Creates a new `GtkTreeModel`, with @child_model as the child_model
3760 * and @root as the virtual root.
3761 *
3762 * Returns: (transfer full): A new `GtkTreeModel`.
3763 */
3764GtkTreeModel *
3765gtk_tree_model_filter_new (GtkTreeModel *child_model,
3766 GtkTreePath *root)
3767{
3768 g_return_val_if_fail (GTK_IS_TREE_MODEL (child_model), NULL);
3769
3770 return g_object_new (GTK_TYPE_TREE_MODEL_FILTER,
3771 first_property_name: "child-model", child_model,
3772 "virtual-root", root,
3773 NULL);
3774}
3775
3776/**
3777 * gtk_tree_model_filter_get_model:
3778 * @filter: A `GtkTreeModelFilter`
3779 *
3780 * Returns a pointer to the child model of @filter.
3781 *
3782 * Returns: (transfer none): A pointer to a `GtkTreeModel`
3783 */
3784GtkTreeModel *
3785gtk_tree_model_filter_get_model (GtkTreeModelFilter *filter)
3786{
3787 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (filter), NULL);
3788
3789 return filter->priv->child_model;
3790}
3791
3792/**
3793 * gtk_tree_model_filter_set_visible_func:
3794 * @filter: A `GtkTreeModelFilter`
3795 * @func: A `GtkTreeModelFilterVisibleFunc`, the visible function
3796 * @data: (nullable): User data to pass to the visible function
3797 * @destroy: (nullable): Destroy notifier of @data
3798 *
3799 * Sets the visible function used when filtering the @filter to be @func.
3800 * The function should return %TRUE if the given row should be visible and
3801 * %FALSE otherwise.
3802 *
3803 * If the condition calculated by the function changes over time (e.g.
3804 * because it depends on some global parameters), you must call
3805 * gtk_tree_model_filter_refilter() to keep the visibility information
3806 * of the model up-to-date.
3807 *
3808 * Note that @func is called whenever a row is inserted, when it may still
3809 * be empty. The visible function should therefore take special care of empty
3810 * rows, like in the example below.
3811 *
3812 * |[<!-- language="C" -->
3813 * static gboolean
3814 * visible_func (GtkTreeModel *model,
3815 * GtkTreeIter *iter,
3816 * gpointer data)
3817 * {
3818 * // Visible if row is non-empty and first column is “HI”
3819 * char *str;
3820 * gboolean visible = FALSE;
3821 *
3822 * gtk_tree_model_get (model, iter, 0, &str, -1);
3823 * if (str && strcmp (str, "HI") == 0)
3824 * visible = TRUE;
3825 * g_free (str);
3826 *
3827 * return visible;
3828 * }
3829 * ]|
3830 *
3831 * Note that gtk_tree_model_filter_set_visible_func() or
3832 * gtk_tree_model_filter_set_visible_column() can only be called
3833 * once for a given filter model.
3834 */
3835void
3836gtk_tree_model_filter_set_visible_func (GtkTreeModelFilter *filter,
3837 GtkTreeModelFilterVisibleFunc func,
3838 gpointer data,
3839 GDestroyNotify destroy)
3840{
3841 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
3842 g_return_if_fail (func != NULL);
3843 g_return_if_fail (filter->priv->visible_method_set == FALSE);
3844
3845 filter->priv->visible_func = func;
3846 filter->priv->visible_data = data;
3847 filter->priv->visible_destroy = destroy;
3848
3849 filter->priv->visible_method_set = TRUE;
3850}
3851
3852/**
3853 * gtk_tree_model_filter_set_modify_func:
3854 * @filter: A `GtkTreeModelFilter`
3855 * @n_columns: The number of columns in the filter model.
3856 * @types: (array length=n_columns): The `GType`s of the columns.
3857 * @func: A `GtkTreeModelFilterModifyFunc`
3858 * @data: (nullable): User data to pass to the modify function
3859 * @destroy: (nullable): Destroy notifier of @data
3860 *
3861 * With the @n_columns and @types parameters, you give an array of column
3862 * types for this model (which will be exposed to the parent model/view).
3863 * The @func, @data and @destroy parameters are for specifying the modify
3864 * function. The modify function will get called for each
3865 * data access, the goal of the modify function is to return the data which
3866 * should be displayed at the location specified using the parameters of the
3867 * modify function.
3868 *
3869 * Note that gtk_tree_model_filter_set_modify_func()
3870 * can only be called once for a given filter model.
3871 */
3872void
3873gtk_tree_model_filter_set_modify_func (GtkTreeModelFilter *filter,
3874 int n_columns,
3875 GType *types,
3876 GtkTreeModelFilterModifyFunc func,
3877 gpointer data,
3878 GDestroyNotify destroy)
3879{
3880 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
3881 g_return_if_fail (func != NULL);
3882 g_return_if_fail (filter->priv->modify_func_set == FALSE);
3883
3884 filter->priv->modify_n_columns = n_columns;
3885 filter->priv->modify_types = g_new0 (GType, n_columns);
3886 memcpy (dest: filter->priv->modify_types, src: types, n: sizeof (GType) * n_columns);
3887 filter->priv->modify_func = func;
3888 filter->priv->modify_data = data;
3889 filter->priv->modify_destroy = destroy;
3890
3891 filter->priv->modify_func_set = TRUE;
3892}
3893
3894/**
3895 * gtk_tree_model_filter_set_visible_column:
3896 * @filter: A `GtkTreeModelFilter`
3897 * @column: A `int` which is the column containing the visible information
3898 *
3899 * Sets @column of the child_model to be the column where @filter should
3900 * look for visibility information. @columns should be a column of type
3901 * %G_TYPE_BOOLEAN, where %TRUE means that a row is visible, and %FALSE
3902 * if not.
3903 *
3904 * Note that gtk_tree_model_filter_set_visible_func() or
3905 * gtk_tree_model_filter_set_visible_column() can only be called
3906 * once for a given filter model.
3907 */
3908void
3909gtk_tree_model_filter_set_visible_column (GtkTreeModelFilter *filter,
3910 int column)
3911{
3912 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
3913 g_return_if_fail (column >= 0);
3914 g_return_if_fail (filter->priv->visible_method_set == FALSE);
3915
3916 filter->priv->visible_column = column;
3917
3918 filter->priv->visible_method_set = TRUE;
3919}
3920
3921/* conversion */
3922
3923/**
3924 * gtk_tree_model_filter_convert_child_iter_to_iter:
3925 * @filter: A `GtkTreeModelFilter`
3926 * @filter_iter: (out): An uninitialized `GtkTreeIter`
3927 * @child_iter: A valid `GtkTreeIter` pointing to a row on the child model.
3928 *
3929 * Sets @filter_iter to point to the row in @filter that corresponds to the
3930 * row pointed at by @child_iter. If @filter_iter was not set, %FALSE is
3931 * returned.
3932 *
3933 * Returns: %TRUE, if @filter_iter was set, i.e. if @child_iter is a
3934 * valid iterator pointing to a visible row in child model.
3935 */
3936gboolean
3937gtk_tree_model_filter_convert_child_iter_to_iter (GtkTreeModelFilter *filter,
3938 GtkTreeIter *filter_iter,
3939 GtkTreeIter *child_iter)
3940{
3941 gboolean ret;
3942 GtkTreePath *child_path, *path;
3943
3944 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (filter), FALSE);
3945 g_return_val_if_fail (filter->priv->child_model != NULL, FALSE);
3946 g_return_val_if_fail (filter_iter != NULL, FALSE);
3947 g_return_val_if_fail (child_iter != NULL, FALSE);
3948 g_return_val_if_fail (filter_iter != child_iter, FALSE);
3949
3950 filter_iter->stamp = 0;
3951
3952 child_path = gtk_tree_model_get_path (tree_model: filter->priv->child_model, iter: child_iter);
3953 g_return_val_if_fail (child_path != NULL, FALSE);
3954
3955 path = gtk_tree_model_filter_convert_child_path_to_path (filter,
3956 child_path);
3957 gtk_tree_path_free (path: child_path);
3958
3959 if (!path)
3960 return FALSE;
3961
3962 ret = gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), iter: filter_iter, path);
3963 gtk_tree_path_free (path);
3964
3965 return ret;
3966}
3967
3968/**
3969 * gtk_tree_model_filter_convert_iter_to_child_iter:
3970 * @filter: A `GtkTreeModelFilter`
3971 * @child_iter: (out): An uninitialized `GtkTreeIter`
3972 * @filter_iter: A valid `GtkTreeIter` pointing to a row on @filter.
3973 *
3974 * Sets @child_iter to point to the row pointed to by @filter_iter.
3975 */
3976void
3977gtk_tree_model_filter_convert_iter_to_child_iter (GtkTreeModelFilter *filter,
3978 GtkTreeIter *child_iter,
3979 GtkTreeIter *filter_iter)
3980{
3981 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
3982 g_return_if_fail (filter->priv->child_model != NULL);
3983 g_return_if_fail (child_iter != NULL);
3984 g_return_if_fail (filter_iter != NULL);
3985 g_return_if_fail (filter_iter->stamp == filter->priv->stamp);
3986 g_return_if_fail (filter_iter != child_iter);
3987
3988 if (GTK_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
3989 {
3990 *child_iter = FILTER_ELT (filter_iter->user_data2)->iter;
3991 }
3992 else
3993 {
3994 GtkTreePath *path;
3995 gboolean valid = FALSE;
3996
3997 path = gtk_tree_model_filter_elt_get_path (level: filter_iter->user_data,
3998 elt: filter_iter->user_data2,
3999 root: filter->priv->virtual_root);
4000 valid = gtk_tree_model_get_iter (tree_model: filter->priv->child_model, iter: child_iter,
4001 path);
4002 gtk_tree_path_free (path);
4003
4004 g_return_if_fail (valid == TRUE);
4005 }
4006}
4007
4008/* The path returned can only be used internally in the filter model. */
4009static GtkTreePath *
4010gtk_real_tree_model_filter_convert_child_path_to_path (GtkTreeModelFilter *filter,
4011 GtkTreePath *child_path,
4012 gboolean build_levels,
4013 gboolean fetch_children)
4014{
4015 int *child_indices;
4016 GtkTreePath *retval;
4017 GtkTreePath *real_path;
4018 FilterLevel *level;
4019 FilterElt *tmp;
4020 int i;
4021
4022 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (filter), NULL);
4023 g_return_val_if_fail (filter->priv->child_model != NULL, NULL);
4024 g_return_val_if_fail (child_path != NULL, NULL);
4025
4026 if (!filter->priv->virtual_root)
4027 real_path = gtk_tree_path_copy (path: child_path);
4028 else
4029 real_path = gtk_tree_model_filter_remove_root (src: child_path,
4030 root: filter->priv->virtual_root);
4031
4032 if (!real_path)
4033 return NULL;
4034
4035 retval = gtk_tree_path_new ();
4036 child_indices = gtk_tree_path_get_indices (path: real_path);
4037
4038 if (filter->priv->root == NULL && build_levels)
4039 gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
4040 level = FILTER_LEVEL (filter->priv->root);
4041
4042 for (i = 0; i < gtk_tree_path_get_depth (path: real_path); i++)
4043 {
4044 GSequenceIter *siter;
4045 gboolean found_child = FALSE;
4046
4047 if (!level)
4048 {
4049 gtk_tree_path_free (path: real_path);
4050 gtk_tree_path_free (path: retval);
4051 return NULL;
4052 }
4053
4054 tmp = lookup_elt_with_offset (seq: level->seq, offset: child_indices[i], ret_siter: &siter);
4055 if (tmp)
4056 {
4057 gtk_tree_path_append_index (path: retval, index_: g_sequence_iter_get_position (iter: siter));
4058 if (!tmp->children && build_levels)
4059 gtk_tree_model_filter_build_level (filter, parent_level: level, parent_elt: tmp, FALSE);
4060 level = tmp->children;
4061 found_child = TRUE;
4062 }
4063
4064 if (!found_child && fetch_children)
4065 {
4066 int j;
4067
4068 tmp = gtk_tree_model_filter_fetch_child (filter, level,
4069 offset: child_indices[i],
4070 index: &j);
4071
4072 /* didn't find the child, let's try to bring it back */
4073 if (!tmp || tmp->offset != child_indices[i])
4074 {
4075 /* not there */
4076 gtk_tree_path_free (path: real_path);
4077 gtk_tree_path_free (path: retval);
4078 return NULL;
4079 }
4080
4081 gtk_tree_path_append_index (path: retval, index_: j);
4082 if (!tmp->children && build_levels)
4083 gtk_tree_model_filter_build_level (filter, parent_level: level, parent_elt: tmp, FALSE);
4084 level = tmp->children;
4085 found_child = TRUE;
4086 }
4087 else if (!found_child && !fetch_children)
4088 {
4089 /* no path */
4090 gtk_tree_path_free (path: real_path);
4091 gtk_tree_path_free (path: retval);
4092 return NULL;
4093 }
4094 }
4095
4096 gtk_tree_path_free (path: real_path);
4097 return retval;
4098}
4099
4100/**
4101 * gtk_tree_model_filter_convert_child_path_to_path:
4102 * @filter: A `GtkTreeModelFilter`
4103 * @child_path: A `GtkTreePath` to convert.
4104 *
4105 * Converts @child_path to a path relative to @filter. That is, @child_path
4106 * points to a path in the child model. The rerturned path will point to the
4107 * same row in the filtered model. If @child_path isn’t a valid path on the
4108 * child model or points to a row which is not visible in @filter, then %NULL
4109 * is returned.
4110 *
4111 * Returns: (nullable) (transfer full): A newly allocated `GtkTreePath`
4112 */
4113GtkTreePath *
4114gtk_tree_model_filter_convert_child_path_to_path (GtkTreeModelFilter *filter,
4115 GtkTreePath *child_path)
4116{
4117 GtkTreeIter iter;
4118 GtkTreePath *path;
4119
4120 /* this function does the sanity checks */
4121 path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
4122 child_path,
4123 TRUE,
4124 TRUE);
4125
4126 if (!path)
4127 return NULL;
4128
4129 /* get a new path which only takes visible nodes into account.
4130 * -- if this gives any performance issues, we can write a special
4131 * version of convert_child_path_to_path immediately returning
4132 * a visible-nodes-only path.
4133 */
4134 gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (filter), iter: &iter, path);
4135
4136 gtk_tree_path_free (path);
4137 path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter: &iter);
4138
4139 return path;
4140}
4141
4142/**
4143 * gtk_tree_model_filter_convert_path_to_child_path:
4144 * @filter: A `GtkTreeModelFilter`
4145 * @filter_path: A `GtkTreePath` to convert.
4146 *
4147 * Converts @filter_path to a path on the child model of @filter. That is,
4148 * @filter_path points to a location in @filter. The returned path will
4149 * point to the same location in the model not being filtered. If @filter_path
4150 * does not point to a location in the child model, %NULL is returned.
4151 *
4152 * Returns: (nullable) (transfer full): A newly allocated `GtkTreePath`
4153 */
4154GtkTreePath *
4155gtk_tree_model_filter_convert_path_to_child_path (GtkTreeModelFilter *filter,
4156 GtkTreePath *filter_path)
4157{
4158 int *filter_indices;
4159 GtkTreePath *retval;
4160 FilterLevel *level;
4161 int i;
4162
4163 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (filter), NULL);
4164 g_return_val_if_fail (filter->priv->child_model != NULL, NULL);
4165 g_return_val_if_fail (filter_path != NULL, NULL);
4166
4167 /* convert path */
4168 retval = gtk_tree_path_new ();
4169 filter_indices = gtk_tree_path_get_indices (path: filter_path);
4170 if (!filter->priv->root)
4171 gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
4172 level = FILTER_LEVEL (filter->priv->root);
4173
4174 for (i = 0; i < gtk_tree_path_get_depth (path: filter_path); i++)
4175 {
4176 FilterElt *elt;
4177 GSequenceIter *siter;
4178
4179 if (!level)
4180 {
4181 gtk_tree_path_free (path: retval);
4182 return NULL;
4183 }
4184
4185 siter = g_sequence_get_iter_at_pos (seq: level->visible_seq, pos: filter_indices[i]);
4186 if (g_sequence_iter_is_end (iter: siter))
4187 {
4188 gtk_tree_path_free (path: retval);
4189 return NULL;
4190 }
4191
4192 elt = GET_ELT (siter);
4193 g_assert (elt);
4194 if (elt->children == NULL)
4195 gtk_tree_model_filter_build_level (filter, parent_level: level, parent_elt: elt, FALSE);
4196
4197 gtk_tree_path_append_index (path: retval, index_: elt->offset);
4198 level = elt->children;
4199 }
4200
4201 /* apply vroot */
4202
4203 if (filter->priv->virtual_root)
4204 {
4205 GtkTreePath *real_retval;
4206
4207 real_retval = gtk_tree_model_filter_add_root (src: retval,
4208 root: filter->priv->virtual_root);
4209 gtk_tree_path_free (path: retval);
4210
4211 return real_retval;
4212 }
4213
4214 return retval;
4215}
4216
4217static gboolean
4218gtk_tree_model_filter_refilter_helper (GtkTreeModel *model,
4219 GtkTreePath *path,
4220 GtkTreeIter *iter,
4221 gpointer data)
4222{
4223 /* evil, don't try this at home, but certainly speeds things up */
4224 gtk_tree_model_filter_row_changed (c_model: model, c_path: path, c_iter: iter, data);
4225
4226 return FALSE;
4227}
4228
4229/**
4230 * gtk_tree_model_filter_refilter:
4231 * @filter: A `GtkTreeModelFilter`
4232 *
4233 * Emits ::row_changed for each row in the child model, which causes
4234 * the filter to re-evaluate whether a row is visible or not.
4235 */
4236void
4237gtk_tree_model_filter_refilter (GtkTreeModelFilter *filter)
4238{
4239 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
4240
4241 /* S L O W */
4242 gtk_tree_model_foreach (model: filter->priv->child_model,
4243 func: gtk_tree_model_filter_refilter_helper,
4244 user_data: filter);
4245}
4246
4247/**
4248 * gtk_tree_model_filter_clear_cache:
4249 * @filter: A `GtkTreeModelFilter`
4250 *
4251 * This function should almost never be called. It clears the @filter
4252 * of any cached iterators that haven’t been reffed with
4253 * gtk_tree_model_ref_node(). This might be useful if the child model
4254 * being filtered is static (and doesn’t change often) and there has been
4255 * a lot of unreffed access to nodes. As a side effect of this function,
4256 * all unreffed iters will be invalid.
4257 */
4258void
4259gtk_tree_model_filter_clear_cache (GtkTreeModelFilter *filter)
4260{
4261 g_return_if_fail (GTK_IS_TREE_MODEL_FILTER (filter));
4262
4263 if (filter->priv->zero_ref_count > 0)
4264 gtk_tree_model_filter_clear_cache_helper (filter,
4265 FILTER_LEVEL (filter->priv->root));
4266}
4267

source code of gtk/gtk/gtktreemodelfilter.c