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