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 | |
237 | typedef struct _FilterElt FilterElt; |
238 | typedef struct _FilterLevel FilterLevel; |
239 | |
240 | struct _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 | |
251 | struct _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 | |
263 | struct _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 */ |
299 | enum |
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) */ |
328 | static void gtk_tree_model_filter_tree_model_init (GtkTreeModelIface *iface); |
329 | static void gtk_tree_model_filter_drag_source_init (GtkTreeDragSourceIface *iface); |
330 | static void gtk_tree_model_filter_finalize (GObject *object); |
331 | static void gtk_tree_model_filter_set_property (GObject *object, |
332 | guint prop_id, |
333 | const GValue *value, |
334 | GParamSpec *pspec); |
335 | static void gtk_tree_model_filter_get_property (GObject *object, |
336 | guint prop_id, |
337 | GValue *value, |
338 | GParamSpec *pspec); |
339 | |
340 | /* signal handlers */ |
341 | static void gtk_tree_model_filter_row_changed (GtkTreeModel *c_model, |
342 | GtkTreePath *c_path, |
343 | GtkTreeIter *c_iter, |
344 | gpointer data); |
345 | static void gtk_tree_model_filter_row_inserted (GtkTreeModel *c_model, |
346 | GtkTreePath *c_path, |
347 | GtkTreeIter *c_iter, |
348 | gpointer data); |
349 | static void gtk_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model, |
350 | GtkTreePath *c_path, |
351 | GtkTreeIter *c_iter, |
352 | gpointer data); |
353 | static void gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model, |
354 | GtkTreePath *c_path, |
355 | gpointer data); |
356 | static 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 */ |
363 | static GtkTreeModelFlags gtk_tree_model_filter_get_flags (GtkTreeModel *model); |
364 | static int gtk_tree_model_filter_get_n_columns (GtkTreeModel *model); |
365 | static GType gtk_tree_model_filter_get_column_type (GtkTreeModel *model, |
366 | int index); |
367 | static gboolean gtk_tree_model_filter_get_iter_full (GtkTreeModel *model, |
368 | GtkTreeIter *iter, |
369 | GtkTreePath *path); |
370 | static gboolean gtk_tree_model_filter_get_iter (GtkTreeModel *model, |
371 | GtkTreeIter *iter, |
372 | GtkTreePath *path); |
373 | static GtkTreePath *gtk_tree_model_filter_get_path (GtkTreeModel *model, |
374 | GtkTreeIter *iter); |
375 | static void gtk_tree_model_filter_get_value (GtkTreeModel *model, |
376 | GtkTreeIter *iter, |
377 | int column, |
378 | GValue *value); |
379 | static gboolean gtk_tree_model_filter_iter_next (GtkTreeModel *model, |
380 | GtkTreeIter *iter); |
381 | static gboolean gtk_tree_model_filter_iter_previous (GtkTreeModel *model, |
382 | GtkTreeIter *iter); |
383 | static gboolean gtk_tree_model_filter_iter_children (GtkTreeModel *model, |
384 | GtkTreeIter *iter, |
385 | GtkTreeIter *parent); |
386 | static gboolean gtk_tree_model_filter_iter_has_child (GtkTreeModel *model, |
387 | GtkTreeIter *iter); |
388 | static int gtk_tree_model_filter_iter_n_children (GtkTreeModel *model, |
389 | GtkTreeIter *iter); |
390 | static gboolean gtk_tree_model_filter_iter_nth_child (GtkTreeModel *model, |
391 | GtkTreeIter *iter, |
392 | GtkTreeIter *parent, |
393 | int n); |
394 | static gboolean gtk_tree_model_filter_iter_parent (GtkTreeModel *model, |
395 | GtkTreeIter *iter, |
396 | GtkTreeIter *child); |
397 | static void gtk_tree_model_filter_ref_node (GtkTreeModel *model, |
398 | GtkTreeIter *iter); |
399 | static void gtk_tree_model_filter_unref_node (GtkTreeModel *model, |
400 | GtkTreeIter *iter); |
401 | |
402 | /* TreeDragSource interface */ |
403 | static gboolean gtk_tree_model_filter_row_draggable (GtkTreeDragSource *drag_source, |
404 | GtkTreePath *path); |
405 | static GdkContentProvider * |
406 | gtk_tree_model_filter_drag_data_get (GtkTreeDragSource *drag_source, |
407 | GtkTreePath *path); |
408 | static gboolean gtk_tree_model_filter_drag_data_delete (GtkTreeDragSource *drag_source, |
409 | GtkTreePath *path); |
410 | |
411 | /* private functions */ |
412 | static void gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter, |
413 | FilterLevel *parent_level, |
414 | FilterElt *parent_elt, |
415 | gboolean emit_inserted); |
416 | |
417 | static 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 | |
423 | static GtkTreePath *gtk_tree_model_filter_elt_get_path (FilterLevel *level, |
424 | FilterElt *elt, |
425 | GtkTreePath *root); |
426 | |
427 | static GtkTreePath *gtk_tree_model_filter_add_root (GtkTreePath *src, |
428 | GtkTreePath *root); |
429 | static GtkTreePath *gtk_tree_model_filter_remove_root (GtkTreePath *src, |
430 | GtkTreePath *root); |
431 | |
432 | static void gtk_tree_model_filter_increment_stamp (GtkTreeModelFilter *filter); |
433 | |
434 | static void gtk_tree_model_filter_real_modify (GtkTreeModelFilter *self, |
435 | GtkTreeModel *child_model, |
436 | GtkTreeIter *iter, |
437 | GValue *value, |
438 | int column); |
439 | static gboolean gtk_tree_model_filter_real_visible (GtkTreeModelFilter *filter, |
440 | GtkTreeModel *child_model, |
441 | GtkTreeIter *child_iter); |
442 | static gboolean gtk_tree_model_filter_visible (GtkTreeModelFilter *filter, |
443 | GtkTreeIter *child_iter); |
444 | static void gtk_tree_model_filter_clear_cache_helper (GtkTreeModelFilter *filter, |
445 | FilterLevel *level); |
446 | |
447 | static void gtk_tree_model_filter_real_ref_node (GtkTreeModel *model, |
448 | GtkTreeIter *iter, |
449 | gboolean external); |
450 | static void gtk_tree_model_filter_real_unref_node (GtkTreeModel *model, |
451 | GtkTreeIter *iter, |
452 | gboolean external, |
453 | gboolean propagate_unref); |
454 | |
455 | static void gtk_tree_model_filter_set_model (GtkTreeModelFilter *filter, |
456 | GtkTreeModel *child_model); |
457 | static void gtk_tree_model_filter_ref_path (GtkTreeModelFilter *filter, |
458 | GtkTreePath *path); |
459 | static void gtk_tree_model_filter_unref_path (GtkTreeModelFilter *filter, |
460 | GtkTreePath *path, |
461 | int depth); |
462 | static void gtk_tree_model_filter_set_root (GtkTreeModelFilter *filter, |
463 | GtkTreePath *root); |
464 | |
465 | static 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 | |
470 | static gboolean gtk_tree_model_filter_elt_is_visible_in_target (FilterLevel *level, |
471 | FilterElt *elt); |
472 | |
473 | static FilterElt *gtk_tree_model_filter_insert_elt_in_level (GtkTreeModelFilter *filter, |
474 | GtkTreeIter *c_iter, |
475 | FilterLevel *level, |
476 | int offset, |
477 | int *index); |
478 | static FilterElt *gtk_tree_model_filter_fetch_child (GtkTreeModelFilter *filter, |
479 | FilterLevel *level, |
480 | int offset, |
481 | int *index); |
482 | static void gtk_tree_model_filter_remove_elt_from_level (GtkTreeModelFilter *filter, |
483 | FilterLevel *level, |
484 | FilterElt *elt); |
485 | static void gtk_tree_model_filter_update_children (GtkTreeModelFilter *filter, |
486 | FilterLevel *level, |
487 | FilterElt *elt); |
488 | static 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 | |
494 | G_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 | |
501 | static void |
502 | gtk_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 | |
513 | static void |
514 | gtk_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 | |
545 | static void |
546 | gtk_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 | |
565 | static void |
566 | gtk_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 | |
574 | static void |
575 | gtk_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 | |
606 | static void |
607 | gtk_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 | |
628 | static void |
629 | gtk_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 | |
652 | static FilterElt * |
653 | filter_elt_new (void) |
654 | { |
655 | return g_slice_new (FilterElt); |
656 | } |
657 | |
658 | static void |
659 | filter_elt_free (gpointer elt) |
660 | { |
661 | g_slice_free (FilterElt, elt); |
662 | } |
663 | |
664 | static int |
665 | filter_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 | |
680 | static FilterElt * |
681 | lookup_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 | |
697 | static void |
698 | increase_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 | |
708 | static void |
709 | decrease_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 | |
719 | static void |
720 | gtk_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 | |
916 | static void |
917 | gtk_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 | */ |
1027 | static void |
1028 | gtk_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 | |
1115 | static void |
1116 | gtk_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 | |
1138 | static void |
1139 | gtk_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. */ |
1150 | static GtkTreePath * |
1151 | gtk_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 | |
1183 | static GtkTreePath * |
1184 | gtk_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 | |
1198 | static GtkTreePath * |
1199 | gtk_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 | |
1225 | static void |
1226 | gtk_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 | |
1237 | static gboolean |
1238 | gtk_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 | |
1270 | static gboolean |
1271 | gtk_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 | |
1278 | static void |
1279 | gtk_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 | |
1293 | static void |
1294 | gtk_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 | |
1320 | static gboolean |
1321 | gtk_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 | */ |
1348 | static void |
1349 | gtk_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 | |
1516 | static FilterElt * |
1517 | gtk_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 | |
1555 | static FilterElt * |
1556 | gtk_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 | */ |
1620 | static void |
1621 | gtk_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 | */ |
1806 | static void |
1807 | gtk_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 | */ |
1846 | static gboolean |
1847 | find_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 */ |
1886 | static void |
1887 | gtk_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 | |
1979 | static void |
1980 | gtk_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 | |
2096 | done: |
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 | |
2107 | static void |
2108 | gtk_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 | |
2277 | done: |
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 | |
2292 | static void |
2293 | gtk_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 | |
2389 | static void |
2390 | gtk_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 | |
2434 | static void |
2435 | gtk_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 | |
2458 | static void |
2459 | gtk_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 | |
2524 | static void |
2525 | gtk_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 | |
2703 | static void |
2704 | gtk_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 */ |
2898 | static GtkTreeModelFlags |
2899 | gtk_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 | |
2914 | static int |
2915 | gtk_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 | |
2934 | static GType |
2935 | gtk_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 | */ |
2960 | static gboolean |
2961 | gtk_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 | |
3031 | static gboolean |
3032 | gtk_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 | |
3101 | static GtkTreePath * |
3102 | gtk_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 | |
3135 | static void |
3136 | gtk_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 | |
3161 | static void |
3162 | gtk_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 | |
3177 | static gboolean |
3178 | gtk_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 | |
3202 | static gboolean |
3203 | gtk_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 | |
3227 | static gboolean |
3228 | gtk_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 | |
3289 | static gboolean |
3290 | gtk_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 | |
3323 | static int |
3324 | gtk_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 | |
3366 | static gboolean |
3367 | gtk_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 | |
3399 | static gboolean |
3400 | gtk_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 | |
3425 | static void |
3426 | gtk_tree_model_filter_ref_node (GtkTreeModel *model, |
3427 | GtkTreeIter *iter) |
3428 | { |
3429 | gtk_tree_model_filter_real_ref_node (model, iter, TRUE); |
3430 | } |
3431 | |
3432 | static void |
3433 | gtk_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 | |
3493 | static void |
3494 | gtk_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 | |
3500 | static void |
3501 | gtk_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 */ |
3572 | static gboolean |
3573 | gtk_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 | |
3590 | static GdkContentProvider * |
3591 | gtk_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 | |
3608 | static gboolean |
3609 | gtk_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 */ |
3627 | static void |
3628 | gtk_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 | |
3689 | static void |
3690 | gtk_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 | |
3710 | static void |
3711 | gtk_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 | |
3736 | static void |
3737 | gtk_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 | */ |
3764 | GtkTreeModel * |
3765 | gtk_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 | */ |
3784 | GtkTreeModel * |
3785 | gtk_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 | */ |
3835 | void |
3836 | gtk_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 | */ |
3872 | void |
3873 | gtk_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 | */ |
3908 | void |
3909 | gtk_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 | */ |
3936 | gboolean |
3937 | gtk_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 | */ |
3976 | void |
3977 | gtk_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. */ |
4009 | static GtkTreePath * |
4010 | gtk_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 | */ |
4113 | GtkTreePath * |
4114 | gtk_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 | */ |
4154 | GtkTreePath * |
4155 | gtk_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 | |
4217 | static gboolean |
4218 | gtk_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 | */ |
4236 | void |
4237 | gtk_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 | */ |
4258 | void |
4259 | gtk_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 | |