]> Pileus Git - ~andy/gtk/blob - gtk/tests/filtermodel.c
Update filtermodel ref count unit tests to new cache depth
[~andy/gtk] / gtk / tests / filtermodel.c
1 /* Extensive GtkTreeModelFilter tests.
2  * Copyright (C) 2009,2011  Kristian Rietveld  <kris@gtk.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <gtk/gtk.h>
21
22 #include "treemodel.h"
23 #include "gtktreemodelrefcount.h"
24
25 /* Left to do:
26  *   - Proper coverage checking to see if the unit tests cover
27  *     all possible cases.
28  *   - Check if the iterator stamp is incremented at the correct times.
29  */
30
31
32 /*
33  * Model creation
34  */
35
36 #define LEVEL_LENGTH 5
37
38 static void
39 create_tree_store_set_values (GtkTreeStore *store,
40                               GtkTreeIter  *iter,
41                               gboolean      visible)
42 {
43   GtkTreePath *path;
44   gchar *path_string;
45
46   path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
47   path_string = gtk_tree_path_to_string (path);
48
49   gtk_tree_store_set (store, iter,
50                       0, path_string,
51                       1, visible,
52                       -1);
53
54   gtk_tree_path_free (path);
55   g_free (path_string);
56 }
57
58 static void
59 create_tree_store_recurse (int           depth,
60                            GtkTreeStore *store,
61                            GtkTreeIter  *parent,
62                            gboolean      visible)
63 {
64   int i;
65
66   for (i = 0; i < LEVEL_LENGTH; i++)
67     {
68       GtkTreeIter iter;
69
70       gtk_tree_store_insert (store, &iter, parent, i);
71       create_tree_store_set_values (store, &iter, visible);
72
73       if (depth > 0)
74         create_tree_store_recurse (depth - 1, store, &iter, visible);
75     }
76 }
77
78 static GtkTreeStore *
79 create_tree_store (int      depth,
80                    gboolean visible)
81 {
82   GtkTreeStore *store;
83
84   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
85
86   create_tree_store_recurse (depth, store, NULL, visible);
87
88   return store;
89 }
90
91 /*
92  * Fixture
93  */
94
95 typedef struct
96 {
97   GtkWidget *tree_view;
98
99   GtkTreeStore *store;
100   GtkTreeModelFilter *filter;
101
102   SignalMonitor *monitor;
103
104   guint block_signals : 1;
105 } FilterTest;
106
107
108 static void
109 filter_test_store_signal (FilterTest *fixture)
110 {
111   if (fixture->block_signals)
112     g_signal_stop_emission_by_name (fixture->store, "row-changed");
113 }
114
115
116 static void
117 filter_test_setup_generic (FilterTest    *fixture,
118                            gconstpointer  test_data,
119                            int            depth,
120                            gboolean       empty,
121                            gboolean       unfiltered)
122 {
123   const GtkTreePath *vroot = test_data;
124   GtkTreeModel *filter;
125
126   fixture->store = create_tree_store (depth, !empty);
127
128   g_signal_connect_swapped (fixture->store, "row-changed",
129                             G_CALLBACK (filter_test_store_signal), fixture);
130
131   /* Please forgive me for casting const away. */
132   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture->store),
133                                       (GtkTreePath *)vroot);
134   fixture->filter = GTK_TREE_MODEL_FILTER (filter);
135
136   if (!unfiltered)
137     gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
138
139   /* We need a tree view that's listening to get ref counting from that
140    * side.
141    */
142   fixture->tree_view = gtk_tree_view_new_with_model (filter);
143
144   fixture->monitor = signal_monitor_new (filter);
145 }
146
147 static void
148 filter_test_setup_expand_root (FilterTest *fixture)
149 {
150   int i;
151   GtkTreePath *path;
152
153   path = gtk_tree_path_new_from_indices (0, -1);
154
155   for (i = 0; i < LEVEL_LENGTH; i++)
156     {
157       gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view),
158                                 path, FALSE);
159       gtk_tree_path_next (path);
160     }
161   gtk_tree_path_free (path);
162 }
163
164 static void
165 filter_test_setup (FilterTest    *fixture,
166                    gconstpointer  test_data)
167 {
168   filter_test_setup_generic (fixture, test_data, 3, FALSE, FALSE);
169 }
170
171 static void
172 filter_test_setup_empty (FilterTest    *fixture,
173                          gconstpointer  test_data)
174 {
175   filter_test_setup_generic (fixture, test_data, 3, TRUE, FALSE);
176 }
177
178 static void
179 filter_test_setup_unfiltered (FilterTest    *fixture,
180                               gconstpointer  test_data)
181 {
182   filter_test_setup_generic (fixture, test_data, 3, FALSE, TRUE);
183 }
184
185 static void
186 filter_test_setup_unfiltered_root_expanded (FilterTest    *fixture,
187                                             gconstpointer  test_data)
188 {
189   filter_test_setup_unfiltered (fixture, test_data);
190   filter_test_setup_expand_root (fixture);
191 }
192
193 static void
194 filter_test_setup_empty_unfiltered (FilterTest    *fixture,
195                                     gconstpointer  test_data)
196 {
197   filter_test_setup_generic (fixture, test_data, 3, TRUE, TRUE);
198 }
199
200 static void
201 filter_test_setup_empty_unfiltered_root_expanded (FilterTest    *fixture,
202                                                   gconstpointer  test_data)
203 {
204   filter_test_setup_empty_unfiltered (fixture, test_data);
205   filter_test_setup_expand_root (fixture);
206 }
207
208 static GtkTreePath *
209 strip_virtual_root (GtkTreePath *path,
210                     GtkTreePath *root_path)
211 {
212   GtkTreePath *real_path;
213
214   if (root_path)
215     {
216       int j;
217       int depth = gtk_tree_path_get_depth (path);
218       int root_depth = gtk_tree_path_get_depth (root_path);
219
220       real_path = gtk_tree_path_new ();
221
222       for (j = 0; j < depth - root_depth; j++)
223         gtk_tree_path_append_index (real_path,
224                                     gtk_tree_path_get_indices (path)[root_depth + j]);
225     }
226   else
227     real_path = gtk_tree_path_copy (path);
228
229   return real_path;
230 }
231
232 static int
233 count_visible (FilterTest  *fixture,
234                GtkTreePath *store_path)
235 {
236   int i;
237   int n_visible = 0;
238   GtkTreeIter iter;
239
240   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
241                            &iter, store_path);
242
243   for (i = 0; i < LEVEL_LENGTH; i++)
244     {
245       gboolean visible;
246
247       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store), &iter,
248                           1, &visible,
249                           -1);
250
251       if (visible)
252         n_visible++;
253     }
254
255   return n_visible;
256 }
257
258 static void
259 filter_test_append_refilter_signals_recurse (FilterTest  *fixture,
260                                              GtkTreePath *store_path,
261                                              GtkTreePath *filter_path,
262                                              int          depth,
263                                              GtkTreePath *root_path)
264 {
265   int i;
266   int rows_deleted = 0;
267   GtkTreeIter iter;
268
269   gtk_tree_path_down (store_path);
270   gtk_tree_path_down (filter_path);
271
272   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
273                            &iter, store_path);
274
275   for (i = 0; i < LEVEL_LENGTH; i++)
276     {
277       gboolean visible;
278       GtkTreePath *real_path;
279
280       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store), &iter,
281                           1, &visible,
282                           -1);
283
284       if (root_path &&
285           (!gtk_tree_path_is_descendant (store_path, root_path)
286            || !gtk_tree_path_compare (store_path, root_path)))
287         {
288           if (!gtk_tree_path_compare (store_path, root_path))
289             {
290               if (depth > 1
291                   && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
292                                                     &iter))
293                 {
294                   GtkTreePath *store_copy;
295                   GtkTreePath *filter_copy;
296
297                   store_copy = gtk_tree_path_copy (store_path);
298                   filter_copy = gtk_tree_path_copy (filter_path);
299                   filter_test_append_refilter_signals_recurse (fixture,
300                                                                store_copy,
301                                                                filter_copy,
302                                                                depth - 1,
303                                                                root_path);
304                   gtk_tree_path_free (store_copy);
305                   gtk_tree_path_free (filter_copy);
306                 }
307             }
308
309           gtk_tree_path_next (store_path);
310           gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
311
312           if (visible)
313             gtk_tree_path_next (filter_path);
314
315           continue;
316         }
317
318       real_path = strip_virtual_root (filter_path, root_path);
319
320       if (visible)
321         {
322           /* This row will be inserted */
323           signal_monitor_append_signal_path (fixture->monitor, ROW_CHANGED,
324                                              real_path);
325
326           if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
327                                              &iter))
328             {
329               signal_monitor_append_signal_path (fixture->monitor,
330                                                  ROW_HAS_CHILD_TOGGLED,
331                                                  real_path);
332
333               if (depth > 1)
334                 {
335                   GtkTreePath *store_copy;
336                   GtkTreePath *filter_copy;
337
338                   store_copy = gtk_tree_path_copy (store_path);
339                   filter_copy = gtk_tree_path_copy (filter_path);
340                   filter_test_append_refilter_signals_recurse (fixture,
341                                                                store_copy,
342                                                                filter_copy,
343                                                                depth - 1,
344                                                                root_path);
345                   gtk_tree_path_free (store_copy);
346                   gtk_tree_path_free (filter_copy);
347                 }
348               else if (depth == 1)
349                 {
350                   GtkTreePath *tmp_path;
351
352                   /* If all child rows are invisible, then the last row to
353                    * become invisible will emit row-has-child-toggled on the
354                    * parent.
355                    */
356
357                   tmp_path = gtk_tree_path_copy (store_path);
358                   gtk_tree_path_append_index (tmp_path, 0);
359
360                   if (count_visible (fixture, tmp_path) == 0)
361                     signal_monitor_append_signal_path (fixture->monitor,
362                                                        ROW_HAS_CHILD_TOGGLED,
363                                                        real_path);
364
365                   gtk_tree_path_free (tmp_path);
366                 }
367             }
368
369           gtk_tree_path_next (filter_path);
370         }
371       else
372         {
373           /* This row will be deleted */
374           rows_deleted++;
375           signal_monitor_append_signal_path (fixture->monitor, ROW_DELETED,
376                                              real_path);
377         }
378
379       gtk_tree_path_free (real_path);
380
381       gtk_tree_path_next (store_path);
382       gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
383     }
384
385   if (rows_deleted == LEVEL_LENGTH
386       && gtk_tree_path_get_depth (filter_path) > 1)
387     {
388       GtkTreePath *real_path;
389
390       gtk_tree_path_up (store_path);
391       gtk_tree_path_up (filter_path);
392
393       /* A row-has-child-toggled will be emitted on the parent */
394       if (!root_path
395           || (root_path
396               && gtk_tree_path_is_descendant (store_path, root_path)
397               && gtk_tree_path_compare (store_path, root_path)))
398         {
399           real_path = strip_virtual_root (filter_path, root_path);
400           signal_monitor_append_signal_path (fixture->monitor,
401                                              ROW_HAS_CHILD_TOGGLED,
402                                              real_path);
403
404           gtk_tree_path_free (real_path);
405         }
406     }
407 }
408
409 static void
410 filter_test_append_refilter_signals (FilterTest *fixture,
411                                      int         depth)
412 {
413   /* A special function that walks the tree store like the
414    * model validation functions below.
415    */
416   GtkTreePath *path;
417   GtkTreePath *filter_path;
418
419   path = gtk_tree_path_new ();
420   filter_path = gtk_tree_path_new ();
421   filter_test_append_refilter_signals_recurse (fixture,
422                                                path,
423                                                filter_path,
424                                                depth,
425                                                NULL);
426   gtk_tree_path_free (path);
427   gtk_tree_path_free (filter_path);
428 }
429
430 static void
431 filter_test_append_refilter_signals_with_vroot (FilterTest  *fixture,
432                                                 int          depth,
433                                                 GtkTreePath *root_path)
434 {
435   /* A special function that walks the tree store like the
436    * model validation functions below.
437    */
438   GtkTreePath *path;
439   GtkTreePath *filter_path;
440
441   path = gtk_tree_path_new ();
442   filter_path = gtk_tree_path_new ();
443   filter_test_append_refilter_signals_recurse (fixture,
444                                                path,
445                                                filter_path,
446                                                depth,
447                                                root_path);
448   gtk_tree_path_free (path);
449   gtk_tree_path_free (filter_path);
450 }
451
452 static void
453 filter_test_enable_filter (FilterTest *fixture)
454 {
455   gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
456   gtk_tree_model_filter_refilter (fixture->filter);
457 }
458
459 static void
460 filter_test_block_signals (FilterTest *fixture)
461 {
462   fixture->block_signals = TRUE;
463 }
464
465 static void
466 filter_test_unblock_signals (FilterTest *fixture)
467 {
468   fixture->block_signals = FALSE;
469 }
470
471 static void
472 filter_test_teardown (FilterTest    *fixture,
473                       gconstpointer  test_data)
474 {
475   signal_monitor_free (fixture->monitor);
476
477   gtk_widget_destroy (fixture->tree_view);
478
479   g_object_unref (fixture->filter);
480   g_object_unref (fixture->store);
481 }
482
483 /*
484  * Model structure validation
485  */
486
487 static void
488 check_filter_model_recurse (FilterTest  *fixture,
489                             GtkTreePath *store_parent_path,
490                             GtkTreePath *filter_parent_path)
491 {
492   int i;
493   GtkTreeIter store_iter;
494   GtkTreeIter filter_iter;
495   gboolean store_has_next, filter_has_next;
496
497   gtk_tree_path_down (store_parent_path);
498   gtk_tree_path_down (filter_parent_path);
499
500   store_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
501                                             &store_iter, store_parent_path);
502   filter_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->filter),
503                                              &filter_iter, filter_parent_path);
504
505   for (i = 0; i < LEVEL_LENGTH; i++)
506     {
507       gboolean visible;
508
509       g_return_if_fail (store_has_next == TRUE);
510
511       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
512                           &store_iter,
513                           1, &visible,
514                           -1);
515
516       if (visible)
517         {
518           GtkTreePath *tmp;
519           gchar *filter_str, *store_str;
520
521           g_return_if_fail (filter_has_next == TRUE);
522
523           /* Verify path */
524           tmp = gtk_tree_model_get_path (GTK_TREE_MODEL (fixture->filter),
525                                          &filter_iter);
526           g_return_if_fail (gtk_tree_path_compare (tmp, filter_parent_path) == 0);
527
528           /* Verify model content */
529           gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
530                               &store_iter,
531                               0, &store_str,
532                               -1);
533           gtk_tree_model_get (GTK_TREE_MODEL (fixture->filter),
534                               &filter_iter,
535                               0, &filter_str,
536                               -1);
537
538           g_return_if_fail (g_strcmp0 (store_str, filter_str) == 0);
539
540           g_free (store_str);
541           g_free (filter_str);
542
543           if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->filter),
544                                              &filter_iter))
545             {
546               g_return_if_fail (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store), &store_iter));
547
548               check_filter_model_recurse (fixture,
549                                           gtk_tree_path_copy (store_parent_path),
550                                           tmp);
551             }
552           else
553             /* Only when we do not recurse we need to free tmp */
554             gtk_tree_path_free (tmp);
555
556           gtk_tree_path_next (filter_parent_path);
557           filter_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->filter), &filter_iter);
558         }
559
560       gtk_tree_path_next (store_parent_path);
561       store_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &store_iter);
562     }
563
564   /* Both models should have no more content! */
565   g_return_if_fail (store_has_next == FALSE);
566   g_return_if_fail (filter_has_next == FALSE);
567
568   gtk_tree_path_free (store_parent_path);
569   gtk_tree_path_free (filter_parent_path);
570 }
571
572 static void
573 check_filter_model (FilterTest *fixture)
574 {
575   GtkTreePath *path;
576
577   if (fixture->monitor)
578     signal_monitor_assert_is_empty (fixture->monitor);
579
580   path = gtk_tree_path_new ();
581
582   check_filter_model_recurse (fixture, path, gtk_tree_path_copy (path));
583 }
584
585 static void
586 check_filter_model_with_root (FilterTest  *fixture,
587                               GtkTreePath *path)
588 {
589   if (fixture->monitor)
590     signal_monitor_assert_is_empty (fixture->monitor);
591
592   check_filter_model_recurse (fixture,
593                               gtk_tree_path_copy (path),
594                               gtk_tree_path_new ());
595 }
596
597 /* Helpers */
598
599 static void
600 check_level_length (GtkTreeModelFilter *filter,
601                     const gchar        *level,
602                     const int           expected_length)
603 {
604   if (!level)
605     {
606       int model_length;
607
608       model_length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), NULL);
609       g_assert_cmpint (model_length, ==, expected_length);
610     }
611   else
612     {
613       int model_length;
614       gboolean retrieved_iter = FALSE;
615       GtkTreeIter iter;
616
617       retrieved_iter = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (filter),
618                                                             &iter, level);
619       g_return_if_fail (retrieved_iter);
620       model_length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), &iter);
621       g_assert_cmpint (model_length, ==, expected_length);
622     }
623 }
624
625 static void
626 set_path_visibility (FilterTest  *fixture,
627                      const gchar *path,
628                      gboolean     visible)
629 {
630   GtkTreeIter store_iter;
631
632   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
633                                        &store_iter, path);
634   gtk_tree_store_set (fixture->store, &store_iter,
635                       1, visible,
636                       -1);
637 }
638
639 #if 0
640 static void
641 insert_path_with_visibility (FilterTest  *fixture,
642                              const gchar *path_string,
643                              gboolean     visible)
644 {
645   int position;
646   GtkTreePath *path;
647   GtkTreeIter parent, iter;
648
649   path = gtk_tree_path_new_from_string (path_string);
650   position = gtk_tree_path_get_indices (path)[gtk_tree_path_get_depth (path)];
651   gtk_tree_path_up (path);
652
653   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &parent, path))
654     {
655       gtk_tree_store_insert (fixture->store, &iter, &parent, position);
656       create_tree_store_set_values (fixture->store, &iter, visible);
657     }
658   gtk_tree_path_free (path);
659 }
660 #endif
661
662 /*
663  * The actual tests.
664  */
665
666 static void
667 verify_test_suite (FilterTest    *fixture,
668                    gconstpointer  user_data)
669 {
670   check_filter_model (fixture);
671 }
672
673 static void
674 verify_test_suite_vroot (FilterTest    *fixture,
675                          gconstpointer  user_data)
676 {
677   check_filter_model_with_root (fixture, (GtkTreePath *)user_data);
678 }
679
680
681 static void
682 filled_hide_root_level (FilterTest    *fixture,
683                         gconstpointer  user_data)
684 {
685   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
686   set_path_visibility (fixture, "2", FALSE);
687   check_filter_model (fixture);
688   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
689
690   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
691   set_path_visibility (fixture, "0", FALSE);
692   check_filter_model (fixture);
693   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
694
695   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
696   set_path_visibility (fixture, "4", FALSE);
697   check_filter_model (fixture);
698   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
699
700
701   /* Hide remaining */
702   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
703   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
704
705   set_path_visibility (fixture, "1", FALSE);
706   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
707
708   set_path_visibility (fixture, "3", FALSE);
709   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 5);
710
711   check_filter_model (fixture);
712
713   /* Show some */
714   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
715   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
716   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
717   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
718
719   set_path_visibility (fixture, "1", TRUE);
720   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
721
722   set_path_visibility (fixture, "3", TRUE);
723   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
724
725   check_filter_model (fixture);
726 }
727
728 static void
729 filled_hide_child_levels (FilterTest    *fixture,
730                           gconstpointer  user_data)
731 {
732   set_path_visibility (fixture, "0:2", FALSE);
733   check_filter_model (fixture);
734   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
735   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
736
737   set_path_visibility (fixture, "0:4", FALSE);
738   check_filter_model (fixture);
739   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
740   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
741
742   set_path_visibility (fixture, "0:4:3", FALSE);
743   check_filter_model (fixture);
744   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
745   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
746
747   set_path_visibility (fixture, "0:4:0", FALSE);
748   set_path_visibility (fixture, "0:4:1", FALSE);
749   set_path_visibility (fixture, "0:4:2", FALSE);
750   set_path_visibility (fixture, "0:4:4", FALSE);
751   check_filter_model (fixture);
752   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
753   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
754
755   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
756   set_path_visibility (fixture, "0:4", TRUE);
757   check_filter_model (fixture);
758   check_level_length (fixture->filter, "0:3", 0);
759
760   set_path_visibility (fixture, "0:2", TRUE);
761   check_filter_model (fixture);
762   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
763   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
764   check_level_length (fixture->filter, "0:4", 0);
765
766   /* Once 0:4:0 got inserted, 0:4 became a parent.  Because 0:4 is
767    * not visible, not signals are emitted.
768    */
769   set_path_visibility (fixture, "0:4:2", TRUE);
770   set_path_visibility (fixture, "0:4:4", TRUE);
771   signal_monitor_assert_is_empty (fixture->monitor);
772   check_level_length (fixture->filter, "0:4", 2);
773 }
774
775 static void
776 filled_hide_child_levels_root_expanded (FilterTest    *fixture,
777                                         gconstpointer  user_data)
778 {
779   GtkTreePath *path;
780
781   path = gtk_tree_path_new_from_indices (0, -1);
782   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
783   gtk_tree_path_free (path);
784
785   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
786   set_path_visibility (fixture, "0:2", FALSE);
787   check_filter_model (fixture);
788   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
789   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
790
791   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
792   set_path_visibility (fixture, "0:4", FALSE);
793   check_filter_model (fixture);
794   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
795   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
796
797   set_path_visibility (fixture, "0:4:3", FALSE);
798   check_filter_model (fixture);
799   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
800   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
801
802   set_path_visibility (fixture, "0:4:0", FALSE);
803   set_path_visibility (fixture, "0:4:1", FALSE);
804   set_path_visibility (fixture, "0:4:2", FALSE);
805   set_path_visibility (fixture, "0:4:4", FALSE);
806   check_filter_model (fixture);
807   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
808   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
809
810   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
811   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
812   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
813   set_path_visibility (fixture, "0:4", TRUE);
814   check_filter_model (fixture);
815   check_level_length (fixture->filter, "0:3", 0);
816
817   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
818   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
819   set_path_visibility (fixture, "0:2", TRUE);
820   check_filter_model (fixture);
821   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
822   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
823   check_level_length (fixture->filter, "0:4", 0);
824
825   /* has-child-toggled for 0:4 is required.  */
826   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
827   set_path_visibility (fixture, "0:4:2", TRUE);
828   set_path_visibility (fixture, "0:4:4", TRUE);
829   signal_monitor_assert_is_empty (fixture->monitor);
830   check_level_length (fixture->filter, "0:4", 2);
831 }
832
833
834 static void
835 filled_vroot_hide_root_level (FilterTest    *fixture,
836                               gconstpointer  user_data)
837 {
838   GtkTreePath *path = (GtkTreePath *)user_data;
839
840   /* These changes do not affect the filter's root level */
841   set_path_visibility (fixture, "0", FALSE);
842   check_filter_model_with_root (fixture, path);
843   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
844   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
845
846   set_path_visibility (fixture, "4", FALSE);
847   check_filter_model_with_root (fixture, path);
848   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
849   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
850
851   /* Even though we set the virtual root parent node to FALSE,
852    * the virtual root contents remain.
853    */
854   set_path_visibility (fixture, "2", FALSE);
855   check_filter_model_with_root (fixture, path);
856   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
857   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
858
859   /* No change */
860   set_path_visibility (fixture, "1", FALSE);
861   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
862   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
863
864   set_path_visibility (fixture, "3", FALSE);
865   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
866   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
867
868   check_filter_model_with_root (fixture, path);
869
870   /* Show some */
871   set_path_visibility (fixture, "2", TRUE);
872   check_filter_model_with_root (fixture, path);
873   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
874   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
875
876   set_path_visibility (fixture, "1", TRUE);
877   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
878   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
879
880   set_path_visibility (fixture, "3", TRUE);
881   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
882   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
883
884   check_filter_model_with_root (fixture, path);
885
886   /* Now test changes in the virtual root level */
887   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
888   set_path_visibility (fixture, "2:2", FALSE);
889   check_filter_model_with_root (fixture, path);
890   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
891
892   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "3");
893   set_path_visibility (fixture, "2:4", FALSE);
894   check_filter_model_with_root (fixture, path);
895   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
896
897   set_path_visibility (fixture, "1:4", FALSE);
898   check_filter_model_with_root (fixture, path);
899   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
900
901   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "3");
902   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "3");
903   set_path_visibility (fixture, "2:4", TRUE);
904   check_filter_model_with_root (fixture, path);
905   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
906
907   set_path_visibility (fixture, "2", FALSE);
908   check_filter_model_with_root (fixture, path);
909   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
910
911   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
912   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
913   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
914   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
915   set_path_visibility (fixture, "2:0", FALSE);
916   set_path_visibility (fixture, "2:1", FALSE);
917   set_path_visibility (fixture, "2:2", FALSE);
918   set_path_visibility (fixture, "2:3", FALSE);
919   set_path_visibility (fixture, "2:4", FALSE);
920   check_filter_model_with_root (fixture, path);
921   check_level_length (fixture->filter, NULL, 0);
922
923   set_path_visibility (fixture, "2", TRUE);
924   check_filter_model_with_root (fixture, path);
925   check_level_length (fixture->filter, NULL, 0);
926
927   set_path_visibility (fixture, "1:4", FALSE);
928   check_filter_model_with_root (fixture, path);
929   check_level_length (fixture->filter, NULL, 0);
930
931   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
932   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
933   set_path_visibility (fixture, "2:4", TRUE);
934   check_filter_model_with_root (fixture, path);
935   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
936
937   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
938   set_path_visibility (fixture, "2:4", FALSE);
939   check_filter_model_with_root (fixture, path);
940   check_level_length (fixture->filter, NULL, 0);
941
942   set_path_visibility (fixture, "2", FALSE);
943   check_filter_model_with_root (fixture, path);
944   check_level_length (fixture->filter, NULL, 0);
945
946   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
947   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
948   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
949   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
950   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2");
951   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
952   set_path_visibility (fixture, "2:0", TRUE);
953   set_path_visibility (fixture, "2:1", TRUE);
954   set_path_visibility (fixture, "2:2", TRUE);
955   check_filter_model_with_root (fixture, path);
956   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
957
958   set_path_visibility (fixture, "2", TRUE);
959   check_filter_model_with_root (fixture, path);
960   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
961 }
962
963 static void
964 filled_vroot_hide_child_levels (FilterTest    *fixture,
965                                 gconstpointer  user_data)
966 {
967   GtkTreePath *path = (GtkTreePath *)user_data;
968
969   set_path_visibility (fixture, "2:0:2", FALSE);
970   check_filter_model_with_root (fixture, path);
971   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
972   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
973
974   set_path_visibility (fixture, "2:0:4", FALSE);
975   check_filter_model_with_root (fixture, path);
976   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
977   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
978
979   set_path_visibility (fixture, "2:0:4:3", FALSE);
980   check_filter_model_with_root (fixture, path);
981   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
982   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
983
984   set_path_visibility (fixture, "2:0:4:0", FALSE);
985   set_path_visibility (fixture, "2:0:4:1", FALSE);
986   set_path_visibility (fixture, "2:0:4:2", FALSE);
987   set_path_visibility (fixture, "2:0:4:4", FALSE);
988   check_filter_model_with_root (fixture, path);
989   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
990   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
991
992   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
993   set_path_visibility (fixture, "2:0:4", TRUE);
994   check_filter_model_with_root (fixture, path);
995   check_level_length (fixture->filter, "0:3", 0);
996
997   set_path_visibility (fixture, "2:0:2", TRUE);
998   check_filter_model_with_root (fixture, path);
999   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
1000   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
1001   check_level_length (fixture->filter, "0:4", 0);
1002
1003   /* Once 0:4:0 got inserted, 0:4 became a parent */
1004   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
1005   set_path_visibility (fixture, "2:0:4:2", TRUE);
1006   set_path_visibility (fixture, "2:0:4:4", TRUE);
1007   check_level_length (fixture->filter, "0:4", 2);
1008 }
1009
1010 static void
1011 filled_vroot_hide_child_levels_root_expanded (FilterTest    *fixture,
1012                                               gconstpointer  user_data)
1013 {
1014   GtkTreePath *path = (GtkTreePath *)user_data;
1015   GtkTreePath *tmp_path;
1016
1017   tmp_path = gtk_tree_path_new_from_indices (0, -1);
1018   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), tmp_path, FALSE);
1019   gtk_tree_path_free (tmp_path);
1020
1021   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
1022   set_path_visibility (fixture, "2:0:2", FALSE);
1023   check_filter_model_with_root (fixture, path);
1024   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1025   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
1026
1027   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
1028   set_path_visibility (fixture, "2:0:4", FALSE);
1029   check_filter_model_with_root (fixture, path);
1030   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1031   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1032
1033   set_path_visibility (fixture, "2:0:4:3", FALSE);
1034   check_filter_model_with_root (fixture, path);
1035   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1036   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1037
1038   set_path_visibility (fixture, "2:0:4:0", FALSE);
1039   set_path_visibility (fixture, "2:0:4:1", FALSE);
1040   set_path_visibility (fixture, "2:0:4:2", FALSE);
1041   set_path_visibility (fixture, "2:0:4:4", FALSE);
1042   check_filter_model_with_root (fixture, path);
1043   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1044   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1045
1046   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
1047   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
1048   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
1049   set_path_visibility (fixture, "2:0:4", TRUE);
1050   check_filter_model_with_root (fixture, path);
1051   check_level_length (fixture->filter, "0:3", 0);
1052
1053   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
1054   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
1055   set_path_visibility (fixture, "2:0:2", TRUE);
1056   check_filter_model_with_root (fixture, path);
1057   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
1058   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
1059   check_level_length (fixture->filter, "0:4", 0);
1060
1061   /* Once 0:4:0 got inserted, 0:4 became a parent */
1062   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
1063   set_path_visibility (fixture, "2:0:4:2", TRUE);
1064   set_path_visibility (fixture, "2:0:4:4", TRUE);
1065   check_level_length (fixture->filter, "0:4", 2);
1066 }
1067
1068 static void
1069 empty_show_nodes (FilterTest    *fixture,
1070                   gconstpointer  user_data)
1071 {
1072   check_filter_model (fixture);
1073   check_level_length (fixture->filter, NULL, 0);
1074
1075   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1076   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1077   set_path_visibility (fixture, "3", TRUE);
1078   check_filter_model (fixture);
1079   check_level_length (fixture->filter, NULL, 1);
1080   check_level_length (fixture->filter, "0", 0);
1081
1082   set_path_visibility (fixture, "3:2:2", TRUE);
1083   check_filter_model (fixture);
1084   check_level_length (fixture->filter, NULL, 1);
1085   check_level_length (fixture->filter, "0", 0);
1086
1087   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1088   set_path_visibility (fixture, "3:2", TRUE);
1089   check_filter_model (fixture);
1090   check_level_length (fixture->filter, NULL, 1);
1091   check_level_length (fixture->filter, "0", 1);
1092   check_level_length (fixture->filter, "0:0", 1);
1093   check_level_length (fixture->filter, "0:0:0", 0);
1094
1095   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1096   set_path_visibility (fixture, "3", FALSE);
1097   check_filter_model (fixture);
1098   check_level_length (fixture->filter, NULL, 0);
1099
1100   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1101   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1102   set_path_visibility (fixture, "3:2:1", TRUE);
1103   set_path_visibility (fixture, "3", TRUE);
1104   check_filter_model (fixture);
1105   check_level_length (fixture->filter, NULL, 1);
1106   check_level_length (fixture->filter, "0", 1);
1107   check_level_length (fixture->filter, "0:0", 2);
1108   check_level_length (fixture->filter, "0:0:0", 0);
1109 }
1110
1111 static void
1112 empty_show_multiple_nodes (FilterTest    *fixture,
1113                            gconstpointer  user_data)
1114 {
1115   GtkTreeIter iter;
1116   GtkTreePath *changed_path;
1117
1118   check_filter_model (fixture);
1119   check_level_length (fixture->filter, NULL, 0);
1120
1121   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1122   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1123   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1124   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1125
1126   /* We simulate a change in visible func condition with this.  The
1127    * visibility state of multiple nodes changes at once, we emit row-changed
1128    * for these nodes (and others) after that.
1129    */
1130   filter_test_block_signals (fixture);
1131   set_path_visibility (fixture, "3", TRUE);
1132   set_path_visibility (fixture, "4", TRUE);
1133   filter_test_unblock_signals (fixture);
1134
1135   changed_path = gtk_tree_path_new ();
1136   gtk_tree_path_append_index (changed_path, 2);
1137   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1138                            &iter, changed_path);
1139   /* Invisible node - so no signals expected */
1140   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1141                               changed_path, &iter);
1142
1143   gtk_tree_path_next (changed_path);
1144   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1145   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1146                               changed_path, &iter);
1147
1148   gtk_tree_path_next (changed_path);
1149   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1150   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1151                               changed_path, &iter);
1152
1153   gtk_tree_path_free (changed_path);
1154
1155   check_filter_model (fixture);
1156   check_level_length (fixture->filter, NULL, 2);
1157   check_level_length (fixture->filter, "0", 0);
1158
1159   set_path_visibility (fixture, "3:2:2", TRUE);
1160   check_filter_model (fixture);
1161   check_level_length (fixture->filter, NULL, 2);
1162   check_level_length (fixture->filter, "0", 0);
1163
1164   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1165   set_path_visibility (fixture, "3:2", TRUE);
1166   check_filter_model (fixture);
1167   check_level_length (fixture->filter, NULL, 2);
1168   check_level_length (fixture->filter, "0", 1);
1169   check_level_length (fixture->filter, "0:0", 1);
1170   check_level_length (fixture->filter, "0:0:0", 0);
1171
1172   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1173   set_path_visibility (fixture, "3", FALSE);
1174   check_filter_model (fixture);
1175   check_level_length (fixture->filter, NULL, 1);
1176
1177   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1178   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1179   set_path_visibility (fixture, "3:2:1", TRUE);
1180   set_path_visibility (fixture, "3", TRUE);
1181   check_filter_model (fixture);
1182   check_level_length (fixture->filter, NULL, 2);
1183   check_level_length (fixture->filter, "0", 1);
1184   check_level_length (fixture->filter, "0:0", 2);
1185   check_level_length (fixture->filter, "0:0:0", 0);
1186 }
1187
1188 static void
1189 empty_vroot_show_nodes (FilterTest    *fixture,
1190                         gconstpointer  user_data)
1191 {
1192   GtkTreePath *path = (GtkTreePath *)user_data;
1193
1194   check_filter_model_with_root (fixture, path);
1195   check_level_length (fixture->filter, NULL, 0);
1196
1197   set_path_visibility (fixture, "2", TRUE);
1198   check_filter_model_with_root (fixture, path);
1199   check_level_length (fixture->filter, NULL, 0);
1200
1201   set_path_visibility (fixture, "2:2:2", TRUE);
1202   check_filter_model_with_root (fixture, path);
1203   check_level_length (fixture->filter, NULL, 0);
1204
1205   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1206   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1207   set_path_visibility (fixture, "2:2", TRUE);
1208   check_filter_model_with_root (fixture, path);
1209   check_level_length (fixture->filter, NULL, 1);
1210   check_level_length (fixture->filter, "0", 1);
1211   check_level_length (fixture->filter, "0:0", 0);
1212
1213   set_path_visibility (fixture, "3", TRUE);
1214   check_filter_model_with_root (fixture, path);
1215   check_level_length (fixture->filter, NULL, 1);
1216
1217   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1218   set_path_visibility (fixture, "2:2", FALSE);
1219   check_filter_model_with_root (fixture, path);
1220   check_level_length (fixture->filter, NULL, 0);
1221
1222   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1223   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1224   set_path_visibility (fixture, "2:2:1", TRUE);
1225   set_path_visibility (fixture, "2:2", TRUE);
1226   check_filter_model_with_root (fixture, path);
1227   check_level_length (fixture->filter, NULL, 1);
1228   check_level_length (fixture->filter, "0", 2);
1229   check_level_length (fixture->filter, "0:1", 0);
1230 }
1231
1232 static void
1233 empty_vroot_show_multiple_nodes (FilterTest    *fixture,
1234                                  gconstpointer  user_data)
1235 {
1236   GtkTreeIter iter;
1237   GtkTreePath *changed_path;
1238   GtkTreePath *path = (GtkTreePath *)user_data;
1239
1240   check_filter_model_with_root (fixture, path);
1241   check_level_length (fixture->filter, NULL, 0);
1242
1243   /* We simulate a change in visible func condition with this.  The
1244    * visibility state of multiple nodes changes at once, we emit row-changed
1245    * for these nodes (and others) after that.
1246    */
1247   filter_test_block_signals (fixture);
1248   set_path_visibility (fixture, "2", TRUE);
1249   set_path_visibility (fixture, "3", TRUE);
1250   filter_test_unblock_signals (fixture);
1251
1252   changed_path = gtk_tree_path_new ();
1253   gtk_tree_path_append_index (changed_path, 1);
1254   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1255                            &iter, changed_path);
1256   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1257                               changed_path, &iter);
1258
1259   gtk_tree_path_next (changed_path);
1260   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1261   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1262                               changed_path, &iter);
1263
1264   gtk_tree_path_next (changed_path);
1265   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1266   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1267                               changed_path, &iter);
1268
1269   gtk_tree_path_next (changed_path);
1270   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1271   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1272                               changed_path, &iter);
1273
1274   gtk_tree_path_free (changed_path);
1275
1276   check_filter_model_with_root (fixture, path);
1277   check_level_length (fixture->filter, NULL, 0);
1278
1279   set_path_visibility (fixture, "2:2:2", TRUE);
1280   check_filter_model_with_root (fixture, path);
1281   check_level_length (fixture->filter, NULL, 0);
1282
1283   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1284   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1285   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1286   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1287
1288   /* Again, we simulate a call to refilter */
1289   filter_test_block_signals (fixture);
1290   set_path_visibility (fixture, "2:2", TRUE);
1291   set_path_visibility (fixture, "2:3", TRUE);
1292   filter_test_unblock_signals (fixture);
1293
1294   changed_path = gtk_tree_path_new ();
1295   gtk_tree_path_append_index (changed_path, 2);
1296   gtk_tree_path_append_index (changed_path, 1);
1297   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1298                            &iter, changed_path);
1299   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1300                               changed_path, &iter);
1301
1302   gtk_tree_path_next (changed_path);
1303   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1304   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1305                               changed_path, &iter);
1306
1307   gtk_tree_path_next (changed_path);
1308   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1309   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1310                               changed_path, &iter);
1311
1312   gtk_tree_path_next (changed_path);
1313   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1314   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1315                               changed_path, &iter);
1316
1317   gtk_tree_path_free (changed_path);
1318
1319   check_filter_model_with_root (fixture, path);
1320   check_level_length (fixture->filter, NULL, 2);
1321   check_level_length (fixture->filter, "0", 1);
1322   check_level_length (fixture->filter, "0:0", 0);
1323
1324   set_path_visibility (fixture, "3", TRUE);
1325   check_filter_model_with_root (fixture, path);
1326   check_level_length (fixture->filter, NULL, 2);
1327
1328   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1329   set_path_visibility (fixture, "2:2", FALSE);
1330   check_filter_model_with_root (fixture, path);
1331   check_level_length (fixture->filter, NULL, 1);
1332
1333   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1334   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1335   set_path_visibility (fixture, "2:2:1", TRUE);
1336   set_path_visibility (fixture, "2:2", TRUE);
1337   check_filter_model_with_root (fixture, path);
1338   check_level_length (fixture->filter, NULL, 2);
1339   check_level_length (fixture->filter, "0", 2);
1340   check_level_length (fixture->filter, "0:1", 0);
1341 }
1342
1343
1344 static void
1345 unfiltered_hide_single (FilterTest    *fixture,
1346                         gconstpointer  user_data)
1347
1348 {
1349   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1350   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1351   set_path_visibility (fixture, "2", FALSE);
1352
1353   signal_monitor_assert_is_empty (fixture->monitor);
1354   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1355
1356   /* The view only shows the root level, so we only expect signals
1357    * for the root level.
1358    */
1359   filter_test_append_refilter_signals (fixture, 1);
1360   filter_test_enable_filter (fixture);
1361
1362   check_filter_model (fixture);
1363   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1364 }
1365
1366 static void
1367 unfiltered_hide_single_root_expanded (FilterTest    *fixture,
1368                                       gconstpointer  user_data)
1369
1370 {
1371   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1372   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1373   set_path_visibility (fixture, "2", FALSE);
1374
1375   signal_monitor_assert_is_empty (fixture->monitor);
1376   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1377
1378   filter_test_append_refilter_signals (fixture, 2);
1379   filter_test_enable_filter (fixture);
1380
1381   check_filter_model (fixture);
1382   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1383 }
1384
1385 static void
1386 unfiltered_hide_single_child (FilterTest    *fixture,
1387                               gconstpointer  user_data)
1388
1389 {
1390   /* This row is not shown, so its signal is not propagated */
1391   set_path_visibility (fixture, "2:2", FALSE);
1392
1393   signal_monitor_assert_is_empty (fixture->monitor);
1394   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1395   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1396
1397   /* The view only shows the root level, so we only expect signals
1398    * for the root level.
1399    */
1400   filter_test_append_refilter_signals (fixture, 0);
1401   filter_test_enable_filter (fixture);
1402
1403   check_filter_model (fixture);
1404   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1405   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1406 }
1407
1408 static void
1409 unfiltered_hide_single_child_root_expanded (FilterTest    *fixture,
1410                                             gconstpointer  user_data)
1411
1412 {
1413   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1414   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1415   set_path_visibility (fixture, "2:2", FALSE);
1416
1417   signal_monitor_assert_is_empty (fixture->monitor);
1418   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1419   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1420
1421   filter_test_append_refilter_signals (fixture, 2);
1422   filter_test_enable_filter (fixture);
1423
1424   check_filter_model (fixture);
1425   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1426   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1427 }
1428
1429 static void
1430 unfiltered_hide_single_multi_level (FilterTest    *fixture,
1431                                     gconstpointer  user_data)
1432
1433 {
1434   /* This row is not shown, so its signal is not propagated */
1435   set_path_visibility (fixture, "2:2:2", FALSE);
1436
1437   /* This row is not shown, so its signal is not propagated */
1438   set_path_visibility (fixture, "2:2", FALSE);
1439
1440   signal_monitor_assert_is_empty (fixture->monitor);
1441   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1442   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1443   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1444
1445   /* The view only shows the root level, so we only expect signals
1446    * for the root level.
1447    */
1448   filter_test_append_refilter_signals (fixture, 1);
1449   filter_test_enable_filter (fixture);
1450
1451   check_filter_model (fixture);
1452   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1453   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1454
1455   set_path_visibility (fixture, "2:2", TRUE);
1456
1457   check_filter_model (fixture);
1458   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1459   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1460   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1461 }
1462
1463 static void
1464 unfiltered_hide_single_multi_level_root_expanded (FilterTest    *fixture,
1465                                                   gconstpointer  user_data)
1466
1467 {
1468   /* This row is not shown, so its signal is not propagated */
1469   set_path_visibility (fixture, "2:2:2", FALSE);
1470
1471   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1472   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1473   set_path_visibility (fixture, "2:2", FALSE);
1474
1475   signal_monitor_assert_is_empty (fixture->monitor);
1476   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1477   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1478   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1479
1480   filter_test_append_refilter_signals (fixture, 2);
1481   filter_test_enable_filter (fixture);
1482
1483   check_filter_model (fixture);
1484   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1485   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1486
1487   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
1488   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1489   set_path_visibility (fixture, "2:2", TRUE);
1490
1491   check_filter_model (fixture);
1492   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1493   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1494   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1495 }
1496
1497
1498
1499 static void
1500 unfiltered_vroot_hide_single (FilterTest    *fixture,
1501                               gconstpointer  user_data)
1502
1503 {
1504   GtkTreePath *path = (GtkTreePath *)user_data;
1505
1506   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1507   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1508   set_path_visibility (fixture, "2:2", FALSE);
1509
1510   signal_monitor_assert_is_empty (fixture->monitor);
1511   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1512
1513   /* The view only shows the root level, so we only expect signals
1514    * for the root level.  (Though for the depth argument, we have to
1515    * take the virtual root into account).
1516    */
1517   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1518   filter_test_enable_filter (fixture);
1519
1520   check_filter_model_with_root (fixture, path);
1521   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1522 }
1523
1524 static void
1525 unfiltered_vroot_hide_single_child (FilterTest    *fixture,
1526                                     gconstpointer  user_data)
1527
1528 {
1529   GtkTreePath *path = (GtkTreePath *)user_data;
1530
1531   /* Not visible, so no signal will be received. */
1532   set_path_visibility (fixture, "2:2:2", FALSE);
1533
1534   signal_monitor_assert_is_empty (fixture->monitor);
1535   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1536   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1537
1538   /* The view only shows the root level, so we only expect signals
1539    * for the root level.  (Though for the depth argument, we have to
1540    * take the virtual root into account).
1541    */
1542   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1543   filter_test_enable_filter (fixture);
1544
1545   check_filter_model_with_root (fixture, path);
1546   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1547   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1548 }
1549
1550 static void
1551 unfiltered_vroot_hide_single_child_root_expanded (FilterTest    *fixture,
1552                                                   gconstpointer  user_data)
1553
1554 {
1555   GtkTreePath *path = (GtkTreePath *)user_data;
1556
1557   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1558   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1559   set_path_visibility (fixture, "2:2:2", FALSE);
1560
1561   signal_monitor_assert_is_empty (fixture->monitor);
1562   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1563   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1564
1565   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1566   filter_test_enable_filter (fixture);
1567
1568   check_filter_model_with_root (fixture, path);
1569   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1570   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1571 }
1572
1573 static void
1574 unfiltered_vroot_hide_single_multi_level (FilterTest    *fixture,
1575                                           gconstpointer  user_data)
1576
1577 {
1578   GtkTreePath *path = (GtkTreePath *)user_data;
1579
1580   /* This row is not shown, so its signal is not propagated */
1581   set_path_visibility (fixture, "2:2:2:2", FALSE);
1582
1583   /* Not shown, so no signal */
1584   set_path_visibility (fixture, "2:2:2", FALSE);
1585
1586   signal_monitor_assert_is_empty (fixture->monitor);
1587   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1588   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1589   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1590
1591   /* We only expect signals for the root level.  The depth is 2
1592    * because we have to take the virtual root into account.
1593    */
1594   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1595   filter_test_enable_filter (fixture);
1596
1597   check_filter_model_with_root (fixture, path);
1598   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1599   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1600
1601   /* Not shown, so no signal */
1602   set_path_visibility (fixture, "2:2:2", TRUE);
1603
1604   check_filter_model_with_root (fixture, path);
1605   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1606   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1607   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1608 }
1609
1610 static void
1611 unfiltered_vroot_hide_single_multi_level_root_expanded (FilterTest    *fixture,
1612                                                         gconstpointer  user_data)
1613
1614 {
1615   GtkTreePath *path = (GtkTreePath *)user_data;
1616
1617   /* This row is not shown, so its signal is not propagated */
1618   set_path_visibility (fixture, "2:2:2:2", FALSE);
1619
1620   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1621   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1622   set_path_visibility (fixture, "2:2:2", FALSE);
1623
1624   signal_monitor_assert_is_empty (fixture->monitor);
1625   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1626   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1627   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1628
1629   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1630   filter_test_enable_filter (fixture);
1631
1632   check_filter_model_with_root (fixture, path);
1633   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1634   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1635
1636   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
1637   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1638   set_path_visibility (fixture, "2:2:2", TRUE);
1639
1640   check_filter_model_with_root (fixture, path);
1641   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1642   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1643   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1644 }
1645
1646 static void
1647 unfiltered_show_single (FilterTest    *fixture,
1648                         gconstpointer  user_data)
1649
1650 {
1651   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1652   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1653   set_path_visibility (fixture, "2", TRUE);
1654
1655   signal_monitor_assert_is_empty (fixture->monitor);
1656   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1657
1658   /* We only expect signals for the root level */
1659   filter_test_append_refilter_signals (fixture, 1);
1660   filter_test_enable_filter (fixture);
1661
1662   check_filter_model (fixture);
1663   check_level_length (fixture->filter, NULL, 1);
1664 }
1665
1666 static void
1667 unfiltered_show_single_child (FilterTest    *fixture,
1668                               gconstpointer  user_data)
1669
1670 {
1671   set_path_visibility (fixture, "2:2", TRUE);
1672
1673   signal_monitor_assert_is_empty (fixture->monitor);
1674   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1675   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1676
1677   /* We only expect signals for the root level */
1678   filter_test_append_refilter_signals (fixture, 1);
1679   filter_test_enable_filter (fixture);
1680
1681   check_filter_model (fixture);
1682   check_level_length (fixture->filter, NULL, 0);
1683
1684   /* From here we are filtered, "2" in the real model is "0" in the filter
1685    * model.
1686    */
1687   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1688   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1689   set_path_visibility (fixture, "2", TRUE);
1690   signal_monitor_assert_is_empty (fixture->monitor);
1691   check_level_length (fixture->filter, NULL, 1);
1692   check_level_length (fixture->filter, "0", 1);
1693 }
1694
1695 static void
1696 unfiltered_show_single_child_root_expanded (FilterTest    *fixture,
1697                                             gconstpointer  user_data)
1698
1699 {
1700   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1701   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1702   set_path_visibility (fixture, "2:2", TRUE);
1703
1704   signal_monitor_assert_is_empty (fixture->monitor);
1705   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1706   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1707
1708   filter_test_append_refilter_signals (fixture, 2);
1709   filter_test_enable_filter (fixture);
1710
1711   check_filter_model (fixture);
1712   check_level_length (fixture->filter, NULL, 0);
1713
1714   /* From here we are filtered, "2" in the real model is "0" in the filter
1715    * model.
1716    */
1717   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1718   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1719   set_path_visibility (fixture, "2", TRUE);
1720   signal_monitor_assert_is_empty (fixture->monitor);
1721   check_level_length (fixture->filter, NULL, 1);
1722   check_level_length (fixture->filter, "0", 1);
1723 }
1724
1725 static void
1726 unfiltered_show_single_multi_level (FilterTest    *fixture,
1727                                     gconstpointer  user_data)
1728
1729 {
1730   /* The view is not showing these rows (collapsed state), so it is not
1731    * referenced.  The signal should not go through.
1732    */
1733   set_path_visibility (fixture, "2:2:2", TRUE);
1734   set_path_visibility (fixture, "2:2", TRUE);
1735
1736   signal_monitor_assert_is_empty (fixture->monitor);
1737   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1738   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1739   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1740
1741   /* We only expect signals for the first level */
1742   filter_test_append_refilter_signals (fixture, 1);
1743   filter_test_enable_filter (fixture);
1744
1745   check_filter_model (fixture);
1746   check_level_length (fixture->filter, NULL, 0);
1747
1748   /* From here we are filtered, "2" in the real model is "0" in the filter
1749    * model.
1750    */
1751   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1752   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1753   set_path_visibility (fixture, "2", TRUE);
1754   check_filter_model (fixture);
1755   check_level_length (fixture->filter, NULL, 1);
1756   check_level_length (fixture->filter, "0", 1);
1757   check_level_length (fixture->filter, "0:0", 1);
1758 }
1759
1760 static void
1761 unfiltered_show_single_multi_level_root_expanded (FilterTest    *fixture,
1762                                                   gconstpointer  user_data)
1763
1764 {
1765   /* The view is not showing this row (collapsed state), so it is not
1766    * referenced.  The signal should not go through.
1767    */
1768   set_path_visibility (fixture, "2:2:2", TRUE);
1769
1770   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1771   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1772   set_path_visibility (fixture, "2:2", TRUE);
1773
1774   signal_monitor_assert_is_empty (fixture->monitor);
1775   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1776   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1777   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1778
1779   filter_test_append_refilter_signals (fixture, 2);
1780   filter_test_enable_filter (fixture);
1781
1782   check_filter_model (fixture);
1783   check_level_length (fixture->filter, NULL, 0);
1784
1785   /* From here we are filtered, "2" in the real model is "0" in the filter
1786    * model.
1787    */
1788   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1789   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1790   set_path_visibility (fixture, "2", TRUE);
1791   check_filter_model (fixture);
1792   check_level_length (fixture->filter, NULL, 1);
1793   check_level_length (fixture->filter, "0", 1);
1794   check_level_length (fixture->filter, "0:0", 1);
1795 }
1796
1797 static void
1798 unfiltered_vroot_show_single (FilterTest    *fixture,
1799                               gconstpointer  user_data)
1800
1801 {
1802   GtkTreePath *path = (GtkTreePath *)user_data;
1803
1804   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1805   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1806   set_path_visibility (fixture, "2:2", TRUE);
1807
1808   signal_monitor_assert_is_empty (fixture->monitor);
1809   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1810
1811   /* The view only shows the root level, so the filter model only has
1812    * the first two levels cached.
1813    */
1814   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1815   filter_test_enable_filter (fixture);
1816
1817   check_filter_model_with_root (fixture, path);
1818   check_level_length (fixture->filter, NULL, 1);
1819 }
1820
1821 static void
1822 unfiltered_vroot_show_single_child (FilterTest    *fixture,
1823                                     gconstpointer  user_data)
1824
1825 {
1826   GtkTreePath *path = (GtkTreePath *)user_data;
1827
1828   set_path_visibility (fixture, "2:2:2", TRUE);
1829
1830   signal_monitor_assert_is_empty (fixture->monitor);
1831   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1832   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1833
1834   /* The view only shows the root level, so the filter model only has
1835    * the first two levels cached.
1836    */
1837   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1838   filter_test_enable_filter (fixture);
1839
1840   check_filter_model_with_root (fixture, path);
1841   check_level_length (fixture->filter, NULL, 0);
1842
1843   /* From here we are filtered, "2" in the real model is "0" in the filter
1844    * model.
1845    */
1846   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1847   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1848   set_path_visibility (fixture, "2:2", TRUE);
1849   signal_monitor_assert_is_empty (fixture->monitor);
1850   check_level_length (fixture->filter, NULL, 1);
1851   check_level_length (fixture->filter, "0", 1);
1852 }
1853
1854 static void
1855 unfiltered_vroot_show_single_child_root_expanded (FilterTest    *fixture,
1856                                                   gconstpointer  user_data)
1857
1858 {
1859   GtkTreePath *path = (GtkTreePath *)user_data;
1860
1861   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1862   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1863   set_path_visibility (fixture, "2:2:2", TRUE);
1864
1865   signal_monitor_assert_is_empty (fixture->monitor);
1866   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1867   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1868
1869   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1870   filter_test_enable_filter (fixture);
1871
1872   check_filter_model_with_root (fixture, path);
1873   check_level_length (fixture->filter, NULL, 0);
1874
1875   /* From here we are filtered, "2" in the real model is "0" in the filter
1876    * model.
1877    */
1878   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1879   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1880   set_path_visibility (fixture, "2:2", TRUE);
1881   signal_monitor_assert_is_empty (fixture->monitor);
1882   check_level_length (fixture->filter, NULL, 1);
1883   check_level_length (fixture->filter, "0", 1);
1884 }
1885
1886
1887 static void
1888 unfiltered_vroot_show_single_multi_level (FilterTest    *fixture,
1889                                           gconstpointer  user_data)
1890
1891 {
1892   GtkTreePath *path = (GtkTreePath *)user_data;
1893
1894   /* The view is not showing this row (collapsed state), so it is not
1895    * referenced.  The signal should not go through.
1896    */
1897   set_path_visibility (fixture, "2:2:2:2", TRUE);
1898
1899   set_path_visibility (fixture, "2:2:2", TRUE);
1900
1901   signal_monitor_assert_is_empty (fixture->monitor);
1902   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1903   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1904   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1905
1906   /* We only expect signals for the root level */
1907   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1908   filter_test_enable_filter (fixture);
1909
1910   check_filter_model_with_root (fixture, path);
1911   check_level_length (fixture->filter, NULL, 0);
1912
1913   /* From here we are filtered, "2" in the real model is "0" in the filter
1914    * model.
1915    */
1916   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1917   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1918   set_path_visibility (fixture, "2:2", TRUE);
1919   check_filter_model_with_root (fixture, path);
1920   check_level_length (fixture->filter, NULL, 1);
1921   check_level_length (fixture->filter, "0", 1);
1922   check_level_length (fixture->filter, "0:0", 1);
1923 }
1924
1925 static void
1926 unfiltered_vroot_show_single_multi_level_root_expanded (FilterTest    *fixture,
1927                                                         gconstpointer  user_data)
1928
1929 {
1930   GtkTreePath *path = (GtkTreePath *)user_data;
1931
1932   /* The view is not showing this row (collapsed state), so it is not
1933    * referenced.  The signal should not go through.
1934    */
1935   set_path_visibility (fixture, "2:2:2:2", TRUE);
1936
1937   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1938   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1939   set_path_visibility (fixture, "2:2:2", TRUE);
1940
1941   signal_monitor_assert_is_empty (fixture->monitor);
1942   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1943   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1944   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1945
1946   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1947   filter_test_enable_filter (fixture);
1948
1949   check_filter_model_with_root (fixture, path);
1950   check_level_length (fixture->filter, NULL, 0);
1951
1952   /* From here we are filtered, "2" in the real model is "0" in the filter
1953    * model.
1954    */
1955   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1956   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1957   set_path_visibility (fixture, "2:2", TRUE);
1958   check_filter_model_with_root (fixture, path);
1959   check_level_length (fixture->filter, NULL, 1);
1960   check_level_length (fixture->filter, "0", 1);
1961   check_level_length (fixture->filter, "0:0", 1);
1962 }
1963
1964 static void
1965 unfiltered_rows_reordered_root_level (FilterTest    *fixture,
1966                                       gconstpointer  user_data)
1967 {
1968   int order0[] = { 1, 2, 3, 4, 0 };
1969   int order1[] = { 0, 2, 1, 3, 4 };
1970   int order2[] = { 4, 0, 1, 2, 3 };
1971   GtkTreeIter iter0, iter1, iter2, iter3, iter4;
1972   GtkTreePath *path;
1973
1974   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
1975                                        &iter0, "0");
1976   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
1977                                        &iter1, "1");
1978   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
1979                                        &iter2, "2");
1980   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
1981                                        &iter3, "3");
1982   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
1983                                        &iter4, "4");
1984
1985   path = gtk_tree_path_new ();
1986   signal_monitor_append_signal_reordered (fixture->monitor,
1987                                           ROWS_REORDERED,
1988                                           path, order0, 5);
1989   gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
1990   signal_monitor_assert_is_empty (fixture->monitor);
1991
1992   signal_monitor_append_signal_reordered (fixture->monitor,
1993                                           ROWS_REORDERED,
1994                                           path, order1, 5);
1995   gtk_tree_store_move_after (fixture->store, &iter2, &iter3);
1996   signal_monitor_assert_is_empty (fixture->monitor);
1997
1998   signal_monitor_append_signal_reordered (fixture->monitor,
1999                                           ROWS_REORDERED,
2000                                           path, order2, 5);
2001   gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
2002   signal_monitor_assert_is_empty (fixture->monitor);
2003
2004   gtk_tree_path_free (path);
2005 }
2006
2007 static void
2008 unfiltered_rows_reordered_child_level (FilterTest    *fixture,
2009                                        gconstpointer  user_data)
2010 {
2011   int order0[] = { 1, 2, 3, 4, 0 };
2012   int order1[] = { 0, 2, 1, 3, 4 };
2013   int order2[] = { 4, 0, 1, 2, 3 };
2014   GtkTreeIter iter0, iter1, iter2, iter3, iter4;
2015   GtkTreePath *path;
2016
2017   /* Expand row 0 */
2018   path = gtk_tree_path_new_from_indices (0, -1);
2019   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
2020
2021   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2022                                        &iter0, "0:0");
2023   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2024                                        &iter1, "0:1");
2025   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2026                                        &iter2, "0:2");
2027   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2028                                        &iter3, "0:3");
2029   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2030                                        &iter4, "0:4");
2031
2032   signal_monitor_append_signal_reordered (fixture->monitor,
2033                                           ROWS_REORDERED,
2034                                           path, order0, 5);
2035   gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
2036   signal_monitor_assert_is_empty (fixture->monitor);
2037
2038   signal_monitor_append_signal_reordered (fixture->monitor,
2039                                           ROWS_REORDERED,
2040                                           path, order1, 5);
2041   gtk_tree_store_move_after (fixture->store, &iter2, &iter3);
2042   signal_monitor_assert_is_empty (fixture->monitor);
2043
2044   signal_monitor_append_signal_reordered (fixture->monitor,
2045                                           ROWS_REORDERED,
2046                                           path, order2, 5);
2047   gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
2048   signal_monitor_assert_is_empty (fixture->monitor);
2049
2050   gtk_tree_path_free (path);
2051 }
2052
2053 static void
2054 filtered_rows_reordered_root_level_first_hidden (FilterTest    *fixture,
2055                                                  gconstpointer  user_data)
2056 {
2057   int order0[] = { 1, 2, 3, 0 };
2058   int order1[] = { 0, 2, 1, 3 };
2059   int order2[] = { 3, 0, 1, 2 };
2060   GtkTreeIter iter1, iter2, iter3, iter4;
2061   GtkTreePath *path;
2062
2063   /* Hide middle path */
2064   signal_monitor_append_signal (fixture->monitor,
2065                                 ROW_DELETED, "0");
2066   set_path_visibility (fixture, "0", FALSE);
2067   signal_monitor_assert_is_empty (fixture->monitor);
2068
2069   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2070                                        &iter1, "1");
2071   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2072                                        &iter2, "2");
2073   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2074                                        &iter3, "3");
2075   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2076                                        &iter4, "4");
2077
2078   path = gtk_tree_path_new ();
2079   signal_monitor_append_signal_reordered (fixture->monitor,
2080                                           ROWS_REORDERED,
2081                                           path, order0, 4);
2082   gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
2083   signal_monitor_assert_is_empty (fixture->monitor);
2084
2085   signal_monitor_append_signal_reordered (fixture->monitor,
2086                                           ROWS_REORDERED,
2087                                           path, order1, 4);
2088   gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
2089   signal_monitor_assert_is_empty (fixture->monitor);
2090
2091   signal_monitor_append_signal_reordered (fixture->monitor,
2092                                           ROWS_REORDERED,
2093                                           path, order2, 4);
2094   gtk_tree_store_move_before (fixture->store, &iter1, &iter2);
2095   signal_monitor_assert_is_empty (fixture->monitor);
2096
2097   gtk_tree_path_free (path);
2098 }
2099
2100 static void
2101 filtered_rows_reordered_root_level_middle_hidden (FilterTest    *fixture,
2102                                                   gconstpointer  user_data)
2103 {
2104   int order0[] = { 1, 2, 3, 0 };
2105   int order1[] = { 0, 2, 1, 3 };
2106   int order2[] = { 3, 0, 1, 2 };
2107   GtkTreeIter iter0, iter1, iter3, iter4;
2108   GtkTreePath *path;
2109
2110   /* Hide middle path */
2111   signal_monitor_append_signal (fixture->monitor,
2112                                 ROW_DELETED, "2");
2113   set_path_visibility (fixture, "2", FALSE);
2114   signal_monitor_assert_is_empty (fixture->monitor);
2115
2116   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2117                                        &iter0, "0");
2118   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2119                                        &iter1, "1");
2120   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2121                                        &iter3, "3");
2122   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2123                                        &iter4, "4");
2124
2125   path = gtk_tree_path_new ();
2126   signal_monitor_append_signal_reordered (fixture->monitor,
2127                                           ROWS_REORDERED,
2128                                           path, order0, 4);
2129   gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
2130   signal_monitor_assert_is_empty (fixture->monitor);
2131
2132   signal_monitor_append_signal_reordered (fixture->monitor,
2133                                           ROWS_REORDERED,
2134                                           path, order1, 4);
2135   gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
2136   signal_monitor_assert_is_empty (fixture->monitor);
2137
2138   signal_monitor_append_signal_reordered (fixture->monitor,
2139                                           ROWS_REORDERED,
2140                                           path, order2, 4);
2141   gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
2142   signal_monitor_assert_is_empty (fixture->monitor);
2143
2144   gtk_tree_path_free (path);
2145 }
2146
2147 static void
2148 filtered_rows_reordered_child_level_first_hidden (FilterTest    *fixture,
2149                                                   gconstpointer  user_data)
2150 {
2151   int order0[] = { 1, 2, 3, 0 };
2152   int order1[] = { 0, 2, 1, 3 };
2153   int order2[] = { 3, 0, 1, 2 };
2154   GtkTreeIter iter1, iter2, iter3, iter4;
2155   GtkTreePath *path;
2156
2157   /* Expand row 0 */
2158   path = gtk_tree_path_new_from_indices (0, -1);
2159   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, TRUE);
2160
2161   /* Hide middle path */
2162   signal_monitor_append_signal (fixture->monitor,
2163                                 ROW_DELETED, "0:0");
2164   set_path_visibility (fixture, "0:0", FALSE);
2165   signal_monitor_assert_is_empty (fixture->monitor);
2166
2167   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2168                                        &iter1, "0:1");
2169   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2170                                        &iter2, "0:2");
2171   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2172                                        &iter3, "0:3");
2173   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2174                                        &iter4, "0:4");
2175
2176   signal_monitor_append_signal_reordered (fixture->monitor,
2177                                           ROWS_REORDERED,
2178                                           path, order0, 4);
2179   gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
2180   signal_monitor_assert_is_empty (fixture->monitor);
2181
2182   signal_monitor_append_signal_reordered (fixture->monitor,
2183                                           ROWS_REORDERED,
2184                                           path, order1, 4);
2185   gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
2186   signal_monitor_assert_is_empty (fixture->monitor);
2187
2188   signal_monitor_append_signal_reordered (fixture->monitor,
2189                                           ROWS_REORDERED,
2190                                           path, order2, 4);
2191   gtk_tree_store_move_before (fixture->store, &iter1, &iter2);
2192   signal_monitor_assert_is_empty (fixture->monitor);
2193
2194   gtk_tree_path_free (path);
2195 }
2196
2197 static void
2198 filtered_rows_reordered_child_level_middle_hidden (FilterTest    *fixture,
2199                                                    gconstpointer  user_data)
2200 {
2201   int order0[] = { 1, 2, 3, 0 };
2202   int order1[] = { 0, 2, 1, 3 };
2203   int order2[] = { 3, 0, 1, 2 };
2204   GtkTreeIter iter0, iter1, iter3, iter4;
2205   GtkTreePath *path;
2206
2207   /* Expand row 0 */
2208   path = gtk_tree_path_new_from_indices (0, -1);
2209   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
2210
2211   /* Hide middle path */
2212   signal_monitor_append_signal (fixture->monitor,
2213                                 ROW_DELETED, "0:2");
2214   set_path_visibility (fixture, "0:2", FALSE);
2215   signal_monitor_assert_is_empty (fixture->monitor);
2216
2217   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2218                                        &iter0, "0:0");
2219   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2220                                        &iter1, "0:1");
2221   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2222                                        &iter3, "0:3");
2223   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2224                                        &iter4, "0:4");
2225
2226   signal_monitor_append_signal_reordered (fixture->monitor,
2227                                           ROWS_REORDERED,
2228                                           path, order0, 4);
2229   gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
2230   signal_monitor_assert_is_empty (fixture->monitor);
2231
2232   signal_monitor_append_signal_reordered (fixture->monitor,
2233                                           ROWS_REORDERED,
2234                                           path, order1, 4);
2235   gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
2236   signal_monitor_assert_is_empty (fixture->monitor);
2237
2238   signal_monitor_append_signal_reordered (fixture->monitor,
2239                                           ROWS_REORDERED,
2240                                           path, order2, 4);
2241   gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
2242   signal_monitor_assert_is_empty (fixture->monitor);
2243
2244   gtk_tree_path_free (path);
2245 }
2246
2247 static void
2248 filtered_rows_reordered_child_level_4_hidden (FilterTest    *fixture,
2249                                               gconstpointer  user_data)
2250 {
2251   int order0[] = { 0 };
2252   GtkTreeIter iter1, iter4;
2253   GtkTreePath *path;
2254
2255   /* Expand row 0 */
2256   path = gtk_tree_path_new_from_indices (0, -1);
2257   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
2258
2259   /* Hide last 4 paths */
2260   signal_monitor_append_signal (fixture->monitor,
2261                                 ROW_DELETED, "0:4");
2262   signal_monitor_append_signal (fixture->monitor,
2263                                 ROW_DELETED, "0:3");
2264   signal_monitor_append_signal (fixture->monitor,
2265                                 ROW_DELETED, "0:2");
2266   signal_monitor_append_signal (fixture->monitor,
2267                                 ROW_DELETED, "0:0");
2268   set_path_visibility (fixture, "0:4", FALSE);
2269   set_path_visibility (fixture, "0:3", FALSE);
2270   set_path_visibility (fixture, "0:2", FALSE);
2271   set_path_visibility (fixture, "0:0", FALSE);
2272   signal_monitor_assert_is_empty (fixture->monitor);
2273
2274   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2275                                        &iter1, "0:1");
2276   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2277                                        &iter4, "0:4");
2278
2279   signal_monitor_append_signal_reordered (fixture->monitor,
2280                                           ROWS_REORDERED,
2281                                           path, order0, 1);
2282   gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
2283   signal_monitor_assert_is_empty (fixture->monitor);
2284
2285   gtk_tree_path_free (path);
2286 }
2287
2288 static void
2289 filtered_rows_reordered_child_level_all_hidden (FilterTest    *fixture,
2290                                                 gconstpointer  user_data)
2291 {
2292   GtkTreeIter iter1, iter4;
2293   GtkTreePath *path;
2294
2295   /* Expand row 0 */
2296   path = gtk_tree_path_new_from_indices (0, -1);
2297   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
2298   gtk_tree_path_free (path);
2299
2300   /* Hide last 4 paths */
2301   signal_monitor_append_signal (fixture->monitor,
2302                                 ROW_DELETED, "0:4");
2303   signal_monitor_append_signal (fixture->monitor,
2304                                 ROW_DELETED, "0:3");
2305   signal_monitor_append_signal (fixture->monitor,
2306                                 ROW_DELETED, "0:2");
2307   signal_monitor_append_signal (fixture->monitor,
2308                                 ROW_DELETED, "0:1");
2309   signal_monitor_append_signal (fixture->monitor,
2310                                 ROW_DELETED, "0:0");
2311   signal_monitor_append_signal (fixture->monitor,
2312                                 ROW_HAS_CHILD_TOGGLED, "0");
2313   set_path_visibility (fixture, "0:4", FALSE);
2314   set_path_visibility (fixture, "0:3", FALSE);
2315   set_path_visibility (fixture, "0:2", FALSE);
2316   set_path_visibility (fixture, "0:1", FALSE);
2317   set_path_visibility (fixture, "0:0", FALSE);
2318   signal_monitor_assert_is_empty (fixture->monitor);
2319
2320   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2321                                        &iter1, "0:1");
2322   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2323                                        &iter4, "0:4");
2324
2325   gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
2326   signal_monitor_assert_is_empty (fixture->monitor);
2327 }
2328
2329 static void
2330 insert_before (void)
2331 {
2332   GtkTreeStore *store;
2333   GtkTreeModel *filter;
2334   GtkWidget *tree_view;
2335   SignalMonitor *monitor;
2336   GtkTreeIter iter;
2337   GtkTreeIter last_iter;
2338   GtkTreePath *path;
2339
2340   /* This tests two aspects of the row-inserted handling:
2341    *   1) If the newly inserted node was already handled by building
2342    *      the root level, don't handle it a second time.
2343    *   2) Offsets of existing nodes must be updated when a new
2344    *      node is inserted.
2345    */
2346
2347   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2348   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2349   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
2350                                             1);
2351
2352   tree_view = gtk_tree_view_new_with_model (filter);
2353   monitor = signal_monitor_new (filter);
2354
2355   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 0);
2356
2357   /* Insert 0 */
2358   path = gtk_tree_path_new_from_indices (0, -1);
2359   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
2360   gtk_tree_path_free (path);
2361
2362   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
2363                                      0, "Foo", 1, TRUE, -1);
2364
2365   signal_monitor_assert_is_empty (monitor);
2366   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
2367
2368   /* Insert 1 */
2369   path = gtk_tree_path_new_from_indices (1, -1);
2370   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
2371   gtk_tree_path_free (path);
2372
2373   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
2374                                      0, "Foo", 1, TRUE, -1);
2375   last_iter = iter;
2376
2377   signal_monitor_assert_is_empty (monitor);
2378   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
2379
2380   /* Insert on 1 again -- invisible */
2381   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
2382                                      0, "Foo", 1, FALSE, -1);
2383
2384   signal_monitor_assert_is_empty (monitor);
2385   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
2386
2387   /* Insert on 1 again -- visible */
2388   path = gtk_tree_path_new_from_indices (1, -1);
2389   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
2390   gtk_tree_path_free (path);
2391
2392   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
2393                                      0, "Foo", 1, TRUE, -1);
2394
2395   signal_monitor_assert_is_empty (monitor);
2396   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
2397
2398   /* Modify the iter that should be at the last position and check the
2399    * signal we get.
2400    */
2401   path = gtk_tree_path_new_from_indices (2, -1);
2402   signal_monitor_append_signal_path (monitor, ROW_CHANGED, path);
2403   gtk_tree_path_free (path);
2404
2405   gtk_tree_store_set (store, &last_iter, 0, "Foo changed", -1);
2406
2407   signal_monitor_assert_is_empty (monitor);
2408   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
2409 }
2410
2411 static void
2412 insert_child (void)
2413 {
2414   GtkTreeStore *store;
2415   GtkTreeModel *filter;
2416   GtkWidget *tree_view;
2417   SignalMonitor *monitor;
2418   GtkTreeIter parent, iter;
2419   GtkTreePath *path;
2420
2421   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2422
2423   gtk_tree_store_insert_with_values (store, &parent, NULL, 0,
2424                                      0, "Parent", 1, TRUE, -1);
2425
2426
2427   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2428   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
2429                                             1);
2430
2431   tree_view = gtk_tree_view_new_with_model (filter);
2432   monitor = signal_monitor_new (filter);
2433
2434   /* Insert child -- invisible */
2435   path = gtk_tree_path_new_from_indices (0, -1);
2436   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
2437   /* The signal is received twice, once a pass through from GtkTreeStore
2438    * and one generated by GtkTreeModelFilter.  Not accurate, but cannot
2439    * hurt.
2440    */
2441   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
2442   gtk_tree_path_free (path);
2443
2444   gtk_tree_store_insert_with_values (store, &iter, &parent, 1,
2445                                      0, "Child", 1, FALSE, -1);
2446
2447   signal_monitor_assert_is_empty (monitor);
2448   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
2449
2450   /* Insert child */
2451   path = gtk_tree_path_new_from_indices (0, 0, -1);
2452   gtk_tree_path_up (path); /* 0 */
2453   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
2454   gtk_tree_path_free (path);
2455
2456   gtk_tree_store_insert_with_values (store, &iter, &parent, 0,
2457                                      0, "Child", 1, TRUE, -1);
2458
2459   signal_monitor_assert_is_empty (monitor);
2460   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
2461
2462   /* Insert child -- invisible */
2463   gtk_tree_store_insert_with_values (store, &iter, &parent, 1,
2464                                      0, "Child", 1, FALSE, -1);
2465
2466   signal_monitor_assert_is_empty (monitor);
2467   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
2468 }
2469
2470
2471
2472 static void
2473 remove_node (void)
2474 {
2475   GtkTreeIter iter, iter1, iter2, iter3;
2476   GtkListStore *list;
2477   GtkTreeModel *filter;
2478   GtkWidget *view G_GNUC_UNUSED;
2479
2480   list = gtk_list_store_new (1, G_TYPE_INT);
2481   gtk_list_store_insert_with_values (list, &iter1, 0, 0, 1, -1);
2482   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
2483   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
2484   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
2485   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
2486   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
2487   gtk_list_store_insert_with_values (list, &iter2, 6, 0, 7, -1);
2488   gtk_list_store_insert_with_values (list, &iter3, 7, 0, 8, -1);
2489
2490   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
2491   view = gtk_tree_view_new_with_model (filter);
2492
2493   gtk_list_store_remove (list, &iter1);
2494   gtk_list_store_remove (list, &iter3);
2495   gtk_list_store_remove (list, &iter2);
2496
2497   gtk_widget_destroy (view);
2498   g_object_unref (filter);
2499   g_object_unref (list);
2500 }
2501
2502 static void
2503 remove_node_vroot (void)
2504 {
2505   GtkTreeIter parent, root;
2506   GtkTreeIter iter, iter1, iter2, iter3;
2507   GtkTreeStore *tree;
2508   GtkTreeModel *filter;
2509   GtkTreePath *path;
2510   GtkWidget *view G_GNUC_UNUSED;
2511
2512   tree = gtk_tree_store_new (1, G_TYPE_INT);
2513   gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
2514   gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
2515
2516   gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
2517   gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
2518   gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
2519   gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
2520   gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
2521   gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
2522   gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
2523   gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
2524
2525   path = gtk_tree_path_new_from_indices (0, 0, -1);
2526   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
2527   gtk_tree_path_free (path);
2528
2529   view = gtk_tree_view_new_with_model (filter);
2530
2531   gtk_tree_store_remove (tree, &iter1);
2532   gtk_tree_store_remove (tree, &iter3);
2533   gtk_tree_store_remove (tree, &iter2);
2534
2535   gtk_widget_destroy (view);
2536   g_object_unref (filter);
2537   g_object_unref (tree);
2538 }
2539
2540 static void
2541 remove_vroot_ancestor (void)
2542 {
2543   GtkTreeIter parent, root;
2544   GtkTreeIter iter, iter1, iter2, iter3;
2545   GtkTreeStore *tree;
2546   GtkTreeModel *filter;
2547   GtkTreePath *path;
2548   GtkWidget *view G_GNUC_UNUSED;
2549
2550   tree = gtk_tree_store_new (1, G_TYPE_INT);
2551   gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
2552   gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
2553
2554   gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
2555   gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
2556   gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
2557   gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
2558   gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
2559   gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
2560   gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
2561   gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
2562
2563   path = gtk_tree_path_new_from_indices (0, 0, -1);
2564   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
2565   gtk_tree_path_free (path);
2566
2567   view = gtk_tree_view_new_with_model (filter);
2568
2569   gtk_tree_store_remove (tree, &parent);
2570
2571   gtk_widget_destroy (view);
2572   g_object_unref (filter);
2573   g_object_unref (tree);
2574 }
2575
2576 static void
2577 ref_count_single_level (void)
2578 {
2579   GtkTreeIter iter[5];
2580   GtkTreeModel *model;
2581   GtkTreeModelRefCount *ref_model;
2582   GtkTreeModel *filter_model;
2583   GtkWidget *tree_view;
2584
2585   model = gtk_tree_model_ref_count_new ();
2586   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2587
2588   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[0], NULL);
2589   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[1], NULL);
2590   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[2], NULL);
2591   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[3], NULL);
2592   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[4], NULL);
2593
2594   assert_root_level_unreferenced (ref_model);
2595
2596   filter_model = gtk_tree_model_filter_new (model, NULL);
2597   tree_view = gtk_tree_view_new_with_model (filter_model);
2598
2599   assert_node_ref_count (ref_model, &iter[0], 2);
2600   assert_node_ref_count (ref_model, &iter[1], 1);
2601   assert_node_ref_count (ref_model, &iter[2], 1);
2602   assert_node_ref_count (ref_model, &iter[3], 1);
2603   assert_node_ref_count (ref_model, &iter[4], 1);
2604
2605   gtk_widget_destroy (tree_view);
2606
2607   assert_node_ref_count (ref_model, &iter[0], 1);
2608   assert_node_ref_count (ref_model, &iter[1], 0);
2609   assert_node_ref_count (ref_model, &iter[2], 0);
2610   assert_node_ref_count (ref_model, &iter[3], 0);
2611   assert_node_ref_count (ref_model, &iter[4], 0);
2612
2613   g_object_unref (filter_model);
2614
2615   assert_node_ref_count (ref_model, &iter[0], 0);
2616
2617   g_object_unref (ref_model);
2618 }
2619
2620 static void
2621 ref_count_two_levels (void)
2622 {
2623   GtkTreeIter parent1, parent2, iter, iter_first;
2624   GtkTreeModel *model;
2625   GtkTreeModelRefCount *ref_model;
2626   GtkTreeModel *filter_model;
2627   GtkWidget *tree_view;
2628
2629   model = gtk_tree_model_ref_count_new ();
2630   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2631
2632   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, NULL);
2633   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, NULL);
2634   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_first, &parent2);
2635   gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent2);
2636   gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent2);
2637
2638   assert_entire_model_unreferenced (ref_model);
2639
2640   filter_model = gtk_tree_model_filter_new (model, NULL);
2641   tree_view = gtk_tree_view_new_with_model (filter_model);
2642
2643   /* This is quite confusing:
2644    *  - node 0 has a ref count of 2 because it is referenced as the
2645    *    first node in a level and by the tree view.
2646    *  - node 1 has a ref count of 2 because it is referenced by its
2647    *    child level and by the tree view.
2648    */
2649   assert_root_level_referenced (ref_model, 2);
2650   assert_node_ref_count (ref_model, &iter_first, 1);
2651   assert_node_ref_count (ref_model, &iter, 0);
2652
2653   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2654
2655   assert_node_ref_count (ref_model, &parent1, 2);
2656   assert_node_ref_count (ref_model, &parent2, 2);
2657   assert_node_ref_count (ref_model, &iter_first, 2);
2658   assert_node_ref_count (ref_model, &iter, 1);
2659
2660   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
2661
2662   /* The child level is not destroyed because its parent is visible */
2663   assert_node_ref_count (ref_model, &parent1, 2);
2664   assert_node_ref_count (ref_model, &parent2, 2);
2665   assert_node_ref_count (ref_model, &iter_first, 1);
2666   assert_node_ref_count (ref_model, &iter, 0);
2667
2668   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2669
2670   assert_node_ref_count (ref_model, &parent1, 2);
2671   assert_node_ref_count (ref_model, &parent2, 2);
2672   assert_node_ref_count (ref_model, &iter_first, 1);
2673   assert_node_ref_count (ref_model, &iter, 0);
2674
2675   gtk_widget_destroy (tree_view);
2676
2677   assert_root_level_referenced (ref_model, 1);
2678   assert_node_ref_count (ref_model, &iter_first, 1);
2679   assert_node_ref_count (ref_model, &iter, 0);
2680
2681   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2682
2683   /* Only the reference on the first node of the root level is kept. */
2684   assert_node_ref_count (ref_model, &parent1, 1);
2685   assert_node_ref_count (ref_model, &parent2, 0);
2686   assert_node_ref_count (ref_model, &iter_first, 0);
2687   assert_node_ref_count (ref_model, &iter, 0);
2688
2689   g_object_unref (filter_model);
2690   g_object_unref (ref_model);
2691 }
2692
2693 static void
2694 ref_count_three_levels (void)
2695 {
2696   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
2697   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
2698   GtkTreeModel *model;
2699   GtkTreeModelRefCount *ref_model;
2700   GtkTreeModel *filter_model;
2701   GtkTreePath *path;
2702   GtkWidget *tree_view;
2703
2704   model = gtk_tree_model_ref_count_new ();
2705   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2706
2707   /* + grandparent1
2708    * + grandparent2
2709    *   + parent1
2710    *     + iter_parent1
2711    *   + parent2
2712    *     + iter_parent2_first
2713    *     + iter_parent2
2714    */
2715
2716   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
2717   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
2718   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
2719   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
2720   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
2721   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
2722   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
2723
2724   assert_entire_model_unreferenced (ref_model);
2725
2726   filter_model = gtk_tree_model_filter_new (model, NULL);
2727   tree_view = gtk_tree_view_new_with_model (filter_model);
2728
2729   /* This is quite confusing:
2730    *  - node 0 has a ref count of 2 because it is referenced as the
2731    *    first node in a level and by the tree view.
2732    *  - node 1 has a ref count of 2 because it is referenced by its
2733    *    child level and by the tree view.
2734    */
2735   assert_root_level_referenced (ref_model, 2);
2736   assert_node_ref_count (ref_model, &parent1, 1);
2737   assert_node_ref_count (ref_model, &parent2, 0);
2738   assert_level_unreferenced (ref_model, &parent1);
2739   assert_level_unreferenced (ref_model, &parent2);
2740
2741   path = gtk_tree_path_new_from_indices (1, -1);
2742   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
2743
2744   assert_node_ref_count (ref_model, &grandparent1, 2);
2745   assert_node_ref_count (ref_model, &grandparent2, 2);
2746   assert_node_ref_count (ref_model, &parent1, 3);
2747   assert_node_ref_count (ref_model, &parent2, 2);
2748   assert_node_ref_count (ref_model, &iter_parent1, 1);
2749   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2750   assert_node_ref_count (ref_model, &iter_parent2, 0);
2751
2752   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
2753
2754   assert_node_ref_count (ref_model, &grandparent1, 2);
2755   assert_node_ref_count (ref_model, &grandparent2, 2);
2756   assert_node_ref_count (ref_model, &parent1, 3);
2757   assert_node_ref_count (ref_model, &parent2, 2);
2758   assert_node_ref_count (ref_model, &iter_parent1, 2);
2759   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2760   assert_node_ref_count (ref_model, &iter_parent2, 1);
2761
2762   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
2763
2764   assert_node_ref_count (ref_model, &grandparent1, 2);
2765   assert_node_ref_count (ref_model, &grandparent2, 2);
2766   assert_node_ref_count (ref_model, &parent1, 2);
2767   assert_node_ref_count (ref_model, &parent2, 1);
2768   assert_node_ref_count (ref_model, &iter_parent1, 1);
2769   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2770   assert_node_ref_count (ref_model, &iter_parent2, 0);
2771
2772   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2773
2774   assert_node_ref_count (ref_model, &grandparent1, 2);
2775   assert_node_ref_count (ref_model, &grandparent2, 2);
2776   assert_node_ref_count (ref_model, &parent1, 1);
2777   assert_node_ref_count (ref_model, &parent2, 0);
2778   assert_node_ref_count (ref_model, &iter_parent1, 0);
2779   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
2780   assert_node_ref_count (ref_model, &iter_parent2, 0);
2781
2782   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
2783
2784   assert_node_ref_count (ref_model, &grandparent1, 2);
2785   assert_node_ref_count (ref_model, &grandparent2, 2);
2786   assert_node_ref_count (ref_model, &parent1, 3);
2787   assert_node_ref_count (ref_model, &parent2, 2);
2788   assert_node_ref_count (ref_model, &iter_parent1, 1);
2789   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2790   assert_node_ref_count (ref_model, &iter_parent2, 0);
2791
2792   gtk_tree_path_append_index (path, 1);
2793   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
2794
2795   assert_node_ref_count (ref_model, &grandparent1, 2);
2796   assert_node_ref_count (ref_model, &grandparent2, 2);
2797   assert_node_ref_count (ref_model, &parent1, 3);
2798   assert_node_ref_count (ref_model, &parent2, 2);
2799   assert_node_ref_count (ref_model, &iter_parent1, 1);
2800   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2801   assert_node_ref_count (ref_model, &iter_parent2, 1);
2802
2803   gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path);
2804
2805   assert_node_ref_count (ref_model, &grandparent1, 2);
2806   assert_node_ref_count (ref_model, &grandparent2, 2);
2807   assert_node_ref_count (ref_model, &parent1, 3);
2808   assert_node_ref_count (ref_model, &parent2, 2);
2809   assert_node_ref_count (ref_model, &iter_parent1, 1);
2810   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2811   assert_node_ref_count (ref_model, &iter_parent2, 0);
2812
2813   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2814
2815   assert_node_ref_count (ref_model, &grandparent1, 2);
2816   assert_node_ref_count (ref_model, &grandparent2, 2);
2817   assert_node_ref_count (ref_model, &parent1, 3);
2818   assert_node_ref_count (ref_model, &parent2, 2);
2819   assert_node_ref_count (ref_model, &iter_parent1, 1);
2820   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2821   assert_node_ref_count (ref_model, &iter_parent2, 0);
2822
2823   gtk_tree_path_up (path);
2824   gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path);
2825   gtk_tree_path_free (path);
2826
2827   assert_node_ref_count (ref_model, &grandparent1, 2);
2828   assert_node_ref_count (ref_model, &grandparent2, 2);
2829   assert_node_ref_count (ref_model, &parent1, 2);
2830   assert_node_ref_count (ref_model, &parent2, 1);
2831   assert_node_ref_count (ref_model, &iter_parent1, 1);
2832   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2833   assert_node_ref_count (ref_model, &iter_parent2, 0);
2834
2835   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2836
2837   assert_node_ref_count (ref_model, &grandparent1, 2);
2838   assert_node_ref_count (ref_model, &grandparent2, 2);
2839   assert_node_ref_count (ref_model, &parent1, 1);
2840   assert_node_ref_count (ref_model, &parent2, 0);
2841   assert_node_ref_count (ref_model, &iter_parent1, 0);
2842   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
2843   assert_node_ref_count (ref_model, &iter_parent2, 0);
2844
2845   gtk_widget_destroy (tree_view);
2846
2847   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2848
2849   /* Only the reference on the first node of the root level is kept. */
2850   assert_node_ref_count (ref_model, &grandparent1, 1);
2851   assert_node_ref_count (ref_model, &grandparent2, 0);
2852   assert_node_ref_count (ref_model, &parent1, 0);
2853   assert_node_ref_count (ref_model, &parent2, 0);
2854   assert_node_ref_count (ref_model, &iter_parent1, 0);
2855   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
2856   assert_node_ref_count (ref_model, &iter_parent2, 0);
2857
2858   g_object_unref (filter_model);
2859   g_object_unref (ref_model);
2860 }
2861
2862 static void
2863 ref_count_delete_row (void)
2864 {
2865   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
2866   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
2867   GtkTreeModel *model;
2868   GtkTreeModelRefCount *ref_model;
2869   GtkTreeModel *filter_model;
2870   GtkTreePath *path;
2871   GtkWidget *tree_view;
2872
2873   model = gtk_tree_model_ref_count_new ();
2874   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2875
2876   /* + grandparent1
2877    * + grandparent2
2878    *   + parent1
2879    *     + iter_parent1
2880    *   + parent2
2881    *     + iter_parent2_first
2882    *     + iter_parent2
2883    */
2884
2885   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
2886   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
2887   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
2888   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
2889   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
2890   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
2891   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
2892
2893   assert_entire_model_unreferenced (ref_model);
2894
2895   filter_model = gtk_tree_model_filter_new (model, NULL);
2896   tree_view = gtk_tree_view_new_with_model (filter_model);
2897
2898   assert_root_level_referenced (ref_model, 2);
2899   assert_node_ref_count (ref_model, &parent1, 1);
2900   assert_node_ref_count (ref_model, &parent2, 0);
2901   assert_level_unreferenced (ref_model, &parent1);
2902   assert_level_unreferenced (ref_model, &parent2);
2903
2904   path = gtk_tree_path_new_from_indices (1, -1);
2905   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
2906
2907   assert_node_ref_count (ref_model, &grandparent1, 2);
2908   assert_node_ref_count (ref_model, &grandparent2, 2);
2909   assert_node_ref_count (ref_model, &parent1, 3);
2910   assert_node_ref_count (ref_model, &parent2, 2);
2911   assert_node_ref_count (ref_model, &iter_parent1, 2);
2912   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2913   assert_node_ref_count (ref_model, &iter_parent2, 1);
2914
2915   gtk_tree_store_remove (GTK_TREE_STORE (model), &iter_parent2);
2916
2917   assert_node_ref_count (ref_model, &grandparent1, 2);
2918   assert_node_ref_count (ref_model, &grandparent2, 2);
2919   assert_node_ref_count (ref_model, &parent1, 3);
2920   assert_node_ref_count (ref_model, &parent2, 2);
2921   assert_node_ref_count (ref_model, &iter_parent1, 2);
2922   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2923
2924   gtk_tree_store_remove (GTK_TREE_STORE (model), &parent1);
2925
2926   assert_node_ref_count (ref_model, &grandparent1, 2);
2927   assert_node_ref_count (ref_model, &grandparent2, 2);
2928   assert_node_ref_count (ref_model, &parent2, 3);
2929   assert_level_referenced (ref_model, 2, &parent2);
2930
2931   gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
2932
2933   assert_node_ref_count (ref_model, &grandparent1, 2);
2934
2935   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2936
2937   assert_node_ref_count (ref_model, &grandparent1, 2);
2938
2939   gtk_widget_destroy (tree_view);
2940   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2941
2942   assert_node_ref_count (ref_model, &grandparent1, 1);
2943
2944   g_object_unref (filter_model);
2945
2946   assert_node_ref_count (ref_model, &grandparent1, 0);
2947
2948   g_object_unref (ref_model);
2949 }
2950
2951 static void
2952 ref_count_cleanup (void)
2953 {
2954   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
2955   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
2956   GtkTreeModel *model;
2957   GtkTreeModelRefCount *ref_model;
2958   GtkTreeModel *filter_model;
2959   GtkWidget *tree_view;
2960
2961   model = gtk_tree_model_ref_count_new ();
2962   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2963
2964   /* + grandparent1
2965    * + grandparent2
2966    *   + parent1
2967    *     + iter_parent1
2968    *   + parent2
2969    *     + iter_parent2_first
2970    *     + iter_parent2
2971    */
2972
2973   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
2974   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
2975   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
2976   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
2977   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
2978   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
2979   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
2980
2981   filter_model = gtk_tree_model_filter_new (model, NULL);
2982   tree_view = gtk_tree_view_new_with_model (filter_model);
2983
2984   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2985
2986   assert_node_ref_count (ref_model, &grandparent1, 2);
2987   assert_node_ref_count (ref_model, &grandparent2, 2);
2988   assert_node_ref_count (ref_model, &parent1, 3);
2989   assert_node_ref_count (ref_model, &parent2, 2);
2990   assert_node_ref_count (ref_model, &iter_parent1, 2);
2991   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2992   assert_node_ref_count (ref_model, &iter_parent2, 1);
2993
2994   gtk_widget_destroy (tree_view);
2995
2996   assert_node_ref_count (ref_model, &grandparent1, 1);
2997   assert_node_ref_count (ref_model, &grandparent2, 1);
2998   assert_node_ref_count (ref_model, &parent1, 2);
2999   assert_node_ref_count (ref_model, &parent2, 1);
3000   assert_node_ref_count (ref_model, &iter_parent1, 1);
3001   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3002   assert_node_ref_count (ref_model, &iter_parent2, 0);
3003
3004   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3005
3006   /* Only the reference on the first node of the root level is kept. */
3007   assert_node_ref_count (ref_model, &grandparent1, 1);
3008   assert_node_ref_count (ref_model, &grandparent2, 0);
3009   assert_node_ref_count (ref_model, &parent1, 0);
3010   assert_node_ref_count (ref_model, &parent2, 0);
3011   assert_node_ref_count (ref_model, &iter_parent1, 0);
3012   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
3013   assert_node_ref_count (ref_model, &iter_parent2, 0);
3014
3015   g_object_unref (filter_model);
3016   g_object_unref (ref_model);
3017 }
3018
3019 static void
3020 ref_count_row_ref (void)
3021 {
3022   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
3023   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
3024   GtkTreeModel *model;
3025   GtkTreeModelRefCount *ref_model;
3026   GtkTreeModel *filter_model;
3027   GtkWidget *tree_view;
3028   GtkTreePath *path;
3029   GtkTreeRowReference *row_ref;
3030
3031   model = gtk_tree_model_ref_count_new ();
3032   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3033
3034   /* + grandparent1
3035    * + grandparent2
3036    *   + parent1
3037    *     + iter_parent1
3038    *   + parent2
3039    *     + iter_parent2
3040    *     + iter_parent2
3041    */
3042
3043   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3044   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3045   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
3046   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
3047   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
3048   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
3049   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
3050
3051   filter_model = gtk_tree_model_filter_new (model, NULL);
3052   tree_view = gtk_tree_view_new_with_model (filter_model);
3053
3054   path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
3055   row_ref = gtk_tree_row_reference_new (filter_model, path);
3056   gtk_tree_path_free (path);
3057
3058   assert_node_ref_count (ref_model, &grandparent1, 2);
3059   assert_node_ref_count (ref_model, &grandparent2, 3);
3060   assert_node_ref_count (ref_model, &parent1, 1);
3061   assert_node_ref_count (ref_model, &parent2, 2);
3062   assert_node_ref_count (ref_model, &iter_parent1, 0);
3063   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3064   assert_node_ref_count (ref_model, &iter_parent2, 1);
3065
3066   gtk_tree_row_reference_free (row_ref);
3067
3068   assert_node_ref_count (ref_model, &grandparent1, 2);
3069   assert_node_ref_count (ref_model, &grandparent2, 2);
3070   assert_node_ref_count (ref_model, &parent1, 1);
3071   assert_node_ref_count (ref_model, &parent2, 1);
3072   assert_node_ref_count (ref_model, &iter_parent1, 0);
3073   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3074   assert_node_ref_count (ref_model, &iter_parent2, 0);
3075
3076   path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
3077   row_ref = gtk_tree_row_reference_new (filter_model, path);
3078   gtk_tree_path_free (path);
3079
3080   assert_node_ref_count (ref_model, &grandparent1, 2);
3081   assert_node_ref_count (ref_model, &grandparent2, 3);
3082   assert_node_ref_count (ref_model, &parent1, 1);
3083   assert_node_ref_count (ref_model, &parent2, 2);
3084   assert_node_ref_count (ref_model, &iter_parent1, 0);
3085   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3086   assert_node_ref_count (ref_model, &iter_parent2, 1);
3087
3088   gtk_tree_store_remove (GTK_TREE_STORE (model), &parent2);
3089
3090   assert_node_ref_count (ref_model, &grandparent1, 2);
3091   assert_node_ref_count (ref_model, &grandparent2, 2);
3092   assert_node_ref_count (ref_model, &parent1, 1);
3093   assert_node_ref_count (ref_model, &iter_parent1, 0);
3094
3095   gtk_tree_row_reference_free (row_ref);
3096
3097   assert_node_ref_count (ref_model, &grandparent1, 2);
3098   assert_node_ref_count (ref_model, &grandparent2, 2);
3099   assert_node_ref_count (ref_model, &parent1, 1);
3100   assert_node_ref_count (ref_model, &iter_parent1, 0);
3101
3102   gtk_widget_destroy (tree_view);
3103
3104   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3105
3106   /* Only the reference on the first node of the root level is kept. */
3107   assert_node_ref_count (ref_model, &grandparent1, 1);
3108   assert_node_ref_count (ref_model, &grandparent2, 0);
3109   assert_node_ref_count (ref_model, &parent1, 0);
3110
3111   g_object_unref (filter_model);
3112   g_object_unref (ref_model);
3113 }
3114
3115 static void
3116 ref_count_transfer_root_level_insert (void)
3117 {
3118   GtkTreeIter grandparent1, grandparent2, grandparent3;
3119   GtkTreeIter new_node;
3120   GtkTreeModel *model;
3121   GtkTreeModelRefCount *ref_model;
3122   GtkTreeModel *filter_model;
3123   GtkWidget *tree_view;
3124
3125   model = gtk_tree_model_ref_count_new ();
3126   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3127
3128   /* + grandparent1
3129    * + grandparent2
3130    * + grandparent3
3131    */
3132
3133   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3134   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3135   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
3136
3137   filter_model = gtk_tree_model_filter_new (model, NULL);
3138   tree_view = gtk_tree_view_new_with_model (filter_model);
3139
3140   assert_node_ref_count (ref_model, &grandparent1, 2);
3141   assert_node_ref_count (ref_model, &grandparent2, 1);
3142   assert_node_ref_count (ref_model, &grandparent3, 1);
3143
3144   gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, NULL);
3145
3146   assert_node_ref_count (ref_model, &new_node, 2);
3147   assert_node_ref_count (ref_model, &grandparent1, 1);
3148   assert_node_ref_count (ref_model, &grandparent2, 1);
3149   assert_node_ref_count (ref_model, &grandparent3, 1);
3150
3151   gtk_widget_destroy (tree_view);
3152   g_object_unref (filter_model);
3153   g_object_unref (ref_model);
3154 }
3155
3156 static void
3157 ref_count_transfer_root_level_reordered (void)
3158 {
3159   GtkTreeIter grandparent1, grandparent2, grandparent3;
3160   GtkTreeModel *model;
3161   GtkTreeModelRefCount *ref_model;
3162   GtkTreeModel *filter_model;
3163   GtkWidget *tree_view;
3164
3165   model = gtk_tree_model_ref_count_new ();
3166   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3167
3168   /* + grandparent1
3169    * + grandparent2
3170    * + grandparent3
3171    */
3172
3173   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3174   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3175   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
3176
3177   filter_model = gtk_tree_model_filter_new (model, NULL);
3178   tree_view = gtk_tree_view_new_with_model (filter_model);
3179
3180   assert_node_ref_count (ref_model, &grandparent1, 2);
3181   assert_node_ref_count (ref_model, &grandparent2, 1);
3182   assert_node_ref_count (ref_model, &grandparent3, 1);
3183
3184   /* gtk_tree_store_move() will emit rows-reordered */
3185   gtk_tree_store_move_after (GTK_TREE_STORE (model),
3186                              &grandparent1, &grandparent3);
3187
3188   assert_node_ref_count (ref_model, &grandparent2, 2);
3189   assert_node_ref_count (ref_model, &grandparent3, 1);
3190   assert_node_ref_count (ref_model, &grandparent1, 1);
3191
3192   gtk_widget_destroy (tree_view);
3193   g_object_unref (filter_model);
3194   g_object_unref (ref_model);
3195 }
3196
3197 static void
3198 ref_count_transfer_child_level_insert (void)
3199 {
3200   GtkTreeIter grandparent1;
3201   GtkTreeIter parent1, parent2, parent3;
3202   GtkTreeIter new_node;
3203   GtkTreeModel *model;
3204   GtkTreeModelRefCount *ref_model;
3205   GtkTreeModel *filter_model;
3206   GtkWidget *tree_view;
3207
3208   model = gtk_tree_model_ref_count_new ();
3209   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3210
3211   /* + grandparent1
3212    *   + parent1
3213    *   + parent2
3214    *   + parent3
3215    */
3216
3217   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3218   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
3219   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
3220   gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
3221
3222   filter_model = gtk_tree_model_filter_new (model, NULL);
3223   tree_view = gtk_tree_view_new_with_model (filter_model);
3224
3225   assert_node_ref_count (ref_model, &grandparent1, 3);
3226   assert_node_ref_count (ref_model, &parent1, 1);
3227   assert_node_ref_count (ref_model, &parent2, 0);
3228   assert_node_ref_count (ref_model, &parent3, 0);
3229
3230   gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, &grandparent1);
3231
3232   assert_node_ref_count (ref_model, &grandparent1, 3);
3233   assert_node_ref_count (ref_model, &new_node, 1);
3234   assert_node_ref_count (ref_model, &parent1, 0);
3235   assert_node_ref_count (ref_model, &parent2, 0);
3236   assert_node_ref_count (ref_model, &parent3, 0);
3237
3238   gtk_widget_destroy (tree_view);
3239   g_object_unref (filter_model);
3240   g_object_unref (ref_model);
3241 }
3242
3243 static void
3244 ref_count_transfer_child_level_reordered (void)
3245 {
3246   GtkTreeIter grandparent1;
3247   GtkTreeIter parent1, parent2, parent3;
3248   GtkTreeModel *model;
3249   GtkTreeModelRefCount *ref_model;
3250   GtkTreeModel *filter_model;
3251   GtkWidget *tree_view;
3252
3253   model = gtk_tree_model_ref_count_new ();
3254   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3255
3256   /* + grandparent1
3257    *   + parent1
3258    *   + parent2
3259    *   + parent3
3260    */
3261
3262   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3263   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
3264   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
3265   gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
3266
3267   filter_model = gtk_tree_model_filter_new (model, NULL);
3268   tree_view = gtk_tree_view_new_with_model (filter_model);
3269
3270   assert_node_ref_count (ref_model, &grandparent1, 3);
3271   assert_node_ref_count (ref_model, &parent1, 1);
3272   assert_node_ref_count (ref_model, &parent2, 0);
3273   assert_node_ref_count (ref_model, &parent3, 0);
3274
3275   /* gtk_tree_store_move() will emit rows-reordered */
3276   gtk_tree_store_move_after (GTK_TREE_STORE (model),
3277                              &parent1, &parent3);
3278
3279   assert_node_ref_count (ref_model, &grandparent1, 3);
3280   assert_node_ref_count (ref_model, &parent2, 1);
3281   assert_node_ref_count (ref_model, &parent3, 0);
3282   assert_node_ref_count (ref_model, &parent1, 0);
3283
3284   gtk_widget_destroy (tree_view);
3285   g_object_unref (filter_model);
3286   g_object_unref (ref_model);
3287 }
3288
3289
3290 static gboolean
3291 specific_path_dependent_filter_func (GtkTreeModel *model,
3292                                      GtkTreeIter  *iter,
3293                                      gpointer      data)
3294 {
3295   GtkTreePath *path;
3296
3297   path = gtk_tree_model_get_path (model, iter);
3298   if (gtk_tree_path_get_indices (path)[0] < 4)
3299     return FALSE;
3300
3301   return TRUE;
3302 }
3303
3304 static void
3305 specific_path_dependent_filter (void)
3306 {
3307   int i;
3308   GtkTreeIter iter;
3309   GtkListStore *list;
3310   GtkTreeModel *sort;
3311   GtkTreeModel *filter;
3312
3313   list = gtk_list_store_new (1, G_TYPE_INT);
3314   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
3315   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
3316   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
3317   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
3318   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
3319   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
3320   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
3321   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
3322
3323   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list));
3324   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort), NULL);
3325   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3326                                           specific_path_dependent_filter_func,
3327                                           NULL, NULL);
3328
3329   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), 0,
3330                                         GTK_SORT_DESCENDING);
3331
3332   for (i = 0; i < 4; i++)
3333     {
3334       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
3335                                          NULL, 1))
3336         gtk_list_store_remove (list, &iter);
3337
3338       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
3339                                          NULL, 2))
3340         gtk_list_store_remove (list, &iter);
3341     }
3342
3343   g_object_unref (filter);
3344   g_object_unref (sort);
3345   g_object_unref (list);
3346 }
3347
3348
3349 static gboolean
3350 specific_append_after_collapse_visible_func (GtkTreeModel *model,
3351                                              GtkTreeIter  *iter,
3352                                              gpointer      data)
3353 {
3354   gint number;
3355   gboolean hide_negative_numbers;
3356
3357   gtk_tree_model_get (model, iter, 1, &number, -1);
3358   hide_negative_numbers = GPOINTER_TO_INT (g_object_get_data (data, "private-hide-negative-numbers"));
3359
3360   return (number >= 0 || !hide_negative_numbers);
3361 }
3362
3363 static void
3364 specific_append_after_collapse (void)
3365 {
3366   /* This test is based on one of the test cases I found in my
3367    * old test cases directory.  I unfortunately do not have a record
3368    * from who this test case originated.  -Kris.
3369    *
3370    * General idea:
3371    * - Construct tree.
3372    * - Show tree, expand, collapse.
3373    * - Add a row.
3374    */
3375
3376   GtkTreeIter iter;
3377   GtkTreeIter child_iter;
3378   GtkTreeIter child_iter2;
3379   GtkTreePath *append_path;
3380   GtkTreeStore *store;
3381   GtkTreeModel *filter;
3382   GtkTreeModel *sort;
3383
3384   GtkWidget *window;
3385   GtkWidget *tree_view;
3386
3387   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
3388
3389   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
3390   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
3391                      GINT_TO_POINTER (FALSE));
3392   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3393                                           specific_append_after_collapse_visible_func,
3394                                           filter, NULL);
3395
3396   sort = gtk_tree_model_sort_new_with_model (filter);
3397
3398   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3399   tree_view = gtk_tree_view_new_with_model (sort);
3400   gtk_container_add (GTK_CONTAINER (window), tree_view);
3401   gtk_widget_realize (tree_view);
3402
3403   while (gtk_events_pending ())
3404     gtk_main_iteration ();
3405
3406   gtk_tree_store_prepend (store, &iter, NULL);
3407   gtk_tree_store_set (store, &iter,
3408                       0, "hallo", 1, 1, -1);
3409
3410   gtk_tree_store_append (store, &child_iter, &iter);
3411   gtk_tree_store_set (store, &child_iter,
3412                       0, "toemaar", 1, 1, -1);
3413
3414   gtk_tree_store_append (store, &child_iter2, &child_iter);
3415   gtk_tree_store_set (store, &child_iter2,
3416                       0, "very deep", 1, 1, -1);
3417
3418   append_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &child_iter2);
3419
3420   gtk_tree_store_append (store, &child_iter, &iter);
3421   gtk_tree_store_set (store, &child_iter,
3422                       0, "sja", 1, 1, -1);
3423
3424   gtk_tree_store_append (store, &child_iter, &iter);
3425   gtk_tree_store_set (store, &child_iter,
3426                       0, "some word", 1, -1, -1);
3427
3428   /* Expand and collapse the tree */
3429   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
3430   while (gtk_events_pending ())
3431     gtk_main_iteration ();
3432
3433   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
3434   while (gtk_events_pending ())
3435     gtk_main_iteration ();
3436
3437   /* Add another it */
3438   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
3439                      GINT_TO_POINTER (TRUE));
3440
3441   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, append_path))
3442     {
3443       gtk_tree_store_append (store, &child_iter, &iter);
3444       gtk_tree_store_set (store, &child_iter,
3445                           0, "new new new !!", 1, 1, -1);
3446     }
3447   gtk_tree_path_free (append_path);
3448
3449   /* Expand */
3450   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
3451   while (gtk_events_pending ())
3452     gtk_main_iteration ();
3453 }
3454
3455
3456 static gint
3457 specific_sort_filter_remove_node_compare_func (GtkTreeModel  *model,
3458                                                GtkTreeIter   *iter1,
3459                                                GtkTreeIter   *iter2,
3460                                                gpointer       data)
3461 {
3462   return -1;
3463 }
3464
3465 static gboolean
3466 specific_sort_filter_remove_node_visible_func (GtkTreeModel  *model,
3467                                                GtkTreeIter   *iter,
3468                                                gpointer       data)
3469 {
3470   char *item = NULL;
3471
3472   /* Do reference the model */
3473   gtk_tree_model_get (model, iter, 0, &item, -1);
3474   g_free (item);
3475
3476   return FALSE;
3477 }
3478
3479 static void
3480 specific_sort_filter_remove_node (void)
3481 {
3482   /* This test is based on one of the test cases I found in my
3483    * old test cases directory.  I unfortunately do not have a record
3484    * from who this test case originated.  -Kris.
3485    *
3486    * General idea:
3487    *  - Create tree store, sort, filter models.  The sort model has
3488    *    a default sort func that is enabled, filter model a visible func
3489    *    that defaults to returning FALSE.
3490    *  - Remove a node from the tree store.
3491    */
3492
3493   GtkTreeIter iter;
3494   GtkTreeStore *store;
3495   GtkTreeModel *filter;
3496   GtkTreeModel *sort;
3497
3498   GtkWidget *window;
3499   GtkWidget *tree_view;
3500
3501   store = gtk_tree_store_new (1, G_TYPE_STRING);
3502   gtk_tree_store_append (store, &iter, NULL);
3503   gtk_tree_store_set (store, &iter, 0, "Hello1", -1);
3504
3505   gtk_tree_store_append (store, &iter, NULL);
3506   gtk_tree_store_set (store, &iter, 0, "Hello2", -1);
3507
3508   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
3509   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
3510                                            specific_sort_filter_remove_node_compare_func, NULL, NULL);
3511
3512   filter = gtk_tree_model_filter_new (sort, NULL);
3513   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3514                                           specific_sort_filter_remove_node_visible_func,
3515                                           filter, NULL);
3516
3517
3518   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3519   tree_view = gtk_tree_view_new_with_model (filter);
3520   gtk_container_add (GTK_CONTAINER (window), tree_view);
3521   gtk_widget_realize (tree_view);
3522
3523   while (gtk_events_pending ())
3524     gtk_main_iteration ();
3525
3526   /* Remove a node */
3527   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
3528   gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
3529   gtk_tree_store_remove (store, &iter);
3530
3531   while (gtk_events_pending ())
3532     gtk_main_iteration ();
3533 }
3534
3535
3536 static void
3537 specific_sort_filter_remove_root (void)
3538 {
3539   /* This test is based on one of the test cases I found in my
3540    * old test cases directory.  I unfortunately do not have a record
3541    * from who this test case originated.  -Kris.
3542    */
3543
3544   GtkTreeModel *model, *sort, *filter;
3545   GtkTreeIter root, mid, leaf;
3546   GtkTreePath *path;
3547
3548   model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
3549   gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
3550   gtk_tree_store_append (GTK_TREE_STORE (model), &mid, &root);
3551   gtk_tree_store_append (GTK_TREE_STORE (model), &leaf, &mid);
3552
3553   path = gtk_tree_model_get_path (model, &mid);
3554
3555   sort = gtk_tree_model_sort_new_with_model (model);
3556   filter = gtk_tree_model_filter_new (sort, path);
3557
3558   gtk_tree_path_free (path);
3559
3560   gtk_tree_store_remove (GTK_TREE_STORE (model), &root);
3561
3562   g_object_unref (filter);
3563   g_object_unref (sort);
3564   g_object_unref (model);
3565 }
3566
3567
3568 static void
3569 specific_root_mixed_visibility (void)
3570 {
3571   int i;
3572   GtkTreeModel *filter;
3573   /* A bit nasty, apologies */
3574   FilterTest fixture;
3575
3576   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3577
3578   for (i = 0; i < LEVEL_LENGTH; i++)
3579     {
3580       GtkTreeIter iter;
3581
3582       gtk_tree_store_insert (fixture.store, &iter, NULL, i);
3583       if (i % 2 == 0)
3584         create_tree_store_set_values (fixture.store, &iter, TRUE);
3585       else
3586         create_tree_store_set_values (fixture.store, &iter, FALSE);
3587     }
3588
3589   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3590   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3591   fixture.monitor = NULL;
3592
3593   gtk_tree_model_filter_set_visible_column (fixture.filter, 1);
3594
3595   /* In order to trigger the potential bug, we should not access
3596    * the filter model here (so don't call the check functions).
3597    */
3598
3599   /* Change visibility of an odd row to TRUE */
3600   set_path_visibility (&fixture, "3", TRUE);
3601   check_filter_model (&fixture);
3602   check_level_length (fixture.filter, NULL, 4);
3603 }
3604
3605
3606
3607 static gboolean
3608 specific_has_child_filter_filter_func (GtkTreeModel *model,
3609                                        GtkTreeIter  *iter,
3610                                        gpointer      data)
3611 {
3612   return gtk_tree_model_iter_has_child (model, iter);
3613 }
3614
3615 static void
3616 specific_has_child_filter (void)
3617 {
3618   GtkTreeModel *filter;
3619   GtkTreeIter iter, root;
3620   FilterTest fixture; /* This is not how it should be done */
3621   GtkWidget *tree_view;
3622
3623   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3624   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3625   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3626   fixture.monitor = signal_monitor_new (filter);
3627
3628   tree_view = gtk_tree_view_new_with_model (filter);
3629
3630   /* We will filter on parent state using a filter function.  We will
3631    * manually keep the boolean column in sync, so that we can use
3632    * check_filter_model() to check the consistency of the model.
3633    */
3634   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
3635    * to be able to check the structure here.  We keep the calls to
3636    * check_filter_model() commented out until then.
3637    */
3638   gtk_tree_model_filter_set_visible_func (fixture.filter,
3639                                           specific_has_child_filter_filter_func,
3640                                           NULL, NULL);
3641
3642   /* The first node will be initially invisible: no signals */
3643   gtk_tree_store_append (fixture.store, &root, NULL);
3644   create_tree_store_set_values (fixture.store, &root, FALSE);
3645
3646   /* check_filter_model (&fixture); */
3647   check_level_length (fixture.filter, NULL, 0);
3648   signal_monitor_assert_is_empty (fixture.monitor);
3649
3650   /* Insert a child node. This will cause the parent to become visible
3651    * since there is a child now.
3652    */
3653   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
3654   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3655   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3656
3657   gtk_tree_store_append (fixture.store, &iter, &root);
3658   create_tree_store_set_values (fixture.store, &iter, TRUE);
3659
3660   /* Parent must now be visible.  Do the level length check first,
3661    * to avoid modifying the child model triggering a row-changed to
3662    * the filter model.
3663    */
3664   check_level_length (fixture.filter, NULL, 1);
3665   check_level_length (fixture.filter, "0", 0);
3666   signal_monitor_assert_is_empty (fixture.monitor);
3667
3668   /* This should propagate row-changed */
3669   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
3670   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3671
3672   set_path_visibility (&fixture, "0", TRUE);
3673   /* check_filter_model (&fixture); */
3674   signal_monitor_assert_is_empty (fixture.monitor);
3675
3676   /* New root node, no child, so no signal */
3677   gtk_tree_store_append (fixture.store, &root, NULL);
3678   check_level_length (fixture.filter, NULL, 1);
3679   signal_monitor_assert_is_empty (fixture.monitor);
3680
3681   /* When the child comes in, this node will become visible */
3682   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
3683   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3684   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3685   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
3686   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3687
3688   gtk_tree_store_append (fixture.store, &iter, &root);
3689   check_level_length (fixture.filter, NULL, 2);
3690   check_level_length (fixture.filter, "1", 0);
3691
3692   create_tree_store_set_values (fixture.store, &root, TRUE);
3693   create_tree_store_set_values (fixture.store, &iter, TRUE);
3694
3695   /* check_filter_model (&fixture); */
3696   signal_monitor_assert_is_empty (fixture.monitor);
3697
3698   /* Add another child for 1 */
3699   gtk_tree_store_append (fixture.store, &iter, &root);
3700   create_tree_store_set_values (fixture.store, &iter, TRUE);
3701   check_level_length (fixture.filter, NULL, 2);
3702   check_level_length (fixture.filter, "0", 0);
3703   check_level_length (fixture.filter, "1", 0);
3704   signal_monitor_assert_is_empty (fixture.monitor);
3705
3706   /* Now remove one of the remaining child rows */
3707   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
3708
3709   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
3710                                        &iter, "0:0");
3711   gtk_tree_store_remove (fixture.store, &iter);
3712
3713   check_level_length (fixture.filter, NULL, 1);
3714   check_level_length (fixture.filter, "0", 0);
3715
3716   set_path_visibility (&fixture, "0", FALSE);
3717   /* check_filter_model (&fixture); */
3718   signal_monitor_assert_is_empty (fixture.monitor);
3719 }
3720
3721
3722 static gboolean
3723 specific_root_has_child_filter_filter_func (GtkTreeModel *model,
3724                                             GtkTreeIter  *iter,
3725                                             gpointer      data)
3726 {
3727   int depth;
3728   GtkTreePath *path;
3729
3730   path = gtk_tree_model_get_path (model, iter);
3731   depth = gtk_tree_path_get_depth (path);
3732   gtk_tree_path_free (path);
3733
3734   if (depth > 1)
3735     return TRUE;
3736   /* else */
3737   return gtk_tree_model_iter_has_child (model, iter);
3738 }
3739
3740 static void
3741 specific_root_has_child_filter (void)
3742 {
3743   GtkTreeModel *filter;
3744   GtkTreeIter iter, root;
3745   FilterTest fixture; /* This is not how it should be done ... */
3746   GtkWidget *tree_view;
3747
3748   /* This is a variation on the above test case, specific has-child-filter,
3749    * herein the has-child check for visibility only applies to root level
3750    * nodes.  In this test, children are always visible because we
3751    * only filter based on the "has child" criterion.
3752    */
3753
3754   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3755   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3756   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3757   fixture.monitor = signal_monitor_new (filter);
3758
3759   tree_view = gtk_tree_view_new_with_model (filter);
3760
3761   /* We will filter on parent state using a filter function.  We will
3762    * manually keep the boolean column in sync, so that we can use
3763    * check_filter_model() to check the consistency of the model.
3764    */
3765   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
3766    * to be able to check the structure here.  We keep the calls to
3767    * check_filter_model() commented out until then.
3768    */
3769   gtk_tree_model_filter_set_visible_func (fixture.filter,
3770                                           specific_root_has_child_filter_filter_func,
3771                                           NULL, NULL);
3772
3773   /* Add a first node, this will be invisible initially, so no signal
3774    * should be emitted.
3775    */
3776   gtk_tree_store_append (fixture.store, &root, NULL);
3777   create_tree_store_set_values (fixture.store, &root, FALSE);
3778
3779   signal_monitor_assert_is_empty (fixture.monitor);
3780   /* check_filter_model (&fixture); */
3781   check_level_length (fixture.filter, NULL, 0);
3782
3783   /* Add a child node.  This will cause the parent to become visible,
3784    * so we expect row-inserted signals for both.
3785    */
3786   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
3787   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3788   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3789
3790   gtk_tree_store_append (fixture.store, &iter, &root);
3791   signal_monitor_assert_is_empty (fixture.monitor);
3792
3793   check_level_length (fixture.filter, NULL, 1);
3794   check_level_length (fixture.filter, "0", 1);
3795
3796   /* Modify the content of iter, no signals because the parent is not
3797    * expanded.
3798    */
3799   create_tree_store_set_values (fixture.store, &iter, TRUE);
3800   signal_monitor_assert_is_empty (fixture.monitor);
3801
3802   /* Parent must now be visible.  Do the level length check first,
3803    * to avoid modifying the child model triggering a row-changed to
3804    * the filter model.
3805    */
3806   check_level_length (fixture.filter, NULL, 1);
3807   check_level_length (fixture.filter, "0", 1);
3808
3809   /* Modify path 0 */
3810   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
3811   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3812
3813   set_path_visibility (&fixture, "0", TRUE);
3814   /* check_filter_model (&fixture); */
3815
3816   signal_monitor_assert_is_empty (fixture.monitor);
3817
3818   /* Insert another node in the root level.  Initially invisible, so
3819    * not expecting any signal.
3820    */
3821   gtk_tree_store_append (fixture.store, &root, NULL);
3822   check_level_length (fixture.filter, NULL, 1);
3823
3824   signal_monitor_assert_is_empty (fixture.monitor);
3825
3826   /* Adding a child node which also makes parent at path 1 visible. */
3827   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
3828   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3829   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3830
3831   gtk_tree_store_append (fixture.store, &iter, &root);
3832   check_level_length (fixture.filter, NULL, 2);
3833   check_level_length (fixture.filter, "1", 1);
3834
3835   signal_monitor_assert_is_empty (fixture.monitor);
3836
3837   /* Check if row-changed is propagated */
3838   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
3839   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3840
3841   create_tree_store_set_values (fixture.store, &root, TRUE);
3842   create_tree_store_set_values (fixture.store, &iter, TRUE);
3843   /* check_filter_model (&fixture); */
3844   signal_monitor_assert_is_empty (fixture.monitor);
3845
3846   /* Insert another child under node 1 */
3847   gtk_tree_store_append (fixture.store, &iter, &root);
3848   create_tree_store_set_values (fixture.store, &iter, TRUE);
3849   check_level_length (fixture.filter, NULL, 2);
3850   check_level_length (fixture.filter, "0", 1);
3851   check_level_length (fixture.filter, "1", 2);
3852   signal_monitor_assert_is_empty (fixture.monitor);
3853
3854   /* Set a child node to invisible.  This should not yield any
3855    * change, because filtering is only done on whether the root
3856    * node has a child, which it still has.
3857    */
3858   set_path_visibility (&fixture, "0:0", FALSE);
3859   signal_monitor_assert_is_empty (fixture.monitor);
3860
3861   /* Now remove one of the remaining child rows */
3862   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3863   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
3864
3865   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
3866                                        &iter, "0:0");
3867   gtk_tree_store_remove (fixture.store, &iter);
3868
3869   check_level_length (fixture.filter, NULL, 1);
3870   check_level_length (fixture.filter, "0", 2);
3871   signal_monitor_assert_is_empty (fixture.monitor);
3872
3873   /* Set visibility of 0 to FALSE, no-op for filter model since
3874    * the child 0:0 is already gone
3875    */
3876   set_path_visibility (&fixture, "0", FALSE);
3877   /* check_filter_model (&fixture); */
3878   signal_monitor_assert_is_empty (fixture.monitor);
3879 }
3880
3881 static void
3882 specific_has_child_filter_on_sort_model (void)
3883 {
3884   GtkTreeModel *filter;
3885   GtkTreeModel *sort_model;
3886   GtkTreeIter iter, root;
3887   FilterTest fixture; /* This is not how it should be done */
3888   GtkWidget *tree_view;
3889
3890   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3891   sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (fixture.store));
3892   filter = gtk_tree_model_filter_new (sort_model, NULL);
3893   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3894   fixture.monitor = signal_monitor_new (filter);
3895
3896   tree_view = gtk_tree_view_new_with_model (filter);
3897
3898   /* We will filter on parent state using a filter function.  We will
3899    * manually keep the boolean column in sync, so that we can use
3900    * check_filter_model() to check the consistency of the model.
3901    */
3902   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
3903    * to be able to check the structure here.  We keep the calls to
3904    * check_filter_model() commented out until then.
3905    */
3906   gtk_tree_model_filter_set_visible_func (fixture.filter,
3907                                           specific_has_child_filter_filter_func,
3908                                           NULL, NULL);
3909
3910   /* The first node will be initially invisible: no signals */
3911   gtk_tree_store_append (fixture.store, &root, NULL);
3912   create_tree_store_set_values (fixture.store, &root, FALSE);
3913
3914   /* check_filter_model (&fixture); */
3915   check_level_length (fixture.filter, NULL, 0);
3916   signal_monitor_assert_is_empty (fixture.monitor);
3917
3918   /* Insert a child node. This will cause the parent to become visible
3919    * since there is a child now.
3920    */
3921   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
3922   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3923
3924   gtk_tree_store_append (fixture.store, &iter, &root);
3925   create_tree_store_set_values (fixture.store, &iter, TRUE);
3926
3927   /* Parent must now be visible.  Do the level length check first,
3928    * to avoid modifying the child model triggering a row-changed to
3929    * the filter model.
3930    */
3931   check_level_length (fixture.filter, NULL, 1);
3932   check_level_length (fixture.filter, "0", 0);
3933   signal_monitor_assert_is_empty (fixture.monitor);
3934
3935   /* This should propagate row-changed */
3936   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
3937   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3938
3939   set_path_visibility (&fixture, "0", TRUE);
3940   /* check_filter_model (&fixture); */
3941   signal_monitor_assert_is_empty (fixture.monitor);
3942
3943   /* New root node, no child, so no signal */
3944   gtk_tree_store_append (fixture.store, &root, NULL);
3945   check_level_length (fixture.filter, NULL, 1);
3946   signal_monitor_assert_is_empty (fixture.monitor);
3947
3948   /* When the child comes in, this node will become visible */
3949   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
3950   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3951   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
3952   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3953
3954   gtk_tree_store_append (fixture.store, &iter, &root);
3955   check_level_length (fixture.filter, NULL, 2);
3956   check_level_length (fixture.filter, "1", 0);
3957
3958   create_tree_store_set_values (fixture.store, &root, TRUE);
3959   create_tree_store_set_values (fixture.store, &iter, TRUE);
3960
3961   /* check_filter_model (&fixture); */
3962   signal_monitor_assert_is_empty (fixture.monitor);
3963
3964   /* Add another child for 1 */
3965   gtk_tree_store_append (fixture.store, &iter, &root);
3966   create_tree_store_set_values (fixture.store, &iter, TRUE);
3967   check_level_length (fixture.filter, NULL, 2);
3968   check_level_length (fixture.filter, "0", 0);
3969   check_level_length (fixture.filter, "1", 0);
3970   signal_monitor_assert_is_empty (fixture.monitor);
3971
3972   /* Now remove one of the remaining child rows */
3973   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
3974
3975   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
3976                                        &iter, "0:0");
3977   gtk_tree_store_remove (fixture.store, &iter);
3978
3979   check_level_length (fixture.filter, NULL, 1);
3980   check_level_length (fixture.filter, "0", 0);
3981
3982   set_path_visibility (&fixture, "0", FALSE);
3983   /* check_filter_model (&fixture); */
3984   signal_monitor_assert_is_empty (fixture.monitor);
3985 }
3986
3987 static gboolean
3988 specific_at_least_2_children_filter_filter_func (GtkTreeModel *model,
3989                                                  GtkTreeIter  *iter,
3990                                                  gpointer      data)
3991 {
3992   return gtk_tree_model_iter_n_children (model, iter) >= 2;
3993 }
3994
3995 static void
3996 specific_at_least_2_children_filter (void)
3997 {
3998   GtkTreeModel *filter;
3999   GtkTreeIter iter, root;
4000   FilterTest fixture; /* This is not how it should be done */
4001   GtkWidget *tree_view;
4002
4003   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
4004   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
4005   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
4006   fixture.monitor = signal_monitor_new (filter);
4007
4008   tree_view = gtk_tree_view_new_with_model (filter);
4009
4010   gtk_tree_model_filter_set_visible_func (fixture.filter,
4011                                           specific_at_least_2_children_filter_filter_func,
4012                                           NULL, NULL);
4013
4014   /* The first node will be initially invisible: no signals */
4015   gtk_tree_store_append (fixture.store, &root, NULL);
4016   create_tree_store_set_values (fixture.store, &root, FALSE);
4017
4018   /* check_filter_model (&fixture); */
4019   check_level_length (fixture.filter, NULL, 0);
4020   signal_monitor_assert_is_empty (fixture.monitor);
4021
4022   /* Insert a child node.  Nothing should happen.
4023    */
4024   gtk_tree_store_append (fixture.store, &iter, &root);
4025   create_tree_store_set_values (fixture.store, &iter, TRUE);
4026
4027   check_level_length (fixture.filter, NULL, 0);
4028   signal_monitor_assert_is_empty (fixture.monitor);
4029
4030   /* Insert a second child node.  This will cause the parent to become
4031    * visible.
4032    */
4033   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
4034   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4035
4036   gtk_tree_store_append (fixture.store, &iter, &root);
4037   create_tree_store_set_values (fixture.store, &iter, TRUE);
4038
4039   /* Parent must now be visible.  Do the level length check first,
4040    * to avoid modifying the child model triggering a row-changed to
4041    * the filter model.
4042    */
4043   check_level_length (fixture.filter, NULL, 1);
4044   check_level_length (fixture.filter, "0", 0);
4045   signal_monitor_assert_is_empty (fixture.monitor);
4046
4047   /* This should propagate row-changed */
4048   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
4049   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4050
4051   set_path_visibility (&fixture, "0", TRUE);
4052   /* check_filter_model (&fixture); */
4053   signal_monitor_assert_is_empty (fixture.monitor);
4054
4055   /* New root node, no child, so no signal */
4056   gtk_tree_store_append (fixture.store, &root, NULL);
4057   check_level_length (fixture.filter, NULL, 1);
4058   signal_monitor_assert_is_empty (fixture.monitor);
4059
4060   /* First child, no signal, no change */
4061   gtk_tree_store_append (fixture.store, &iter, &root);
4062   check_level_length (fixture.filter, NULL, 1);
4063   signal_monitor_assert_is_empty (fixture.monitor);
4064
4065   /* When the second child comes in, this node will become visible */
4066   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
4067   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4068   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
4069   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4070
4071   gtk_tree_store_append (fixture.store, &iter, &root);
4072   check_level_length (fixture.filter, NULL, 2);
4073   check_level_length (fixture.filter, "1", 0);
4074
4075   create_tree_store_set_values (fixture.store, &root, TRUE);
4076   create_tree_store_set_values (fixture.store, &iter, TRUE);
4077
4078   /* check_filter_model (&fixture); */
4079   signal_monitor_assert_is_empty (fixture.monitor);
4080
4081   /* Add another child for 1 */
4082   gtk_tree_store_append (fixture.store, &iter, &root);
4083   create_tree_store_set_values (fixture.store, &iter, TRUE);
4084   check_level_length (fixture.filter, NULL, 2);
4085   check_level_length (fixture.filter, "0", 0);
4086   check_level_length (fixture.filter, "1", 0);
4087   signal_monitor_assert_is_empty (fixture.monitor);
4088
4089   /* Now remove one of the remaining child rows */
4090   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
4091
4092   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
4093                                        &iter, "0:0");
4094   gtk_tree_store_remove (fixture.store, &iter);
4095
4096   check_level_length (fixture.filter, NULL, 1);
4097   check_level_length (fixture.filter, "0", 0);
4098
4099   set_path_visibility (&fixture, "0", FALSE);
4100   /* check_filter_model (&fixture); */
4101   signal_monitor_assert_is_empty (fixture.monitor);
4102 }
4103
4104 static void
4105 specific_at_least_2_children_filter_on_sort_model (void)
4106 {
4107   GtkTreeModel *filter;
4108   GtkTreeModel *sort_model;
4109   GtkTreeIter iter, root;
4110   FilterTest fixture; /* This is not how it should be done */
4111   GtkWidget *tree_view;
4112
4113   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
4114   sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (fixture.store));
4115   filter = gtk_tree_model_filter_new (sort_model, NULL);
4116   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
4117   fixture.monitor = signal_monitor_new (filter);
4118
4119   tree_view = gtk_tree_view_new_with_model (filter);
4120
4121   gtk_tree_model_filter_set_visible_func (fixture.filter,
4122                                           specific_at_least_2_children_filter_filter_func,
4123                                           NULL, NULL);
4124
4125   /* The first node will be initially invisible: no signals */
4126   gtk_tree_store_append (fixture.store, &root, NULL);
4127   create_tree_store_set_values (fixture.store, &root, FALSE);
4128
4129   /* check_filter_model (&fixture); */
4130   check_level_length (fixture.filter, NULL, 0);
4131   signal_monitor_assert_is_empty (fixture.monitor);
4132
4133   /* Insert a child node.  Nothing should happen.
4134    */
4135   gtk_tree_store_append (fixture.store, &iter, &root);
4136   create_tree_store_set_values (fixture.store, &iter, TRUE);
4137
4138   check_level_length (fixture.filter, NULL, 0);
4139   signal_monitor_assert_is_empty (fixture.monitor);
4140
4141     {
4142       GtkTreePath *path = gtk_tree_path_new_from_indices (0, 0, -1);
4143       GtkTreeRowReference *ref;
4144
4145       ref = gtk_tree_row_reference_new (sort_model, path);
4146       gtk_tree_path_free (path);
4147     }
4148
4149   /* Insert a second child node.  This will cause the parent to become
4150    * visible.
4151    */
4152   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
4153   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4154
4155   gtk_tree_store_append (fixture.store, &iter, &root);
4156   create_tree_store_set_values (fixture.store, &iter, TRUE);
4157
4158   /* Parent must now be visible.  Do the level length check first,
4159    * to avoid modifying the child model triggering a row-changed to
4160    * the filter model.
4161    */
4162   check_level_length (fixture.filter, NULL, 1);
4163   check_level_length (fixture.filter, "0", 0);
4164   signal_monitor_assert_is_empty (fixture.monitor);
4165
4166   /* This should propagate row-changed */
4167   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
4168   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4169
4170   set_path_visibility (&fixture, "0", TRUE);
4171   /* check_filter_model (&fixture); */
4172   signal_monitor_assert_is_empty (fixture.monitor);
4173
4174   /* New root node, no child, so no signal */
4175   gtk_tree_store_append (fixture.store, &root, NULL);
4176   check_level_length (fixture.filter, NULL, 1);
4177   signal_monitor_assert_is_empty (fixture.monitor);
4178 }
4179
4180
4181 static void
4182 specific_filter_add_child (void)
4183 {
4184   /* This test is based on one of the test cases I found in my
4185    * old test cases directory.  I unfortunately do not have a record
4186    * from who this test case originated.  -Kris.
4187    */
4188
4189   GtkTreeIter iter;
4190   GtkTreeIter iter_first;
4191   GtkTreeIter child;
4192   GtkTreeStore *store;
4193   GtkTreeModel *filter G_GNUC_UNUSED;
4194
4195   store = gtk_tree_store_new (1, G_TYPE_STRING);
4196
4197   gtk_tree_store_append (store, &iter_first, NULL);
4198   gtk_tree_store_set (store, &iter_first, 0, "Hello", -1);
4199
4200   gtk_tree_store_append (store, &iter, NULL);
4201   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4202
4203   gtk_tree_store_append (store, &iter, NULL);
4204   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4205
4206   gtk_tree_store_append (store, &iter, NULL);
4207   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4208
4209   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4210
4211   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4212   gtk_tree_store_append (store, &child, &iter_first);
4213   gtk_tree_store_set (store, &child, 0, "Hello", -1);
4214 }
4215
4216 static void
4217 specific_list_store_clear (void)
4218 {
4219   GtkTreeIter iter;
4220   GtkListStore *list;
4221   GtkTreeModel *filter;
4222   GtkWidget *view G_GNUC_UNUSED;
4223
4224   list = gtk_list_store_new (1, G_TYPE_INT);
4225   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
4226   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
4227   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
4228   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
4229   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
4230   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
4231   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
4232   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
4233
4234   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
4235   view = gtk_tree_view_new_with_model (filter);
4236
4237   gtk_list_store_clear (list);
4238 }
4239
4240 static void
4241 specific_sort_ref_leaf_and_remove_ancestor (void)
4242 {
4243   GtkTreeIter iter, child, child2, child3;
4244   GtkTreeStore *tree;
4245   GtkTreeModel *sort;
4246   GtkTreePath *path;
4247   GtkTreeRowReference *rowref;
4248   GtkWidget *view G_GNUC_UNUSED;
4249
4250   tree = gtk_tree_store_new (1, G_TYPE_INT);
4251   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4252   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4253   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4254   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4255
4256   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4257   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4258   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4259
4260   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
4261   view = gtk_tree_view_new_with_model (sort);
4262   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4263
4264   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4265   rowref = gtk_tree_row_reference_new (sort, path);
4266   gtk_tree_path_free (path);
4267
4268   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4269   rowref = gtk_tree_row_reference_new (sort, path);
4270   gtk_tree_path_free (path);
4271
4272   path = gtk_tree_path_new_from_indices (3, 0, -1);
4273   rowref = gtk_tree_row_reference_new (sort, path);
4274   gtk_tree_path_free (path);
4275
4276   path = gtk_tree_path_new_from_indices (3, -1);
4277   rowref = gtk_tree_row_reference_new (sort, path);
4278   gtk_tree_path_free (path);
4279
4280   /* Deleting a parent */
4281   path = gtk_tree_path_new_from_indices (3, 0, -1);
4282   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4283   gtk_tree_store_remove (tree, &iter);
4284   gtk_tree_path_free (path);
4285
4286   gtk_tree_row_reference_free (rowref);
4287 }
4288
4289 static void
4290 specific_ref_leaf_and_remove_ancestor (void)
4291 {
4292   GtkTreeIter iter, child, child2, child3;
4293   GtkTreeStore *tree;
4294   GtkTreeModel *filter;
4295   GtkTreePath *path;
4296   GtkTreeRowReference *rowref;
4297   GtkWidget *view G_GNUC_UNUSED;
4298
4299   tree = gtk_tree_store_new (1, G_TYPE_INT);
4300   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4301   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4302   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4303   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4304
4305   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4306   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4307   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4308
4309   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), NULL);
4310   view = gtk_tree_view_new_with_model (filter);
4311   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4312
4313   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4314   rowref = gtk_tree_row_reference_new (filter, path);
4315   gtk_tree_path_free (path);
4316
4317   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4318   rowref = gtk_tree_row_reference_new (filter, path);
4319   gtk_tree_path_free (path);
4320
4321   path = gtk_tree_path_new_from_indices (3, 0, -1);
4322   rowref = gtk_tree_row_reference_new (filter, path);
4323   gtk_tree_path_free (path);
4324
4325   path = gtk_tree_path_new_from_indices (3, -1);
4326   rowref = gtk_tree_row_reference_new (filter, path);
4327   gtk_tree_path_free (path);
4328
4329   /* Deleting a parent */
4330   path = gtk_tree_path_new_from_indices (3, 0, -1);
4331   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4332   gtk_tree_store_remove (tree, &iter);
4333   gtk_tree_path_free (path);
4334
4335   gtk_tree_row_reference_free (rowref);
4336 }
4337
4338 static void
4339 specific_virtual_ref_leaf_and_remove_ancestor (void)
4340 {
4341   GtkTreeIter iter, child, child2, child3;
4342   GtkTreeStore *tree;
4343   GtkTreeModel *filter;
4344   GtkTreePath *path;
4345   GtkTreeRowReference *rowref;
4346   GtkWidget *view G_GNUC_UNUSED;
4347
4348   tree = gtk_tree_store_new (1, G_TYPE_INT);
4349   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4350   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4351   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4352   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4353
4354   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4355   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4356   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4357
4358   /* Set a virtual root of 3:0 */
4359   path = gtk_tree_path_new_from_indices (3, 0, -1);
4360   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
4361   gtk_tree_path_free (path);
4362
4363   view = gtk_tree_view_new_with_model (filter);
4364   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4365
4366   path = gtk_tree_path_new_from_indices (0, 0, -1);
4367   rowref = gtk_tree_row_reference_new (filter, path);
4368   gtk_tree_path_free (path);
4369
4370   path = gtk_tree_path_new_from_indices (0, 0, -1);
4371   rowref = gtk_tree_row_reference_new (filter, path);
4372   gtk_tree_path_free (path);
4373
4374   path = gtk_tree_path_new_from_indices (0, -1);
4375   rowref = gtk_tree_row_reference_new (filter, path);
4376   gtk_tree_path_free (path);
4377
4378   /* Deleting the virtual root */
4379   path = gtk_tree_path_new_from_indices (3, 0, -1);
4380   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4381   gtk_tree_store_remove (tree, &iter);
4382   gtk_tree_path_free (path);
4383
4384   gtk_tree_row_reference_free (rowref);
4385 }
4386
4387
4388 static int
4389 specific_bug_301558_sort_func (GtkTreeModel *model,
4390                                GtkTreeIter  *a,
4391                                GtkTreeIter  *b,
4392                                gpointer      data)
4393 {
4394   int i, j;
4395
4396   gtk_tree_model_get (model, a, 0, &i, -1);
4397   gtk_tree_model_get (model, b, 0, &j, -1);
4398
4399   return j - i;
4400 }
4401
4402 static void
4403 specific_bug_301558 (void)
4404 {
4405   /* Test case for GNOME Bugzilla bug 301558 provided by
4406    * Markku Vire.
4407    */
4408   GtkTreeStore *tree;
4409   GtkTreeModel *filter;
4410   GtkTreeModel *sort;
4411   GtkTreeIter root, iter, iter2;
4412   GtkWidget *view G_GNUC_UNUSED;
4413   int i;
4414   gboolean add;
4415
4416   g_test_bug ("301558");
4417
4418   tree = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_BOOLEAN);
4419   gtk_tree_store_append (tree, &iter, NULL);
4420   gtk_tree_store_set (tree, &iter, 0, 123, 1, TRUE, -1);
4421   gtk_tree_store_append (tree, &iter2, &iter);
4422   gtk_tree_store_set (tree, &iter2, 0, 73, 1, TRUE, -1);
4423
4424   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
4425   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
4426                                            specific_bug_301558_sort_func,
4427                                            NULL, NULL);
4428
4429   filter = gtk_tree_model_filter_new (sort, NULL);
4430   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), 1);
4431
4432   view = gtk_tree_view_new_with_model (filter);
4433
4434   while (gtk_events_pending ())
4435     gtk_main_iteration ();
4436
4437   add = TRUE;
4438
4439   for (i = 0; i < 10; i++)
4440     {
4441       if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree), &root))
4442         g_assert_not_reached ();
4443
4444       if (add)
4445         {
4446           gtk_tree_store_append (tree, &iter, &root);
4447           gtk_tree_store_set (tree, &iter, 0, 456, 1, TRUE, -1);
4448         }
4449       else
4450         {
4451           int n;
4452           n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree), &root);
4453           gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (tree), &iter,
4454                                          &root, n - 1);
4455           gtk_tree_store_remove (tree, &iter);
4456         }
4457
4458       add = !add;
4459     }
4460 }
4461
4462
4463 static gboolean
4464 specific_bug_311955_filter_func (GtkTreeModel *model,
4465                                  GtkTreeIter  *iter,
4466                                  gpointer      data)
4467 {
4468   int value;
4469
4470   gtk_tree_model_get (model, iter, 0, &value, -1);
4471
4472   return (value != 0);
4473 }
4474
4475 static void
4476 specific_bug_311955 (void)
4477 {
4478   /* This is a test case for GNOME Bugzilla bug 311955.  It was written
4479    * by Markku Vire.
4480    */
4481   GtkTreeIter iter, child, root;
4482   GtkTreeStore *store;
4483   GtkTreeModel *sort;
4484   GtkTreeModel *filter;
4485
4486   GtkWidget *window G_GNUC_UNUSED;
4487   GtkWidget *tree_view;
4488   int i;
4489   int n;
4490   GtkTreePath *path;
4491
4492   g_test_bug ("311955");
4493
4494   store = gtk_tree_store_new (1, G_TYPE_INT);
4495
4496   gtk_tree_store_append (store, &root, NULL);
4497   gtk_tree_store_set (store, &root, 0, 33, -1);
4498
4499   gtk_tree_store_append (store, &iter, &root);
4500   gtk_tree_store_set (store, &iter, 0, 50, -1);
4501
4502   gtk_tree_store_append (store, &iter, NULL);
4503   gtk_tree_store_set (store, &iter, 0, 22, -1);
4504
4505   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
4506   filter = gtk_tree_model_filter_new (sort, NULL);
4507
4508   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4509                                           specific_bug_311955_filter_func,
4510                                           NULL, NULL);
4511
4512   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4513   tree_view = gtk_tree_view_new_with_model (filter);
4514   g_object_unref (store);
4515
4516   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
4517
4518   while (gtk_events_pending ())
4519     gtk_main_iteration ();
4520
4521   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
4522   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 1);
4523
4524   /* Fill model */
4525   for (i = 0; i < 4; i++)
4526     {
4527       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
4528
4529       gtk_tree_store_append (store, &iter, &root);
4530
4531       if (i < 3)
4532         gtk_tree_store_set (store, &iter, 0, i, -1);
4533
4534       if (i % 2 == 0)
4535         {
4536           gtk_tree_store_append (store, &child, &iter);
4537           gtk_tree_store_set (store, &child, 0, 10, -1);
4538         }
4539     }
4540
4541   while (gtk_events_pending ())
4542     gtk_main_iteration ();
4543
4544   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4545   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 1);
4546
4547   /* Remove bottommost child from the tree. */
4548   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
4549   n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &root);
4550
4551   if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
4552     {
4553       if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
4554         gtk_tree_store_remove (store, &child);
4555     }
4556   else
4557     g_assert_not_reached ();
4558
4559   path = gtk_tree_path_new_from_indices (0, 2, -1);
4560   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
4561   gtk_tree_path_free (path);
4562
4563   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4564   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 0);
4565 }
4566
4567 static void
4568 specific_bug_311955_clean (void)
4569 {
4570   /* Cleaned up version of the test case for GNOME Bugzilla bug 311955,
4571    * which is easier to understand.
4572    */
4573   GtkTreeIter iter, child, grandchild;
4574   GtkTreeStore *store;
4575   GtkTreeModel *sort;
4576   GtkTreeModel *filter;
4577
4578   GtkWidget *tree_view;
4579   GtkTreePath *path;
4580
4581   store = gtk_tree_store_new (1, G_TYPE_INT);
4582
4583   gtk_tree_store_append (store, &iter, NULL);
4584   gtk_tree_store_set (store, &iter, 0, 1, -1);
4585
4586   gtk_tree_store_append (store, &child, &iter);
4587   gtk_tree_store_set (store, &child, 0, 1, -1);
4588
4589   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
4590   filter = gtk_tree_model_filter_new (sort, NULL);
4591
4592   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4593                                           specific_bug_311955_filter_func,
4594                                           NULL, NULL);
4595
4596   tree_view = gtk_tree_view_new_with_model (filter);
4597   g_object_unref (store);
4598
4599   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
4600
4601   while (gtk_events_pending ())
4602     gtk_main_iteration ();
4603
4604   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
4605   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 1);
4606
4607   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
4608
4609   gtk_tree_store_append (store, &child, &iter);
4610   gtk_tree_store_set (store, &child, 0, 0, -1);
4611
4612   gtk_tree_store_append (store, &child, &iter);
4613   gtk_tree_store_set (store, &child, 0, 1, -1);
4614
4615   gtk_tree_store_append (store, &child, &iter);
4616   gtk_tree_store_set (store, &child, 0, 1, -1);
4617
4618   gtk_tree_store_append (store, &grandchild, &child);
4619   gtk_tree_store_set (store, &grandchild, 0, 1, -1);
4620
4621   gtk_tree_store_append (store, &child, &iter);
4622   /* Don't set a value: assume 0 */
4623
4624   /* Remove leaf node, check trigger row-has-child-toggled */
4625   path = gtk_tree_path_new_from_indices (0, 3, 0, -1);
4626   gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
4627   gtk_tree_path_free (path);
4628   gtk_tree_store_remove (store, &iter);
4629
4630   path = gtk_tree_path_new_from_indices (0, 2, -1);
4631   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
4632   gtk_tree_path_free (path);
4633
4634   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4635   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 0);
4636
4637   gtk_widget_destroy (tree_view);
4638 }
4639
4640 static void
4641 specific_bug_346800 (void)
4642 {
4643   /* This is a test case for GNOME Bugzilla bug 346800.  It was written
4644    * by Jonathan Matthew.
4645    */
4646
4647   GtkTreeIter node_iters[50];
4648   GtkTreeIter child_iters[50];
4649   GtkTreeModel *model;
4650   GtkTreeModelFilter *filter;
4651   GtkTreeStore *store;
4652   GType *columns;
4653   int i;
4654   int items = 50;
4655   columns = g_new (GType, 2);
4656   columns[0] = G_TYPE_STRING;
4657   columns[1] = G_TYPE_BOOLEAN;
4658   store = gtk_tree_store_newv (2, columns);
4659   model = GTK_TREE_MODEL (store);
4660
4661   g_test_bug ("346800");
4662
4663   filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
4664   gtk_tree_model_filter_set_visible_column (filter, 1);
4665
4666   for (i=0; i<items; i++)
4667     {
4668       /* allocate random amounts of junk, otherwise the filter model's arrays can expand without moving */
4669
4670       g_malloc (138);
4671       gtk_tree_store_append (store, &node_iters[i], NULL);
4672       gtk_tree_store_set (store, &node_iters[i],
4673                           0, "something",
4674                           1, ((i%6) == 0) ? FALSE : TRUE,
4675                           -1);
4676
4677       g_malloc (47);
4678       gtk_tree_store_append (store, &child_iters[i], &node_iters[i]);
4679       gtk_tree_store_set (store, &child_iters[i],
4680                           0, "something else",
4681                           1, FALSE,
4682                           -1);
4683       gtk_tree_model_filter_refilter (filter);
4684
4685       if (i > 6)
4686         {
4687           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-1], 1,
4688                               (i & 1) ? TRUE : FALSE, -1);
4689           gtk_tree_model_filter_refilter (filter);
4690
4691           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
4692                               (i & 1) ? FALSE: TRUE, -1);
4693           gtk_tree_model_filter_refilter (filter);
4694         }
4695     }
4696 }
4697
4698 static gboolean
4699 specific_bug_464173_visible_func (GtkTreeModel *model,
4700                                   GtkTreeIter  *iter,
4701                                   gpointer      data)
4702 {
4703   gboolean *visible = (gboolean *)data;
4704
4705   return *visible;
4706 }
4707
4708 static void
4709 specific_bug_464173 (void)
4710 {
4711   /* Test case for GNOME Bugzilla bug 464173, test case written
4712    * by Andreas Koehler.
4713    */
4714   GtkTreeStore *model;
4715   GtkTreeModelFilter *f_model;
4716   GtkTreeIter iter1, iter2;
4717   GtkWidget *view G_GNUC_UNUSED;
4718   gboolean visible = TRUE;
4719
4720   g_test_bug ("464173");
4721
4722   model = gtk_tree_store_new (1, G_TYPE_STRING);
4723   gtk_tree_store_append (model, &iter1, NULL);
4724   gtk_tree_store_set (model, &iter1, 0, "Foo", -1);
4725   gtk_tree_store_append (model, &iter2, &iter1);
4726   gtk_tree_store_set (model, &iter2, 0, "Bar", -1);
4727
4728   f_model = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL(model), NULL));
4729   gtk_tree_model_filter_set_visible_func (f_model,
4730                                           specific_bug_464173_visible_func,
4731                                           &visible, NULL);
4732
4733   view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (f_model));
4734
4735   visible = FALSE;
4736   gtk_tree_model_filter_refilter (f_model);
4737 }
4738
4739
4740 static gboolean
4741 specific_bug_540201_filter_func (GtkTreeModel *model,
4742                                  GtkTreeIter  *iter,
4743                                  gpointer      data)
4744 {
4745   gboolean has_children;
4746
4747   has_children = gtk_tree_model_iter_has_child (model, iter);
4748
4749   return has_children;
4750 }
4751
4752 static void
4753 specific_bug_540201 (void)
4754 {
4755   /* Test case for GNOME Bugzilla bug 540201, steps provided by
4756    * Charles Day.
4757    */
4758   GtkTreeIter iter, root;
4759   GtkTreeStore *store;
4760   GtkTreeModel *filter;
4761
4762   GtkWidget *tree_view G_GNUC_UNUSED;
4763
4764   g_test_bug ("540201");
4765
4766   store = gtk_tree_store_new (1, G_TYPE_INT);
4767
4768   gtk_tree_store_append (store, &root, NULL);
4769   gtk_tree_store_set (store, &root, 0, 33, -1);
4770
4771   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4772   tree_view = gtk_tree_view_new_with_model (filter);
4773
4774   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4775                                           specific_bug_540201_filter_func,
4776                                           NULL, NULL);
4777
4778   gtk_tree_store_append (store, &iter, &root);
4779   gtk_tree_store_set (store, &iter, 0, 50, -1);
4780
4781   gtk_tree_store_append (store, &iter, &root);
4782   gtk_tree_store_set (store, &iter, 0, 22, -1);
4783
4784
4785   gtk_tree_store_append (store, &root, NULL);
4786   gtk_tree_store_set (store, &root, 0, 33, -1);
4787
4788   gtk_tree_store_append (store, &iter, &root);
4789   gtk_tree_store_set (store, &iter, 0, 22, -1);
4790 }
4791
4792
4793 static gboolean
4794 specific_bug_549287_visible_func (GtkTreeModel *model,
4795                                   GtkTreeIter  *iter,
4796                                   gpointer      data)
4797 {
4798   gboolean result = FALSE;
4799
4800   result = gtk_tree_model_iter_has_child (model, iter);
4801
4802   return result;
4803 }
4804
4805 static void
4806 specific_bug_549287 (void)
4807 {
4808   /* Test case for GNOME Bugzilla bug 529287, provided by Julient Puydt */
4809
4810   int i;
4811   GtkTreeStore *store;
4812   GtkTreeModel *filtered;
4813   GtkWidget *view G_GNUC_UNUSED;
4814   GtkTreeIter iter;
4815   GtkTreeIter *swap, *parent, *child;
4816
4817   g_test_bug ("529287");
4818
4819   store = gtk_tree_store_new (1, G_TYPE_STRING);
4820   filtered = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4821   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered),
4822                                           specific_bug_549287_visible_func,
4823                                           NULL, NULL);
4824
4825   view = gtk_tree_view_new_with_model (filtered);
4826
4827   for (i = 0; i < 4; i++)
4828     {
4829       if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
4830         {
4831           parent = gtk_tree_iter_copy (&iter);
4832           child = gtk_tree_iter_copy (&iter);
4833
4834           while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
4835                                                 child, parent, 0))
4836             {
4837
4838               swap = parent;
4839               parent = child;
4840               child = swap;
4841             }
4842
4843           gtk_tree_store_append (store, child, parent);
4844           gtk_tree_store_set (store, child,
4845                               0, "Something",
4846                               -1);
4847
4848           gtk_tree_iter_free (parent);
4849           gtk_tree_iter_free (child);
4850         }
4851       else
4852         {
4853           gtk_tree_store_append (store, &iter, NULL);
4854           gtk_tree_store_set (store, &iter,
4855                               0, "Something",
4856                               -1);
4857         }
4858
4859       /* since we inserted something, we changed the visibility conditions: */
4860       gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filtered));
4861     }
4862 }
4863
4864 static gboolean
4865 specific_bug_621076_visible_func (GtkTreeModel *model,
4866                                   GtkTreeIter  *iter,
4867                                   gpointer      data)
4868 {
4869   gboolean visible = FALSE;
4870   gchar *str = NULL;
4871
4872   gtk_tree_model_get (model, iter, 0, &str, -1);
4873   if (str != NULL && g_str_has_prefix (str, "visible"))
4874     {
4875       visible = TRUE;
4876     }
4877   else
4878     {
4879       GtkTreeIter child_iter;
4880       gboolean valid;
4881
4882       /* Recursively check if we have a visible child */
4883       for (valid = gtk_tree_model_iter_children (model, &child_iter, iter);
4884            valid; valid = gtk_tree_model_iter_next (model, &child_iter))
4885         {
4886           if (specific_bug_621076_visible_func (model, &child_iter, data))
4887             {
4888               visible = TRUE;
4889               break;
4890             }
4891         }
4892     }
4893
4894   if (str)
4895     g_free (str);
4896
4897   return visible;
4898 }
4899
4900 static void
4901 specific_bug_621076 (void)
4902 {
4903   /* Test case for GNOME Bugzilla bug 621076, provided by Xavier Claessens */
4904
4905   /* This test case differs from has-child-filter and root-has-child-filter
4906    * in that the visible function both filters on content and model
4907    * structure.  Also, it is recursive.
4908    */
4909
4910   GtkTreeStore *store;
4911   GtkTreeModel *filter;
4912   GtkWidget *view;
4913   GtkTreeIter group_iter;
4914   GtkTreeIter item_iter;
4915   SignalMonitor *monitor;
4916
4917   g_test_bug ("621076");
4918
4919   store = gtk_tree_store_new (1, G_TYPE_STRING);
4920   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4921   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4922                                           specific_bug_621076_visible_func,
4923                                           NULL, NULL);
4924
4925   view = gtk_tree_view_new_with_model (filter);
4926   g_object_ref_sink (view);
4927
4928   monitor = signal_monitor_new (filter);
4929
4930   signal_monitor_append_signal (monitor, ROW_INSERTED, "0");
4931   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
4932                                      0, "visible-group-0",
4933                                      -1);
4934   signal_monitor_assert_is_empty (monitor);
4935
4936   /* visible-group-0 is not expanded, so ROW_INSERTED should not be emitted
4937    * for its children. However, ROW_HAS_CHILD_TOGGLED should be emitted on
4938    * visible-group-0 to tell the view that row can be expanded. */
4939   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
4940   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
4941   group_iter = item_iter;
4942   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
4943                                      0, "visible-0:0",
4944                                      -1);
4945   signal_monitor_assert_is_empty (monitor);
4946
4947   signal_monitor_append_signal (monitor, ROW_INSERTED, "1");
4948   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
4949                                      0, "visible-group-1",
4950                                      -1);
4951   signal_monitor_assert_is_empty (monitor);
4952
4953   /* We are adding an hidden item inside visible-group-1, so
4954    * ROW_HAS_CHILD_TOGGLED should not be emitted.  It is emitted though,
4955    * because the signal originating at TreeStore will be propagated,
4956    * as well a generated signal because the state of the parent *could*
4957    * change by a change in the model.
4958    */
4959   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
4960   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
4961   group_iter = item_iter;
4962   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
4963                                      0, "group-1:0",
4964                                      -1);
4965   signal_monitor_assert_is_empty (monitor);
4966
4967   /* This group is invisible and its parent too. Nothing should be emitted */
4968   group_iter = item_iter;
4969   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
4970                                      0, "group-1:0:0",
4971                                      -1);
4972   signal_monitor_assert_is_empty (monitor);
4973
4974   /* Adding a visible item in this group hierarchy will make all nodes
4975    * in this path visible.  The first level should simply tell the view
4976    * that it now has a child, and the view will load the tree if needed
4977    * (depends on the expanded state).
4978    */
4979   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
4980   group_iter = item_iter;
4981   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
4982                                      0, "visible-1:0:0:0",
4983                                      -1);
4984   signal_monitor_assert_is_empty (monitor);
4985
4986   check_level_length (GTK_TREE_MODEL_FILTER (filter), "1", 1);
4987
4988   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
4989                                      0, "group-2",
4990                                      -1);
4991   signal_monitor_assert_is_empty (monitor);
4992
4993   /* Parent is invisible, and adding this invisible item won't change that,
4994    * so no signal should be emitted. */
4995   group_iter = item_iter;
4996   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
4997                                      0, "invisible-2:0",
4998                                      -1);
4999   signal_monitor_assert_is_empty (monitor);
5000
5001   /* This makes group-2 visible, so it gets inserted and tells it has
5002    * children.
5003    */
5004   signal_monitor_append_signal (monitor, ROW_INSERTED, "2");
5005   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5006   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5007                                      0, "visible-2:1",
5008                                      -1);
5009   signal_monitor_assert_is_empty (monitor);
5010
5011   /* group-2 is already visible, so this time it is a normal insertion */
5012   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5013                                      0, "visible-2:2",
5014                                      -1);
5015   signal_monitor_assert_is_empty (monitor);
5016
5017
5018   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5019                                      0, "group-3",
5020                                      -1);
5021   signal_monitor_assert_is_empty (monitor);
5022
5023   /* Parent is invisible, and adding this invisible item won't change that,
5024    * so no signal should be emitted. */
5025   group_iter = item_iter;
5026   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5027                                      0, "invisible-3:0",
5028                                      -1);
5029   signal_monitor_assert_is_empty (monitor);
5030
5031   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5032                                      0, "invisible-3:1",
5033                                      -1);
5034   signal_monitor_assert_is_empty (monitor);
5035
5036   /* This will make group 3 visible. */
5037   signal_monitor_append_signal (monitor, ROW_INSERTED, "3");
5038   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3");
5039   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3");
5040   gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1);
5041   signal_monitor_assert_is_empty (monitor);
5042
5043   /* Make sure all groups are expanded, so the filter has the tree cached */
5044   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
5045   while (gtk_events_pending ())
5046     gtk_main_iteration ();
5047
5048   /* Should only yield a row-changed */
5049   signal_monitor_append_signal (monitor, ROW_CHANGED, "3:0");
5050   gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1);
5051   signal_monitor_assert_is_empty (monitor);
5052
5053   /* Now remove/hide some items. If a group loses its last item, the group
5054    * should be deleted instead of the item.
5055    */
5056
5057   signal_monitor_append_signal (monitor, ROW_DELETED, "2:1");
5058   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:2");
5059   gtk_tree_store_remove (store, &item_iter);
5060   signal_monitor_assert_is_empty (monitor);
5061
5062   signal_monitor_append_signal (monitor, ROW_DELETED, "2:0");
5063   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5064   signal_monitor_append_signal (monitor, ROW_DELETED, "2");
5065   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:1");
5066   gtk_tree_store_set (store, &item_iter, 0, "invisible-2:1", -1);
5067   signal_monitor_assert_is_empty (monitor);
5068
5069   signal_monitor_append_signal (monitor, ROW_DELETED, "1:0:0:0");
5070   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1:0:0");
5071   signal_monitor_append_signal (monitor, ROW_DELETED, "1:0");
5072   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
5073   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "1:0:0:0");
5074   gtk_tree_store_remove (store, &item_iter);
5075   signal_monitor_assert_is_empty (monitor);
5076
5077   /* Hide a group using row-changed instead of row-deleted */
5078   /* Caution: group 2 is gone, so offsets of the signals have moved. */
5079   signal_monitor_append_signal (monitor, ROW_DELETED, "2:0");
5080   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5081   signal_monitor_append_signal (monitor, ROW_DELETED, "2");
5082   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter,
5083                                        "3:1");
5084   gtk_tree_store_set (store, &item_iter, 0, "invisible-3:1", -1);
5085   signal_monitor_assert_is_empty (monitor);
5086
5087 #if 0
5088   {
5089     GtkWidget *window;
5090     GtkTreeViewColumn *col;
5091
5092     gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
5093
5094     col = gtk_tree_view_column_new_with_attributes ("foo",
5095         gtk_cell_renderer_text_new (),
5096         "text", 0, NULL);
5097     gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
5098
5099     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5100     g_signal_connect (window, "delete-event",
5101         G_CALLBACK (gtk_widget_destroy), NULL);
5102     g_signal_connect (window, "destroy",
5103         G_CALLBACK (gtk_main_quit), NULL);
5104
5105     gtk_container_add (GTK_CONTAINER (window), view);
5106
5107     gtk_widget_show (view);
5108     gtk_widget_show (window);
5109
5110     gtk_main ();
5111   }
5112 #endif
5113
5114   /* Cleanup */
5115   signal_monitor_free (monitor);
5116   g_object_unref (view);
5117   g_object_unref (store);
5118   g_object_unref (filter);
5119 }
5120
5121 /* main */
5122
5123 void
5124 register_filter_model_tests (void)
5125 {
5126   g_test_add ("/TreeModelFilter/self/verify-test-suite",
5127               FilterTest, NULL,
5128               filter_test_setup,
5129               verify_test_suite,
5130               filter_test_teardown);
5131
5132   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-1",
5133               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5134               filter_test_setup,
5135               verify_test_suite_vroot,
5136               filter_test_teardown);
5137   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-2",
5138               FilterTest, gtk_tree_path_new_from_indices (2, 3, -1),
5139               filter_test_setup,
5140               verify_test_suite_vroot,
5141               filter_test_teardown);
5142
5143
5144   g_test_add ("/TreeModelFilter/filled/hide-root-level",
5145               FilterTest, NULL,
5146               filter_test_setup,
5147               filled_hide_root_level,
5148               filter_test_teardown);
5149   g_test_add ("/TreeModelFilter/filled/hide-child-levels",
5150               FilterTest, NULL,
5151               filter_test_setup,
5152               filled_hide_child_levels,
5153               filter_test_teardown);
5154   g_test_add ("/TreeModelFilter/filled/hide-child-levels/root-expanded",
5155               FilterTest, NULL,
5156               filter_test_setup,
5157               filled_hide_child_levels_root_expanded,
5158               filter_test_teardown);
5159
5160   g_test_add ("/TreeModelFilter/filled/hide-root-level/vroot",
5161               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5162               filter_test_setup,
5163               filled_vroot_hide_root_level,
5164               filter_test_teardown);
5165   g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot",
5166               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5167               filter_test_setup,
5168               filled_vroot_hide_child_levels,
5169               filter_test_teardown);
5170   g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot-root-expanded",
5171               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5172               filter_test_setup,
5173               filled_vroot_hide_child_levels_root_expanded,
5174               filter_test_teardown);
5175
5176
5177   g_test_add ("/TreeModelFilter/empty/show-nodes",
5178               FilterTest, NULL,
5179               filter_test_setup_empty,
5180               empty_show_nodes,
5181               filter_test_teardown);
5182   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes",
5183               FilterTest, NULL,
5184               filter_test_setup_empty,
5185               empty_show_multiple_nodes,
5186               filter_test_teardown);
5187
5188   g_test_add ("/TreeModelFilter/empty/show-nodes/vroot",
5189               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5190               filter_test_setup_empty,
5191               empty_vroot_show_nodes,
5192               filter_test_teardown);
5193   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes/vroot",
5194               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5195               filter_test_setup_empty,
5196               empty_vroot_show_multiple_nodes,
5197               filter_test_teardown);
5198
5199
5200   g_test_add ("/TreeModelFilter/unfiltered/hide-single",
5201               FilterTest, NULL,
5202               filter_test_setup_unfiltered,
5203               unfiltered_hide_single,
5204               filter_test_teardown);
5205   g_test_add ("/TreeModelFilter/unfiltered/hide-single/root-expanded",
5206               FilterTest, NULL,
5207               filter_test_setup_unfiltered_root_expanded,
5208               unfiltered_hide_single_root_expanded,
5209               filter_test_teardown);
5210   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child",
5211               FilterTest, NULL,
5212               filter_test_setup_unfiltered,
5213               unfiltered_hide_single_child,
5214               filter_test_teardown);
5215   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/root-expanded",
5216               FilterTest, NULL,
5217               filter_test_setup_unfiltered_root_expanded,
5218               unfiltered_hide_single_child_root_expanded,
5219               filter_test_teardown);
5220   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level",
5221               FilterTest, NULL,
5222               filter_test_setup_unfiltered,
5223               unfiltered_hide_single_multi_level,
5224               filter_test_teardown);
5225   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/root-expanded",
5226               FilterTest, NULL,
5227               filter_test_setup_unfiltered_root_expanded,
5228               unfiltered_hide_single_multi_level_root_expanded,
5229               filter_test_teardown);
5230
5231   g_test_add ("/TreeModelFilter/unfiltered/hide-single/vroot",
5232               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5233               filter_test_setup_unfiltered,
5234               unfiltered_vroot_hide_single,
5235               filter_test_teardown);
5236   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot",
5237               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5238               filter_test_setup_unfiltered,
5239               unfiltered_vroot_hide_single_child,
5240               filter_test_teardown);
5241   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot/root-expanded",
5242               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5243               filter_test_setup_unfiltered_root_expanded,
5244               unfiltered_vroot_hide_single_child_root_expanded,
5245               filter_test_teardown);
5246   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot",
5247               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5248               filter_test_setup_unfiltered,
5249               unfiltered_vroot_hide_single_multi_level,
5250               filter_test_teardown);
5251   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot/root-expanded",
5252               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5253               filter_test_setup_unfiltered_root_expanded,
5254               unfiltered_vroot_hide_single_multi_level_root_expanded,
5255               filter_test_teardown);
5256
5257
5258
5259   g_test_add ("/TreeModelFilter/unfiltered/show-single",
5260               FilterTest, NULL,
5261               filter_test_setup_empty_unfiltered,
5262               unfiltered_show_single,
5263               filter_test_teardown);
5264   g_test_add ("/TreeModelFilter/unfiltered/show-single-child",
5265               FilterTest, NULL,
5266               filter_test_setup_empty_unfiltered,
5267               unfiltered_show_single_child,
5268               filter_test_teardown);
5269   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/root-expanded",
5270               FilterTest, NULL,
5271               filter_test_setup_empty_unfiltered_root_expanded,
5272               unfiltered_show_single_child_root_expanded,
5273               filter_test_teardown);
5274   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level",
5275               FilterTest, NULL,
5276               filter_test_setup_empty_unfiltered,
5277               unfiltered_show_single_multi_level,
5278               filter_test_teardown);
5279   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/root-expanded",
5280               FilterTest, NULL,
5281               filter_test_setup_empty_unfiltered_root_expanded,
5282               unfiltered_show_single_multi_level_root_expanded,
5283               filter_test_teardown);
5284
5285   g_test_add ("/TreeModelFilter/unfiltered/show-single/vroot",
5286               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5287               filter_test_setup_empty_unfiltered,
5288               unfiltered_vroot_show_single,
5289               filter_test_teardown);
5290   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot",
5291               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5292               filter_test_setup_empty_unfiltered,
5293               unfiltered_vroot_show_single_child,
5294               filter_test_teardown);
5295   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot/root-expanded",
5296               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5297               filter_test_setup_empty_unfiltered_root_expanded,
5298               unfiltered_vroot_show_single_child_root_expanded,
5299               filter_test_teardown);
5300   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot",
5301               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5302               filter_test_setup_empty_unfiltered,
5303               unfiltered_vroot_show_single_multi_level,
5304               filter_test_teardown);
5305   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot/root-expanded",
5306               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5307               filter_test_setup_empty_unfiltered_root_expanded,
5308               unfiltered_vroot_show_single_multi_level_root_expanded,
5309               filter_test_teardown);
5310
5311
5312   g_test_add ("/TreeModelFilter/unfiltered/rows-reordered/root-level",
5313               FilterTest, NULL,
5314               filter_test_setup_unfiltered,
5315               unfiltered_rows_reordered_root_level,
5316               filter_test_teardown);
5317   g_test_add ("/TreeModelFilter/unfiltered/rows-reordered/child-level",
5318               FilterTest, NULL,
5319               filter_test_setup_unfiltered,
5320               unfiltered_rows_reordered_child_level,
5321               filter_test_teardown);
5322
5323   g_test_add ("/TreeModelFilter/filtered/rows-reordered/root-level/first-hidden",
5324               FilterTest, NULL,
5325               filter_test_setup,
5326               filtered_rows_reordered_root_level_first_hidden,
5327               filter_test_teardown);
5328   g_test_add ("/TreeModelFilter/filtered/rows-reordered/root-level/middle-hidden",
5329               FilterTest, NULL,
5330               filter_test_setup,
5331               filtered_rows_reordered_root_level_middle_hidden,
5332               filter_test_teardown);
5333   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/first-hidden",
5334               FilterTest, NULL,
5335               filter_test_setup,
5336               filtered_rows_reordered_child_level_first_hidden,
5337               filter_test_teardown);
5338   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/middle-hidden",
5339               FilterTest, NULL,
5340               filter_test_setup,
5341               filtered_rows_reordered_child_level_middle_hidden,
5342               filter_test_teardown);
5343   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/4-hidden",
5344               FilterTest, NULL,
5345               filter_test_setup,
5346               filtered_rows_reordered_child_level_4_hidden,
5347               filter_test_teardown);
5348   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/all-hidden",
5349               FilterTest, NULL,
5350               filter_test_setup,
5351               filtered_rows_reordered_child_level_all_hidden,
5352               filter_test_teardown);
5353
5354   /* Inserts in child models after creation of filter model */
5355   g_test_add_func ("/TreeModelFilter/insert/before",
5356                    insert_before);
5357   g_test_add_func ("/TreeModelFilter/insert/child",
5358                    insert_child);
5359
5360   /* Removals from child model after creating of filter model */
5361   g_test_add_func ("/TreeModelFilter/remove/node",
5362                    remove_node);
5363   g_test_add_func ("/TreeModelFilter/remove/node-vroot",
5364                    remove_node_vroot);
5365   g_test_add_func ("/TreeModelFilter/remove/vroot-ancestor",
5366                    remove_vroot_ancestor);
5367
5368   /* Reference counting */
5369   g_test_add_func ("/TreeModelFilter/ref-count/single-level",
5370                    ref_count_single_level);
5371   g_test_add_func ("/TreeModelFilter/ref-count/two-levels",
5372                    ref_count_two_levels);
5373   g_test_add_func ("/TreeModelFilter/ref-count/three-levels",
5374                    ref_count_three_levels);
5375   g_test_add_func ("/TreeModelFilter/ref-count/delete-row",
5376                    ref_count_delete_row);
5377   g_test_add_func ("/TreeModelFilter/ref-count/cleanup",
5378                    ref_count_cleanup);
5379   g_test_add_func ("/TreeModelFilter/ref-count/row-ref",
5380                    ref_count_row_ref);
5381
5382   /* Reference counting, transfer of first reference on
5383    * first node in level.  This is a GtkTreeModelFilter-specific
5384    * feature.
5385    */
5386   g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/insert",
5387                    ref_count_transfer_root_level_insert);
5388   g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/reordered",
5389                    ref_count_transfer_root_level_reordered);
5390   g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/insert",
5391                    ref_count_transfer_child_level_insert);
5392   g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/reordered",
5393                    ref_count_transfer_child_level_reordered);
5394
5395   g_test_add_func ("/TreeModelFilter/specific/path-dependent-filter",
5396                    specific_path_dependent_filter);
5397   g_test_add_func ("/TreeModelFilter/specific/append-after-collapse",
5398                    specific_append_after_collapse);
5399   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-node",
5400                    specific_sort_filter_remove_node);
5401   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-root",
5402                    specific_sort_filter_remove_root);
5403   g_test_add_func ("/TreeModelFilter/specific/root-mixed-visibility",
5404                    specific_root_mixed_visibility);
5405   g_test_add_func ("/TreeModelFilter/specific/has-child-filter",
5406                    specific_has_child_filter);
5407   g_test_add_func ("/TreeModelFilter/specific/has-child-filter-on-sort-model",
5408                    specific_has_child_filter_on_sort_model);
5409   g_test_add_func ("/TreeModelFilter/specific/at-least-2-children-filter",
5410                    specific_at_least_2_children_filter);
5411   g_test_add_func ("/TreeModelFilter/specific/at-least-2-children-filter-on-sort-model",
5412                    specific_at_least_2_children_filter_on_sort_model);
5413   g_test_add_func ("/TreeModelFilter/specific/root-has-child-filter",
5414                    specific_root_has_child_filter);
5415   g_test_add_func ("/TreeModelFilter/specific/filter-add-child",
5416                    specific_filter_add_child);
5417   g_test_add_func ("/TreeModelFilter/specific/list-store-clear",
5418                    specific_list_store_clear);
5419   g_test_add_func ("/TreeModelFilter/specific/sort-ref-leaf-and-remove-ancestor",
5420                    specific_sort_ref_leaf_and_remove_ancestor);
5421   g_test_add_func ("/TreeModelFilter/specific/ref-leaf-and-remove-ancestor",
5422                    specific_ref_leaf_and_remove_ancestor);
5423   g_test_add_func ("/TreeModelFilter/specific/virtual-ref-leaf-and-remove-ancestor",
5424                    specific_virtual_ref_leaf_and_remove_ancestor);
5425
5426   g_test_add_func ("/TreeModelFilter/specific/bug-301558",
5427                    specific_bug_301558);
5428   g_test_add_func ("/TreeModelFilter/specific/bug-311955",
5429                    specific_bug_311955);
5430   g_test_add_func ("/TreeModelFilter/specific/bug-311955-clean",
5431                    specific_bug_311955_clean);
5432   g_test_add_func ("/TreeModelFilter/specific/bug-346800",
5433                    specific_bug_346800);
5434   g_test_add_func ("/TreeModelFilter/specific/bug-464173",
5435                    specific_bug_464173);
5436   g_test_add_func ("/TreeModelFilter/specific/bug-540201",
5437                    specific_bug_540201);
5438   g_test_add_func ("/TreeModelFilter/specific/bug-549287",
5439                    specific_bug_549287);
5440   g_test_add_func ("/TreeModelFilter/specific/bug-621076",
5441                    specific_bug_621076);
5442 }