]> Pileus Git - ~andy/gtk/blob - gtk/tests/filtermodel.c
Fix some memory leaks in treemodel unit tests
[~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   gtk_tree_path_free (path);
2917
2918   assert_node_ref_count (ref_model, &grandparent1, 2);
2919   assert_node_ref_count (ref_model, &grandparent2, 2);
2920   assert_node_ref_count (ref_model, &parent1, 3);
2921   assert_node_ref_count (ref_model, &parent2, 2);
2922   assert_node_ref_count (ref_model, &iter_parent1, 2);
2923   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2924   assert_node_ref_count (ref_model, &iter_parent2, 1);
2925
2926   gtk_tree_store_remove (GTK_TREE_STORE (model), &iter_parent2);
2927
2928   assert_node_ref_count (ref_model, &grandparent1, 2);
2929   assert_node_ref_count (ref_model, &grandparent2, 2);
2930   assert_node_ref_count (ref_model, &parent1, 3);
2931   assert_node_ref_count (ref_model, &parent2, 2);
2932   assert_node_ref_count (ref_model, &iter_parent1, 2);
2933   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2934
2935   gtk_tree_store_remove (GTK_TREE_STORE (model), &parent1);
2936
2937   assert_node_ref_count (ref_model, &grandparent1, 2);
2938   assert_node_ref_count (ref_model, &grandparent2, 2);
2939   assert_node_ref_count (ref_model, &parent2, 3);
2940   assert_level_referenced (ref_model, 2, &parent2);
2941
2942   gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
2943
2944   assert_node_ref_count (ref_model, &grandparent1, 2);
2945
2946   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2947
2948   assert_node_ref_count (ref_model, &grandparent1, 2);
2949
2950   gtk_widget_destroy (tree_view);
2951   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2952
2953   assert_node_ref_count (ref_model, &grandparent1, 1);
2954
2955   g_object_unref (filter_model);
2956
2957   assert_node_ref_count (ref_model, &grandparent1, 0);
2958
2959   g_object_unref (ref_model);
2960 }
2961
2962 static void
2963 ref_count_cleanup (void)
2964 {
2965   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
2966   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
2967   GtkTreeModel *model;
2968   GtkTreeModelRefCount *ref_model;
2969   GtkTreeModel *filter_model;
2970   GtkWidget *tree_view;
2971
2972   model = gtk_tree_model_ref_count_new ();
2973   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2974
2975   /* + grandparent1
2976    * + grandparent2
2977    *   + parent1
2978    *     + iter_parent1
2979    *   + parent2
2980    *     + iter_parent2_first
2981    *     + iter_parent2
2982    */
2983
2984   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
2985   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
2986   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
2987   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
2988   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
2989   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
2990   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
2991
2992   filter_model = gtk_tree_model_filter_new (model, NULL);
2993   tree_view = gtk_tree_view_new_with_model (filter_model);
2994
2995   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2996
2997   assert_node_ref_count (ref_model, &grandparent1, 2);
2998   assert_node_ref_count (ref_model, &grandparent2, 2);
2999   assert_node_ref_count (ref_model, &parent1, 3);
3000   assert_node_ref_count (ref_model, &parent2, 2);
3001   assert_node_ref_count (ref_model, &iter_parent1, 2);
3002   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
3003   assert_node_ref_count (ref_model, &iter_parent2, 1);
3004
3005   gtk_widget_destroy (tree_view);
3006
3007   assert_node_ref_count (ref_model, &grandparent1, 1);
3008   assert_node_ref_count (ref_model, &grandparent2, 1);
3009   assert_node_ref_count (ref_model, &parent1, 2);
3010   assert_node_ref_count (ref_model, &parent2, 1);
3011   assert_node_ref_count (ref_model, &iter_parent1, 1);
3012   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3013   assert_node_ref_count (ref_model, &iter_parent2, 0);
3014
3015   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3016
3017   /* Only the reference on the first node of the root level is kept. */
3018   assert_node_ref_count (ref_model, &grandparent1, 1);
3019   assert_node_ref_count (ref_model, &grandparent2, 0);
3020   assert_node_ref_count (ref_model, &parent1, 0);
3021   assert_node_ref_count (ref_model, &parent2, 0);
3022   assert_node_ref_count (ref_model, &iter_parent1, 0);
3023   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
3024   assert_node_ref_count (ref_model, &iter_parent2, 0);
3025
3026   g_object_unref (filter_model);
3027   g_object_unref (ref_model);
3028 }
3029
3030 static void
3031 ref_count_row_ref (void)
3032 {
3033   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
3034   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
3035   GtkTreeModel *model;
3036   GtkTreeModelRefCount *ref_model;
3037   GtkTreeModel *filter_model;
3038   GtkWidget *tree_view;
3039   GtkTreePath *path;
3040   GtkTreeRowReference *row_ref;
3041
3042   model = gtk_tree_model_ref_count_new ();
3043   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3044
3045   /* + grandparent1
3046    * + grandparent2
3047    *   + parent1
3048    *     + iter_parent1
3049    *   + parent2
3050    *     + iter_parent2
3051    *     + iter_parent2
3052    */
3053
3054   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3055   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3056   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
3057   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
3058   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
3059   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
3060   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
3061
3062   filter_model = gtk_tree_model_filter_new (model, NULL);
3063   tree_view = gtk_tree_view_new_with_model (filter_model);
3064
3065   path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
3066   row_ref = gtk_tree_row_reference_new (filter_model, path);
3067   gtk_tree_path_free (path);
3068
3069   assert_node_ref_count (ref_model, &grandparent1, 2);
3070   assert_node_ref_count (ref_model, &grandparent2, 3);
3071   assert_node_ref_count (ref_model, &parent1, 1);
3072   assert_node_ref_count (ref_model, &parent2, 2);
3073   assert_node_ref_count (ref_model, &iter_parent1, 0);
3074   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3075   assert_node_ref_count (ref_model, &iter_parent2, 1);
3076
3077   gtk_tree_row_reference_free (row_ref);
3078
3079   assert_node_ref_count (ref_model, &grandparent1, 2);
3080   assert_node_ref_count (ref_model, &grandparent2, 2);
3081   assert_node_ref_count (ref_model, &parent1, 1);
3082   assert_node_ref_count (ref_model, &parent2, 1);
3083   assert_node_ref_count (ref_model, &iter_parent1, 0);
3084   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3085   assert_node_ref_count (ref_model, &iter_parent2, 0);
3086
3087   path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
3088   row_ref = gtk_tree_row_reference_new (filter_model, path);
3089   gtk_tree_path_free (path);
3090
3091   assert_node_ref_count (ref_model, &grandparent1, 2);
3092   assert_node_ref_count (ref_model, &grandparent2, 3);
3093   assert_node_ref_count (ref_model, &parent1, 1);
3094   assert_node_ref_count (ref_model, &parent2, 2);
3095   assert_node_ref_count (ref_model, &iter_parent1, 0);
3096   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3097   assert_node_ref_count (ref_model, &iter_parent2, 1);
3098
3099   gtk_tree_store_remove (GTK_TREE_STORE (model), &parent2);
3100
3101   assert_node_ref_count (ref_model, &grandparent1, 2);
3102   assert_node_ref_count (ref_model, &grandparent2, 2);
3103   assert_node_ref_count (ref_model, &parent1, 1);
3104   assert_node_ref_count (ref_model, &iter_parent1, 0);
3105
3106   gtk_tree_row_reference_free (row_ref);
3107
3108   assert_node_ref_count (ref_model, &grandparent1, 2);
3109   assert_node_ref_count (ref_model, &grandparent2, 2);
3110   assert_node_ref_count (ref_model, &parent1, 1);
3111   assert_node_ref_count (ref_model, &iter_parent1, 0);
3112
3113   gtk_widget_destroy (tree_view);
3114
3115   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3116
3117   /* Only the reference on the first node of the root level is kept. */
3118   assert_node_ref_count (ref_model, &grandparent1, 1);
3119   assert_node_ref_count (ref_model, &grandparent2, 0);
3120   assert_node_ref_count (ref_model, &parent1, 0);
3121
3122   g_object_unref (filter_model);
3123   g_object_unref (ref_model);
3124 }
3125
3126 static void
3127 ref_count_transfer_root_level_insert (void)
3128 {
3129   GtkTreeIter grandparent1, grandparent2, grandparent3;
3130   GtkTreeIter new_node;
3131   GtkTreeModel *model;
3132   GtkTreeModelRefCount *ref_model;
3133   GtkTreeModel *filter_model;
3134   GtkWidget *tree_view;
3135
3136   model = gtk_tree_model_ref_count_new ();
3137   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3138
3139   /* + grandparent1
3140    * + grandparent2
3141    * + grandparent3
3142    */
3143
3144   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3145   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3146   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
3147
3148   filter_model = gtk_tree_model_filter_new (model, NULL);
3149   tree_view = gtk_tree_view_new_with_model (filter_model);
3150
3151   assert_node_ref_count (ref_model, &grandparent1, 2);
3152   assert_node_ref_count (ref_model, &grandparent2, 1);
3153   assert_node_ref_count (ref_model, &grandparent3, 1);
3154
3155   gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, NULL);
3156
3157   assert_node_ref_count (ref_model, &new_node, 2);
3158   assert_node_ref_count (ref_model, &grandparent1, 1);
3159   assert_node_ref_count (ref_model, &grandparent2, 1);
3160   assert_node_ref_count (ref_model, &grandparent3, 1);
3161
3162   gtk_widget_destroy (tree_view);
3163   g_object_unref (filter_model);
3164   g_object_unref (ref_model);
3165 }
3166
3167 static void
3168 ref_count_transfer_root_level_reordered (void)
3169 {
3170   GtkTreeIter grandparent1, grandparent2, grandparent3;
3171   GtkTreeModel *model;
3172   GtkTreeModelRefCount *ref_model;
3173   GtkTreeModel *filter_model;
3174   GtkWidget *tree_view;
3175
3176   model = gtk_tree_model_ref_count_new ();
3177   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3178
3179   /* + grandparent1
3180    * + grandparent2
3181    * + grandparent3
3182    */
3183
3184   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3185   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3186   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
3187
3188   filter_model = gtk_tree_model_filter_new (model, NULL);
3189   tree_view = gtk_tree_view_new_with_model (filter_model);
3190
3191   assert_node_ref_count (ref_model, &grandparent1, 2);
3192   assert_node_ref_count (ref_model, &grandparent2, 1);
3193   assert_node_ref_count (ref_model, &grandparent3, 1);
3194
3195   /* gtk_tree_store_move() will emit rows-reordered */
3196   gtk_tree_store_move_after (GTK_TREE_STORE (model),
3197                              &grandparent1, &grandparent3);
3198
3199   assert_node_ref_count (ref_model, &grandparent2, 2);
3200   assert_node_ref_count (ref_model, &grandparent3, 1);
3201   assert_node_ref_count (ref_model, &grandparent1, 1);
3202
3203   gtk_widget_destroy (tree_view);
3204   g_object_unref (filter_model);
3205   g_object_unref (ref_model);
3206 }
3207
3208 static void
3209 ref_count_transfer_child_level_insert (void)
3210 {
3211   GtkTreeIter grandparent1;
3212   GtkTreeIter parent1, parent2, parent3;
3213   GtkTreeIter new_node;
3214   GtkTreeModel *model;
3215   GtkTreeModelRefCount *ref_model;
3216   GtkTreeModel *filter_model;
3217   GtkWidget *tree_view;
3218
3219   model = gtk_tree_model_ref_count_new ();
3220   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3221
3222   /* + grandparent1
3223    *   + parent1
3224    *   + parent2
3225    *   + parent3
3226    */
3227
3228   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3229   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
3230   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
3231   gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
3232
3233   filter_model = gtk_tree_model_filter_new (model, NULL);
3234   tree_view = gtk_tree_view_new_with_model (filter_model);
3235
3236   assert_node_ref_count (ref_model, &grandparent1, 3);
3237   assert_node_ref_count (ref_model, &parent1, 1);
3238   assert_node_ref_count (ref_model, &parent2, 0);
3239   assert_node_ref_count (ref_model, &parent3, 0);
3240
3241   gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, &grandparent1);
3242
3243   assert_node_ref_count (ref_model, &grandparent1, 3);
3244   assert_node_ref_count (ref_model, &new_node, 1);
3245   assert_node_ref_count (ref_model, &parent1, 0);
3246   assert_node_ref_count (ref_model, &parent2, 0);
3247   assert_node_ref_count (ref_model, &parent3, 0);
3248
3249   gtk_widget_destroy (tree_view);
3250   g_object_unref (filter_model);
3251   g_object_unref (ref_model);
3252 }
3253
3254 static void
3255 ref_count_transfer_child_level_reordered (void)
3256 {
3257   GtkTreeIter grandparent1;
3258   GtkTreeIter parent1, parent2, parent3;
3259   GtkTreeModel *model;
3260   GtkTreeModelRefCount *ref_model;
3261   GtkTreeModel *filter_model;
3262   GtkWidget *tree_view;
3263
3264   model = gtk_tree_model_ref_count_new ();
3265   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3266
3267   /* + grandparent1
3268    *   + parent1
3269    *   + parent2
3270    *   + parent3
3271    */
3272
3273   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3274   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
3275   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
3276   gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
3277
3278   filter_model = gtk_tree_model_filter_new (model, NULL);
3279   tree_view = gtk_tree_view_new_with_model (filter_model);
3280
3281   assert_node_ref_count (ref_model, &grandparent1, 3);
3282   assert_node_ref_count (ref_model, &parent1, 1);
3283   assert_node_ref_count (ref_model, &parent2, 0);
3284   assert_node_ref_count (ref_model, &parent3, 0);
3285
3286   /* gtk_tree_store_move() will emit rows-reordered */
3287   gtk_tree_store_move_after (GTK_TREE_STORE (model),
3288                              &parent1, &parent3);
3289
3290   assert_node_ref_count (ref_model, &grandparent1, 3);
3291   assert_node_ref_count (ref_model, &parent2, 1);
3292   assert_node_ref_count (ref_model, &parent3, 0);
3293   assert_node_ref_count (ref_model, &parent1, 0);
3294
3295   gtk_widget_destroy (tree_view);
3296   g_object_unref (filter_model);
3297   g_object_unref (ref_model);
3298 }
3299
3300
3301 static gboolean
3302 specific_path_dependent_filter_func (GtkTreeModel *model,
3303                                      GtkTreeIter  *iter,
3304                                      gpointer      data)
3305 {
3306   GtkTreePath *path;
3307
3308   path = gtk_tree_model_get_path (model, iter);
3309   if (gtk_tree_path_get_indices (path)[0] < 4)
3310     return FALSE;
3311
3312   return TRUE;
3313 }
3314
3315 static void
3316 specific_path_dependent_filter (void)
3317 {
3318   int i;
3319   GtkTreeIter iter;
3320   GtkListStore *list;
3321   GtkTreeModel *sort;
3322   GtkTreeModel *filter;
3323
3324   list = gtk_list_store_new (1, G_TYPE_INT);
3325   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
3326   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
3327   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
3328   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
3329   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
3330   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
3331   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
3332   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
3333
3334   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list));
3335   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort), NULL);
3336   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3337                                           specific_path_dependent_filter_func,
3338                                           NULL, NULL);
3339
3340   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), 0,
3341                                         GTK_SORT_DESCENDING);
3342
3343   for (i = 0; i < 4; i++)
3344     {
3345       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
3346                                          NULL, 1))
3347         gtk_list_store_remove (list, &iter);
3348
3349       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
3350                                          NULL, 2))
3351         gtk_list_store_remove (list, &iter);
3352     }
3353
3354   g_object_unref (filter);
3355   g_object_unref (sort);
3356   g_object_unref (list);
3357 }
3358
3359
3360 static gboolean
3361 specific_append_after_collapse_visible_func (GtkTreeModel *model,
3362                                              GtkTreeIter  *iter,
3363                                              gpointer      data)
3364 {
3365   gint number;
3366   gboolean hide_negative_numbers;
3367
3368   gtk_tree_model_get (model, iter, 1, &number, -1);
3369   hide_negative_numbers = GPOINTER_TO_INT (g_object_get_data (data, "private-hide-negative-numbers"));
3370
3371   return (number >= 0 || !hide_negative_numbers);
3372 }
3373
3374 static void
3375 specific_append_after_collapse (void)
3376 {
3377   /* This test is based on one of the test cases I found in my
3378    * old test cases directory.  I unfortunately do not have a record
3379    * from who this test case originated.  -Kris.
3380    *
3381    * General idea:
3382    * - Construct tree.
3383    * - Show tree, expand, collapse.
3384    * - Add a row.
3385    */
3386
3387   GtkTreeIter iter;
3388   GtkTreeIter child_iter;
3389   GtkTreeIter child_iter2;
3390   GtkTreePath *append_path;
3391   GtkTreeStore *store;
3392   GtkTreeModel *filter;
3393   GtkTreeModel *sort;
3394
3395   GtkWidget *window;
3396   GtkWidget *tree_view;
3397
3398   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
3399
3400   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
3401   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
3402                      GINT_TO_POINTER (FALSE));
3403   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3404                                           specific_append_after_collapse_visible_func,
3405                                           filter, NULL);
3406
3407   sort = gtk_tree_model_sort_new_with_model (filter);
3408
3409   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3410   tree_view = gtk_tree_view_new_with_model (sort);
3411   gtk_container_add (GTK_CONTAINER (window), tree_view);
3412   gtk_widget_realize (tree_view);
3413
3414   while (gtk_events_pending ())
3415     gtk_main_iteration ();
3416
3417   gtk_tree_store_prepend (store, &iter, NULL);
3418   gtk_tree_store_set (store, &iter,
3419                       0, "hallo", 1, 1, -1);
3420
3421   gtk_tree_store_append (store, &child_iter, &iter);
3422   gtk_tree_store_set (store, &child_iter,
3423                       0, "toemaar", 1, 1, -1);
3424
3425   gtk_tree_store_append (store, &child_iter2, &child_iter);
3426   gtk_tree_store_set (store, &child_iter2,
3427                       0, "very deep", 1, 1, -1);
3428
3429   append_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &child_iter2);
3430
3431   gtk_tree_store_append (store, &child_iter, &iter);
3432   gtk_tree_store_set (store, &child_iter,
3433                       0, "sja", 1, 1, -1);
3434
3435   gtk_tree_store_append (store, &child_iter, &iter);
3436   gtk_tree_store_set (store, &child_iter,
3437                       0, "some word", 1, -1, -1);
3438
3439   /* Expand and collapse the tree */
3440   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
3441   while (gtk_events_pending ())
3442     gtk_main_iteration ();
3443
3444   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
3445   while (gtk_events_pending ())
3446     gtk_main_iteration ();
3447
3448   /* Add another it */
3449   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
3450                      GINT_TO_POINTER (TRUE));
3451
3452   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, append_path))
3453     {
3454       gtk_tree_store_append (store, &child_iter, &iter);
3455       gtk_tree_store_set (store, &child_iter,
3456                           0, "new new new !!", 1, 1, -1);
3457     }
3458   gtk_tree_path_free (append_path);
3459
3460   /* Expand */
3461   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
3462   while (gtk_events_pending ())
3463     gtk_main_iteration ();
3464 }
3465
3466
3467 static gint
3468 specific_sort_filter_remove_node_compare_func (GtkTreeModel  *model,
3469                                                GtkTreeIter   *iter1,
3470                                                GtkTreeIter   *iter2,
3471                                                gpointer       data)
3472 {
3473   return -1;
3474 }
3475
3476 static gboolean
3477 specific_sort_filter_remove_node_visible_func (GtkTreeModel  *model,
3478                                                GtkTreeIter   *iter,
3479                                                gpointer       data)
3480 {
3481   char *item = NULL;
3482
3483   /* Do reference the model */
3484   gtk_tree_model_get (model, iter, 0, &item, -1);
3485   g_free (item);
3486
3487   return FALSE;
3488 }
3489
3490 static void
3491 specific_sort_filter_remove_node (void)
3492 {
3493   /* This test is based on one of the test cases I found in my
3494    * old test cases directory.  I unfortunately do not have a record
3495    * from who this test case originated.  -Kris.
3496    *
3497    * General idea:
3498    *  - Create tree store, sort, filter models.  The sort model has
3499    *    a default sort func that is enabled, filter model a visible func
3500    *    that defaults to returning FALSE.
3501    *  - Remove a node from the tree store.
3502    */
3503
3504   GtkTreeIter iter;
3505   GtkTreeStore *store;
3506   GtkTreeModel *filter;
3507   GtkTreeModel *sort;
3508
3509   GtkWidget *window;
3510   GtkWidget *tree_view;
3511
3512   store = gtk_tree_store_new (1, G_TYPE_STRING);
3513   gtk_tree_store_append (store, &iter, NULL);
3514   gtk_tree_store_set (store, &iter, 0, "Hello1", -1);
3515
3516   gtk_tree_store_append (store, &iter, NULL);
3517   gtk_tree_store_set (store, &iter, 0, "Hello2", -1);
3518
3519   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
3520   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
3521                                            specific_sort_filter_remove_node_compare_func, NULL, NULL);
3522
3523   filter = gtk_tree_model_filter_new (sort, NULL);
3524   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3525                                           specific_sort_filter_remove_node_visible_func,
3526                                           filter, NULL);
3527
3528
3529   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3530   tree_view = gtk_tree_view_new_with_model (filter);
3531   gtk_container_add (GTK_CONTAINER (window), tree_view);
3532   gtk_widget_realize (tree_view);
3533
3534   while (gtk_events_pending ())
3535     gtk_main_iteration ();
3536
3537   /* Remove a node */
3538   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
3539   gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
3540   gtk_tree_store_remove (store, &iter);
3541
3542   while (gtk_events_pending ())
3543     gtk_main_iteration ();
3544 }
3545
3546
3547 static void
3548 specific_sort_filter_remove_root (void)
3549 {
3550   /* This test is based on one of the test cases I found in my
3551    * old test cases directory.  I unfortunately do not have a record
3552    * from who this test case originated.  -Kris.
3553    */
3554
3555   GtkTreeModel *model, *sort, *filter;
3556   GtkTreeIter root, mid, leaf;
3557   GtkTreePath *path;
3558
3559   model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
3560   gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
3561   gtk_tree_store_append (GTK_TREE_STORE (model), &mid, &root);
3562   gtk_tree_store_append (GTK_TREE_STORE (model), &leaf, &mid);
3563
3564   path = gtk_tree_model_get_path (model, &mid);
3565
3566   sort = gtk_tree_model_sort_new_with_model (model);
3567   filter = gtk_tree_model_filter_new (sort, path);
3568
3569   gtk_tree_path_free (path);
3570
3571   gtk_tree_store_remove (GTK_TREE_STORE (model), &root);
3572
3573   g_object_unref (filter);
3574   g_object_unref (sort);
3575   g_object_unref (model);
3576 }
3577
3578
3579 static void
3580 specific_root_mixed_visibility (void)
3581 {
3582   int i;
3583   GtkTreeModel *filter;
3584   /* A bit nasty, apologies */
3585   FilterTest fixture;
3586
3587   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3588
3589   for (i = 0; i < LEVEL_LENGTH; i++)
3590     {
3591       GtkTreeIter iter;
3592
3593       gtk_tree_store_insert (fixture.store, &iter, NULL, i);
3594       if (i % 2 == 0)
3595         create_tree_store_set_values (fixture.store, &iter, TRUE);
3596       else
3597         create_tree_store_set_values (fixture.store, &iter, FALSE);
3598     }
3599
3600   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3601   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3602   fixture.monitor = NULL;
3603
3604   gtk_tree_model_filter_set_visible_column (fixture.filter, 1);
3605
3606   /* In order to trigger the potential bug, we should not access
3607    * the filter model here (so don't call the check functions).
3608    */
3609
3610   /* Change visibility of an odd row to TRUE */
3611   set_path_visibility (&fixture, "3", TRUE);
3612   check_filter_model (&fixture);
3613   check_level_length (fixture.filter, NULL, 4);
3614 }
3615
3616
3617
3618 static gboolean
3619 specific_has_child_filter_filter_func (GtkTreeModel *model,
3620                                        GtkTreeIter  *iter,
3621                                        gpointer      data)
3622 {
3623   return gtk_tree_model_iter_has_child (model, iter);
3624 }
3625
3626 static void
3627 specific_has_child_filter (void)
3628 {
3629   GtkTreeModel *filter;
3630   GtkTreeIter iter, root;
3631   FilterTest fixture; /* This is not how it should be done */
3632   GtkWidget *tree_view;
3633
3634   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3635   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3636   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3637   fixture.monitor = signal_monitor_new (filter);
3638
3639   tree_view = gtk_tree_view_new_with_model (filter);
3640
3641   /* We will filter on parent state using a filter function.  We will
3642    * manually keep the boolean column in sync, so that we can use
3643    * check_filter_model() to check the consistency of the model.
3644    */
3645   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
3646    * to be able to check the structure here.  We keep the calls to
3647    * check_filter_model() commented out until then.
3648    */
3649   gtk_tree_model_filter_set_visible_func (fixture.filter,
3650                                           specific_has_child_filter_filter_func,
3651                                           NULL, NULL);
3652
3653   /* The first node will be initially invisible: no signals */
3654   gtk_tree_store_append (fixture.store, &root, NULL);
3655   create_tree_store_set_values (fixture.store, &root, FALSE);
3656
3657   /* check_filter_model (&fixture); */
3658   check_level_length (fixture.filter, NULL, 0);
3659   signal_monitor_assert_is_empty (fixture.monitor);
3660
3661   /* Insert a child node. This will cause the parent to become visible
3662    * since there is a child now.
3663    */
3664   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
3665   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3666   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3667
3668   gtk_tree_store_append (fixture.store, &iter, &root);
3669   create_tree_store_set_values (fixture.store, &iter, TRUE);
3670
3671   /* Parent must now be visible.  Do the level length check first,
3672    * to avoid modifying the child model triggering a row-changed to
3673    * the filter model.
3674    */
3675   check_level_length (fixture.filter, NULL, 1);
3676   check_level_length (fixture.filter, "0", 0);
3677   signal_monitor_assert_is_empty (fixture.monitor);
3678
3679   /* This should propagate row-changed */
3680   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
3681   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3682
3683   set_path_visibility (&fixture, "0", TRUE);
3684   /* check_filter_model (&fixture); */
3685   signal_monitor_assert_is_empty (fixture.monitor);
3686
3687   /* New root node, no child, so no signal */
3688   gtk_tree_store_append (fixture.store, &root, NULL);
3689   check_level_length (fixture.filter, NULL, 1);
3690   signal_monitor_assert_is_empty (fixture.monitor);
3691
3692   /* When the child comes in, this node will become visible */
3693   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
3694   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3695   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3696   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
3697   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3698
3699   gtk_tree_store_append (fixture.store, &iter, &root);
3700   check_level_length (fixture.filter, NULL, 2);
3701   check_level_length (fixture.filter, "1", 0);
3702
3703   create_tree_store_set_values (fixture.store, &root, TRUE);
3704   create_tree_store_set_values (fixture.store, &iter, TRUE);
3705
3706   /* check_filter_model (&fixture); */
3707   signal_monitor_assert_is_empty (fixture.monitor);
3708
3709   /* Add another child for 1 */
3710   gtk_tree_store_append (fixture.store, &iter, &root);
3711   create_tree_store_set_values (fixture.store, &iter, TRUE);
3712   check_level_length (fixture.filter, NULL, 2);
3713   check_level_length (fixture.filter, "0", 0);
3714   check_level_length (fixture.filter, "1", 0);
3715   signal_monitor_assert_is_empty (fixture.monitor);
3716
3717   /* Now remove one of the remaining child rows */
3718   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
3719
3720   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
3721                                        &iter, "0:0");
3722   gtk_tree_store_remove (fixture.store, &iter);
3723
3724   check_level_length (fixture.filter, NULL, 1);
3725   check_level_length (fixture.filter, "0", 0);
3726
3727   set_path_visibility (&fixture, "0", FALSE);
3728   /* check_filter_model (&fixture); */
3729   signal_monitor_assert_is_empty (fixture.monitor);
3730 }
3731
3732
3733 static gboolean
3734 specific_root_has_child_filter_filter_func (GtkTreeModel *model,
3735                                             GtkTreeIter  *iter,
3736                                             gpointer      data)
3737 {
3738   int depth;
3739   GtkTreePath *path;
3740
3741   path = gtk_tree_model_get_path (model, iter);
3742   depth = gtk_tree_path_get_depth (path);
3743   gtk_tree_path_free (path);
3744
3745   if (depth > 1)
3746     return TRUE;
3747   /* else */
3748   return gtk_tree_model_iter_has_child (model, iter);
3749 }
3750
3751 static void
3752 specific_root_has_child_filter (void)
3753 {
3754   GtkTreeModel *filter;
3755   GtkTreeIter iter, root;
3756   FilterTest fixture; /* This is not how it should be done ... */
3757   GtkWidget *tree_view;
3758
3759   /* This is a variation on the above test case, specific has-child-filter,
3760    * herein the has-child check for visibility only applies to root level
3761    * nodes.  In this test, children are always visible because we
3762    * only filter based on the "has child" criterion.
3763    */
3764
3765   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3766   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3767   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3768   fixture.monitor = signal_monitor_new (filter);
3769
3770   tree_view = gtk_tree_view_new_with_model (filter);
3771
3772   /* We will filter on parent state using a filter function.  We will
3773    * manually keep the boolean column in sync, so that we can use
3774    * check_filter_model() to check the consistency of the model.
3775    */
3776   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
3777    * to be able to check the structure here.  We keep the calls to
3778    * check_filter_model() commented out until then.
3779    */
3780   gtk_tree_model_filter_set_visible_func (fixture.filter,
3781                                           specific_root_has_child_filter_filter_func,
3782                                           NULL, NULL);
3783
3784   /* Add a first node, this will be invisible initially, so no signal
3785    * should be emitted.
3786    */
3787   gtk_tree_store_append (fixture.store, &root, NULL);
3788   create_tree_store_set_values (fixture.store, &root, FALSE);
3789
3790   signal_monitor_assert_is_empty (fixture.monitor);
3791   /* check_filter_model (&fixture); */
3792   check_level_length (fixture.filter, NULL, 0);
3793
3794   /* Add a child node.  This will cause the parent to become visible,
3795    * so we expect row-inserted signals for both.
3796    */
3797   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
3798   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3799   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3800
3801   gtk_tree_store_append (fixture.store, &iter, &root);
3802   signal_monitor_assert_is_empty (fixture.monitor);
3803
3804   check_level_length (fixture.filter, NULL, 1);
3805   check_level_length (fixture.filter, "0", 1);
3806
3807   /* Modify the content of iter, no signals because the parent is not
3808    * expanded.
3809    */
3810   create_tree_store_set_values (fixture.store, &iter, TRUE);
3811   signal_monitor_assert_is_empty (fixture.monitor);
3812
3813   /* Parent must now be visible.  Do the level length check first,
3814    * to avoid modifying the child model triggering a row-changed to
3815    * the filter model.
3816    */
3817   check_level_length (fixture.filter, NULL, 1);
3818   check_level_length (fixture.filter, "0", 1);
3819
3820   /* Modify path 0 */
3821   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
3822   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3823
3824   set_path_visibility (&fixture, "0", TRUE);
3825   /* check_filter_model (&fixture); */
3826
3827   signal_monitor_assert_is_empty (fixture.monitor);
3828
3829   /* Insert another node in the root level.  Initially invisible, so
3830    * not expecting any signal.
3831    */
3832   gtk_tree_store_append (fixture.store, &root, NULL);
3833   check_level_length (fixture.filter, NULL, 1);
3834
3835   signal_monitor_assert_is_empty (fixture.monitor);
3836
3837   /* Adding a child node which also makes parent at path 1 visible. */
3838   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
3839   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3840   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3841
3842   gtk_tree_store_append (fixture.store, &iter, &root);
3843   check_level_length (fixture.filter, NULL, 2);
3844   check_level_length (fixture.filter, "1", 1);
3845
3846   signal_monitor_assert_is_empty (fixture.monitor);
3847
3848   /* Check if row-changed is propagated */
3849   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
3850   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3851
3852   create_tree_store_set_values (fixture.store, &root, TRUE);
3853   create_tree_store_set_values (fixture.store, &iter, TRUE);
3854   /* check_filter_model (&fixture); */
3855   signal_monitor_assert_is_empty (fixture.monitor);
3856
3857   /* Insert another child under node 1 */
3858   gtk_tree_store_append (fixture.store, &iter, &root);
3859   create_tree_store_set_values (fixture.store, &iter, TRUE);
3860   check_level_length (fixture.filter, NULL, 2);
3861   check_level_length (fixture.filter, "0", 1);
3862   check_level_length (fixture.filter, "1", 2);
3863   signal_monitor_assert_is_empty (fixture.monitor);
3864
3865   /* Set a child node to invisible.  This should not yield any
3866    * change, because filtering is only done on whether the root
3867    * node has a child, which it still has.
3868    */
3869   set_path_visibility (&fixture, "0:0", FALSE);
3870   signal_monitor_assert_is_empty (fixture.monitor);
3871
3872   /* Now remove one of the remaining child rows */
3873   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3874   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
3875
3876   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
3877                                        &iter, "0:0");
3878   gtk_tree_store_remove (fixture.store, &iter);
3879
3880   check_level_length (fixture.filter, NULL, 1);
3881   check_level_length (fixture.filter, "0", 2);
3882   signal_monitor_assert_is_empty (fixture.monitor);
3883
3884   /* Set visibility of 0 to FALSE, no-op for filter model since
3885    * the child 0:0 is already gone
3886    */
3887   set_path_visibility (&fixture, "0", FALSE);
3888   /* check_filter_model (&fixture); */
3889   signal_monitor_assert_is_empty (fixture.monitor);
3890 }
3891
3892 static void
3893 specific_has_child_filter_on_sort_model (void)
3894 {
3895   GtkTreeModel *filter;
3896   GtkTreeModel *sort_model;
3897   GtkTreeIter iter, root;
3898   FilterTest fixture; /* This is not how it should be done */
3899   GtkWidget *tree_view;
3900
3901   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3902   sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (fixture.store));
3903   filter = gtk_tree_model_filter_new (sort_model, NULL);
3904   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3905   fixture.monitor = signal_monitor_new (filter);
3906
3907   tree_view = gtk_tree_view_new_with_model (filter);
3908
3909   /* We will filter on parent state using a filter function.  We will
3910    * manually keep the boolean column in sync, so that we can use
3911    * check_filter_model() to check the consistency of the model.
3912    */
3913   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
3914    * to be able to check the structure here.  We keep the calls to
3915    * check_filter_model() commented out until then.
3916    */
3917   gtk_tree_model_filter_set_visible_func (fixture.filter,
3918                                           specific_has_child_filter_filter_func,
3919                                           NULL, NULL);
3920
3921   /* The first node will be initially invisible: no signals */
3922   gtk_tree_store_append (fixture.store, &root, NULL);
3923   create_tree_store_set_values (fixture.store, &root, FALSE);
3924
3925   /* check_filter_model (&fixture); */
3926   check_level_length (fixture.filter, NULL, 0);
3927   signal_monitor_assert_is_empty (fixture.monitor);
3928
3929   /* Insert a child node. This will cause the parent to become visible
3930    * since there is a child now.
3931    */
3932   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
3933   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3934
3935   gtk_tree_store_append (fixture.store, &iter, &root);
3936   create_tree_store_set_values (fixture.store, &iter, TRUE);
3937
3938   /* Parent must now be visible.  Do the level length check first,
3939    * to avoid modifying the child model triggering a row-changed to
3940    * the filter model.
3941    */
3942   check_level_length (fixture.filter, NULL, 1);
3943   check_level_length (fixture.filter, "0", 0);
3944   signal_monitor_assert_is_empty (fixture.monitor);
3945
3946   /* This should propagate row-changed */
3947   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
3948   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3949
3950   set_path_visibility (&fixture, "0", TRUE);
3951   /* check_filter_model (&fixture); */
3952   signal_monitor_assert_is_empty (fixture.monitor);
3953
3954   /* New root node, no child, so no signal */
3955   gtk_tree_store_append (fixture.store, &root, NULL);
3956   check_level_length (fixture.filter, NULL, 1);
3957   signal_monitor_assert_is_empty (fixture.monitor);
3958
3959   /* When the child comes in, this node will become visible */
3960   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
3961   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3962   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
3963   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3964
3965   gtk_tree_store_append (fixture.store, &iter, &root);
3966   check_level_length (fixture.filter, NULL, 2);
3967   check_level_length (fixture.filter, "1", 0);
3968
3969   create_tree_store_set_values (fixture.store, &root, TRUE);
3970   create_tree_store_set_values (fixture.store, &iter, TRUE);
3971
3972   /* check_filter_model (&fixture); */
3973   signal_monitor_assert_is_empty (fixture.monitor);
3974
3975   /* Add another child for 1 */
3976   gtk_tree_store_append (fixture.store, &iter, &root);
3977   create_tree_store_set_values (fixture.store, &iter, TRUE);
3978   check_level_length (fixture.filter, NULL, 2);
3979   check_level_length (fixture.filter, "0", 0);
3980   check_level_length (fixture.filter, "1", 0);
3981   signal_monitor_assert_is_empty (fixture.monitor);
3982
3983   /* Now remove one of the remaining child rows */
3984   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
3985
3986   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
3987                                        &iter, "0:0");
3988   gtk_tree_store_remove (fixture.store, &iter);
3989
3990   check_level_length (fixture.filter, NULL, 1);
3991   check_level_length (fixture.filter, "0", 0);
3992
3993   set_path_visibility (&fixture, "0", FALSE);
3994   /* check_filter_model (&fixture); */
3995   signal_monitor_assert_is_empty (fixture.monitor);
3996 }
3997
3998 static gboolean
3999 specific_at_least_2_children_filter_filter_func (GtkTreeModel *model,
4000                                                  GtkTreeIter  *iter,
4001                                                  gpointer      data)
4002 {
4003   return gtk_tree_model_iter_n_children (model, iter) >= 2;
4004 }
4005
4006 static void
4007 specific_at_least_2_children_filter (void)
4008 {
4009   GtkTreeModel *filter;
4010   GtkTreeIter iter, root;
4011   FilterTest fixture; /* This is not how it should be done */
4012   GtkWidget *tree_view;
4013
4014   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
4015   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
4016   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
4017   fixture.monitor = signal_monitor_new (filter);
4018
4019   tree_view = gtk_tree_view_new_with_model (filter);
4020
4021   gtk_tree_model_filter_set_visible_func (fixture.filter,
4022                                           specific_at_least_2_children_filter_filter_func,
4023                                           NULL, NULL);
4024
4025   /* The first node will be initially invisible: no signals */
4026   gtk_tree_store_append (fixture.store, &root, NULL);
4027   create_tree_store_set_values (fixture.store, &root, FALSE);
4028
4029   /* check_filter_model (&fixture); */
4030   check_level_length (fixture.filter, NULL, 0);
4031   signal_monitor_assert_is_empty (fixture.monitor);
4032
4033   /* Insert a child node.  Nothing should happen.
4034    */
4035   gtk_tree_store_append (fixture.store, &iter, &root);
4036   create_tree_store_set_values (fixture.store, &iter, TRUE);
4037
4038   check_level_length (fixture.filter, NULL, 0);
4039   signal_monitor_assert_is_empty (fixture.monitor);
4040
4041   /* Insert a second child node.  This will cause the parent to become
4042    * visible.
4043    */
4044   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
4045   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4046
4047   gtk_tree_store_append (fixture.store, &iter, &root);
4048   create_tree_store_set_values (fixture.store, &iter, TRUE);
4049
4050   /* Parent must now be visible.  Do the level length check first,
4051    * to avoid modifying the child model triggering a row-changed to
4052    * the filter model.
4053    */
4054   check_level_length (fixture.filter, NULL, 1);
4055   check_level_length (fixture.filter, "0", 0);
4056   signal_monitor_assert_is_empty (fixture.monitor);
4057
4058   /* This should propagate row-changed */
4059   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
4060   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4061
4062   set_path_visibility (&fixture, "0", TRUE);
4063   /* check_filter_model (&fixture); */
4064   signal_monitor_assert_is_empty (fixture.monitor);
4065
4066   /* New root node, no child, so no signal */
4067   gtk_tree_store_append (fixture.store, &root, NULL);
4068   check_level_length (fixture.filter, NULL, 1);
4069   signal_monitor_assert_is_empty (fixture.monitor);
4070
4071   /* First child, no signal, no change */
4072   gtk_tree_store_append (fixture.store, &iter, &root);
4073   check_level_length (fixture.filter, NULL, 1);
4074   signal_monitor_assert_is_empty (fixture.monitor);
4075
4076   /* When the second child comes in, this node will become visible */
4077   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
4078   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4079   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
4080   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4081
4082   gtk_tree_store_append (fixture.store, &iter, &root);
4083   check_level_length (fixture.filter, NULL, 2);
4084   check_level_length (fixture.filter, "1", 0);
4085
4086   create_tree_store_set_values (fixture.store, &root, TRUE);
4087   create_tree_store_set_values (fixture.store, &iter, TRUE);
4088
4089   /* check_filter_model (&fixture); */
4090   signal_monitor_assert_is_empty (fixture.monitor);
4091
4092   /* Add another child for 1 */
4093   gtk_tree_store_append (fixture.store, &iter, &root);
4094   create_tree_store_set_values (fixture.store, &iter, TRUE);
4095   check_level_length (fixture.filter, NULL, 2);
4096   check_level_length (fixture.filter, "0", 0);
4097   check_level_length (fixture.filter, "1", 0);
4098   signal_monitor_assert_is_empty (fixture.monitor);
4099
4100   /* Now remove one of the remaining child rows */
4101   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
4102
4103   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
4104                                        &iter, "0:0");
4105   gtk_tree_store_remove (fixture.store, &iter);
4106
4107   check_level_length (fixture.filter, NULL, 1);
4108   check_level_length (fixture.filter, "0", 0);
4109
4110   set_path_visibility (&fixture, "0", FALSE);
4111   /* check_filter_model (&fixture); */
4112   signal_monitor_assert_is_empty (fixture.monitor);
4113 }
4114
4115 static void
4116 specific_at_least_2_children_filter_on_sort_model (void)
4117 {
4118   GtkTreeModel *filter;
4119   GtkTreeModel *sort_model;
4120   GtkTreeIter iter, root;
4121   FilterTest fixture; /* This is not how it should be done */
4122   GtkWidget *tree_view;
4123
4124   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
4125   sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (fixture.store));
4126   filter = gtk_tree_model_filter_new (sort_model, NULL);
4127   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
4128   fixture.monitor = signal_monitor_new (filter);
4129
4130   tree_view = gtk_tree_view_new_with_model (filter);
4131
4132   gtk_tree_model_filter_set_visible_func (fixture.filter,
4133                                           specific_at_least_2_children_filter_filter_func,
4134                                           NULL, NULL);
4135
4136   /* The first node will be initially invisible: no signals */
4137   gtk_tree_store_append (fixture.store, &root, NULL);
4138   create_tree_store_set_values (fixture.store, &root, FALSE);
4139
4140   /* check_filter_model (&fixture); */
4141   check_level_length (fixture.filter, NULL, 0);
4142   signal_monitor_assert_is_empty (fixture.monitor);
4143
4144   /* Insert a child node.  Nothing should happen.
4145    */
4146   gtk_tree_store_append (fixture.store, &iter, &root);
4147   create_tree_store_set_values (fixture.store, &iter, TRUE);
4148
4149   check_level_length (fixture.filter, NULL, 0);
4150   signal_monitor_assert_is_empty (fixture.monitor);
4151
4152     {
4153       GtkTreePath *path = gtk_tree_path_new_from_indices (0, 0, -1);
4154       GtkTreeRowReference *ref;
4155
4156       ref = gtk_tree_row_reference_new (sort_model, path);
4157       gtk_tree_path_free (path);
4158     }
4159
4160   /* Insert a second child node.  This will cause the parent to become
4161    * visible.
4162    */
4163   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
4164   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4165
4166   gtk_tree_store_append (fixture.store, &iter, &root);
4167   create_tree_store_set_values (fixture.store, &iter, TRUE);
4168
4169   /* Parent must now be visible.  Do the level length check first,
4170    * to avoid modifying the child model triggering a row-changed to
4171    * the filter model.
4172    */
4173   check_level_length (fixture.filter, NULL, 1);
4174   check_level_length (fixture.filter, "0", 0);
4175   signal_monitor_assert_is_empty (fixture.monitor);
4176
4177   /* This should propagate row-changed */
4178   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
4179   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4180
4181   set_path_visibility (&fixture, "0", TRUE);
4182   /* check_filter_model (&fixture); */
4183   signal_monitor_assert_is_empty (fixture.monitor);
4184
4185   /* New root node, no child, so no signal */
4186   gtk_tree_store_append (fixture.store, &root, NULL);
4187   check_level_length (fixture.filter, NULL, 1);
4188   signal_monitor_assert_is_empty (fixture.monitor);
4189 }
4190
4191
4192 static void
4193 specific_filter_add_child (void)
4194 {
4195   /* This test is based on one of the test cases I found in my
4196    * old test cases directory.  I unfortunately do not have a record
4197    * from who this test case originated.  -Kris.
4198    */
4199
4200   GtkTreeIter iter;
4201   GtkTreeIter iter_first;
4202   GtkTreeIter child;
4203   GtkTreeStore *store;
4204   GtkTreeModel *filter G_GNUC_UNUSED;
4205
4206   store = gtk_tree_store_new (1, G_TYPE_STRING);
4207
4208   gtk_tree_store_append (store, &iter_first, NULL);
4209   gtk_tree_store_set (store, &iter_first, 0, "Hello", -1);
4210
4211   gtk_tree_store_append (store, &iter, NULL);
4212   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4213
4214   gtk_tree_store_append (store, &iter, NULL);
4215   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4216
4217   gtk_tree_store_append (store, &iter, NULL);
4218   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4219
4220   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4221
4222   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4223   gtk_tree_store_append (store, &child, &iter_first);
4224   gtk_tree_store_set (store, &child, 0, "Hello", -1);
4225 }
4226
4227 static void
4228 specific_list_store_clear (void)
4229 {
4230   GtkTreeIter iter;
4231   GtkListStore *list;
4232   GtkTreeModel *filter;
4233   GtkWidget *view G_GNUC_UNUSED;
4234
4235   list = gtk_list_store_new (1, G_TYPE_INT);
4236   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
4237   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
4238   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
4239   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
4240   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
4241   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
4242   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
4243   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
4244
4245   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
4246   view = gtk_tree_view_new_with_model (filter);
4247
4248   gtk_list_store_clear (list);
4249 }
4250
4251 static void
4252 specific_sort_ref_leaf_and_remove_ancestor (void)
4253 {
4254   GtkTreeIter iter, child, child2, child3;
4255   GtkTreeStore *tree;
4256   GtkTreeModel *sort;
4257   GtkTreePath *path;
4258   GtkTreeRowReference *rowref;
4259   GtkWidget *view G_GNUC_UNUSED;
4260
4261   tree = gtk_tree_store_new (1, G_TYPE_INT);
4262   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4263   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4264   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4265   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4266
4267   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4268   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4269   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4270
4271   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
4272   view = gtk_tree_view_new_with_model (sort);
4273   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4274
4275   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4276   rowref = gtk_tree_row_reference_new (sort, path);
4277   gtk_tree_path_free (path);
4278
4279   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4280   rowref = gtk_tree_row_reference_new (sort, path);
4281   gtk_tree_path_free (path);
4282
4283   path = gtk_tree_path_new_from_indices (3, 0, -1);
4284   rowref = gtk_tree_row_reference_new (sort, path);
4285   gtk_tree_path_free (path);
4286
4287   path = gtk_tree_path_new_from_indices (3, -1);
4288   rowref = gtk_tree_row_reference_new (sort, path);
4289   gtk_tree_path_free (path);
4290
4291   /* Deleting a parent */
4292   path = gtk_tree_path_new_from_indices (3, 0, -1);
4293   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4294   gtk_tree_store_remove (tree, &iter);
4295   gtk_tree_path_free (path);
4296
4297   gtk_tree_row_reference_free (rowref);
4298 }
4299
4300 static void
4301 specific_ref_leaf_and_remove_ancestor (void)
4302 {
4303   GtkTreeIter iter, child, child2, child3;
4304   GtkTreeStore *tree;
4305   GtkTreeModel *filter;
4306   GtkTreePath *path;
4307   GtkTreeRowReference *rowref;
4308   GtkWidget *view G_GNUC_UNUSED;
4309
4310   tree = gtk_tree_store_new (1, G_TYPE_INT);
4311   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4312   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4313   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4314   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4315
4316   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4317   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4318   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4319
4320   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), NULL);
4321   view = gtk_tree_view_new_with_model (filter);
4322   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4323
4324   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4325   rowref = gtk_tree_row_reference_new (filter, path);
4326   gtk_tree_path_free (path);
4327
4328   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4329   rowref = gtk_tree_row_reference_new (filter, path);
4330   gtk_tree_path_free (path);
4331
4332   path = gtk_tree_path_new_from_indices (3, 0, -1);
4333   rowref = gtk_tree_row_reference_new (filter, path);
4334   gtk_tree_path_free (path);
4335
4336   path = gtk_tree_path_new_from_indices (3, -1);
4337   rowref = gtk_tree_row_reference_new (filter, path);
4338   gtk_tree_path_free (path);
4339
4340   /* Deleting a parent */
4341   path = gtk_tree_path_new_from_indices (3, 0, -1);
4342   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4343   gtk_tree_store_remove (tree, &iter);
4344   gtk_tree_path_free (path);
4345
4346   gtk_tree_row_reference_free (rowref);
4347 }
4348
4349 static void
4350 specific_virtual_ref_leaf_and_remove_ancestor (void)
4351 {
4352   GtkTreeIter iter, child, child2, child3;
4353   GtkTreeStore *tree;
4354   GtkTreeModel *filter;
4355   GtkTreePath *path;
4356   GtkTreeRowReference *rowref;
4357   GtkWidget *view G_GNUC_UNUSED;
4358
4359   tree = gtk_tree_store_new (1, G_TYPE_INT);
4360   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4361   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4362   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4363   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4364
4365   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4366   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4367   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4368
4369   /* Set a virtual root of 3:0 */
4370   path = gtk_tree_path_new_from_indices (3, 0, -1);
4371   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
4372   gtk_tree_path_free (path);
4373
4374   view = gtk_tree_view_new_with_model (filter);
4375   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4376
4377   path = gtk_tree_path_new_from_indices (0, 0, -1);
4378   rowref = gtk_tree_row_reference_new (filter, path);
4379   gtk_tree_path_free (path);
4380
4381   path = gtk_tree_path_new_from_indices (0, 0, -1);
4382   rowref = gtk_tree_row_reference_new (filter, path);
4383   gtk_tree_path_free (path);
4384
4385   path = gtk_tree_path_new_from_indices (0, -1);
4386   rowref = gtk_tree_row_reference_new (filter, path);
4387   gtk_tree_path_free (path);
4388
4389   /* Deleting the virtual root */
4390   path = gtk_tree_path_new_from_indices (3, 0, -1);
4391   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4392   gtk_tree_store_remove (tree, &iter);
4393   gtk_tree_path_free (path);
4394
4395   gtk_tree_row_reference_free (rowref);
4396 }
4397
4398
4399 static int
4400 specific_bug_301558_sort_func (GtkTreeModel *model,
4401                                GtkTreeIter  *a,
4402                                GtkTreeIter  *b,
4403                                gpointer      data)
4404 {
4405   int i, j;
4406
4407   gtk_tree_model_get (model, a, 0, &i, -1);
4408   gtk_tree_model_get (model, b, 0, &j, -1);
4409
4410   return j - i;
4411 }
4412
4413 static void
4414 specific_bug_301558 (void)
4415 {
4416   /* Test case for GNOME Bugzilla bug 301558 provided by
4417    * Markku Vire.
4418    */
4419   GtkTreeStore *tree;
4420   GtkTreeModel *filter;
4421   GtkTreeModel *sort;
4422   GtkTreeIter root, iter, iter2;
4423   GtkWidget *view G_GNUC_UNUSED;
4424   int i;
4425   gboolean add;
4426
4427   g_test_bug ("301558");
4428
4429   tree = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_BOOLEAN);
4430   gtk_tree_store_append (tree, &iter, NULL);
4431   gtk_tree_store_set (tree, &iter, 0, 123, 1, TRUE, -1);
4432   gtk_tree_store_append (tree, &iter2, &iter);
4433   gtk_tree_store_set (tree, &iter2, 0, 73, 1, TRUE, -1);
4434
4435   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
4436   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
4437                                            specific_bug_301558_sort_func,
4438                                            NULL, NULL);
4439
4440   filter = gtk_tree_model_filter_new (sort, NULL);
4441   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), 1);
4442
4443   view = gtk_tree_view_new_with_model (filter);
4444
4445   while (gtk_events_pending ())
4446     gtk_main_iteration ();
4447
4448   add = TRUE;
4449
4450   for (i = 0; i < 10; i++)
4451     {
4452       if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree), &root))
4453         g_assert_not_reached ();
4454
4455       if (add)
4456         {
4457           gtk_tree_store_append (tree, &iter, &root);
4458           gtk_tree_store_set (tree, &iter, 0, 456, 1, TRUE, -1);
4459         }
4460       else
4461         {
4462           int n;
4463           n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree), &root);
4464           gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (tree), &iter,
4465                                          &root, n - 1);
4466           gtk_tree_store_remove (tree, &iter);
4467         }
4468
4469       add = !add;
4470     }
4471 }
4472
4473
4474 static gboolean
4475 specific_bug_311955_filter_func (GtkTreeModel *model,
4476                                  GtkTreeIter  *iter,
4477                                  gpointer      data)
4478 {
4479   int value;
4480
4481   gtk_tree_model_get (model, iter, 0, &value, -1);
4482
4483   return (value != 0);
4484 }
4485
4486 static void
4487 specific_bug_311955 (void)
4488 {
4489   /* This is a test case for GNOME Bugzilla bug 311955.  It was written
4490    * by Markku Vire.
4491    */
4492   GtkTreeIter iter, child, root;
4493   GtkTreeStore *store;
4494   GtkTreeModel *sort;
4495   GtkTreeModel *filter;
4496
4497   GtkWidget *window G_GNUC_UNUSED;
4498   GtkWidget *tree_view;
4499   int i;
4500   int n;
4501   GtkTreePath *path;
4502
4503   g_test_bug ("311955");
4504
4505   store = gtk_tree_store_new (1, G_TYPE_INT);
4506
4507   gtk_tree_store_append (store, &root, NULL);
4508   gtk_tree_store_set (store, &root, 0, 33, -1);
4509
4510   gtk_tree_store_append (store, &iter, &root);
4511   gtk_tree_store_set (store, &iter, 0, 50, -1);
4512
4513   gtk_tree_store_append (store, &iter, NULL);
4514   gtk_tree_store_set (store, &iter, 0, 22, -1);
4515
4516   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
4517   filter = gtk_tree_model_filter_new (sort, NULL);
4518
4519   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4520                                           specific_bug_311955_filter_func,
4521                                           NULL, NULL);
4522
4523   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4524   tree_view = gtk_tree_view_new_with_model (filter);
4525   g_object_unref (store);
4526
4527   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
4528
4529   while (gtk_events_pending ())
4530     gtk_main_iteration ();
4531
4532   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
4533   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 1);
4534
4535   /* Fill model */
4536   for (i = 0; i < 4; i++)
4537     {
4538       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
4539
4540       gtk_tree_store_append (store, &iter, &root);
4541
4542       if (i < 3)
4543         gtk_tree_store_set (store, &iter, 0, i, -1);
4544
4545       if (i % 2 == 0)
4546         {
4547           gtk_tree_store_append (store, &child, &iter);
4548           gtk_tree_store_set (store, &child, 0, 10, -1);
4549         }
4550     }
4551
4552   while (gtk_events_pending ())
4553     gtk_main_iteration ();
4554
4555   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4556   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 1);
4557
4558   /* Remove bottommost child from the tree. */
4559   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
4560   n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &root);
4561
4562   if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
4563     {
4564       if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
4565         gtk_tree_store_remove (store, &child);
4566     }
4567   else
4568     g_assert_not_reached ();
4569
4570   path = gtk_tree_path_new_from_indices (0, 2, -1);
4571   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
4572   gtk_tree_path_free (path);
4573
4574   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4575   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 0);
4576 }
4577
4578 static void
4579 specific_bug_311955_clean (void)
4580 {
4581   /* Cleaned up version of the test case for GNOME Bugzilla bug 311955,
4582    * which is easier to understand.
4583    */
4584   GtkTreeIter iter, child, grandchild;
4585   GtkTreeStore *store;
4586   GtkTreeModel *sort;
4587   GtkTreeModel *filter;
4588
4589   GtkWidget *tree_view;
4590   GtkTreePath *path;
4591
4592   store = gtk_tree_store_new (1, G_TYPE_INT);
4593
4594   gtk_tree_store_append (store, &iter, NULL);
4595   gtk_tree_store_set (store, &iter, 0, 1, -1);
4596
4597   gtk_tree_store_append (store, &child, &iter);
4598   gtk_tree_store_set (store, &child, 0, 1, -1);
4599
4600   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
4601   filter = gtk_tree_model_filter_new (sort, NULL);
4602
4603   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4604                                           specific_bug_311955_filter_func,
4605                                           NULL, NULL);
4606
4607   tree_view = gtk_tree_view_new_with_model (filter);
4608   g_object_unref (store);
4609
4610   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
4611
4612   while (gtk_events_pending ())
4613     gtk_main_iteration ();
4614
4615   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
4616   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 1);
4617
4618   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
4619
4620   gtk_tree_store_append (store, &child, &iter);
4621   gtk_tree_store_set (store, &child, 0, 0, -1);
4622
4623   gtk_tree_store_append (store, &child, &iter);
4624   gtk_tree_store_set (store, &child, 0, 1, -1);
4625
4626   gtk_tree_store_append (store, &child, &iter);
4627   gtk_tree_store_set (store, &child, 0, 1, -1);
4628
4629   gtk_tree_store_append (store, &grandchild, &child);
4630   gtk_tree_store_set (store, &grandchild, 0, 1, -1);
4631
4632   gtk_tree_store_append (store, &child, &iter);
4633   /* Don't set a value: assume 0 */
4634
4635   /* Remove leaf node, check trigger row-has-child-toggled */
4636   path = gtk_tree_path_new_from_indices (0, 3, 0, -1);
4637   gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
4638   gtk_tree_path_free (path);
4639   gtk_tree_store_remove (store, &iter);
4640
4641   path = gtk_tree_path_new_from_indices (0, 2, -1);
4642   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
4643   gtk_tree_path_free (path);
4644
4645   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4646   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 0);
4647
4648   gtk_widget_destroy (tree_view);
4649 }
4650
4651 static void
4652 specific_bug_346800 (void)
4653 {
4654   /* This is a test case for GNOME Bugzilla bug 346800.  It was written
4655    * by Jonathan Matthew.
4656    */
4657
4658   GtkTreeIter node_iters[50];
4659   GtkTreeIter child_iters[50];
4660   GtkTreeModel *model;
4661   GtkTreeModelFilter *filter;
4662   GtkTreeStore *store;
4663   GType *columns;
4664   int i;
4665   int items = 50;
4666   columns = g_new (GType, 2);
4667   columns[0] = G_TYPE_STRING;
4668   columns[1] = G_TYPE_BOOLEAN;
4669   store = gtk_tree_store_newv (2, columns);
4670   model = GTK_TREE_MODEL (store);
4671
4672   g_test_bug ("346800");
4673
4674   filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
4675   gtk_tree_model_filter_set_visible_column (filter, 1);
4676
4677   for (i=0; i<items; i++)
4678     {
4679       /* allocate random amounts of junk, otherwise the filter model's arrays can expand without moving */
4680
4681       g_malloc (138);
4682       gtk_tree_store_append (store, &node_iters[i], NULL);
4683       gtk_tree_store_set (store, &node_iters[i],
4684                           0, "something",
4685                           1, ((i%6) == 0) ? FALSE : TRUE,
4686                           -1);
4687
4688       g_malloc (47);
4689       gtk_tree_store_append (store, &child_iters[i], &node_iters[i]);
4690       gtk_tree_store_set (store, &child_iters[i],
4691                           0, "something else",
4692                           1, FALSE,
4693                           -1);
4694       gtk_tree_model_filter_refilter (filter);
4695
4696       if (i > 6)
4697         {
4698           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-1], 1,
4699                               (i & 1) ? TRUE : FALSE, -1);
4700           gtk_tree_model_filter_refilter (filter);
4701
4702           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
4703                               (i & 1) ? FALSE: TRUE, -1);
4704           gtk_tree_model_filter_refilter (filter);
4705         }
4706     }
4707 }
4708
4709 static gboolean
4710 specific_bug_464173_visible_func (GtkTreeModel *model,
4711                                   GtkTreeIter  *iter,
4712                                   gpointer      data)
4713 {
4714   gboolean *visible = (gboolean *)data;
4715
4716   return *visible;
4717 }
4718
4719 static void
4720 specific_bug_464173 (void)
4721 {
4722   /* Test case for GNOME Bugzilla bug 464173, test case written
4723    * by Andreas Koehler.
4724    */
4725   GtkTreeStore *model;
4726   GtkTreeModelFilter *f_model;
4727   GtkTreeIter iter1, iter2;
4728   GtkWidget *view G_GNUC_UNUSED;
4729   gboolean visible = TRUE;
4730
4731   g_test_bug ("464173");
4732
4733   model = gtk_tree_store_new (1, G_TYPE_STRING);
4734   gtk_tree_store_append (model, &iter1, NULL);
4735   gtk_tree_store_set (model, &iter1, 0, "Foo", -1);
4736   gtk_tree_store_append (model, &iter2, &iter1);
4737   gtk_tree_store_set (model, &iter2, 0, "Bar", -1);
4738
4739   f_model = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL(model), NULL));
4740   gtk_tree_model_filter_set_visible_func (f_model,
4741                                           specific_bug_464173_visible_func,
4742                                           &visible, NULL);
4743
4744   view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (f_model));
4745
4746   visible = FALSE;
4747   gtk_tree_model_filter_refilter (f_model);
4748 }
4749
4750
4751 static gboolean
4752 specific_bug_540201_filter_func (GtkTreeModel *model,
4753                                  GtkTreeIter  *iter,
4754                                  gpointer      data)
4755 {
4756   gboolean has_children;
4757
4758   has_children = gtk_tree_model_iter_has_child (model, iter);
4759
4760   return has_children;
4761 }
4762
4763 static void
4764 specific_bug_540201 (void)
4765 {
4766   /* Test case for GNOME Bugzilla bug 540201, steps provided by
4767    * Charles Day.
4768    */
4769   GtkTreeIter iter, root;
4770   GtkTreeStore *store;
4771   GtkTreeModel *filter;
4772
4773   GtkWidget *tree_view G_GNUC_UNUSED;
4774
4775   g_test_bug ("540201");
4776
4777   store = gtk_tree_store_new (1, G_TYPE_INT);
4778
4779   gtk_tree_store_append (store, &root, NULL);
4780   gtk_tree_store_set (store, &root, 0, 33, -1);
4781
4782   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4783   tree_view = gtk_tree_view_new_with_model (filter);
4784
4785   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4786                                           specific_bug_540201_filter_func,
4787                                           NULL, NULL);
4788
4789   gtk_tree_store_append (store, &iter, &root);
4790   gtk_tree_store_set (store, &iter, 0, 50, -1);
4791
4792   gtk_tree_store_append (store, &iter, &root);
4793   gtk_tree_store_set (store, &iter, 0, 22, -1);
4794
4795
4796   gtk_tree_store_append (store, &root, NULL);
4797   gtk_tree_store_set (store, &root, 0, 33, -1);
4798
4799   gtk_tree_store_append (store, &iter, &root);
4800   gtk_tree_store_set (store, &iter, 0, 22, -1);
4801 }
4802
4803
4804 static gboolean
4805 specific_bug_549287_visible_func (GtkTreeModel *model,
4806                                   GtkTreeIter  *iter,
4807                                   gpointer      data)
4808 {
4809   gboolean result = FALSE;
4810
4811   result = gtk_tree_model_iter_has_child (model, iter);
4812
4813   return result;
4814 }
4815
4816 static void
4817 specific_bug_549287 (void)
4818 {
4819   /* Test case for GNOME Bugzilla bug 529287, provided by Julient Puydt */
4820
4821   int i;
4822   GtkTreeStore *store;
4823   GtkTreeModel *filtered;
4824   GtkWidget *view G_GNUC_UNUSED;
4825   GtkTreeIter iter;
4826   GtkTreeIter *swap, *parent, *child;
4827
4828   g_test_bug ("529287");
4829
4830   store = gtk_tree_store_new (1, G_TYPE_STRING);
4831   filtered = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4832   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered),
4833                                           specific_bug_549287_visible_func,
4834                                           NULL, NULL);
4835
4836   view = gtk_tree_view_new_with_model (filtered);
4837
4838   for (i = 0; i < 4; i++)
4839     {
4840       if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
4841         {
4842           parent = gtk_tree_iter_copy (&iter);
4843           child = gtk_tree_iter_copy (&iter);
4844
4845           while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
4846                                                 child, parent, 0))
4847             {
4848
4849               swap = parent;
4850               parent = child;
4851               child = swap;
4852             }
4853
4854           gtk_tree_store_append (store, child, parent);
4855           gtk_tree_store_set (store, child,
4856                               0, "Something",
4857                               -1);
4858
4859           gtk_tree_iter_free (parent);
4860           gtk_tree_iter_free (child);
4861         }
4862       else
4863         {
4864           gtk_tree_store_append (store, &iter, NULL);
4865           gtk_tree_store_set (store, &iter,
4866                               0, "Something",
4867                               -1);
4868         }
4869
4870       /* since we inserted something, we changed the visibility conditions: */
4871       gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filtered));
4872     }
4873 }
4874
4875 static gboolean
4876 specific_bug_621076_visible_func (GtkTreeModel *model,
4877                                   GtkTreeIter  *iter,
4878                                   gpointer      data)
4879 {
4880   gboolean visible = FALSE;
4881   gchar *str = NULL;
4882
4883   gtk_tree_model_get (model, iter, 0, &str, -1);
4884   if (str != NULL && g_str_has_prefix (str, "visible"))
4885     {
4886       visible = TRUE;
4887     }
4888   else
4889     {
4890       GtkTreeIter child_iter;
4891       gboolean valid;
4892
4893       /* Recursively check if we have a visible child */
4894       for (valid = gtk_tree_model_iter_children (model, &child_iter, iter);
4895            valid; valid = gtk_tree_model_iter_next (model, &child_iter))
4896         {
4897           if (specific_bug_621076_visible_func (model, &child_iter, data))
4898             {
4899               visible = TRUE;
4900               break;
4901             }
4902         }
4903     }
4904
4905   if (str)
4906     g_free (str);
4907
4908   return visible;
4909 }
4910
4911 static void
4912 specific_bug_621076 (void)
4913 {
4914   /* Test case for GNOME Bugzilla bug 621076, provided by Xavier Claessens */
4915
4916   /* This test case differs from has-child-filter and root-has-child-filter
4917    * in that the visible function both filters on content and model
4918    * structure.  Also, it is recursive.
4919    */
4920
4921   GtkTreeStore *store;
4922   GtkTreeModel *filter;
4923   GtkWidget *view;
4924   GtkTreeIter group_iter;
4925   GtkTreeIter item_iter;
4926   SignalMonitor *monitor;
4927
4928   g_test_bug ("621076");
4929
4930   store = gtk_tree_store_new (1, G_TYPE_STRING);
4931   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4932   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4933                                           specific_bug_621076_visible_func,
4934                                           NULL, NULL);
4935
4936   view = gtk_tree_view_new_with_model (filter);
4937   g_object_ref_sink (view);
4938
4939   monitor = signal_monitor_new (filter);
4940
4941   signal_monitor_append_signal (monitor, ROW_INSERTED, "0");
4942   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
4943                                      0, "visible-group-0",
4944                                      -1);
4945   signal_monitor_assert_is_empty (monitor);
4946
4947   /* visible-group-0 is not expanded, so ROW_INSERTED should not be emitted
4948    * for its children. However, ROW_HAS_CHILD_TOGGLED should be emitted on
4949    * visible-group-0 to tell the view that row can be expanded. */
4950   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
4951   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
4952   group_iter = item_iter;
4953   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
4954                                      0, "visible-0:0",
4955                                      -1);
4956   signal_monitor_assert_is_empty (monitor);
4957
4958   signal_monitor_append_signal (monitor, ROW_INSERTED, "1");
4959   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
4960                                      0, "visible-group-1",
4961                                      -1);
4962   signal_monitor_assert_is_empty (monitor);
4963
4964   /* We are adding an hidden item inside visible-group-1, so
4965    * ROW_HAS_CHILD_TOGGLED should not be emitted.  It is emitted though,
4966    * because the signal originating at TreeStore will be propagated,
4967    * as well a generated signal because the state of the parent *could*
4968    * change by a change in the model.
4969    */
4970   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
4971   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
4972   group_iter = item_iter;
4973   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
4974                                      0, "group-1:0",
4975                                      -1);
4976   signal_monitor_assert_is_empty (monitor);
4977
4978   /* This group is invisible and its parent too. Nothing should be emitted */
4979   group_iter = item_iter;
4980   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
4981                                      0, "group-1:0:0",
4982                                      -1);
4983   signal_monitor_assert_is_empty (monitor);
4984
4985   /* Adding a visible item in this group hierarchy will make all nodes
4986    * in this path visible.  The first level should simply tell the view
4987    * that it now has a child, and the view will load the tree if needed
4988    * (depends on the expanded state).
4989    */
4990   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
4991   group_iter = item_iter;
4992   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
4993                                      0, "visible-1:0:0:0",
4994                                      -1);
4995   signal_monitor_assert_is_empty (monitor);
4996
4997   check_level_length (GTK_TREE_MODEL_FILTER (filter), "1", 1);
4998
4999   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5000                                      0, "group-2",
5001                                      -1);
5002   signal_monitor_assert_is_empty (monitor);
5003
5004   /* Parent is invisible, and adding this invisible item won't change that,
5005    * so no signal should be emitted. */
5006   group_iter = item_iter;
5007   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5008                                      0, "invisible-2:0",
5009                                      -1);
5010   signal_monitor_assert_is_empty (monitor);
5011
5012   /* This makes group-2 visible, so it gets inserted and tells it has
5013    * children.
5014    */
5015   signal_monitor_append_signal (monitor, ROW_INSERTED, "2");
5016   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5017   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5018                                      0, "visible-2:1",
5019                                      -1);
5020   signal_monitor_assert_is_empty (monitor);
5021
5022   /* group-2 is already visible, so this time it is a normal insertion */
5023   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5024                                      0, "visible-2:2",
5025                                      -1);
5026   signal_monitor_assert_is_empty (monitor);
5027
5028
5029   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5030                                      0, "group-3",
5031                                      -1);
5032   signal_monitor_assert_is_empty (monitor);
5033
5034   /* Parent is invisible, and adding this invisible item won't change that,
5035    * so no signal should be emitted. */
5036   group_iter = item_iter;
5037   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5038                                      0, "invisible-3:0",
5039                                      -1);
5040   signal_monitor_assert_is_empty (monitor);
5041
5042   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5043                                      0, "invisible-3:1",
5044                                      -1);
5045   signal_monitor_assert_is_empty (monitor);
5046
5047   /* This will make group 3 visible. */
5048   signal_monitor_append_signal (monitor, ROW_INSERTED, "3");
5049   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3");
5050   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3");
5051   gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1);
5052   signal_monitor_assert_is_empty (monitor);
5053
5054   /* Make sure all groups are expanded, so the filter has the tree cached */
5055   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
5056   while (gtk_events_pending ())
5057     gtk_main_iteration ();
5058
5059   /* Should only yield a row-changed */
5060   signal_monitor_append_signal (monitor, ROW_CHANGED, "3:0");
5061   gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1);
5062   signal_monitor_assert_is_empty (monitor);
5063
5064   /* Now remove/hide some items. If a group loses its last item, the group
5065    * should be deleted instead of the item.
5066    */
5067
5068   signal_monitor_append_signal (monitor, ROW_DELETED, "2:1");
5069   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:2");
5070   gtk_tree_store_remove (store, &item_iter);
5071   signal_monitor_assert_is_empty (monitor);
5072
5073   signal_monitor_append_signal (monitor, ROW_DELETED, "2:0");
5074   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5075   signal_monitor_append_signal (monitor, ROW_DELETED, "2");
5076   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:1");
5077   gtk_tree_store_set (store, &item_iter, 0, "invisible-2:1", -1);
5078   signal_monitor_assert_is_empty (monitor);
5079
5080   signal_monitor_append_signal (monitor, ROW_DELETED, "1:0:0:0");
5081   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1:0:0");
5082   signal_monitor_append_signal (monitor, ROW_DELETED, "1:0");
5083   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
5084   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "1:0:0:0");
5085   gtk_tree_store_remove (store, &item_iter);
5086   signal_monitor_assert_is_empty (monitor);
5087
5088   /* Hide a group using row-changed instead of row-deleted */
5089   /* Caution: group 2 is gone, so offsets of the signals have moved. */
5090   signal_monitor_append_signal (monitor, ROW_DELETED, "2:0");
5091   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5092   signal_monitor_append_signal (monitor, ROW_DELETED, "2");
5093   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter,
5094                                        "3:1");
5095   gtk_tree_store_set (store, &item_iter, 0, "invisible-3:1", -1);
5096   signal_monitor_assert_is_empty (monitor);
5097
5098 #if 0
5099   {
5100     GtkWidget *window;
5101     GtkTreeViewColumn *col;
5102
5103     gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
5104
5105     col = gtk_tree_view_column_new_with_attributes ("foo",
5106         gtk_cell_renderer_text_new (),
5107         "text", 0, NULL);
5108     gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
5109
5110     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5111     g_signal_connect (window, "delete-event",
5112         G_CALLBACK (gtk_widget_destroy), NULL);
5113     g_signal_connect (window, "destroy",
5114         G_CALLBACK (gtk_main_quit), NULL);
5115
5116     gtk_container_add (GTK_CONTAINER (window), view);
5117
5118     gtk_widget_show (view);
5119     gtk_widget_show (window);
5120
5121     gtk_main ();
5122   }
5123 #endif
5124
5125   /* Cleanup */
5126   signal_monitor_free (monitor);
5127   g_object_unref (view);
5128   g_object_unref (store);
5129   g_object_unref (filter);
5130 }
5131
5132 /* main */
5133
5134 void
5135 register_filter_model_tests (void)
5136 {
5137   g_test_add ("/TreeModelFilter/self/verify-test-suite",
5138               FilterTest, NULL,
5139               filter_test_setup,
5140               verify_test_suite,
5141               filter_test_teardown);
5142
5143   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-1",
5144               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5145               filter_test_setup,
5146               verify_test_suite_vroot,
5147               filter_test_teardown);
5148   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-2",
5149               FilterTest, gtk_tree_path_new_from_indices (2, 3, -1),
5150               filter_test_setup,
5151               verify_test_suite_vroot,
5152               filter_test_teardown);
5153
5154
5155   g_test_add ("/TreeModelFilter/filled/hide-root-level",
5156               FilterTest, NULL,
5157               filter_test_setup,
5158               filled_hide_root_level,
5159               filter_test_teardown);
5160   g_test_add ("/TreeModelFilter/filled/hide-child-levels",
5161               FilterTest, NULL,
5162               filter_test_setup,
5163               filled_hide_child_levels,
5164               filter_test_teardown);
5165   g_test_add ("/TreeModelFilter/filled/hide-child-levels/root-expanded",
5166               FilterTest, NULL,
5167               filter_test_setup,
5168               filled_hide_child_levels_root_expanded,
5169               filter_test_teardown);
5170
5171   g_test_add ("/TreeModelFilter/filled/hide-root-level/vroot",
5172               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5173               filter_test_setup,
5174               filled_vroot_hide_root_level,
5175               filter_test_teardown);
5176   g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot",
5177               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5178               filter_test_setup,
5179               filled_vroot_hide_child_levels,
5180               filter_test_teardown);
5181   g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot-root-expanded",
5182               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5183               filter_test_setup,
5184               filled_vroot_hide_child_levels_root_expanded,
5185               filter_test_teardown);
5186
5187
5188   g_test_add ("/TreeModelFilter/empty/show-nodes",
5189               FilterTest, NULL,
5190               filter_test_setup_empty,
5191               empty_show_nodes,
5192               filter_test_teardown);
5193   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes",
5194               FilterTest, NULL,
5195               filter_test_setup_empty,
5196               empty_show_multiple_nodes,
5197               filter_test_teardown);
5198
5199   g_test_add ("/TreeModelFilter/empty/show-nodes/vroot",
5200               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5201               filter_test_setup_empty,
5202               empty_vroot_show_nodes,
5203               filter_test_teardown);
5204   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes/vroot",
5205               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5206               filter_test_setup_empty,
5207               empty_vroot_show_multiple_nodes,
5208               filter_test_teardown);
5209
5210
5211   g_test_add ("/TreeModelFilter/unfiltered/hide-single",
5212               FilterTest, NULL,
5213               filter_test_setup_unfiltered,
5214               unfiltered_hide_single,
5215               filter_test_teardown);
5216   g_test_add ("/TreeModelFilter/unfiltered/hide-single/root-expanded",
5217               FilterTest, NULL,
5218               filter_test_setup_unfiltered_root_expanded,
5219               unfiltered_hide_single_root_expanded,
5220               filter_test_teardown);
5221   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child",
5222               FilterTest, NULL,
5223               filter_test_setup_unfiltered,
5224               unfiltered_hide_single_child,
5225               filter_test_teardown);
5226   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/root-expanded",
5227               FilterTest, NULL,
5228               filter_test_setup_unfiltered_root_expanded,
5229               unfiltered_hide_single_child_root_expanded,
5230               filter_test_teardown);
5231   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level",
5232               FilterTest, NULL,
5233               filter_test_setup_unfiltered,
5234               unfiltered_hide_single_multi_level,
5235               filter_test_teardown);
5236   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/root-expanded",
5237               FilterTest, NULL,
5238               filter_test_setup_unfiltered_root_expanded,
5239               unfiltered_hide_single_multi_level_root_expanded,
5240               filter_test_teardown);
5241
5242   g_test_add ("/TreeModelFilter/unfiltered/hide-single/vroot",
5243               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5244               filter_test_setup_unfiltered,
5245               unfiltered_vroot_hide_single,
5246               filter_test_teardown);
5247   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot",
5248               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5249               filter_test_setup_unfiltered,
5250               unfiltered_vroot_hide_single_child,
5251               filter_test_teardown);
5252   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot/root-expanded",
5253               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5254               filter_test_setup_unfiltered_root_expanded,
5255               unfiltered_vroot_hide_single_child_root_expanded,
5256               filter_test_teardown);
5257   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot",
5258               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5259               filter_test_setup_unfiltered,
5260               unfiltered_vroot_hide_single_multi_level,
5261               filter_test_teardown);
5262   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot/root-expanded",
5263               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5264               filter_test_setup_unfiltered_root_expanded,
5265               unfiltered_vroot_hide_single_multi_level_root_expanded,
5266               filter_test_teardown);
5267
5268
5269
5270   g_test_add ("/TreeModelFilter/unfiltered/show-single",
5271               FilterTest, NULL,
5272               filter_test_setup_empty_unfiltered,
5273               unfiltered_show_single,
5274               filter_test_teardown);
5275   g_test_add ("/TreeModelFilter/unfiltered/show-single-child",
5276               FilterTest, NULL,
5277               filter_test_setup_empty_unfiltered,
5278               unfiltered_show_single_child,
5279               filter_test_teardown);
5280   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/root-expanded",
5281               FilterTest, NULL,
5282               filter_test_setup_empty_unfiltered_root_expanded,
5283               unfiltered_show_single_child_root_expanded,
5284               filter_test_teardown);
5285   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level",
5286               FilterTest, NULL,
5287               filter_test_setup_empty_unfiltered,
5288               unfiltered_show_single_multi_level,
5289               filter_test_teardown);
5290   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/root-expanded",
5291               FilterTest, NULL,
5292               filter_test_setup_empty_unfiltered_root_expanded,
5293               unfiltered_show_single_multi_level_root_expanded,
5294               filter_test_teardown);
5295
5296   g_test_add ("/TreeModelFilter/unfiltered/show-single/vroot",
5297               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5298               filter_test_setup_empty_unfiltered,
5299               unfiltered_vroot_show_single,
5300               filter_test_teardown);
5301   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot",
5302               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5303               filter_test_setup_empty_unfiltered,
5304               unfiltered_vroot_show_single_child,
5305               filter_test_teardown);
5306   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot/root-expanded",
5307               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5308               filter_test_setup_empty_unfiltered_root_expanded,
5309               unfiltered_vroot_show_single_child_root_expanded,
5310               filter_test_teardown);
5311   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot",
5312               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5313               filter_test_setup_empty_unfiltered,
5314               unfiltered_vroot_show_single_multi_level,
5315               filter_test_teardown);
5316   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot/root-expanded",
5317               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5318               filter_test_setup_empty_unfiltered_root_expanded,
5319               unfiltered_vroot_show_single_multi_level_root_expanded,
5320               filter_test_teardown);
5321
5322
5323   g_test_add ("/TreeModelFilter/unfiltered/rows-reordered/root-level",
5324               FilterTest, NULL,
5325               filter_test_setup_unfiltered,
5326               unfiltered_rows_reordered_root_level,
5327               filter_test_teardown);
5328   g_test_add ("/TreeModelFilter/unfiltered/rows-reordered/child-level",
5329               FilterTest, NULL,
5330               filter_test_setup_unfiltered,
5331               unfiltered_rows_reordered_child_level,
5332               filter_test_teardown);
5333
5334   g_test_add ("/TreeModelFilter/filtered/rows-reordered/root-level/first-hidden",
5335               FilterTest, NULL,
5336               filter_test_setup,
5337               filtered_rows_reordered_root_level_first_hidden,
5338               filter_test_teardown);
5339   g_test_add ("/TreeModelFilter/filtered/rows-reordered/root-level/middle-hidden",
5340               FilterTest, NULL,
5341               filter_test_setup,
5342               filtered_rows_reordered_root_level_middle_hidden,
5343               filter_test_teardown);
5344   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/first-hidden",
5345               FilterTest, NULL,
5346               filter_test_setup,
5347               filtered_rows_reordered_child_level_first_hidden,
5348               filter_test_teardown);
5349   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/middle-hidden",
5350               FilterTest, NULL,
5351               filter_test_setup,
5352               filtered_rows_reordered_child_level_middle_hidden,
5353               filter_test_teardown);
5354   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/4-hidden",
5355               FilterTest, NULL,
5356               filter_test_setup,
5357               filtered_rows_reordered_child_level_4_hidden,
5358               filter_test_teardown);
5359   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/all-hidden",
5360               FilterTest, NULL,
5361               filter_test_setup,
5362               filtered_rows_reordered_child_level_all_hidden,
5363               filter_test_teardown);
5364
5365   /* Inserts in child models after creation of filter model */
5366   g_test_add_func ("/TreeModelFilter/insert/before",
5367                    insert_before);
5368   g_test_add_func ("/TreeModelFilter/insert/child",
5369                    insert_child);
5370
5371   /* Removals from child model after creating of filter model */
5372   g_test_add_func ("/TreeModelFilter/remove/node",
5373                    remove_node);
5374   g_test_add_func ("/TreeModelFilter/remove/node-vroot",
5375                    remove_node_vroot);
5376   g_test_add_func ("/TreeModelFilter/remove/vroot-ancestor",
5377                    remove_vroot_ancestor);
5378
5379   /* Reference counting */
5380   g_test_add_func ("/TreeModelFilter/ref-count/single-level",
5381                    ref_count_single_level);
5382   g_test_add_func ("/TreeModelFilter/ref-count/two-levels",
5383                    ref_count_two_levels);
5384   g_test_add_func ("/TreeModelFilter/ref-count/three-levels",
5385                    ref_count_three_levels);
5386   g_test_add_func ("/TreeModelFilter/ref-count/delete-row",
5387                    ref_count_delete_row);
5388   g_test_add_func ("/TreeModelFilter/ref-count/cleanup",
5389                    ref_count_cleanup);
5390   g_test_add_func ("/TreeModelFilter/ref-count/row-ref",
5391                    ref_count_row_ref);
5392
5393   /* Reference counting, transfer of first reference on
5394    * first node in level.  This is a GtkTreeModelFilter-specific
5395    * feature.
5396    */
5397   g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/insert",
5398                    ref_count_transfer_root_level_insert);
5399   g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/reordered",
5400                    ref_count_transfer_root_level_reordered);
5401   g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/insert",
5402                    ref_count_transfer_child_level_insert);
5403   g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/reordered",
5404                    ref_count_transfer_child_level_reordered);
5405
5406   g_test_add_func ("/TreeModelFilter/specific/path-dependent-filter",
5407                    specific_path_dependent_filter);
5408   g_test_add_func ("/TreeModelFilter/specific/append-after-collapse",
5409                    specific_append_after_collapse);
5410   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-node",
5411                    specific_sort_filter_remove_node);
5412   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-root",
5413                    specific_sort_filter_remove_root);
5414   g_test_add_func ("/TreeModelFilter/specific/root-mixed-visibility",
5415                    specific_root_mixed_visibility);
5416   g_test_add_func ("/TreeModelFilter/specific/has-child-filter",
5417                    specific_has_child_filter);
5418   g_test_add_func ("/TreeModelFilter/specific/has-child-filter-on-sort-model",
5419                    specific_has_child_filter_on_sort_model);
5420   g_test_add_func ("/TreeModelFilter/specific/at-least-2-children-filter",
5421                    specific_at_least_2_children_filter);
5422   g_test_add_func ("/TreeModelFilter/specific/at-least-2-children-filter-on-sort-model",
5423                    specific_at_least_2_children_filter_on_sort_model);
5424   g_test_add_func ("/TreeModelFilter/specific/root-has-child-filter",
5425                    specific_root_has_child_filter);
5426   g_test_add_func ("/TreeModelFilter/specific/filter-add-child",
5427                    specific_filter_add_child);
5428   g_test_add_func ("/TreeModelFilter/specific/list-store-clear",
5429                    specific_list_store_clear);
5430   g_test_add_func ("/TreeModelFilter/specific/sort-ref-leaf-and-remove-ancestor",
5431                    specific_sort_ref_leaf_and_remove_ancestor);
5432   g_test_add_func ("/TreeModelFilter/specific/ref-leaf-and-remove-ancestor",
5433                    specific_ref_leaf_and_remove_ancestor);
5434   g_test_add_func ("/TreeModelFilter/specific/virtual-ref-leaf-and-remove-ancestor",
5435                    specific_virtual_ref_leaf_and_remove_ancestor);
5436
5437   g_test_add_func ("/TreeModelFilter/specific/bug-301558",
5438                    specific_bug_301558);
5439   g_test_add_func ("/TreeModelFilter/specific/bug-311955",
5440                    specific_bug_311955);
5441   g_test_add_func ("/TreeModelFilter/specific/bug-311955-clean",
5442                    specific_bug_311955_clean);
5443   g_test_add_func ("/TreeModelFilter/specific/bug-346800",
5444                    specific_bug_346800);
5445   g_test_add_func ("/TreeModelFilter/specific/bug-464173",
5446                    specific_bug_464173);
5447   g_test_add_func ("/TreeModelFilter/specific/bug-540201",
5448                    specific_bug_540201);
5449   g_test_add_func ("/TreeModelFilter/specific/bug-549287",
5450                    specific_bug_549287);
5451   g_test_add_func ("/TreeModelFilter/specific/bug-621076",
5452                    specific_bug_621076);
5453 }