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